; SAVE#D:MDOS.M65
; REN100,10
; ASM,,#D:MDOSDUP.OBJ
; ASM,#D:MDB4.LST,,#D:TEMP
; 
    .OPT NO LIST
    .SET 2,180
    .SET 3,0
    .SET 4,117
    .TITLE "  MyDOS 4.55     beta4        "
;
    .INCLUDE #D:MDOS1.M65
    .INCLUDE #D:MDOS2.M65
    .INCLUDE #D:MDOS3.M65
;
    .INCLUDE #D:MDUP1.M65
; nonresident portion of DUP
    .INCLUDE #D:MDUP2.M65
    .INCLUDE #D:MDUP3.M65
;
DUPEND = *
DUPLEN = DUPEND-DUPBASE
MSLEN = DUPEND-MSBASE
;
;   *=  $02E0
;   .WORD MENUSL
;
; SAVE#D:MDOS1.M65
; REN100,10
;
;   Copyright 1984, Charles Marslett, Wordmark Systems
; 
;  Permission is granted by the author for any use whatsoever of this
;    code, so long as this notice remains in the source code, and so
;    long as the source to this routine, however modified or unmodified,
;    is made available for a nominal cost.
;
;* Lee had to move quite a few of dup's equates here and change some
;* some labels so dos source could live with dup source within the
;* the same assemble run.  Plain lower case comments are Bob Puff's,
;* while mine (Lee's) will have both a star (*) and lower case.
; 
;  DEFINED VALUES
; 
CR  =   $9B     ;* 155 atari Carriage Return
EOF =   $88     ;* 136 End Of File error code
; 
OPEN =  3       ;* cio commands
GETREC = 5
GETCHR = 7
PUTCHR = 11
CLOSE = 12
REN =   32      ;* special xio numbers - rename
DEL =   33      ;* delete file
LOK =   35      ;* lock file
UNLOK = 36      ;* unlock file
FORM =  254     ;* format disk
; 
;  DISK I/O EQUATES
; 
FSTDRV = $31    ; SIO EQUATE FOR DISK DRIVE NUMBER ONE (D1:)
TODK =  $80     ; STATUS BYTE FOR A DATA TRANSFER TO THE DISK
FROMDK = $40    ; STATUS BYTE FOR A DATA TRANSFER FROM THE DISK
; 
READ =  'R      ; SIO COMMAND EQUATE FOR READING A DISK
WRITE = 'P      ; SIO COMMAND EQUATE FOR WRITING A DISK
RDSTAT = 'S     ; SIO COMMAND EQUATE FOR READING THE DRIVE STATUS
WRITEV = 'W     ; SIO COMMAND EQUATE FOR WRITING A DISK WITH VERIFICATION
FMTCMD = '!     ; SIO COMMAND TO FORMAT A DISKETTE
; 
LK128 = 125     ; LOCATION OF 128 BYTE SECTOR LINK
LK256 = 253     ; LOCATION OF 256 BYTE SECTOR LINK
; 
;  ZERO PAGE EQUATES
; 
WARMST = $08
DOSVEC = $0A
DOSINI = $0C
POKMSK = $10
BRKKEY = $11
BUFADR = $1A
; 
    *=  $20
ICHIDZ *= *+1
ICDNOZ *= *+1
ICCOMZ *= *+1
ICSTAZ *= *+1
ICBALZ *= *+1
ICBAHZ *= *+1
ICPTLZ *= *+2
ICBLLZ *= *+1
ICBLHZ *= *+1
ICAX1Z *= *+1
ICAX2Z *= *+1
    *=  *+2
CURFCB *= *+1
DATBYT *= *+1
; 
CHKSUM = $31
BUFR =  $32
; 
    *=  $43
FMSZPG *= *+2
DIRDSP = FMSZPG
DIRSEC = FMSZPG+1
CURFNO *= *+1
FMSBPT *= *+2
TMP1 *= *+1
TMP2 *= *+1
LMARGN = $52
RMARGN = $53
; 
FR0 =   $D4
VECTOR = FR0
HDBUF = $D6
BUFAD = $DA
BUFLEN = $DC
FNPTR = $DE
TEMP =  $E0
TEMP2 = $E1
; 
INBUFF = $F3
; 
;  DEFINITIONS FOR THE ATARI ROM EXECUTIVE
; 
VSERIN = $020A
VIMIRQ = $0216
CDTMV3 = $021C
CDTMF3 = $022A
SHFLOK = $02BE
RUNAD = $02E0
INITAD = $02E2
DSKTIM = $0246
RUNADR = $02E0
INIADR = $02E2
MEMTOP = $02E5
MEMLO = $02E7
DVSTAT = $02EA
; 
;  SIO COMMAND BUFFER DEFINITION
; 
    *=  $0300
DDEVIC *= *+1
DUNIT *= *+1
DCOMND *= *+1
DSTATS *= *+1
DBUFLO *= *+1
DBUFHI *= *+1
DTIMLO *= *+2
DBYTLO *= *+1
DBYTHI *= *+1
DAUX1 *= *+1
DAUX2 *= *+1
; 
;  I/O SYSTEM DEFINITIONS
; 
HATABS = $031A  ; BASE OF THE DYNAMIC HANDLER TABLE
; 
;  CIO COMMAND TABLE BASE DEFINITIONS (FOR IOCB $00)
; 
    *=  $0340
ICHID *= *+1
ICDNO *= *+1
ICCOM *= *+1
ICSTA *= *+1
ICBAL *= *+1
ICBAH *= *+1
ICPTL *= *+1
ICPTH *= *+1
ICBLL *= *+1
ICBLH *= *+1
ICAX1 *= *+1
ICAX2 *= *+1
ICSPR *= *+4
; 
;  CARTRIDGE SUBSYSTEM DEFINITIONS
; 
CARINIT = $BFFE ; LOCATION OF INIT VECTOR
CARTEST = $BFFC ; LOCATION OF FLAGS
CARRUN = $BFFA  ; LOCATION OF RUN VECTOR
; 
;  800XL MAP CONTROL
; 
MAPREG = $D301
PBCTL = $D303
; 
;  OTHER I/O PORT DEFINITIONS
; 
AUDF1 = $D200
AUDCTL = $D208
SKRES = $D20A
SERIN = $D20D
SEROUT = $D20D
IRQEN = $D20E
SKCTL = $D20F
NMIEN = $D40E
; 
;  ROM VECTORS
; 
FASCII = $D8E6
IFP =   $D9AA
EDITRV = $E400
DSKINV = $E453  ; OLD DISK I/O ENTRY POINT
CIOV =  $E456
SIOV =  $E459   ; SERIAL I/O ENTRY POINT
SETVBV = $E45C
CIOINV = $E46E
; 
;  DOS BOOTING CODE
; 
; 
;  DISK BOOT SECTORS (3)
; 
    *=  $0700   ; DOS.BOOT LOADS AT 0700
BOOTFL
    .BYTE "M"   ;* MyDOS 4.50 and above
;
BOOTL
    .BYTE 3     ; NUMBER OF SECTORS IN THE BOOT
;
BOOTAD
    .WORD BOOTFL ; ADDRESS OF BOOT CODE IN RAM
;
BOOTIN
    .WORD MDINIT
    JMP INBOOT  ; JUMP TO THE BOOT CONTINUATION
;
FILES
    .BYTE 3     ; NUMBER OF FILES THAT MAY BE OPEN AT ONCE
; DRIVES = *  ; USED TO BE BIT PATTERN FOR DRIVES
;
RAMDKU
    .BYTE 0     ; RAM DISK UNIT #
; BUFALC = *  ; USED TO BE BUF. ALLOC. DIR.
;
DFUNIT
    .BYTE 1     ; DEFAULT UNIT NUMBER
;
DOSEND
    .WORD RESEND ; ADDRESS OF THE FIRST BYTE OF FREE MEM.
;
SECDAT
    .BYTE 1     ; 1=128 BYTE SECTOR/2=256 BYTE SECTOR
;
DOSLOC
    .WORD 4     ; SECTOR ADDRESS OF DOS.SYS
;
DLINK
    .BYTE LK128 ; OFFSET TO THE SECTOR LINK FIELD
;
DOSAD
    .WORD BASE  ; ADDRESS TO LOAD DOS.SYS INTO
; 
INBOOT
    LDY DOSAD   ; SET UP START OF DOS AS BUFFER ADDRESS
    LDA DOSAD+1
    JSR BTSET   ; LOW ADDR IN Y, HIGH IN A
    LDA DOSLOC+1
    LDY DOSLOC  ; PUT DOS DISK ADDRESS INTO (A,Y)
; 
;  DOS.SYS INPUT LOOP
; 
INITLP
    CLC         ; CLEAR CY, 'DO A READ'
    LDX SECDAT  ; GET CODE FOR SECTOR SIZE
    BEQ NODOS   ; IF ZERO, NO DOS ON DISK!
    JSR DKIO    ; INVOKE DISK I/O ROUTINE
    BMI NODOS   ; IF AN ERROR, RETURN NO-DOS ERROR
    LDY DLINK   ; POINT TO LINK
    LDA (FMSZPG),Y ; CHECK FOR NEXT LINK (10-BITS)
ANDCD
    AND #$03    ; BEING ZERO, 00000011
    PHA         ; SAVE UPPER BYTE OF ADDRESS
    INY 
    ORA (FMSZPG),Y ; IF SO, LOADING IS COMPLETE
    BEQ BOOTXT
    LDA (FMSZPG),Y ; ELSE, IT'S THE ADDRESS OF NEXT SECTOR
    PHA         ; SAVE LOWER BYTE ON STACK
    JSR MVBUFR  ; THEN ADJUST THE BUFFER POINTER IN DCB
    PLA 
    TAY         ; RESTORE LOWER BYTE TO Y-REG
    PLA         ; RECOVER UPPER BYTE OF DISK ADDRESS
    BCC INITLP  ; AND CONTINUE LOADING
NODOS
    LDA #$C0    ; NO BOOT PROGRAM ERROR CODE
    .BYTE $A0   ; SKIP SINGLE BYTE (LDY #)
BOOTXT
    PLA 
DOSXIT
    ASL A       ; SET CARRY, CONVER CODE TO FINAL VALUE
    TAY         ; PUT CODE INTO Y-REG
    RTS         ; AND EXIT
; 
;  MOVE BUFFER POINTERS TO NEXT AREA TO BE LOADED
; 
MVBUFR
    LDA DLINK
    CLC 
    ADC FMSZPG  ; ADD DLINK TO THE CURRENT BUFFER ADDRESS
    TAY         ; LOW BYTE TO Y-REG
    LDA FMSZPG+1
    ADC #0
BTSET
    STY FMSZPG
    STA FMSZPG+1
BUFSET
    STY DBUFLO  ; STORE LOW BYTE INTO DCB
    STA DBUFHI  ; THEN UPPER BYTE
    RTS 
; 
;  PERFORM DISK READ (CY=0) OR WRITE (CY=1)
; 
DKIO
    STA DAUX2   ; STORE UPPER BYTE OF SECTOR ADDRESS
    STY DAUX1   ; THEN LOWER BYTE
DKIO2
    LDY #3
    LDA #READ
    BCC SETRTY  ; IF CY=0, READ INTO RAM
    LDA WRCMD
SETRTY
    STY TMP1    ; SET NUMBER OF TRIES
DKFME
    STA DCOMND
    CLC 
    LDA #WRITE  ; CLC AND CONSTANT FOR POKERS
WRCMD = *-1
    STY DTIMLO
    LDA #128    ; ASSUME A 128-BYTE SECTOR SIZE
    DEX 
    BEQ STBUFL
    LDX DAUX2   ; SECTOR > 256?
    BNE SET256
    LDX DAUX1
    CPX #4      ; SECTOR > 3
    BCC STBUFL  ; IF NOT
SET256
    ASL A       ; MAKE A 256 BYTE SECTOR SIZE
STBUFL
    STA DBYTLO
    ROL A
    STA DBYTHI
    LDY #FSTDRV ; PUT DISK DEVICE CODE INTO DCB
    STY DDEVIC
IORTRY
    DEC TMP1
    BMI DIOXIT
    LDX DCOMND
    INX 
    TXA 
    LDX #FROMDK ; ASSUME DATA ==> DISK
    AND #$06    ;    00000110
    BNE ISREAD  ; IF NOT X0,X7,X8 OR XF, OK
    LDX #TODK   ; ELSE, DATA ==> DISK
ISREAD
    STX DSTATS  ; RESTORE STATUS TO DCB
    JSR SIOV    ; DO THE I/O OPERATIONS
    DEY 
    BMI IORTRY  ; IF NOT OK, RETRY
DIOXIT
    LDX CURFCB  ; ELSE, LOAD FCB OFFSET AND STATUS
    INY 
    TYA 
    RTS 
; 
;  FIXED RAM DEFINITIONS IN BOOT SECTORS:
; 
DIUNIT *= *+1   ; UNIT NO. OF CURRECT DIRECTORY
CDIREC *= *+2   ; SECTOR NO. OF CURRECT DIRECTORY
HOLFN *= *+1
STATE
    .BYTE $70   ; DUP loaded, MEM.SAV inactive, Warmstart
;  bit 7 -- MEM.SAV in use            80
;  bit 6 -- DUP.SYS loaded            40
;  bit 5 -- AUTORUN.SYS already run   20
;  bit 4 -- Initial BUILD active      10
;*      $70 = 01110000
;*     bits   76543210             
; 
STKPSV *= *+1   ; SAVED STACK POINTER
; 
;*     *=  $07C0   ; MUST MATCH DUP LOCATION
; 
TRACKS
    .BYTE 35,40,80,77 ; TRACKS IN EACH DISK FORMAT
; 
;   00100011
;   00101000
;   01010000
;   01001101
;
;
SECSIZ
    .BYTE 0,0,0,0,0,0,0,0 ; BUFFER SIZE TABLE
; 
DRVDEF
    .BYTE $52,$52 ; DRIVE CONFIG TABLE:   01010010
    .BYTE $D2,$D2 ; BIT 7=1 => NO DRIVE   11010010
    .BYTE $D2,$D2 ; BIT 6=1 => ATARI 810 DRIVE
    .BYTE $D2,$D2 ; BITS 5-4 IS TRACKS (SEE ABOVE TABLE)
;  BIT 3=1 => DOUBLE DENSITY
;  BITS 2-1 ARE DRIVE STEP RATE
;  BIT 0=1 => DOUBLE SIDED
; 
;  DOS.SYS PROGRAM FOLLOWS
; 
DKEPT
    .WORD DKOPEN-1 ;* disk handler hatabs vectors
    .WORD DKCLOS-1 ;* open, close, get, put, status
    .WORD DKREAD-1 ;* and 'special' (>13) xio
    .WORD DKWRIT-1
    .WORD DKSTAT-1
    .WORD DKXIO-1
; 
;     *=  $07E0         ;* traditional DOS 2.0 INIT address
; 
;  DOS INITIALIZATION CODE
; 
; 
MDINIT
    LDA # <361  ; INITIALIZE THE CURRENT DIRECTORY
    STA CDIREC  ; TO THE ROOT DIRECTORY OF THE BOOT DRIVE
    LDA # >361
    STA CDIREC+1
; 
;  IDENTIFY DRIVE TYPES
; 
    LDX #8
IDRVLP
    STX DUNIT
    JSR ZERDVS  ; ASSUME THE DRIVE IS NOT PRESENT
    LDA DRVDEF-1,X
    BMI NXTDRV  ; IF IT IS NOT DECLARED, WAIT FOR AN ACCESS
    JSR JSTRD   ; ELSE READ IT'S STATUS
    BEQ NXTDRV  ; IF ABSENT, GO TO THE NEXT ONE
    LDY #9
WOTCPY
    LDA WOTDCB,Y
    STA DDEVIC+2,Y
    DEY 
    BPL WOTCPY
    LDA DRVDEF-1,X
    CMP #$40    ;   01000000
    BCS NXTDRV  ; IF NOT CONFIGURABLE, CONTINUE
    LDY SECSIZ-1,X
    JSR SETDRV  ; ELSE, TELL IT ABOUT MY CONFIGURATION
NXTDRV
    DEX         ; STEP TO NEXT DRIVE NUMBER
    BNE IDRVLP  ; IF MORE, LOOK AT THEM
; 
;  ZERO INITIALIZED MEMORY
; 
INITPT2
    LDY #MAPBUF+7-CHGMAP
    TXA         ; NOTE X=0 HERE
ZERLP1
    STA CHGMAP-1,Y
    DEY 
    BNE ZERLP1
    INC MAP2MOD
; 
;  DEFINE TOP OF FMS FOR USER PROGRAM
; 
    LDA DOSEND
    STA MEMLO
    LDY DOSEND+1
; 
;  ALLOCATE FILE SECTOR BUFFERS
; 
    LDX #15     ; MAX OF 16 SECTOR BUFFERS
DKBFLP
    CPX FILES   ; EMPTY BUFFERS DONE?
    BCC ALCBUF
    DEC BUFFLG,X
    BMI DKBFSQ
ALCBUF
    TYA 
    STA SBTABU,X
    INY 
DKBFSQ
    DEX         ; BUMP BUFFER COUNTER
    BPL DKBFLP  ; IF NOT CONTINUE LOOPING
    STY MEMLO+1 ; DEFINE TOP OF MEMORY USED
; 
;  SET UP HANDLER VECTOR
; 
FNDHND
    INX 
    INX 
    INX 
    LDA HATABS-2,X ; END OF THE HANDLER TABLE?
    BEQ NOHAND  ; THEN INSTALL IT HERE
    CMP #'D     ; A 'D' ALREADY PRESENT?
    BNE FNDHND  ; NO, CONTINUE LOOKING
NOHAND
    LDA #'D     ; END OF TABLE OR CURRENT 'D' ENTRY
    STA HATABS-2,X
    LDA # <DKEPT ; STASH MYDOS 4.55  ENTRY VECTOR
    STA HATABS-1,X
    LDA # >DKEPT
    STA HATABS,X ; BUILD HANDLER VECTOR
    JMP DUPIN   ; DONE, INITIALIZE DUP CODE
; 
; 
;  DOS NON-ZERO PAGE RAM ALLOCATIONS
; 
CHGMAP *= *+1
CURMAP *= *+1
MAP2 *= *+1
MAP2MOD *= *+1
LSTSEC *= *+2
LSTIOCB *= *+1
; 
;  MYDOS 4.50+  FCB STRUCTURE (ALMOST THE SAME AS ATARI DOS 2.0)
; 
FCBFNO *= *+1
FCBOTC *= *+1   ; OPEN TYPE CODE
FCBFLG *= *+1
MAXLEN *= *+1
CURLEN *= *+1
BUFNO *= *+1
CURSEC *= *+2
LNKSEC *= *+2
SECCNT *= *+2
DIRBAS *= *+2   ; BASE ADDRESS OF CUR. SECTOR
SAVSEC *= *+2
FCBLEN = 16
    *=  *+7*FCBLEN
; 
BUFFLG *= *+16  ; IF 0, BUFFER NOT IN USE
SBTABU *= *+16  ; UPPER BYTE OF THE SECTOR BUFFER ADDRESS
MAPBUF *= *+512 ; SPACE ALLOCATED FOR VTOC
DIRBUF = MAPBUF ; SPACE ALLOCATED TO READ DIRECTORIES
FNAME *= *+12
CURMP *= *+1
; 
; 
BASE =  *
HDTAB
    .WORD 0,0,0,0 ; 8 LOGICAL HARD DRIVES OF
    .WORD 0,0,0,0 ; UP TO 65535 SECTORS EACH
; 
; above table is referenced by DUP.SYS, and should not be moved!
; 
; 
;  DOS CONFIGURATION CODE
; 
; 
;  CONTROL BLOCK TO BE WRITTEN TO A DRIVE TO CONFIGURE IT
; 
WOTDCB
    .BYTE "N",$40
    .WORD DIRBUF,1
    .WORD 12,4
; 
;  FORCES A DRIVE INTO THE APPROPRIATE CONFIGURATION
; 
SETDRV
    AND #$3F    ; EXTRACT CONF. BITS   00111111
    STA TMP1
    STY TMP2
    JSR SIOV    ; READ CURRENT CONFIGURATION
    BMI JSTRD
    LDA TMP1
    LDY TMP2
    LSR A
    PHA         ; SAVE REMAINING BITS
    AND #3      ; EXTRACT STEP RATE CODE   00000011
    STA DIRBUF+1
    LDA #0
    STA DIRBUF+2
    ROL A
    STA DIRBUF+4 ; STORE DOUBLE SIDED FLAG
    TYA         ; GET DENSITY
    LSR A
    STA DIRBUF+6 ; STORE UPPER BYTE OF SECTOR SIZE
    ROR A
    STA DIRBUF+7 ; THEN LOWER BYTE
    ROL A
    ASL A
    ASL A
    STA DIRBUF+5
    PLA 
    LSR A
    LSR A
    LSR A       ; POSITION TRACK COUNT FIELD
    TAY 
    LDA TRACKS,Y ; GET NUMBER OF TRACKS
    STA DIRBUF
    AND #$04    ; SEE IF 77 TRACK 8 IN.   00000100
    PHA 
    LSR A
    ORA DIRBUF+5 ; MERGE D/DENSITY WITH 8 IN. FLAG
    STA DIRBUF+5
    PLA 
    ASL A       ; CONVERT TO 0 OR 8
    ADC #18     ; SECTOR COUNT = 18 OR 26
    STA DIRBUF+3
    LDY DUNIT
    LDA HDTAB-1+8,Y
    BEQ TOSIOV
    STA DIRBUF+2 ; SIZE = SECTORS/TK
    LDA HDTAB-1,Y
    STA DIRBUF+3 ; LOW BYTE OF SIZE
    LDA #1
    STA DIRBUF  ; ONE TRACK/DRIVE
TOSIOV
    INC DCOMND  ; CHANGE COMMAND TO WRITE
    LDA #$80
    STA DSTATS  ; SET DIRECTION -> DISK
    JSR SIOV    ; WRITE OPTION TABLE TO DRIVE
; 
;  AND THIS ROUTINE MAKES SURE IT REALLY DID HAPPEN AS WE THOUGHT!
; 
JSTRD
    LDA #'S
    STA DCOMND
    JSR DSKINV
    LDX DUNIT
    TYA 
    BMI ZERDVS
    LDA DVSTAT
    ASL A       ; SECTOR SIZE=256?
    ASL A
    ASL A
    LDA #1
    ADC #0
SETSIZ
    STA SECSIZ-1,X
    RTS 
; 
ZERDVS
    LDA #0
    BEQ SETSIZ  ; branch always
; 
;  DOS RAMDISK CODE
; 
; 
;  RAM DISK I/O HANDLER (POS. IND. CODE)
; 
MAPAGE
    .BYTE $E3,$E7,$EB,$EF
    .BYTE $83,$87,$8B,$8F
    .BYTE $C3,$C7,$CB,$CF
    .BYTE $A3,$A7,$AB,$AF
; 
    .BYTE $93,$97,$9B,$9F
    .BYTE $D3,$D7,$DB,$DF
    .BYTE $B3,$B7,$BB,$BF
    .BYTE $F3,$F7,$FB,$FF
; 
    .BYTE $E3,$E7,$EB,$EF
    .BYTE $83,$87,$8B,$8F
    .BYTE $C3,$C7,$CB,$CF
    .BYTE $A3,$A7,$AB,$AF
; 
    .BYTE $93,$97,$9B,$9F
    .BYTE $D3,$D7,$DB,$DF
    .BYTE $B3,$B7,$BB,$BF
    .BYTE $F3,$F7,$FB,$FF
; 
VALSEC
    PHA 
    TYA 
    ORA #$80
    LSR A
    STA BUFR+1
    SEI         ; DISABLE INT-S
    LDA #0
    STA NMIEN   ; DISABLE NMI-S
    ROR A
    STA BUFR
    PLA 
    TAY 
    LDA MAPREG
RDAD1 = *-2
;*  ORA #$1C    ;* applied Basic
    NOP         ;* patch to work
    NOP         ;* with large and
;*NMLMAP = *-1
    STA CHKSUM
;*  ORA #$7C    ;* unique RD
    NOP         ;* add filler nop
    NOP         ;* to remain
;*  AND MAPAGE,Y  ;* usable...
    LDA MAPAGE,Y ;* Lee
    STA MAPREG  ; SELECT RAMDISK DATA PAGE
RDAD2 = *-2
    LDA DBUFLO  ; USER BUFFER ADDRESS GOES HERE
    STA BUFR+2
    LDA DBUFLO+1
    STA BUFR+3
    LDY #0
    PLP 
    BCC RREADL  ; CY=0 IF READ
RWRITL
    LDA (BUFR+2),Y
    STA (BUFR),Y
    INY 
    BPL RWRITL
    BMI RIOX
RDKIO
    STY DAUX1   ; *** FOR FORMAT CODE ***
    CPY #$80
    ROL A
    CMP #4
RDKLMT = *-1    ; NUMBER OF 16K PAGES IN RAMDISK
    BCC VALSEC  ; CALCULATE MEM. ADDR.
    PLP 
    LDA #139    ;* garbage at serial port
    BMI RERROR
RREADL
    LDA (BUFR),Y
    STA (BUFR+2),Y
    INY 
    BPL RREADL
RIOX
    LDA CHKSUM  ; FORCE REAL RAM PAGE
    STA MAPREG  ; BEFORE EXITING
RDAD3 = *-2
    LDA #$C0    ; 11000000
    STA NMIEN   ; RE-ENABLE NMI
    CLI         ; ENABLE INTERRUPTS
    LDA #1      ; RETURN '1' IN Y-REG
RERROR
    STA DSTATS  ; AND IN STATUS BYTE
    LDX CURFCB  ; RESTORE FCB ADDR
    TAY 
    RTS         ; THEN EXIT
;
; SAVE#D:MDOS2.M65
; REN100,10
;
;  Copyright 1984, Charles Marslett, Wordmark Systems
; 
;  Permission is granted by the author for any use whatsoever of this
;    code, so long as this notice remains in the source code, and so
;    long as the source to this routine, however modified or unmodified,
;    is made available for a nominal cost.
; 
;  DISK OPEN ROUTINE
; 
DKOPEN
    JSR WBITMP  ; fix that nasty bug!
    JSR SETUP   ; SET UP BUFFER POINTERS, ETC.
    JSR GETFNM  ; GET DRIVE ID OR FILE NAME FROM BUFFER
    LDA ICAX1Z  ; GET TYPE OF OPEN FROM IOCB
    STA FCBOTC,X
    AND #$02    ; TEST DIRECTORY READ FLAG
    BEQ DKOPN1
    JMP LSTDIR  ; IF SET, GO HANDLE DIRECTORY FORMATTING
; 
DKOPN1
    STA SAVSEC,X
    STA SAVSEC+1,X ; ZERO SAVSEC
    JSR SFDIR
    PHP         ; SAVE STATUS RETURNED
    BCS OPNEW
    LDA #$10    ; MAKE SURE THIS IS NOT A DIRECTORY
    JSR GETFLAG
    BNE DIROPN  ; IF A DIRECTORY, GO HANDLE IT SEPERATELY
OPNEW
    LDY ICAX1Z
    CPY #8
    BEQ OPNOP   ; IF OPEN FOR OUTPUT
    CPY #4
    BEQ OPNIN   ; IF OPEN FOR INPUT
    CPY #12
    BEQ OPNUP   ; IF OPEN FOR READ/WRITE (UPDATE)
    CPY #9
    BEQ OPNAP   ; IF OPEN AND APPEND
DIROPN
    JMP ERRCMD  ; OTHERWISE, IT IS AN ERROR!
; 
OPNAP
    PLP         ; OPEN APPEND
    BCS OPNCR0
    JSR TSTLOK
    JSR INITYP  ; READ ALL THE SECTORS IN THE FILE
    LDA DIRBUF+1,Y
    STA SECCNT,X
    LDA DIRBUF+2,Y
    STA SECCNT+1,X
APPRD
    JSR RDNXTS
    BCC APPRD   ; IF NOT EOF, READ ANOTHER
    LDA MAXLEN,X
    JSR LENSET  ; SET LENGTHS FOR OUTPUT
    LDA SECCNT,X
    BNE SGLDEC
    DEC SECCNT+1,X
SGLDEC
    DEC SECCNT,X ; ALLOW FOR SECTOR REWRITTEN
    JMP OPOUTX
; 
OPNUP
    PLP         ; OPEN UPDATE (OUTPUT)
    BCS OPNER1
    JSR TSTLOK
OPNOWR
    JSR INSTRT
    JMP DONE
; 
OPNIN
    PLP         ; OPEN INPUT
    BCC OPNOWR
OPNER1
    LDA #170    ; FILE NOT FOUND
    BMI EROXIT
OPNOP
    PLP         ; OPEN (NORMAL) OUTPUT
    BCS OPNCR
    JSR REMOVE
    JMP GET1ST
; 
OPNCR0
    DEC FCBOTC,X
OPNCR
    LDA HOLFN
    STA CURFNO
    BMI OPDIRF
GET1ST
    JSR ALLOC
    LDA ICAX2Z  ; IF OUTPUT, TYPE OF FILE
    AND #$24    ; SAVE LOCKED & FORMAT BITS
    EOR #$43    ; MERGE IN DEFAULT CODE (DOS II, UNLOCKED)
    LDY MAPBUF  ; WHICH TYPE DISK?
    CPY #3      ; IF >2 THEN MYDOS 4.50+
    BCC LLINKS
    ORA #$04
LLINKS
    PHA 
    JSR RDCFNO  ; SELECT PROPER SECTOR IN DIRECTORY
    SEC 
    JSR ENTNAME ; ENTER NAME INTO IT
    LDA LNKSEC+1,X
    STA DIRBUF+4,Y
    LDA LNKSEC,X
    STA DIRBUF+3,Y
    PLA 
    JSR SAVFLAG
    JSR INITYP
    JSR TONXT
OPOUTX
    LDA #$80
    STA FCBFLG,X
    JSR TSTDOS  ; FILE NAME = DOS.SYS?
    BNE JDONE
    LDY CURSEC,X
    LDA CURSEC+1,X
    JSR SETDOS  ; IF SO, UPDATE BOOT SECTORS
    LDA DOSAD
    STA FMSZPG
    LDA DOSAD+1
    STA FMSZPG+1
    BNE OWTDOS  ; NOTE: DOS CANNOT START ON ZERO-PAGE
OPDIRF
    LDA #169
EROXIT
    JMP AEXIT
; 
LWTDOS
    JSR WRNXTS  ; AUTOMATICALLY WRITE DOS.SYS OUT
OWTDOS
    LDY #0      ;   IF WE OPEN IT FOR WRITE (THIS
CDOSBF
    LDA (FMSZPG),Y ;   IS BECAUSE DOS 2.0 WOULD BLOW
    STA (FMSBPT),Y ;   ITSELF AWAY IF A REAL WRITE FROM
    INY         ;   THE DOS CODE WAS ATTEMPTED AND
    CPY DLINK   ;   WE ARE GOING TO REMAIN COMPATIBLE).
    BCC CDOSBF
    TYA 
    STA CURLEN,X
    JSR MVBUFR
    CPY DOSEND
    SBC DOSEND+1
    BCC LWTDOS
JDONE
    JMP DONE
; 
;  READ DATA FROM A FILE
; 
DKREAD
    JSR SETUP   ; SET UP BUFFER POINTERS, ETC.
    LDA FCBOTC,X
    AND #$02    ; TEST THE DIRECTORY INPUT FLAG
    BEQ RDFILE  ; SO WE CAN HANDLE THE
    JMP DIRRD   ;   SPECIAL CASE OF A DIRECTORY READ
; 
RDFILE
    LDA CURLEN,X
    CMP MAXLEN,X
    BCC RDSGBT  ; IF NOT AT SECTOR BOUND., READ A BYTE AT A TIME
    BCS RDASNT  ; ELSE, CHECK FOR READ MODE AND BUFFER SIZE
RDASLP
    LDA ICCOMZ
    AND #$02
    BEQ RDSGBT  ; IF NOT BINARY I/O READ A BYTE AT A TIME
    LDY DLINK
    DEY 
RDSCLP
    LDA (FMSBPT),Y ; SIMULATED BURST I/O (USING UNROLLED LOOP)
    STA (ICBALZ),Y
    DEY 
    BNE RDSCLP
    LDA (FMSBPT),Y ;* rolled it back up
    STA (ICBALZ),Y
    JSR BUFADJ  ; ADJUST BUFFER POINTER BY 125 OR 253
RDASNT
    JSR RDNXTS  ; READ THE NEXT SECTOR
    BCS RETEOF  ; REPORT EOF/ERROR IF NECESSARY
    LDA ICBLLZ+1
    BNE RDASLP  ; AND REPEAT THE LOOP IF MORE THAN 256 BYTES LEFT
RDSGBT
    TAY 
    LDA (FMSBPT),Y ; FETCH DATA BYTE FROM THE BUFFER
    STA DATBYT  ; AND RETURN IT TO CIO
    INY 
    TYA 
    STA CURLEN,X ; BUMP CURLEN
    EOR MAXLEN,X
    ORA LNKSEC,X
    ORA LNKSEC+1,X
    BNE JDONE
    LDA #3      ; AND REPORT LAST BYTE IF IT IS SO!
    .BYTE $2C
RETEOF
    LDA #136    ; RETURN END OF FILE STATUS
    JMP AEXIT
; 
;  WRITE DATA TO A FILE
; 
DKWRIT
    STA DATBYT  ; SAVE DATA BYTE (PERHAPS)
    LDY ICDNO,X
    STY ICDNOZ  ; INSURE ICDNOZ IS SET UP (BASIC DOES NOT)
    JSR SETUPW  ; SET UP REST OF FLAGS AND POINTERS
    LDA FCBOTC,X
    AND #$08
    BEQ CANTWR  ; ERROR OUT IF WRITE IS ILLEGAL (BASIC AGAIN)
    LDA CURLEN,X
    TAY 
    CMP MAXLEN,X
    BCC SKBURST ; SKIP AROUND IF NOT WRITING END OF A SECTOR
WRASLP
    JSR WRNXTS  ; WRITE A SECTOR OF DATA
    BCS RETEOF  ; ERROR OUT IF NO MORE DISK SPACE
    LDY STKPSV
    LDA $0102,Y
    CMP #$C0    ; IF FROM BASIC
    BCC BASWRT  ; PASS SINGLE BYTES
    LDA FCBOTC,X ; fix open for update
    AND #4      ; bug in burst I/O
    BNE BASWRT
    LDA ICCOMZ
    AND #$02    ; AND IF RECORD I/O
    BEQ BASWRT  ; PASS SINGLE BYTES
    LDY ICBLLZ+1 ; AND IF THE BUFFER IS < 256 BYTES
    BEQ BASWRT  ; PASS SINGLE BYTES
    LDY MAXLEN,X
    DEY 
WRSCLP
    LDA (ICBALZ),Y ; ELSE DO SIMULATED BURST I/O
    STA (FMSBPT),Y ; BY UNROLLING THE LOOP
    DEY 
    BNE WRSCLP  ; BUT ONLY 2 ENTRIES FOR WRITING
    LDA (ICBALZ),Y ;* sorry, rolled it back up again
    STA (FMSBPT),Y
    JSR BUFADJ
    LDA (ICBALZ),Y
    STA DATBYT
    JMP WRASLP
; 
BASWRT
    LDY #0
SKBURST
    LDA DATBYT
    INC CURLEN,X
    STA (FMSBPT),Y
    LDA #$40
    ORA FCBFLG,X ; FOR UPDATE, SAY THE SECTOR HAS BEEN MODIFIED
    STA FCBFLG,X
    BNE TODONE  ; BRANCH ALWAYS!
CANTWR
    JMP ERRCMD
; 
BUFADJ
    CLC 
    LDA MAXLEN,X
    STA CURLEN,X
    ADC ICBALZ
    STA ICBALZ
    BCC RBAOK
    INC ICBALZ+1
RBAOK
    SEC 
    LDA ICBLLZ
    SBC MAXLEN,X
    STA ICBLLZ
    BCS RBLOK
    DEC ICBLLZ+1
RBLOK
    RTS 
; 
;  RETURN FILE STATUS
; 
DKSTAT
    JSR SETUP   ; SET UP RETURN ADDRESS, ETC.
    JSR LFFILE  ; FIND IF FILE IS THERE, ETC.
    JSR TSTLOK  ; IS IT LOCKED?
TODONE
    JMP DONE    ; RETURN TO CALLER
; 
;  CLOSE FILE (WRITING ANY PENDING SECTOR)
; 
DKCLOS
    JSR SETUP
    LDA FCBOTC,X
    AND #$08    ; OUTPUT ALLOWED?
    BEQ CLROTC  ; IF NOT, JUST EXIT
    ROL FCBFLG,X
    BCC CKFLSC
    JSR REWRIT  ; REWRITE THE LAST SECTOR
    JSR RRDIR
    LDA SECCNT,X
    LDY DIRDSP
    STA DIRBUF+1,Y
    LDA SECCNT+1,X
    STA DIRBUF+2,Y
    LDA DIRBUF,Y
    AND #$FE    ; NOT OPEN FOR OUTPUT ANY MORE
    JSR SAVFLAG
    LDA SAVSEC,X
    ORA SAVSEC+1,X
    BEQ CLROTC
    CPX LSTIOCB
    BEQ FAPPD
    JSR INITYP  ; READ ALL THE SECTORS AGAIN
APPLP
    JSR RDNXTS
    BCC APPLP   ; NOT EOF YET
    BCS TIELNK
FAPPD
    LDA LSTSEC
    STA CURSEC,X
    LDA LSTSEC+1
    STA CURSEC+1,X
TIELNK
    CLC 
    JSR RWDISK
    LDA DLINK
    STA CURLEN,X
    LDA SAVSEC,X
    LDY SAVSEC+1,X
    JSR SAVLNK
CLROTE
    BPL CLROTC
    LDA #163    ; FAILURE IS A SYSTEM ERROR
    JMP AEXIT
;
CLROTC
    LDA #$FF
    STA ICHID,X
    LDA #0
    STA FCBOTC,X
    JMP FREDON
; 
CKFLSC
    ROL FCBFLG,X
    BCC CLROTC
    JSR WRDISK
    JMP CLROTE
; 
INITYP
    LDA #$06
    JSR GETFLAG
    LSR A
    ROR A
    ROR A
    ROR A
    ORA FCBOTC,X
    STA FCBOTC,X
    LDA DIRBUF+3,Y
    STA LNKSEC,X
    LDA DIRBUF+4,Y
    STA LNKSEC+1,X
    LDA CURFNO
    STA FCBFNO,X
    LDA #0
    STA FCBFLG,X
    STA CURLEN,X
    STA SECCNT,X
    STA SECCNT+1,X
    RTS 
; 
;  DOS XIO ROUTINES
; 
; 
;  Sorry about the lack of comments in this file and some of the others,
;    I just never had to figure this code out after I wrote it (:-)!
; 
NODIRF
    LDA #176    ; FILE NOT A DIRECTORY
    JMP AEXIT
; 
PIKDIR
    LDY #0
    LDA #':
FDVND
    INY 
    CMP (ICBALZ),Y
    BNE FDVND
    INY 
    LDA (ICBALZ),Y
    CMP #'@
    BCC SETRDIR
    CMP #'Z+1
    BCC GFNDIR
    CMP #'_
    BCC SETRDIR
    CMP #'z+1
    BCS SETRDIR
GFNDIR
    JSR LFFILE  ; FIND NEW DEFAULT DIRECTORY
    JSR INITYP
    JSR TONXDR
    BEQ NODIRF  ; IF NOT A DIRECTORY
    LDA DIRBAS+1,X
    TAY 
    LDA DIRBAS,X
SAVDEF
    STY CDIREC+1 ; UPDATE ADDRESS OF DIR.
    STA CDIREC
    LDA ICDNOZ
    STA DFUNIT  ; UPDATE UNIT NUMBER
    ORA #'0     :*
    STA DEFAULT+1 ;*
    LDX #0      ;*
    LDY #0      ;*
    LDA (ICBALZ),Y ;*
    CMP #'D     ;*
    BNE BKSUB3  ;*
    INY         ;* copied here from
    LDA #':     ;* dup.sys
    CMP (ICBALZ),Y ;*
    BNE ALLNEW  ;* IF NOT SUBDIRECTORY
FNDEND
    INX         ;*
    LDY DNAME-1,X ;*
    BNE FNDEND  ;* END OF OLD DIR?
    STA DNAME-1,X ;*
ALLNEW
    INY         ;*
    CMP (ICBALZ),Y ;*
    BNE ALLNEW  ;*
    DEX         ;* POINT BACK AT ':'
    BEQ CPY1ST  ;* IF START, NO ':' TO PRESERVE
CPYNAM
    INX         ;*
CPY1ST
    INY         ;*
    LDA (ICBALZ),Y ;*
    STA DNAME,X ;*
    BNE CPYNAM  ;* end of dup.sys code
    BEQ BKSUB3  ;* this is Lee's
BKSUB
    INY         ;*
    STA (ICBALZ),Y ;*
    LDX #DNAMLEN+2 ;*
BKSUB1
    DEX         ;*
    LDA DNAME-1,X ;*
    BEQ BKSUB1  ;*
BKSUB2
    LDA DNAME-1,X ;*
    DEX         ;*
    BEQ BKSUB3  ;*
    CMP #':     ;*
    BNE BKSUB2  ;*
BKSUB3
    LDA #0      ;*
BKSUB4
    STA DNAME,X ;*
    INX         ;*
    CPX #DNAMLEN+1 ;*
    BNE BKSUB4  ;*
XIT41
    BEQ TOFDN   ;*
SETRDIR
    CMP #':     ;*
    BEQ BKSUB   ;*
    LDA #0      ;*
    STA (ICBALZ),Y ;*
    LDA # <361
    LDY # >361
    BPL SAVDEF
;
RENAME
    JSR LFFILE  ; GET OLD NAME, DRIVE, VALIDATE
    LDY #11
STEMPL
    LDA FNAME-1,Y
    STA MAPBUF+256,Y
    DEY 
    BNE STEMPL
RNLOOP
    JSR TSTLOK  ; CANNOT RENAME IF LOCKED
    JSR TDDOS   ; TEST FOR DOS GONE!
    LDY TMP2
    JSR GETNAM  ; GET NEW NAME
    CLC 
    JSR ENTNAME ; OVERWRITE NAME IN DIR.
    JSR WDIRBK  ; REWRITE DIRECTORY TO DISK
    JSR TSTDOS  ; NEW NAME DOS.SYS?
    BNE REPLDS  ; NO, LOOK AT NEXT
    LDY DIRDSP
    LDA DIRBUF+4,Y
    PHA 
    LDA DIRBUF+3,Y
    TAY 
    PLA 
    JSR SETDOS  ; ELSE, UPDATE BOOT SECTORS
REPLDS
    LDY #11
RTEMPL
    LDA MAPBUF+256,Y
    STA FNAME-1,Y
    DEY 
    BNE RTEMPL
    JSR CSFDIR  ; TO RENAME
    BCC RNLOOP
    BCS TOFDN
DELETE
    JSR LFFILE
DELLP
    JSR REMOVE  ; FLUSH THE SECTORS
    JSR RRDIR   ; REREAD DIRECTORY BLOCK
    JSR TDDOS   ; DOS.SYS DELETED?
    LDA #$80
    JSR SAVFLAG ; REWRITE DIRECTORY BLOCK
    JSR CSFDIR
    BCC DELLP   ; IF ANOTHER FOUND,
TOFDN
    JMP FREDON  ; ELSE, WRAP UP AND EXIT
; 
REMOVE
    JSR TSTLOK  ; ONCE HAD 'OPVTOC' CALL FIRST
    JSR INITYP
    JSR TONXDR
    BNE DELDIR
    JSR CHASE
D0C6C
    JSR FREE
    JSR RDNXTS
    BCC D0C6C
    RTS 
; 
INVDEL
    LDA #175    ; DIRECTORY NOT DELETABLE
    JMP AEXIT
; 
LOCK
    LDA #$20
    .BYTE $2C   ; BIT ABS (SKIP 2 BYTES)
UNLOCK
    LDA #$00
    STA DATBYT
    JSR LFFILE  ; FIND FILE AND VERIFY WRITABLE
LKULKL
    LDA #$DF    ; STRIP OFF OLD BIT 5
    JSR GETFLAG
    ORA DATBYT  ; AND REPLACE WITH NEW
    JSR SAVFLAG
    JSR CSFDIR
    BCC LKULKL
    BCS TOFDN
DELDIR
    LDY #-11
    LDA #'?
DELSET
    STA FNAME+11-256,Y
    INY 
    BNE DELSET
    JSR SFDIR
    BCC INVDEL
    LDA #8
    STA DATBYT
    JSR TONXT
DELDRL
    JSR FREE
    JSR INCCSEC
    DEC DATBYT
    BNE DELDRL
    JMP GETFNM
;
POINT
    LDY FCBFLG,X
    BMI ERRCMD
    LDA ICSPR+1,X
    CMP CURSEC+1,X
    BNE PNTREAD
    LDA ICSPR,X
    CMP CURSEC,X
    BEQ PNTSME
PNTREAD
    TYA 
    BEQ PNTCLN  ; IF SECTOR UNMODIFIED
    JSR WRDISK
    LDA #0
    STA FCBFLG,X
PNTCLN
    LDA ICSPR+1,X
    STA LNKSEC+1,X
    LDA ICSPR,X
    STA LNKSEC,X
    JSR CHASE   ; READ SECTOR POINTED TO
    BCS BADPNT
PNTSME
    LDA ICSPR+2,X
    CMP MAXLEN,X
    BCS PNTEQL
PNTLST
    STA CURLEN,X
    JMP DONE
;
PNTEQL
    BEQ PNTLST  ; IF POINTING AT LAST BYTE
BADPNT
    LDA #166    ; INVALID POINT LOCATION
    .BYTE $AE
ERRCMD
    LDA #168    ; INVALID IOCB PARAMETER
    JMP AEXIT
; 
NOTE
    LDA CURSEC,X
    STA ICSPR,X
    LDA CURSEC+1,X
    STA ICSPR+1,X
    LDA CURLEN,X
    STA ICSPR+2,X
    JMP DONE
;
DKXIO
    JSR SETUP
    LDA ICCOMZ  ; GET COMMAND BYTE
    CMP #254
    BEQ FORMAT
    CMP #43
    BCS ERRCMD  ; IF INVALID COMMAND
    SBC #32-1
    BCC ERRCMD
    TAY 
    LDA VECTBH,Y
    PHA 
    LDA VECTBL,Y
    PHA 
    RTS         ; VECTOR TO PROPER ROUTINE
;
VECTBH
    .BYTE  >RENAME-1, >DELETE-1
    .BYTE  >MKDIR-1, >LOCK-1
    .BYTE  >UNLOCK-1, >POINT-1
    .BYTE  >NOTE-1, >DKLOAD-1
    .BYTE  >DKLOAD-1, >PIKDIR-1
    .BYTE  >MKDIR-1
; 
VECTBL
    .BYTE  <RENAME-1, <DELETE-1
    .BYTE  <MKDIR-1, <LOCK-1
    .BYTE  <UNLOCK-1, <POINT-1
    .BYTE  <NOTE-1, <DKLOAD-1
    .BYTE  <DKLOAD-1, <PIKDIR-1
    .BYTE  <MKDIR-1
; 
;  DOS FORMAT ROUTINES
; 
; 
FORMAT
    JSR WBITMP  ; WRITE OUT ANY PENDING VTOC SECTORS
    LDY #9      ; force format to match current density
WOTCOPY2
    LDA WOTDCB,Y ; set up DCB for
    STA DDEVIC+2,Y ; density stuff
    DEY 
    BPL WOTCOPY2
    LDX ICDNOZ
    CPX RAMDKU
    BEQ WOTRAM  ; don't do it for RAMdisks
    LDY SECSIZ-1,X
    LDA DRVDEF-1,X
    JSR SETDRV  ; set density
WOTRAM
    LDX CURFCB  ; restore X reg
    LDY #0
    TYA         ; THEN INITIALIZE NEW BIT MAP (VTOC)
CLRMAP
    STA MAPBUF,Y
    STA MAPBUF+256,Y
    INY 
    BNE CLRMAP  ; ALLOCATING ALL POSSIBLE BITS
    LDA #2
    STA MAPBUF  ; DEFINE IT AS A DOS 2.0 DISK
    LDA #$FF
    STA (FMSBPT),Y
    INY 
    STA (FMSBPT),Y ; PRESUME NO BAD SECTORS IF BUFFER IS UNMODIFIED
    LDY ICDNOZ
    CPY RAMDKU
    BEQ RAMFMT  ; IF RAMDISK, SKIP EVERYTHING
    LDA FMSBPT+1
    LDY FMSBPT  ; call density junk for patch
    JSR BUFSET  ; SET UP BUFFER POINTER FOR SIO CALL
    LDX #1
    STX TMP1    ; ALLOW ONE TRY ONLY
    LDA #34     ; PRESUME 1050 ED FORMAT REQUEST
    LDY ICAX2Z  ; THEN GET AUX2 BYTE
    BMI FMTOK   ; MINUS --> NO FORMAT REQUIRED
    BNE NMLFMT
    LDY ICAX1Z  ; (AUX2,AUX1) = 1?
    DEY 
    BEQ FT1050  ; YES, FORMAT WITH $22 COMMAND BYTE
NMLFMT
    LDX DUNIT
    LDA SECSIZ-1,X
    TAX 
    LDA #FMTCMD ; AUX IS 0, must not be 1050 ED
FT1050
    STA DAUX1   ; MAKE SURE WE SECTOR > 3
    LDY DSKTIM  ; DISK TIMEOUT VALUE (RETURNED IN STATUS)
    JSR DKFME   ; ENTER DKIO AT FORMAT ENTRY
    BPL FMTOK   ; delete bad sector check
FMEXIT
    JMP AEXIT   ; ELSE, RETURN ERROR CODE
; 
RAMFMT
    STA CURSEC,X ; STUFF PROPER NUMBER OF SECTORS INTO CURSEC
    CLC         ; (256-BYTE PAGES * 2 SINCE SECTOR SIZE IS 128)
    ADC RDKLMT
    LSR A
    ROR CURSEC,X
    BNE NOTDEF  ; FAIL IF NOT 256 SECTORS OR MORE
; 
;  SUCCESSFUL FORMAT, CREATE VTOC AND EMPTY DIRECTORY
; 
FMTOK
    LDY #0      ; check for a bad format
    LDA (FMSBPT),Y
    INY 
    AND (FMSBPT),Y ; first two bytes $FF?
    CMP #$FF
    BEQ FMTOK2  ; yep, continue
    LDA #173    ; otherwise format error
    BNE FMEXIT
FMTOK2
    JSR INVUNIT ; make sure we can to this!
    JSR DELDOS  ; DELETE ANY CURRENT DOS BOOT FILE
    LDA ICAX1Z
    STA CURSEC,X
    LDA ICAX2Z
    AND #$7F    ; DISK MUST HAVE 256 SECTORS
    BNE NOTDEF  ; IF SIZE SPECIFIED, USE IT
    LDY ICDNOZ
    LDA HDTAB-1,Y ; IF NOT AND THIS IS A HARD DISK
    STA CURSEC,X ; USE THE DEFINED SIZE
    LDA HDTAB+8-1,Y
    BNE NOTDEF
    BIT DVSTAT  ; ELSE, IS IT A 1050 DRIVE?
    BPL FIGSIZ  ; NO, FIGURE SIZE THEN
    LDA # <1040 ; YES, FORCE TO 1040 SECTORS
    STA CURSEC,X
    LDA # >1040
    BNE NOTDEF
FIGSIZ
    LDA DRVDEF-1,Y
    AND #$31    ; EXTRACT TRACK COUNT FLAGS   00110001
    LSR A
    PHP 
    LSR A
    LSR A
    TAY 
    LDA NOSECS,Y ; AND USE DRIVE DEFAULT SECTOR COUNT
    STA CURSEC,X
    LDA NOSECS+1,Y
    PLP 
    BCC NOTDEF  ; IF NOT DOUBLE SIDED, THIS IS IT
    ASL CURSEC,X
    ROL A       ; ELSE, DOUBLE IT
NOTDEF
    STA CURSEC+1,X
    CMP #4      ; NEED 16 BIT LINKS?
    BCC SHORTS  ; NO, SHORT FORMAT OK * dos2.0 type
    INC MAPBUF  ; YES, FORCE LONG FORMAT * MyDOS 3 type
SHORTS
    JSR FNDBIT  ; FIND LAST BIT MAP SECTOR
    LDA TMP2
    BNE GT246   ; IF PAST 256TH MAP BYTE
    BIT DLINK   ; SINGLE DENSITY?
    BMI FDBDEN
    CPY #0
    BPL FDBDEN
GT246
    STA MAP2
    CLC        
    ADC #3      
    STA MAPBUF 
FDBDEN
    LDA # >-9
    STA MAPBUF+4
    LDA # <-9
    STA MAPBUF+3 ; START WITH 9 FREE SECTORS UN-FREE!
FLOOP
    JSR FMTFRE
    JSR DECCSEC
    CMP #4      ; BOOT SECTORS YET?
    BNE FLOOP   ; IF NOT, CONTINUE DEALLOCATING
    LDA CURSEC+1,X
    BNE FLOOP
    LDA #1      ; success
    STA FMSBPT  ; bad sector code deleted here
    LDA #$00
    STA MAPBUF+55 ; ALLOCATE THE ROOT DIRECTORY AND BASE VTOC SEC.
    LDA #$7F    ;   NOTE: ALWAYS THE SAME 9 SECTORS
    STA MAPBUF+56
    LDY #44     ; START ALLOC. OF VTOC HERE
    LDA MAPBUF
    SEC
    SBC #2      ; GET NUMBER OF SECTORS
    BIT DLINK   ; (SINGLE DENSITY?)
    BMI MPNSD   ; IF NOT, M-3
    ASL A       ; IF SO, M*2-5
MPNSD
    TAX
    DEX         ; MOVE COUNT TO X
ALCMPL
    LDA #$FF
ALCMAP
    DEX 
    BMI SMBSIZ
    PHA 
    JSR DECCNT
    PLA 
    ASL A
    BNE ALCMAP
    STA MAPBUF+10,Y
    DEY 
    BPL ALCMPL  ; BRANCH ALWAYS!
SMBSIZ
    STA MAPBUF+10,Y
    LDA MAPBUF+3 ; MARK EMPTY SIZE, TOO
    STA MAPBUF+1
    LDA MAPBUF+4
    STA MAPBUF+2
    JSR FMTMAP  ; WRITE MAP TO DISK
; 
;  CREATE AN EMPTY DIRECTORY
; 
    LDA # <361
    LDY # >361
CLRDIR
    JSR SETDIR  ; RESET THE DIRECTORY BASE SECTOR
    TYA 
CLRDLP
    STA DIRBUF,Y ; ZERO THE BUFFER
    INY 
    BNE CLRDLP
    LDA #7
    STA DIRSEC
CLRDL2
    JSR WDIRBK  ; THEN WRITE 8 SECTORS OF ZEROS
    DEC DIRSEC
    BPL CLRDL2
    LDY BUFNO,X
    LDA #0
    STA BUFNO,X
    STA BUFFLG-1,Y ; DONE, SO FREE UP INTERNAL BUFFERS
    LDA FMSBPT
    JMP AEXIT
; 
NOSECS
    .WORD 35*18,40*18,80*18,77*26
; 
SETDIR
    STA DIRBAS,X
    TYA 
    STA DIRBAS+1,X
    LDY #0
    RTS 
; 
;  DOS BINARY LOAD CODE
; 
; 
;  LOAD AND EXECUTE A BINARY FILE (PROGRAM)
; 
DKLOAD
    LDA ICAX1Z
    STA ICPTLZ  ; SAVE PROGRAM NAME BUFFER POINTER
    CMP #$08
    BCS TOERRC  ; IF WRITE, REPORT ERROR
    LDA # <TORTS
    STA RUNADR
    LDA # >TORTS ; ASSUME RUN ADDRESS IS ABSENT
    STA RUNADR+1
    LDA #4
    STA ICAX1Z
    LDA ICHID,X ; IOCB OPEN?
    BPL CCFILE
    JSR DKOPEN  ; IF NOT, OPEN IT
    BMI DKLERV
    JSR WDREAD  ; READ A HEADER WORD
    BEQ CCFILE
    LDY #180    ; NO $FFFF, REPORT HEADER ERROR CODE
    BMI DKLERV
TOERRC
    LDY #168    ; INVALID IOCB
    RTS 
; 
GETTXT
    LDA # <TORTS
    STA INIADR
    LDA # >TORTS ; FOR EACH SEGMENT, RE-FORCE NULL INIT CODE
    STA INIADR+1
TXTLP
    JSR DKREAD
DKLERV
    BMI DKLERR
    LDY #0
    STA (ICBALZ),Y
    INC ICBALZ
    BNE DECLEN
    INC ICBAHZ
DECLEN
    LDA ICBLLZ
    BNE DECLOW
    DEC ICBLHZ
DECLOW
    DEC ICBLLZ
    BNE TXTLP
    LDA ICBLHZ
    BNE TXTLP
    LDA ICBAHZ
    CMP # >INIADR
    BNE CCFILE
    LDA ICPTLZ  ; IF NO INITS,
    LSR A
    BCS CCFILE  ; SKIP TO NEXT PAGE
    TXA         ; ELSE SAVE IOCB
    PHA 
    LDY #256-12
CPSICB
    LDA ICHIDZ-256+12,Y
    STA ICHID,X ; SAVE 12 BYTE IOCB ENTRY
    INX 
    INY 
    BNE CPSICB
    PLA 
    TAX 
    PHA 
    JSR DOINIT  ; AND CALL INIT FUNCTION
    PLA 
    TAX 
    PHA 
    LDY #256-12
CPRICB
    LDA ICHID,X ; THEN RESTORE THE 12 BYTE IOCB
    STA ICHIDZ-256+12,Y
    INX 
    INY 
    BNE CPRICB
    PLA 
    TAX 
CCFILE
    JSR WDREAD  ; READ START ADDRESS
    BEQ CCFILE
    STA ICBALZ
    STY ICBAHZ
    JSR WDREAD  ; READ END ADDRESS
    SEC 
    ADC #0
    BCC CCSUBT
    INY 
CCSUBT
    SEC 
    SBC ICBALZ  ; CALCULATE THE LENGTH
    STA ICBLLZ
    TYA 
    SBC ICBAHZ
    STA ICBLHZ
    BCS GETTXT  ; BRANCH IF A VALID LENGTH (GET DATA)
    LDY #181    ; ELSE, MEMORY WRAP ERROR CODE
    BMI DKLERR
WDXIT
    PLA 
    PLA 
DKLERR
    TYA 
    PHA 
    JSR DKCLOS  ; CLOSE PROGRAM FILE
    PLA 
    TAY         ; AND RETURN HIS ERROR CODE (IF ANY)
    RTS 
; 
;  READ A WORD FROM THE PROGRAM FILE AND COMPARE IT WITH $FFFF
; 
WDREAD
    LDA #0
    STA ICBLLZ
    STA ICBLHZ  ; SET LENGTH TO ZERO
    JSR DKREAD  ; READ A BYTE
    BMI WDEOF
  PHA 
  JSR DKREAD  ; READ THE SECOND
  BMI WDEOF1
  TAY 
  PLA 
  CPY #$FF    ; UPPER BYTE $FF?
  BNE TORTS   ; IF NOT, TOTAL VALUE IS NOT $FFFF
  CMP #$FF    ; UPPER OK, IS LOWER BYTE $FF?
TORTS
  RTS         ; RETURN ZERO FLAG IF WORD WAS $FFFF
;
WDEOF1
  PLA 
WDEOF
  CPY #136    ; IS THIS END OF FILE?
  BNE WDXIT   ; IF NOT, RETURN ERROR CODE
  PLA 
  PLA         ; ELSE, GET RID OF RETURN ADDR
  LDA ICPTLZ
  LSR A
  LSR A
  PHP 
  JSR DKCLOS  ; CLOSE FILE AND SET Y=1
  PLP 
  BCS TORTS   ; EXIT IF NO-RUN SPECIFIED
  JMP (RUNADR) ; OTHERWISE, GO TO RUN ADDRESS
; 
;  INVOKE INIT FOR EVERY BLOCK OF INPUT CODE (USUALLY JUST AN RTS)
; 
DOINIT
  JMP (INIADR) ; CALL INDIRECT
;
; SAVE#D:MDOS3.M65
; REN100,10
; 
;  DOS MAKE DIRECTORY CODE
; 
;  Copyright 1984, Charles Marslett, Wordmark Systems
; 
;  Permission is granted by the author for any use whatsoever of this
;    code, so long as this notice remains in the source code, and so
;    long as the source to this routine, however modified or unmodified,
;    is made available for a nominal cost.
;
; 
;  XIO FUNCTION TO CREATE A NEW DIRECTORY
; 
;  PARSE DIRECTORY NAME
; 
MKDIR
    JSR GETFNM
    JSR SFDIR   ; FIND FILE IN DIRECTORY
    BCS MKDMRD
    LDA #174    ;* duplicate file
    .BYTE $AE   ; SKIP 2 BYTES
DISFUL
    LDA #169    ; DIRECTORY FULL
    JMP AEXIT
; 
;   READ IN BIT MAP
; 
MKDMRD
    LDA HOLFN
    BMI DISFUL
    JSR RBITMP
    LDY MAPBUF
    DEY 
    DEY 
    STY DATBYT
; 
;   FIND EIGHT SECTORS FOR DIRECTORY
; 
    LDA # <369  ; FIRST AVAILABLE SECTOR AFTER ROOT DIR.
    STA CURSEC,X
    LDA # >369
    STA CURSEC+1,X
    LDA #0
    STA TMP1
FDIRLP
    INC TMP1
    JSR FNDLBIT ; IS THIS SECTOR FREE?
    BCS FDIR2
    AND MAPBUF,Y
    BCC FDIR1
FDIR2
    AND MAPBUF+256,Y
FDIR1
    BNE FDIR3
    STA TMP1
FDIR3
    JSR INCCSEC
    LDA TMP1
    CMP #8
    BNE FDIRLP
; 
;  ALLOCATE THE SECTORS USED
; 
ALCDLP
    JSR DECCSEC
    JSR FNDLBIT
    EOR #$FF
    BCS ALCPG2
    AND MAPBUF,Y
    STA MAPBUF,Y
    BCC ALCPG1
ALCPG2
    AND MAPBUF+256,Y
    STA MAPBUF+256,Y
    LSR MAP2MOD
ALCPG1
    JSR DECCNT
    DEC TMP1
    BNE ALCDLP
; 
;  WRITE ALLOCATION MAP BACK TO DISK
; 
    JSR FMTMAP
; 
;  ENTER NAME AND TYPE INFO INTO PARENT DIRECTORY
; 
    LDA HOLFN
    JSR SDIRBK
    SEC 
    JSR ENTNAME
    LDA CURSEC+1,X
    STA DIRBUF+4,Y
    LDA CURSEC,X
    STA DIRBUF+3,Y
    LDA #0
    STA DIRBUF+2,Y
    LDA #8
    STA DIRBUF+1,Y
    ASL A
    JSR SAVFLAG
; 
;  THEN CLEAR NEW DIRECTORY
; 
    LDA #1
    STA FMSBPT
    LDA CURSEC,X
    LDY CURSEC+1,X
    JMP CLRDIR
; 
;  SIMULATE OLD STYLE BIT FINDER
; 
FNDLBIT
    JSR FNDBIT
    PHA         ; SAVE MASK
    LDA TMP2    ; FIRST PAGE?
    BEQ FNDPG0
    STY TMP2    ; SAVE OFFSET IN PAGE
    CMP DATBYT
    BCS DFEJMP
    JSR RDNXTM  ; READ IN PROPER PAGE
    LDY TMP2    ; THEN RESTORE A AND Y REGS
    PLA 
    SEC         ; SET CY (PAGE 1 BUFFER USED)
    RTS 
; 
FNDPG0
    PLA         ; RESTORE SAVED MASK
    CLC         ; AND CLR CY (SAY PAGE 0)
    RTS 
; 
DFEJMP
    JMP DFERR
; 
DECCSEC
    LDA CURSEC,X
    BNE ALCPG0
    DEC CURSEC+1,X
ALCPG0
    DEC CURSEC,X
    RTS 
; 
INCCSEC
    INC CURSEC,X
    BNE DELDIN
    INC CURSEC+1,X
DELDIN
    RTS 
; 
;  DOS DIRECTORY ROUTINES
; 
; 
;  OPEN A DIRECTORY (FOR DIRECT USER ACCESS)
; 
LSTDIR
    LDY #$80-11
SAVFNB
    LDA FNAME-$80+11,Y
    STA (FMSBPT),Y
    INY 
    BPL SAVFNB
    JSR SFDIR   ; FIND A MATCH IN THE DIRECTORY
    BCS ENDDIR  ; IF NO MORE, GO REPORT FREE SPACE
NXTDIR
    JSR FMTDIR  ; ELSE, FORMAT INTO TEXT STRING
    LDA CURFNO
    STA FCBFNO,X ; SAVE FILE NUMBER OF ENTRY FOUND
GODONE
    JMP DONE    ; AND RETURN
; 
GOTEOD
    DEC DATBYT  ; CONVERT EOL TO $9B (REAL EOL)
    STA CURLEN,X ; AND FINISH UP
    BNE GODONE
; 
; 
DIRRD
    LDY #$80-11
RSTFNB
    LDA (FMSBPT),Y ; FETCH BYTES OF PREVIOUS DIRECTORY LINE
    STA FNAME-$80+11,Y
    INY 
    BPL RSTFNB
    LDA CURLEN,X
    BMI DIREOF  ; ALREADY REPORTED THE FREE SPACE
    TAY 
    LDA (FMSBPT),Y
    STA DATBYT
    INC CURLEN,X
    CMP #$9C
    BEQ GOTEOD
    CMP #$9B    ; IS THIS END OF LINE?
    BNE GODONE  ; IF NOT, CONTINUE TEXT DUMP
    LDA FCBFNO,X
    CMP CURFNO
    BNE DMSTRD
    CPX DIUNIT
    BEQ DRDNRQ
DMSTRD
    JSR RRDIR
DRDNRQ
    JSR CSFDIR
    BCC NXTDIR
; 
;  NO MORE ENTRIES, REPORT FREE SECTORS LAST
; 
ENDDIR
    JSR RBITMP  ; READ THE VTOC DATA
    LDY #0
    STY CURMAP  ; FORCE A REREAD NEXT TIME
    LDA MAPBUF+3
    LDX MAPBUF+4 ; AND STUFF BUFFER WITH NUMBER OF FREE SECS.
    JSR CVTDEC
    LDX #-14
FSECL
    LDA FSECM+14-256,X ; FOLLOWED BY "FREE SECTORS" TEXT
    STA (FMSBPT),Y
    INY 
    INX 
    BNE FSECL
    BEQ GODONE  ; THEN LAST LINE IS DONE
DIREOF
    JMP RETEOF  ; NO MORE LINES, RETURN E-O-F INDICATION
; 
FSECM
    .BYTE " FREE SECTORS",$9C
; 
;  FORMAT A DIRECTORY ENTRY FOR BASIC, ETC.
; 
FMTDIR
    LDY #$20    ; space
    LDX DIRDSP
    LDA DIRBUF,X
    PHA 
    AND #$20
    BEQ NOTLCK
    LDY #'*     ; IF SO, MARK AS LOCKED
NOTLCK
    TYA 
    LDY #0
    STA (FMSBPT),Y
    PLA 
    LDY #$20    ; space
    AND #$10
    BEQ NOTDIR
    LDY #':
NOTDIR
    TYA 
    LDY #1
    STA (FMSBPT),Y
CPYNAML
    INY 
    LDA DIRBUF+5,X
    STA (FMSBPT),Y
    INX 
    CPY #13
    BCC CPYNAML
    LDA #$20    ; space
    STA (FMSBPT),Y
    LDY DIRDSP
    LDA DIRBUF+1,Y
    LDX DIRBUF+2,Y
    LDY #14     ; SECTOR COUNT STARTS HERE
; 
;  CONVERT A 16-BIT INTEGER TO A 4 OR 5 DIGIT NUMBER
; 
CVTDEC
    STX TMP2
    STA TMP1
    LDX # >10000
    LDA # <10000
    JSR MKDGT2
    PHA         ;* [D]
    CMP #'0
    BNE SKIP5
    DEY 
SKIP5
    LDX # >1000
    LDA # <1000
    JSR MKDGT2
D34SUB
;*              ;* alt for 4 digit
    CMP #'0+1   ;* [D] pla
    PLA         ;* [D] bne skip4
    BCS SKIP4   ;* [D]
    CMP #'0     ;* [D]
    BNE SKIP4   ;* [D]
    DEY         ;* [D]
SKIP4
;               ;* [D] Skip4
;* [D] is David's 3(4) digit code
;* transplanted from 4.53 to
;* 4.55 by Lee
    LDA #100    ; FOR SHORT STUFF
    JSR MAKDGT
    LDA #10
    JSR MAKDGT
    TXA 
    ADC #'0+10
    STA (FMSBPT),Y
    INY 
    LDA #$9B    ; TERMINATE LINE
    STA DATBYT
    STA (FMSBPT),Y
    LDA #0
    LDX CURFCB
    STA CURLEN,X
    RTS 
; 
;  CREATE A DIGIT AND STORE IT INTO THE DIRECTORY BUFFER
; 
MAKDGT
    LDX #0      ; IF SUBTRAHEND < 256, ZERO UPPER BYTE
MKDGT2
    STX DIRDSP
    STA DIRSEC
    STY DATBYT
    LDY #'0
    SEC 
DGTLP2
    LDA TMP1
    SBC DIRSEC
    TAX 
    LDA TMP2
    SBC DIRDSP
    BCC DGTXIT
    STA TMP2
    STX TMP1
    INY 
    BCS DGTLP2
; 
DGTXIT
    TYA 
    LDY DATBYT
    STA (FMSBPT),Y
    INY 
    RTS 
; 
;  PARSE A FILE NAME WITH WILD CARD CHARACTERS ('*' AND '?')
; 
GETNAM2
    INY         ; look for ">" in
    LDA (ICBALZ),Y ; the start of
    CMP #'>     ; the filename
    BEQ GETNAM
    DEY 
    BNE GETNAM  ; branch always
; 
GETFNM
    LDX CURFCB
    LDY # >361
    LDA # <361
    JSR SETDIR
    INY 
    LDA (ICBALZ),Y
    INY 
    CMP #':     ; DEFAULT DIRECTORY?
    BNE GETNAM2
    DEY 
    STY TMP1
    LDY DFUNIT
    STY ICDNOZ
    TYA 
    STA ICDNO,X
    JSR SETUPD
    LDA CDIREC
    LDY CDIREC+1
    JSR SETDIR
    LDY TMP1
; 
GETNAM
    LDX #-11
    INY 
AFTSTR
    LDA (ICBALZ),Y
    CMP #'*
    BNE TSTPER
    LDA #'?
    INY 
QLOOP
    STA FNAME+11-256,X
    INX 
    BPL TOXITC  ; END OF EXTENSION?
PERFND
    CPX #-3     ; END OF FILE NAME?
    BNE QLOOP   ; NO MORE -?-S
    BEQ AFTSTR
TSTPER
    CMP #'.     ; A PERIOD?
    BNE TSTCHR  ; IF NOT, CHECK FOR INDIVIDUAL CHARACTERS
    LDA #$20    ; IF SO, FILL WITH SPACES
    INY 
    BNE PERFND
TSTCHR
    CMP #'?
    BCC ENDCHR  ; IF < '?', CHECK FOR DIGIT
    CMP #'Z+1   ; ELSE, UPPER CASE LETTER, '?', OR '@'?
    BCC GOTCHR
    CMP #'_
    BCC ENDCHR  ; IF CARET, BACKSL. OR BRACKETS
    CMP #'z+1   ; LOWER CASE, ACCENT OR UNDERSCORE?
    BCC GOTCHR
ENDCHR
    CPX #-11    ; IF FIRST CHAR, ERROR
    BEQ ERRCHR  ; NO BYTES IN FILE NAME
    CMP #'0     ; ELSE, A DIGIT?
    BCC FILLNM  ; IF NOT, THIS IS END OF NAME
    CMP #':
    BCS FILLNM
GOTCHR
    STA FNAME+11-256,X
    INY 
    INX 
    BMI AFTSTR
TOXITC
    LDA (ICBALZ),Y
TSTDIR
    CMP #':     ; look for MYDOS 4.55 
    BEQ MYDIR   ; or SpartaDOS
    CMP #'>     ; directory separator
    BNE XITCHR
MYDIR
    STY TMP2
    JSR SFDIR   ; ELSE, FIND FILE
    BCS FNER1   ; NO SUCH FILE
    JSR TONXDR
    BEQ FNER1
    LDY TMP2
    BNE GETNAM
FNER1
    LDA #174    ;* duplicate file name
    .BYTE $2C   ; BIT ABS (SKIP 2 BYTES)
ERRCHR
    LDA #165    ;* file name error
    JMP AEXIT
; 
FILLNM
    PHA 
    LDA #$20    ; space
FILLLP
    STA FNAME+11-256,X
    INX 
    BMI FILLLP
    PLA 
    JMP TSTDIR
; 
;  RETURN WITH NON-ZERO FLAG IF FILE IS A DIRECTORY
; 
TONXDR
    LDA #$10    ; FILE FOUND, A DIRECTORY?
    JSR GETFLAG
    BEQ TONXIT  ; IF NOT, SET ZERO FLAG
    LDA DIRBUF+3,Y ; YES, MOVE POINTERS TO THE NEW LEVEL
    STA DIRBAS,X
    LDA DIRBUF+4,Y
    STA DIRBAS+1,X
    LDA #$10    ; AND CLEAR ZERO FLAG
TONXIT
    RTS 
; 
;  ENTER A NAME INTO THE DIRECTORY AT DIRBUF[DIRDSP]
; 
ENTNAME
    PHP 
    LDX #-11
    LDY DIRDSP
NAMELP
    LDA FNAME+11-256,X ; LOAD THE MASK CHARACTER
    CMP #'?
    BNE STORIT  ; IF NOT '?', SAVE IT AS IS!
    PLP 
    PHP 
    BCC NOSTOR  ; IF CY CLEAR, LEAVE CHARACTER UNCHANGED
    LDA #$20    ; ELSE, IF CY SET, CONVERT '?' TO ' '
STORIT
    STA DIRBUF+5,Y
NOSTOR
    INY 
    INX 
    BMI NAMELP
    PLP 
    LDY DIRDSP
XITCHR
    LDX CURFCB
    RTS 
; 
SFDIR
    JSR WBITMP  ; INSURE BIT MAP IS SAFE
    LDX #255
    STX HOLFN
    STX CURFNO
    INX 
    STX DAUX2
    INX 
    STX DAUX1
    LDX #READ
    STX DCOMND
    JSR SYSSET  ; SET UP POINTERS, ETC. FOR A NEW DISK ACCESS
    LDA ICDNOZ
    CMP RAMDKU
    BEQ CSFDIR  ; IF RAMDISK, FORGET DENSITY CHECK!
    LDX CURFCB  ; don't read boot sec
    LDA DIRBAS,X ; if in subdirectories
    CMP # <361  ; but allow if first read
    BNE CSFDIR  ;*
    LDA DIRBAS+1,X ;*
    CMP # >361  ;* xio 41 fix?
    BNE CSFDIR  ;* added back in from pre 4.50
    JSR DSKINV  ; ELSE, READ THE FIRST BOOT SECTOR
    BMI ERRX
    JSR INVUNIT ; UPDATE DRIVE CONFIGURATION
CSFDIR
    INC CURFNO  ; READ NEXT 16-BYTE DIR. BLOCK
    LDA CURFNO
    JSR BSECDS  ; CONVERT TO SECTOR AND DISPLACEMENT
XITCHR1
    BCS XITCHR
    BNE NOREAD  ; IF DISP>0, PROCESS BLOCK
    JSR RDIRBK  ; IF DISP=0, READ SECTOR
NOREAD
    LDY DIRDSP
    LDA DIRBUF,Y
    BEQ FNDOLD  ; ZERO IS END OF DIRECTORY (NO MORE ENTRIES)
    BMI FNDOLD  ; NEGATIVE IS EMPTY SLOT (MAY HAVE MORE ENTRIES)
    AND #$DF    ; preserve lock flag
    CMP #3      ; is this DOS 2.5 + file?
    BNE NOD25   ; nope
    LDA #$41    ; otherwise, kludge the
    EOR DIRBUF,Y ; flag to make $42
    STA DIRBUF,Y ; and save lock.
NOD25
    AND #$01
    BNE CSFDIR  ; IF OPEN/CREATE FILE, IT IS NOT REALLY HERE!
    LDX #-11
CPNXCH
    LDA FNAME+11-256,X
    CMP #'?
    BEQ WCMTCH  ; EVERYTHING MATCHES '?'
    CMP DIRBUF+5,Y
    BNE CSFDIR  ; IT DOES NOT MATCH, LOOK AT THE NEXT ONE
WCMTCH
    INY 
    INX 
    BMI CPNXCH
    CLC 
    BCC XITCHR  ; ENTRY FOUND, RETURN WITH CY=0
FNDOLD
    LDX HOLFN
    BPL KPOLD   ; IF AN EMPTY SLOT IS ALREADY FOUND, DO NOTHING
    LDX CURFNO
    STX HOLFN   ; ELSE, SAVE THE SLOT NUMBER (FIRST EMPTY!)
KPOLD
    TAX 
    BMI CSFDIR  ; IF NOT END OF DIRECTORY, KEEP LOOKING
ERRX
    SEC 
    BCS XITCHR1 ; ELSE, ENTRY NOT FOUND, RETURN WITH CY=1
; 
;  DOS I/O ROUTINES
; 
; 
;  DISK SECTOR I/O ROUTINES
; 
WRDISK
    SEC         ; FMS DISK WRITE ENTRY
RWDISK
    LDY FMSBPT  ; DATA SECTOR READ/WRITE ENTRY
    LDA FMSBPT+1
    JSR BUFSET
    LDA CURSEC+1,X
    LDY CURSEC,X
FMDKIO
    PHP 
    LDX DUNIT
    CPX RAMDKU
    BEQ RDKIO1
    PLP 
    PHA 
    LDA SECSIZ-1,X
    TAX 
    PLA 
    JMP DKIO
;
RDKIO1
    JMP RDKIO   ; was moved...
; 
EXTEND
    JSR ALLOC
    LDA FCBOTC,X
    LSR A
    BCC REWRIT
    DEC FCBOTC,X
    JSR WTRICK
    JMP WRTTST
; 
REWRIT
    LDY LNKSEC+1,X
    LDA LNKSEC,X
    JSR SAVLNK
WRTTST
    BMI RTBADF
    INC SECCNT,X
    BNE TONXT
    INC SECCNT+1,X
TONXT
    LDA LNKSEC,X ; MAKE NEXT SECTOR
    STA CURSEC,X ; NEW CURRENT SEC.
    LDA LNKSEC+1,X
    STA CURSEC+1,X
    LDA #0
    STA LNKSEC,X ; ZERO LINK
    STA LNKSEC+1,X
LENSET
    STA CURLEN,X ; ZERO CURRENT OFFSET
    LDA DLINK   ; GET THE LINK LOC.
    STA MAXLEN,X ; MAKE IT MAX. LEN.
    CLC         ; CLEAR CY FOR LATER READ
    RTS 
; 
RDNXTS
    LDA FCBFLG,X
    BEQ CHASE
WRNXTS
    LDA FCBFLG,X
    BMI EXTEND
    ASL A
    BPL RDNXTS
    ASL A
    STA FCBFLG,X
    JSR WRDISK
    BPL RDNXTS
RTBADF
    JMP HWERR   ; RETURN HARDWARE ERROR CODE IF PRESENT
; 
SAVLNK
    PHA 
    TYA 
    LDY DLINK
    STA (FMSBPT),Y
    PLA 
    INY 
    STA (FMSBPT),Y
    INY 
    LDA CURLEN,X
NOBIT
    STA (FMSBPT),Y
    LDY FCBOTC,X
    BMI LEN16   ; 16-BIT LENGTH?
    LDA FCBFNO,X
    ASL A
    ASL A
    LDY DLINK
    ORA (FMSBPT),Y
    STA (FMSBPT),Y
LEN16
    JMP WRDISK
; 
WTRICK
    LDA LNKSEC,X
    STA SAVSEC,X
    LDA LNKSEC+1,X
    STA SAVSEC+1,X
    STX LSTIOCB
    LDA CURSEC,X
    STA LSTSEC
    LDA CURSEC+1,X
    STA LSTSEC+1
    JMP WRDISK
; 
INSTRT
    JSR INITYP
CHASE
    LDA LNKSEC,X
    ORA LNKSEC+1,X
    BEQ NOLINK
    JSR TONXT   ; SET CY=0, FUNC=READ
    JSR RWDISK
    BMI RTBADF  ; CANNOT READ SO BAD FILE NUMBER(ERR=164)
    LDY DLINK
    LDA FCBOTC,X ; 16-BIT LINK?
    ORA #$7F
    BMI LNGLNK
    LDA (FMSBPT),Y
    LSR A
    LSR A
    CMP FCBFNO,X
    BNE XLINKED
    LDA #$03
LNGLNK
    AND (FMSBPT),Y
    STA LNKSEC+1,X
    INY 
    LDA (FMSBPT),Y
    STA LNKSEC,X
    INY 
    LDA (FMSBPT),Y
    STA MAXLEN,X
DRDXIT
    CLC 
    RTS 
; 
XLINKED
    LDA ICCOM,X
    CMP #FMTCMD ; IS THIS A FORMAT?
    BNE FNOERR
NOLINK
    SEC 
    RTS 
; 
;  READ OR WRITE A DIRECTORY BLOCK
; 
RRDIR
    LDA FCBFNO,X
SDIRBK
    STA CURFNO
RDCFNO
    LDA CURFNO
    JSR BSECDS
RDIRBK
    JSR WBITMP  ; TAKE CONTROL OF SYSTEM BUFFER
    CLC 
    .BYTE $A9   ; LDA # (SKIPS 1 BYTE)
WDIRBK
    SEC 
RWDBK
    PHP 
    LDX CURFCB  ; PUT FCB NO. IN X
    STX DIUNIT  ; SAVE THE DIR. BUFFER IOCB
    JSR SYSSET
    CLC 
    LDA DIRSEC
    ADC DIRBAS,X
    TAY 
    LDA DIRBAS+1,X
    ADC #0      ; MULTIPLE DIRS. REQ. THIS
    PLP 
SYSRW
    JSR FMDKIO
    BPL DRDXIT
    LDA #163    ; BIT MAP R/W ERROR, RETURN SYSTEM ERR. CODE
    .BYTE $AE   ; SKIP 2 BYTES
FNOERR
    LDA #164
    STA DSTATS
    JMP HWERR   ; FILE NUMBER MISMATCH
; 
;  READ OR WRITE THE DISK VTOC (BIT MAP)
; 
RBITMP
    LDA CURMAP
    CMP ICDNOZ
    BEQ MAPXIT  ; IF WE READ WHAT IS ALREADY THERE!
    JSR WBITMP  ; ELSE, REAL I/O, SAVE CURRENT BUFFER CONTENTS
    LDA #0
    TAY 
ZMAP
    STA MAPBUF,Y ; THEN ZERO ENTIRE 512
    STA MAPBUF+256,Y ; BYTES OF MAP BUF.
    DEY 
    BNE ZMAP
    CLC 
    JSR RWBMAP  ; THEN READ 128 OR 256 BYTES OF VTOC DATA
    LDY #$FF
    STY DIUNIT  ; INDICATE MAP IS LOADED (NOT DIRECTORY DATA)
    STY MAP2    ; INDICATE NO DATA IN SECOND PAGE OF MAP
    INY 
    STY CHGMAP  ; INDICATE MAP IS UNCHANGED
    INY 
    STY MAP2MOD
    STY CURMP
MAPCLR
    STA CURMAP  ; AND SAVE DRIVE NUMBER MAP APPLIES TO
MAPXIT
    RTS 
; 
WBITMP
    LDA CHGMAP
    BEQ MAPCLR  ; IF MAP NOT CHANGED, SKIP WRITING IT
    STA DUNIT
FMTMAP
    LDA #0
    STA CHGMAP  ; ELSE, MARK IT UNUSED
    STA CURMAP
    LDA DUNIT   ; save drive #
    PHA 
    SEC         ; SET CY TO INDICATE A WRITE
    JSR RWBMAP  ; AND CALL THE READ/WRITE SECTOR ROUTINE
    PLA         ; restore drive #
    STA DUNIT
WRNXTM
    LDA MAP2MOD
    BNE NOMAPI2 ; IF THE PAGE BUFFER IS CLEAN
    LDA #$FF    ; JUST EXIT, ELSE
    PHA 
    LDA MAP2
    INC MAP2MOD
    SEC 
    BCS MUSTWM  ; WRITE IT TO DISK (CY IS SET)
RDNXTM
    CMP MAP2    ; READ A PAGE INTO THE SECOND PAGE BUFFER
    BEQ NOMAPI  ; IF IT IS ALREADY THERE, JUST EXIT
    PHA 
    JSR WRNXTM  ; ELSE, WRITE CURRENT PAGE (IF NECESSARY)
    PLA         ;   AND READ IN THE NEW ONE
    PHA 
    CLC         ;   BY FALLING INTO MUSTWM WITH CY CLEARED
MUSTWM
    PHA 
    LDA # >MAPBUF+256
    LDY # <MAPBUF+256
    JSR BUFSET  ; SET UP BUFFER POINTERS FOR SECOND PAGE
    PLA         ;   OF VTOC BUFFER
    JSR MAPIOC  ; ISSUE I/O OPERATION(S)
    PLA 
    STA MAP2    ; UPDATE ID FOR CONTENTS OF SECOND PAGE BUFFER
NOMAPI
    RTS 
; 
RWBMAP
    JSR SYSSET  ; SET UP BUFFER POINTERS FOR SYSTEM I/O
    LDA #0
MAPIOC
    PHP 
    PHA 
    LDX $0301
    LDA SECSIZ-1,X
    TAX 
    PLA 
    CPX #2      ; 256 BYTE SECS?
    BEQ MAPDDS
    ASL A       ; 128, CHANGE PAGE NUMBER TO PAIR NUMBER
MAPDDS
    EOR #$FF
    SEC 
    ADC # <360
    TAY 
    CPX #2      ; 128 OR 256 BYTE SECTORS?
    BEQ DDMAPX  ; IF 128, READ 2 SECTORS TO FILL BUFFER
    LDA # >360
    PLP 
    PHP 
    JSR SYSRW   ; READ OR WRITE FIRST SECTOR
    LDA MAPBUF
    CMP #3      ; IF DOS 2.0 DISK, ONLY ONE SECTOR EVEN
    BCC XITMBF  ;   IN SINGLE DENSITY!
    JSR STEPBP
    DEY 
DDMAPX
    LDA # >360
    PLP 
    PHP 
    JSR SYSRW   ; READ OR WRITE SECOND OR ONLY SECTOR
XITMBF
    PLP 
NOMAPI2
    LDA ICDNOZ
    STA DUNIT   ; RESTORE USER DRIVE NUMBER TO DUNIT
    RTS         ; SINCE THIS MAY HAVE BEEN ON ANOTHER DRIVE!
; 
SYSSET
    LDA # >MAPBUF ; SET UP BUFFER POINTERS
    LDY # <MAPBUF
    JMP BUFSET
; 
;  ROUTINE TO STEP TO THE NEXT DIRECTORY ENTRY (UNTIL WE RUN OUT)
; 
BSECDS
    LDY #0
    STY DIRDSP
    LSR A
    ROR DIRDSP
    LSR A
    ROR DIRDSP
    LSR A
    ROR DIRDSP  ; (FILE NUMBER MOD 8) * 16 IS OFFSET IN SECTOR
    STA DIRSEC  ; FILE NUMBER/8 IS SECTOR OFFSET
    CMP #8      ; END OF DIRECTORY?
    DEY 
    BCS BSECXT  ; IF SO, RETURN CARRY SET (VALUES ARE BAD!)
    ROR DIRDSP  ; FINAL SHIFT SO NUMBER IS *16 (NOT *32)
BSECXT
    RTS 
; 
;  DOS ALLOCATION ROUTINES
; 
; 
;  FREE A SECTOR FOR LATER USE
; 
FREE
    JSR RBITMP  ; MAKE SURE WE HAVE THE RIGHT MAP
    STA CHGMAP
FMTFRE
    INC MAPBUF+3 ; BUMP LOW BYTE OF FREE SECTOR COUNT
    BNE FREE0   ; IF NO CARRY
    INC MAPBUF+4
FREE0
    JSR FNDBIT
    PHA 
    LDA TMP2
    BEQ SBMP1
    STY TMP2
    CMP CURMP   ; BEFORE FIRST HOLE?
    BCS SBMP2   ; NO, LEAVE UNCHANGED
    STA CURMP   ; YES, NEW FIRST HOLE
SBMP2
    JSR RDNXTM
    LDY TMP2
    LSR MAP2MOD ; MARK MAP PAGE2 DIRTY
    PLA 
    ORA MAPBUF+256,Y
    STA MAPBUF+256,Y
    RTS 
; 
SBMP1
    PLA 
    ORA MAPBUF,Y
    STA MAPBUF,Y
    RTS 
; 
;  FIND BIT ASSOCIATED WITH A SECTOR ON THE DISK
; 
FNDBIT
    LDA CURSEC,X
    AND #7      ; EXTRACT THE BIT NUMBER
    TAY 
    SEC 
    LDA #0
FREE1
    ROR A       ; POSITION CARRY TO THE BIT TO FLIP
    DEY 
    BPL FREE1
    PHA         ; SAVE THE BIT MASK
    LDA CURSEC,X
    CLC 
    ADC #10*8   ; ALLOW FOR 10 BYTE HEADER
    TAY         ; SAVE LOW BYTE
    LDA CURSEC+1,X
    ADC #0      ; PROPOGATE CARRY
    ROR A       ; fix 65535 sector bug
    STA TMP2
    TYA 
    ROR A
    LSR TMP2
    ROR A
    LSR TMP2
    ROR A
    TAY 
    PLA         ; RESTORE THE BIT MASK
    RTS 
; 
;  ALLOCATE AN UNUSED SECTOR TO A FILE
; 
ALLOC
    JSR RBITMP
    STA CHGMAP
    LDY #10
    LDA #0
    STA TMP2
ALL1
    CMP MAPBUF,Y ; ANY BITS LEFT?
    BNE SECFN1  ; IF SO
    INY 
    BNE ALL1
    SEC 
    LDA MAPBUF
    SBC CURMP
    SEC 
    SBC #3
    STA TMP1
ALLCK
    BMI ALGONE
    LDA CURMP
    STA TMP2
    JSR RDNXTM
    LDA #0
    TAY 
ALL2
    CMP MAPBUF+256,Y
    BNE SECFN2  ; IF FREE SECTOR IN SECOND PART OF MAP
    INY 
    BNE ALL2
    INC CURMP   ; TO NEXT SECTOR OF BIT MAP
    DEC TMP1
    BPL ALLCK
ALGONE
    DEC CURMP
DFERR
    LDA #162    ; DISK FULL ERROR CODE
    JMP AEXIT   ; IF THIS IS IT, ERROR-EXIT
; 
SECFN1
  SEC 
  LDX #$AF    ;  -8*10 - 1
ALL3
  ROR A
  INX 
  CMP MAPBUF,Y
  BCC ALL4
  CLC 
  BNE ALL3
ALL4
  EOR MAPBUF,Y
  STA MAPBUF,Y
  BPL ALL7
SECFN2
  SEC 
  LDX #$AF    ;  -8*10 - 1
ALL5
  ROR A
  INX 
  CMP MAPBUF+256,Y
  BCC ALL6
  CLC 
  BNE ALL5
ALL6
  LSR MAP2MOD
  EOR MAPBUF+256,Y
  STA MAPBUF+256,Y
ALL7
  TYA 
  ASL A
  ROL TMP2
  ASL A
  ROL TMP2
  ASL A
  ROL TMP2
  STA TMP1
  TXA 
  ADC TMP1
  LDX CURFCB
  STA LNKSEC,X
  LDA TMP2
  ADC #$FF
  STA LNKSEC+1,X
DECCNT
  LDA MAPBUF+3
  BNE NOBOR
  DEC MAPBUF+4
NOBOR
  DEC MAPBUF+3
  CLC 
  RTS 
; 
;  DOS MISC. SUBROUTINES
; 
; 
;  SET UP STATE VARIABLES ON ENTRY
; 
SETUP
  LDY ICDNOZ  ; GET UNIT NO.
SETUPW
  STX CURFCB
  TSX 
  INX 
  INX 
  STX STKPSV  ; SAVE POINTER TO RETURN ADDR ON STACK
SETUPD
  STY DUNIT   ; COPY UNIT NO. TO DCB
  LDA #1
  CPY RAMDKU
  BEQ UFIXED  ; RAMDISK SECTOR SIZE IS ALWAYS 128 BYTES
  LDA SECSIZ-1,Y
  BEQ INVUNIT ; IF NOT VALID UNIT, TEST FOR CURRENT DENSITY
UFIXED
  STA SECDAT  ; OTHERWISE, STORE CORRECT DENSITY INFORMATION
  LSR A
  ROR A
  ROR A
  ORA #$7D    ; AND UPDATE LINK POSITION IN THE DISK SECTOR
  STA DLINK
  LDX CURFCB
  LDY BUFNO,X ; GET THE BUFFER NUMBER
  BNE RSETUP
  LDY FILES   ; IF ONE IS NOT ALLOCATED
  INY 
SFORB
  DEY 
  BEQ NOSECB  ; ALLOCATE ONE, OR ABORT THE OPERATION NOW!
  LDA BUFFLG-1,Y
  BNE SFORB
  LDA #$80
  STA BUFFLG-1,Y
  TYA 
  STA BUFNO,X
RSETUP
  LDA DOSEND  ; ==SBTABL
  STA FMSBPT  ; STORE THE BUFFER POINTER FOR THIS FILE
  LDA SBTABU-1,Y ;   IN THE ZERO PAGE POINTER "FMSBPT"
  STA FMSBPT+1
  RTS 
; 
INVUNIT
  JSR JSTRD   ; TEST FOR DRIVE STATE
  BNE UFIXED  ; IF IT IS ACCESSABLE, RETURN REAL DENSITY
NOUNIT
  LDA #160    ; RETURN ST=160, DRIVE NOT PRESENT
  .BYTE $AE   ; SKIP TO JMP INSTRUCTION
NOSECB
  LDA #161    ; RETURN ST=161, NO MORE FILE BUFFERS
  JMP AEXIT
; 
;  REMOVE DOS POINTER FROM BOOT SECTORS
; 
TDDOS
  JSR TSTDOS  ; MUST WE UPDATE BOOT?
  BNE TDEXIT  ; NO, RETURN
DELDOS
  LDY #0      ; YES, REMOVE DOS POINTER FROM BOOT
  BEQ UPDBT
; 
;  ADD DOS POINTER TO BOOT SECTORS
; 
SETDOS
  STY DOSLOC
  STA DOSLOC+1
  LDY SECDAT
UPDBT
  LDA DUNIT
  CMP RAMDKU
  BEQ TDEXIT
  STY SECDAT
  LDA DFUNIT
  PHA 
  LDY #$FF
  LDA FCBOTC,X
  BMI NOAND   ; LONG LENGTH FIELD?
  LDY #$03    ; IF NOT, USE ONLY 10 BITS
NOAND
  STY ANDCD+1
  LDA # >BOOTFL
  LDY # <BOOTFL
  JSR BUFSET
  LDY #0
  STY DAUX2
D1230
  INY 
  STY DAUX1
  LDX #1
  STX DFUNIT
  SEC 
  JSR DKIO2
  JSR STEPBP
  CPY BOOTL
  BNE D1230
  PLA 
  STA DFUNIT
  LDY ICDNOZ
  STY DUNIT
  LDA SECSIZ-1,Y
  STA SECDAT
  RTS 
; 
STEPBP
  LDA DBUFLO
  EOR #$80
  STA DBUFLO
  BMI TSTEOD
  INC DBUFHI
TSTEOD
  LDY DAUX1
  RTS 
; 
;  TEST FOR FILE NAME = 'DOS.SYS'
; 
TSTDOS
  LDY #256-11
  LDX DIRDSP
TDLOOP
  LDA DIRBUF+5,X
  EOR DOSSYSL-256+11,Y
  BNE TDEXIT
  INX 
  INY 
  BNE TDLOOP
TDEXIT
  LDX CURFCB
  TAY 
  RTS 
; 
DOSSYSL
  .BYTE "DOS     SYS"
; 
;  FIND AT LEAST ONE FILE MATCHING GIVEN NAME
; 
LFFILE
  JSR GETFNM  ; EXTRACT FILE NAME FROM BUFFER
  STY TMP2    ; SAVE IT FOR -RENAME-
  JSR SFDIR   ; FIND FIRST MATCHING FILE IN DIR
  LDA #170    ; IF NONE, RETURN ERROR 170
  BCS AEXIT   ; ELSE, RETURN
  RTS 
; 
;  RETURN ERROR IF FILE IS LOCKED
; 
TSTLOK
  LDA #$20    ; CHECK BIT 5
  JSR GETFLAG
  BEQ TDEXIT
  LDA #167    ; FILE LOCKED ERROR = 167
  .BYTE $AE   ; SKIP 2 BYTES
; 
;  RETURN WITH NO ERROR
; 
DONE
  LDA #1      ; NORMAL COMPLETION
; 
;  RETURN ERROR CODE IN ACC TO CIO (IN Y)
; 
AEXIT
  LDX STKPSV  ; RESTORE STACK POINTER
  TXS 
  LDX CURFCB  ; RESTORE IOCB OFFSET TO X-REG
  STA ICSTA,X ; RETURN STATUS IN IOCB
  TAY         ; RETURN STATUS IN Y-REG
  LDA DATBYT  ; POSSIBLY RETURN DATA HERE
  CPY #0      ; SET CY FLAG APPROPRIATELY
  RTS 
; 
;  RETURN HARDWARE ERRORS TO CIO
; 
HWERR
  LDA #0      ; fix VTOC updating bug
  STA CURMAP
  STA CHGMAP
  LDA DSTATS  ; LOAD REAL DISK I/O ERROR CODE
  BNE AEXIT   ; AND RETURN IT TO THE CALLER
; 
;   RELEASE FCB AND RETURN NO-ERROR STATUS
; 
FREDON
  LDX CURFCB
  LDY BUFNO,X ; FINISHED WITH THE SECTOR BUFFER, RETURN IT
  BEQ DONE    ; IF NONE ALLOCATED, SO WHAT!
  LDA #0
  STA BUFNO,X ; OTHERWISE, IT'S NOT ALLOCATED ANY MORE!
  STA BUFFLG-1,Y
  BEQ DONE
; 
;  TEST OR CLEAR A BIT IN THE FLAG BYTE
; 
GETFLAG
  LDY DIRDSP
  AND DIRBUF,Y
  RTS 
; 
;  SAVE FLAG BYTE AND WRITE BACK TO DIRECTORY
; 
SAVFLAG
  LDY DIRDSP
  STA DIRBUF,Y
  JMP WDIRBK
;
; SAVE#D:MDUP1.M65
; REN100,10
;
;  Copyright 1984, Charles Marslett, Wordmark Systems
; 
;  Permission is granted by the author for any use whatsoever of this
;    code, so long as this notice remains in the source code, and so
;    long as the source to this routine, however modified or unmodified,
;    is made available for a nominal cost.
; 
;  INITIALIZE MYDOS 4.55  INTERFACE
; 
DUPIN
    LDA # >DUPENT
    STA DOSVEC+1
    LDA # <DUPENT
    STA DOSVEC
    LDA #0
    STA $CFFF   ;* home Axlon
    LDX #$10    ;*
    JSR SOPEN   ;* reset default
    .BYTE 6     ;* directory
    .BYTE 41    ;* xio 41
    .WORD DEFAULT ;*
;*    STA DNAME
    LDA #$30    ;* [D] Lee
    STA AFN+6   ;* [D] Lee
    LDA #$20
    BIT STATE
    BNE CKMDOS  ; IF WARM START CHECK FOR DUP LOADED
; 
;  COLD START CODE
; 
    STA STATE   ; SET MODE TO WARMSTART
MULTIRUN
    LDX #$10
    JSR SOPEN   ; RUN AUTORUN.SYS FILE
    .BYTE 6     ;* init only
    .BYTE 39    ;* xio 39
    .WORD AFN
    BMI CLOSX
    INC AFN+6   ;* [D] inc ar0..ar1
    LDA AFN+6   ;* [D] test ar#
    CMP #'9+1   ;* [D] quit at ar9
    BCC MULTIRUN ;* [D] do another
    JSR CLOSX
    JMP (RUNAD)
; 
;  CLOSE IOCBS  10  AND 20
; 
CLOSX
    JSR CLOS20
CLOS10
    LDX #$10    ; CLOSE IOCB 10
    .BYTE $2C   ; SKIP 2 BYTES
CLOS20
    LDX #$20    ; CLOSE IOCB 20
CLOS2
    LDA #CLOSE  ; CLOSE ANY IOCB
SCMD
    STA ICCOM,X
    JMP CIOV
; 
DBUF10
    LDX #$10
DEFBUF
    STA ICBAL,X
    TYA 
    STA ICBAL+1,X
CKMDOS
    RTS 
; 
;
;* Moved AUTORUN.SYS filename
;  here so SUPERARC will not
;  think this is <=4.3 DOS
;
;* AFN .BYTE"D1:AUTORUN.SYS",$9B
;
;* Changed to David's wonderful
;  running Autorun.sys files by
;  renaming with Ar0 extension
;
AFN
    .BYTE "D1:*AR0",$9B ;* [D]
;
;  OPEN FILE
; 
;  CALLING SEQUENCE:
;     JSR SOPEN
;     DB  AUX
;     DB  CMD
;     DW  BUFFER ADDRESS
; 
SOPEN
    SEC 
    .BYTE $A9   ; LDA #IMM OPCODE
; 
;  DO A READ/WRITE TYPE I/O REQUEST
; 
;  CALLING SEQUENCE:
;     JSR DOIO
;     DB  IOCB#
;     DW  BUFFER LENGTH
;     DB  CMD
;     DW  BUFFER ADDRESS
; 
DOIO
    CLC 
    PLA 
    STA BUFADR
    PLA 
    STA BUFADR+1
    LDY #1
    LDA (BUFADR),Y
    BCC DOIO1
    STA ICAX1,X
    BCS XTRCB
DOIO1
    TAX 
    INY 
    LDA (BUFADR),Y
    STA ICBLL,X
    INY 
    LDA (BUFADR),Y
    STA ICBLL+1,X
XTRCB
    INY 
    LDA (BUFADR),Y
    STA ICCOM,X
    INY 
    LDA (BUFADR),Y
    STA ICBAL,X
    INY 
    LDA (BUFADR),Y
    STA ICBAL+1,X
    TYA 
    CLC 
    ADC BUFADR
    TAY 
    LDA #0
    ADC BUFADR+1
    PHA 
    TYA 
    PHA 
    JMP CIOV    ; DO I/O REQUEST
; 
;  IF NO DUP.SYS, INCREMENT DRIVE NO.
; 
RETRYOS
    INC DUPSYS+1
    LDA DUPSYS+1
    AND #$0F
    CMP #9
    BCC RTYOSV
    BNE GOTO1
    CMP RAMDKU
    BEQ RTYOSV
GOTO1
    LDA #'1
    STA DUPSYS+1
RTYOSV
    TAX 
    LDA SECSIZ-'1,X
    BEQ RETRYOS
    BNE NOWMS
; 
;  LOAD PROGRAM FUNCTION
; 
LDFILE
    JSR LDMEM
    LDX #$10
    JSR TOVECT  ; LOAD PROGRAM OR GO TO IT
    .BYTE $2C   ; skip the LDY #1
; 
; *************************************
; 
;    STANDARD EXIT POINT FOR PROGRAMS
; 
; *************************************
; 
;  RESTORE DOS/DUP INIT VECTOR
; 
DUPENT
    LDY #1
SAVERR
    STY CBSAV
    BIT STATE
    BVS GODOS
    BPL NOWMS
    JSR CLOS10
    JSR SOPEN
    .BYTE $08   ; WRITE MEM.SAV FILE
    .BYTE OPEN
    .WORD NMSAV
    BMI NOWMS
    JSR DOIO
    .BYTE $10
    .WORD MSLEN
    .BYTE PUTCHR
    .WORD MSBASE
NOWMS
    JSR CLOS10
    JSR SOPEN   ; GET DUP.SYS INTO MEMORY
    .BYTE $06
    .BYTE 39
    .WORD DUPSYS
    BMI RETRYOS
    LDA DOSINI
    STA INISAV
    LDA DOSINI+1
    STA INISAV+1
GODOS
    JSR CLOSX
    JMP DOSOS   ; THEN START IT UP
;
;  Subroutines moved from resident code:
;* but moved back by Lee - memsav won't work
;* otherwise 
;  SAVE MEMORY SUBROUTINE: WRITE FILE BODY,
;  INIT AND RUN VECTORS
; 
WDR
    JSR LDMEM   ; LOAD MEM.SAV IF NEEDED
WDR1
    LDX #$10    ; WRITE TEXT TO DISK FILE
    JSR CIOV
    BPL WRERNO  ; don't use BMI!
WRERRO2
    JMP SAVERR
;
WRERNO
    LDX # <INITAD
    JSR WRVEC
    LDX # <RUNAD
    JSR WRVEC
    BIT STATE
    BVS GODOS1
    JMP NOWMS
;
GODOS1
    JMP GODOS
; 
WRVEC
    LSR TEMP    ; WRITE THIS 6-BYTE VECTOR?
    BCC RTS2    ; IF NOT, JUST RETURN
    STX VECTOR
    LDA INITAD&$FF00,X
    STA VECTOR+4
    INX 
    LDA INITAD&$FF00,X
    STA VECTOR+5
    LDA # >INITAD
    STA VECTOR+1
    STA VECTOR+3
    STX VECTOR+2 ; (X,A)=MIDDLE WORD
WR6BYT
    JSR DOIO
    .BYTE $10
    .WORD 6
    .BYTE PUTCHR
    .WORD VECTOR
    BPL RTS2
    JMP WRERRO2
;
RTS2
    RTS 
; 
;  RUN AT ADDRESS
; 
TOVECT
    JMP (VECTOR) ; TO 'RUN AT' ADDRESS
; 
;  LOAD MEM.SAV IF NEED BE
; 
LDMEM
    BIT STATE   ; LOAD MEM.SAV?
    BPL NOLDMS
    LDX #$20
    JSR SOPEN
    .BYTE $04
    .BYTE OPEN
    .WORD NMSAV
    BMI NOLDMS
    JSR DOIO
    .BYTE $20
    .WORD MSLEN
    .BYTE GETCHR
    .WORD MSBASE
NOLDMS
    JMP CLOS20
; 
NMSAV
    .BYTE "D1:MEM.SAV",$9B
EC
    .BYTE "E:"
DUPSYS
    .BYTE "D1:DUP.SYS",$9B
OPT
    .BYTE 0
DUPFLAG
    .BYTE 0     ; DUP RESIDENT = $80
INISAV
    .WORD MDINIT
CBSAV
    .BYTE 0     ; ERROR CODE FROM PROG EXECUTED
DEFAULT
    .BYTE "D1:"
DNAME
    .BYTE 0
    *=  *+39    ; ALLOW FOR 40 CHAR DEF DIR
DNAMLEN = *-DNAME
; 
RESEND *= *+$0300 ; ALLOW FOR 3 FILE BUFFERS
DRIVERS *= *+$0800 ; ALLOW 2K FOR RESIDENT CODE
MSBASE = *
;
; SAVE#D:MDUP2.M65
; REN100,10
;
;  Copyright 1984, Charles Marslett, Wordmark Systems
; 
;  Permission is granted by the author for any use whatsoever of this
;    code, so long as this notice remains in the source code, and so
;    long as the source to this routine, however modified or unmodified,
;    is made available for a nominal cost.
; 
;======================================================================
; 
;  START OF NONRESIDENT PORTION OF DUP.SYS
; 
DATA *= *+80    ; ALLOCATE BUFFER FOR BIT MAP, ETC.
DELIM *= *+1
PAR2 *= *+80    ; another bug fixed RP
PAR3 *= *+80
; 
    *=  DATA+512
UNNO *= *+1
PTR *=  *+1
PTRSAV *= *+1
IPTR *= *+1
IPSAV *= *+1
CBYTE *= *+1
SECTOR *= *+2
CSRC *= *+1
CDES *= *+1
CPYTYP *= *+1
SWPFLG *= *+1
RCNT *= *+1
SIZSEC *= *+2
FNPT *= *+1
FNPT2 *= *+1
PAR *=  *+80    ; REAL PARAMETER (LAST)
DUPBASE = *
; 
DOSSYS
    .BYTE "D1:DOS.SYS",$9B
; 
;  CLOSE (BRUTALLY) ALL IOCBS AND REOPEN SCREEN
; 
INITIO
    JSR CIOINV
    LDX #0
    JSR SOPEN   ; OPEN SCREEN AS IOCB #0
    .BYTE $0C
    .BYTE OPEN
    .WORD EC
    STX CDTMV3  ; CLEAR TIMER #3
    STX CDTMV3+1
    LDY #1
    LDA #3
    STA CDTMF3  ; SET TIMER NOT DONE FLAG
    JSR SETVBV
WAITIM
    LDA CDTMF3  ; DONE?
    BNE WAITIM  ; NO, CONTINUE LOOPING
    RTS 
; 
;  DISK UTILITY PROGRAM ENTRY
; 
DOSOS
    CLC 
    CLD 
    LDX #$FF
    STX BRKKEY  ; ENABLE BREAK KEY
    LDA # >MDINIT
    STA DOSINI+1
    LDA # <MDINIT
    STA DOSINI
    LDA #2
    STA LMARGN  ; SET MARGINS
    LDA #39
    STA RMARGN
    LDA DUPFLAG
    ORA STATE
    AND #$C1
    CMP #$80
    BNE NOSWF
    STA WARMST
NOSWF
    LDA #$40
    ORA STATE
    STA STATE   ; ELSE, SAY IT WAS DONE
    LDA #$80
    ORA POKMSK
    STA POKMSK  ; ALLOW BREAK INTERRUPTS
    STA IRQEN
    JSR INITIO  ; CLOSE ALL FILES
    LDA STATE
    AND #1
    BEQ SHMEN
    JSR ERRXIT  ; MEM.SAV ERROR CAN NOW BE SHOWN
    .BYTE "Error loading MEM.SAV or memory!",$9B,0
; 
SHMEN
    LDA DFUNIT
    ORA #'0
    STA DEFAULT+1
    LDX #28
    LDY #8
DKSLP
    LDA #$20    ; space
    STA D1STAT-1,X
    STA D1STAT,X
    STA D1STAT+1,X
    STA D1STAT+2,X
    CPY RAMDKU
    BNE CKHCD   ; IF NOT RAM DISK
    LDA #'R
    BNE SETUNI
CKHCD
    LDA HDTAB+8-1,Y
    BEQ GENDCD  ; IF NOT HARD DISK
    LDA #'H
SETUNI
    STA D1STAT+1,X
    BNE DKUNIN
GENDCD
    LDA SECSIZ-1,Y
    BEQ NXTDKS
;* LSR A  ; DOUBLE DENSITY?
;* LDA #'S
;* BCS DKSNGD  ; NO, SINGLE
;* LDA #'D  ; YES, DOUBLE
    LDA #'S     ;* new routine to show E
    STA DCOMND  ;* in menu screen
    STY DUNIT   ;*
    STX TMP1    ;*
    JSR DSKINV  ;*
    ASL DVSTAT  ;*
    LDA #0      ;*
    ADC #0      ;*
    BEQ TDS     ;*
    LDA #'E     ;*
    BNE DKSNGD  ;*
TDS ;           ;*
    ASL DVSTAT  ;*
    ASL DVSTAT  ;*
    ADC #0      ;*
    BEQ LDS     ;*
    LDA #'D     ;*
    BNE DKSNGD  ;*
LDS ;           ;*
    LDA #'S     ;*
DKSNGD ;        ; old label left in play
    LDY DUNIT   ;*
    LDX TMP1    ;*
    STA D1STAT+1,X
    LDA DRVDEF-1,Y
    LSR A
    LDA #'-
    BCC DKSSD
    LDA #'=
DKSSD
    STA D1STAT+2,X
DKUNIN
    TYA 
    ORA #'0
    STA D1STAT,X
NXTDKS
    DEX 
    DEX 
    DEX 
    DEX 
    DEY 
    BNE DKSLP
    ASL VER     ;* Shift verify
    LDA WRCMD   ;* status into
    CMP #$55    ;* menu display
    ROR VER     ;* Lee
    JSR PRINT
    .BYTE $7D   ; CLEAR SCREEN
    .BYTE "MyDOS 4.55 Beta"
    .BYTE " 4    (C)1989 "
    .BYTE +$80,"WORDMARK",$1B
;
    .BYTE "Disks "
D1STAT
    .BYTE "1S  2S  3S  4S  5S  6S  7S  8S ",$9B
    .BYTE "D: = ",0 ;* moved default to get
    LDA # <DEFAULT ;* xio 41 to work in
    LDX # >DEFAULT ;* dosini run now
    JSR PRTMSG
    JSR PRINT
    .BYTE $9B,$9B
    .BYTE "1-8.Dir of D1:-D8: *. Dir of D:",$9B
    .BYTE "A. Disk Directory  K. Save Memory",$9B
    .BYTE "B. Run Cartridge   L. Load Memory",$9B
    .BYTE "C. Copy File(s)    M. Run at Address",$9B
    .BYTE "D. Delete File(s)  N. Load MEM.SAV",$9B
    .BYTE "E. Rename File(s)  O. Change Config.",$9B
    .BYTE "F. Lock File(s)    P. Set Density",$9B
    .BYTE "G. Unlock File(s)  Q. Make Directory",$9B
    .BYTE "H. Write DOS Files R. Pick Directory",$9B
    .BYTE "I. Initialize Disk S. Set RAMdisk #",$9B
    .BYTE "J. Duplicate Disk  "
VER
    .BYTE "V. Set Verify Flag",$9B
    .BYTE " ",$9B,0
    LDY CBSAV
    BPL MENUSL
    JSR CIOER1  ; IF LOAD ERROR, REPORT IT
; 
;  SELECT MENU FUNCTION
; 
MENUSL
    LDX #$FF
    TXS 
    INX 
    STX OPT     ; OPT=00 IF NO OPTIONS
    STX SWPFLG
    STX CBSAV   ; FOR DIR SCANS, SKIP NO EXTNS.
    JSR CLOSX   ; CLOSE IOCBs 10 AND 20
    LDX #$30
    JSR CLOS2   ; AND IOCB 30
    LDA #$15    ;* fix David's
    STA COLMN   ;* galloping columns - Lee
    JSR PRINT
    .BYTE "Select Item ("
    .BYTE +$80,"RETURN"
    .BYTE " for menu):",0
    LDA #$40    ; FORCE UPPER CASE
    STA SHFLOK
    ORA STATE
    STA STATE   ; SAY DUP.SYS IN MEMORY
    JSR CHRGET
    CMP #$9B
    BNE CKITEM
    JMP SHMEN
;
CKFDIR
    CMP #'1
    BCC CKFDD
    JMP FASTDIR
;
CKFDD
    CMP #'*
    BNE BADITM
    JMP FASTDD
; 
CKITEM
    CMP #'9+1
    BCC CKFDIR
    CMP #'A+NFUNC
    BCS BADITM
    SBC #'A-1
    BCS ITEMV
BADITM
    LDA #NFUNC
ITEMV
    ASL A
    TAY 
    LDA DUPJT,Y
    STA BUFADR
    LDA DUPJT+1,Y
    STA BUFADR+1
    JMP PRTMEN  ; GO TO MENU EXIT (WITH MESSAGE)
; 
TCOMND = *
UCOMND = *
NSI
    .BYTE "No such item!",$9B,0
    JMP MENUSL
; 
DUPJT
    .WORD DIRLST-1,STCAR-1
    .WORD CPYFIL-1,DELFIL-1
    .WORD RENFIL-1,LKFIL-1
    .WORD ULKFIL-1,WBOOT-1
    .WORD FMTDSK-1,DUPDSK-1
    .WORD SAVFIL-1,LDFIL-1
    .WORD BRUN-1,MEMSAV-1
    .WORD CONFGR-1,CHDISK-1
    .WORD MKDIRD-1,SETDIRD-1
    .WORD RAMDRV-1,TCOMND-1
    .WORD UCOMND-1,VERIFY-1
NFUNC = [*-DUPJT]/2
    .WORD NSI-1
; 
;  * AND 1-8.  FAST DIRECTORY LIST
; 
FASTDD
    STA PAR+2
    LDA #':
    STA PAR+1
    BNE DOFDD
FASTDIR
    STA PAR+1
    LDA #':
    STA PAR+2
DOFDD
    LDA #'*
    STA PAR+3
    STA PAR+4
    LDA #'D
    STA PAR
    LDA #$9B
    STA PAR+5   ; fix the 174 errors in menu
    STA CPYTYP
    STA DELIM
    BNE DODIRL
; 
;  A.  DIRECTORY LIST
; 
DIRLST
    .BYTE "Files to list, Destination?",$9B,0
    LDA #$9B
    STA CPYTYP
    JSR GETFN
    JSR DEFPAR
DODIRL
    LDA # <PAR
    LDY # >PAR
    JSR DBUF10
    LDX #$10
    STX CSRC    ; IOCB10 IS SOURCE
    JSR OPDIR   ; OPEN IOCB10 AS DIRECTORY
    LDA # >DATA+512-38
    STA BUFAD+1
    LDA # <DATA+512-38
    STA BUFAD
    LDA #38
    STA BUFLEN
    LDA #0
    STA BUFLEN+1
    LDX #$00    ; CDES=IOCB00
    LDA DELIM
    BMI CPY1FSP
    LDA DELIM
    BMI SGFCPY
    JSR GETFN2
    STY ICBAL+$20
    STA ICBAL+1+$20
SGFCPY
    LDX #$20
    LDA #GETCHR
    BNE DOCALL
CPY1FSP
    LDA #GETREC
DOCALL
    STX CDES
    JSR COPYF
    JMP MENUSL  ; THEN RETURN TO CMD. LINE
; 
BADRN
    JSR ERRXIT
    .BYTE "Need new file name!",$9B,0
CANTDV
    JSR ERRXIT
    .BYTE "No drive or directories allowed in new name!",$9B,0
LKMSG
    .BYTE "Lock ",0
ULMSG
    .BYTE "Unlock ",0
DELMSG
    .BYTE "Delete ",0
; 
;  F.  LOCK FILES
; 
LKFIL
    .BYTE "Lock which file?",$9B,0
    LDY # <LKMSG
    LDX # >LKMSG
    LDA #LOK
    BNE DOCMD2  ; GET FILE NAME THEN LOCK IT
; 
;  G.  UNLOCK FILES
; 
ULKFIL
    .BYTE "Unlock which file?",$9B,0
    LDY # <ULMSG
    LDX # >ULMSG
    LDA #UNLOK
DOCMD2
    STY SIZSEC  ; do mass lock/unlock
    STX SIZSEC+1 ; unless /Q is specified
    PHA 
    JSR GETFN
    JSR CKDSK
    LDX OPT
    CPX #'Q     ; Query?
    BEQ DOPRM
    BNE AFTCHK  ; branch either way
; 
;  D.  DELETE FILE(S)
; 
DELFIL
    .BYTE "Delete what file?",$9B,0
    LDY # <DELMSG
    LDX # >DELMSG
    LDA #DEL
DOCMD
    STY SIZSEC
    STX SIZSEC+1
    PHA 
    JSR GETFN
    JSR CKDSK
    LDX OPT
    CPX #'N     ; IF '/N' THEN DO IT THE EASY WAY
    BEQ AFTCHK
DOPRM
    JSR PRINT
    .BYTE "Answer 'Y' or 'N'",$9B,0
    PLA 
    JSR SETSCN
RDFN
    JSR SCNDIR
    BCS DELX    ; IF END OF DIRECTORY
    LDA SIZSEC
    LDX SIZSEC+1
    JSR PRTMSG
    LDA # <PAR
    LDX # >PAR
    JSR PRTMSG
    JSR PRINT
    .BYTE "?",0
    JSR CHRGET
    CMP #'Y
    BNE NODELT
    LDX #$20
    JSR CIOCL   ; DELETE THE FILE THEN
NODELT
    JMP RDFN
; 
SMPLCMD
    PHA 
    JSR GETFN   ; GET FILE NAME
    JSR CKDSK   ; VERIFY A DISK FILE
AFTCHK
    PLA 
ISSCMD
    STA ICCOM+$10
    LDX #$10
    JSR CIOCL
    LDA ICCOM+$10
    CMP #41
    BEQ SETFNJ
DELX
    JMP MENUSL
; 
SETFNJ
    JMP SETFNM
; 
JCANTDV
    JMP CANTDV
; 
JBADRN
    JMP BADRN
; 
;  E.  RENAME FILE(S)
; 
RENFIL
    .BYTE "File to rename, new name?",$9B,0
    JSR GETFN
    JSR CKDSK
    LDY PTR
    LDA DELIM
    CMP #',
    BEQ CKNAM2
    CMP #$20    ; space
    BNE JBADRN
CKNAM2
    INY 
    LDA (FNPTR),Y
    CMP #':
    BEQ JCANTDV
    CMP #'>     ; check for sparta type
    BEQ JCANTDV
    CMP #'0
    BCC DOREN
    CMP #'z+1
    BCC CKNAM2
DOREN
    LDA #REN
    BNE ISSCMD
; 
;  Q.  MAKE A DIRECTORY
; 
MKDIRD
    .BYTE "Full directory name?",$9B,0
    LDX #8
    STX ICAX1+$10
    LDA #34     ; MAKE DIR. COMMAND
    JMP SMPLCMD
; 
;  R.  SET DIRECTORY
; 
SETDIRD
    .BYTE "Directory to be used as 'D:'?",$9B,0
    JSR GETFN
    JSR CKDSK
    LDY PTR     ; DRIVE OR NULL?
    CPY #4
    BCC CPYDNE
    LDA #41
    JMP ISSCMD
;
SETFNM
    LDY #3      ;*
    LDA (ICBALZ),Y ;* 
    CMP #':     ;* test for ::
    BNE JMEN    ;*
    JSR CLOS10  ;* go do 2nd xio 41
    LDA # <DEFAULT ;* call to
    STA ICBAL+$10 ;*  shortened
    LDA # >DEFAULT ;* directory
    STA ICBAH+$10 ;*  string
    LDA #41     ;*
    JMP ISSCMD  ;*
;
JMEN
    JMP MENUSL
; 
CPYDNE
    JSR ERRXIT
    .BYTE "Invalid directory!",$9B,0
; 
;  SINGLE FILE (DEVICE) COPY
; 
TOERR1
    JMP CIOER1
;
SGCOPY
    LDX #$10
    STX CSRC    ; SOURCE IS IOCB10
    JSR SOPEN
    .BYTE 4     ; INPUT
    .BYTE OPEN  ; OPEN FUNCTION
    .WORD PAR   ; INPUT DEVICE NAM
    BMI TOERR1
    JMP SGFCPY
; 
;  C.  COPY FILES
; 
DUPFIL = *
CPYFIL
    .BYTE "File source, destination?",$9B,0
    LDA #$20    ; space
    STA PAR3+2  ; DEFINE CHAR 3 OF DEVICE NAME
    LDA #$9B
    STA CPYTYP
    JSR GETFN   ; GET SOURCE FILE NAME
    LDA # >DUPEND
    STA BUFAD+1
    LDA # <DUPEND
    STA BUFAD
    LDA MEMTOP
    SEC 
    SBC # <DUPEND
    STA BUFLEN
    LDA MEMTOP+1
    SBC # >DUPEND
    STA BUFLEN+1
    JSR DEFPAR
    LDA DELIM
    BMI SFNAME
    JSR GETFN2
;*  LDA #0    ; fix /X bug Lee
;*SFNAME 
;*  STA SWAPFLG
SFNAME
    ASL WARMST
    LDA FNPTR+1
    STA ICBAL+1+$20
    LDA FNPTR
    STA ICBAL+$20
    LDA PAR     ; DISK DEVICE?
    CMP #'D
    BNE SGCOPY
    LDA # <PAR
    LDY # >PAR
    JSR DBUF10
    LDA #'?
    LDY #11
QQQ
    STA PAR2-1,Y
    DEY 
    BNE QQQ
    JSR CWFSD
    LDX #$10
    JSR OPDIR   ; OPEN IOCB10 AS DIRECTORY
    LDY #$FF
CPSCL1
    INY 
    LDA (FNPTR),Y
    STA PAR3,Y
    BNE CPSCL1
CPSCL2
    DEY 
    LDA (FNPTR),Y
    CMP #':
    BEQ CPSCL3
    CMP #'>     ; account for sparta type
    BNE CPSCL2
CPSCL3
    INY 
    STY FNPT2
    LDA (FNPTR),Y
    BEQ OPINP
    LDX #0      ; SCAN -PAR- STARTING AT 1-ST BYTE
MVMSK
    LDA (FNPTR),Y
    BMI WCOPYB  ; 1 FILESPEC COPY??
    CMP #'*
    BEQ MVNML
    CMP #'.
    BCC WCOPYB
    BNE DOSTOR
    LDA #$20    ; space
    DEY 
DOSTOR
    STA PAR2,X
    INY 
MVNML
    INX 
    CPX #8
    BCC MVMSK
SKPPRD
    INY 
MVEXT
    LDA (FNPTR),Y
    BEQ WCOPYB
    CMP #'.
    BEQ SKPPRD  ; IF A PERIOD, SKIP OVER IT
    CMP #'*
    BEQ OPINP
    CMP #$20    ; space
    BEQ WCOPYB
    CMP #',
    BEQ WCOPYB
    CMP #$9B
    BEQ WCOPYB
    INY 
SAVBLK
    STA PAR2,X
    INX 
    CPX #11
    BCC MVEXT
    BCS OPINP
WCOPY
    JSR CWFSD
OPINP
    JSR SCNDIR
    BIT CBYTE
    BMI OPINP
    BCC WCNEXT
    JMP MENUSL
; 
WCOPYB
    LDA #$20    ; space
    BNE SAVBLK
WCNEXT
    LDA # >PAR3
    STA ICBAL+$30+1
    LDA # <PAR3
    STA ICBAL+$30
    LDX #0
    LDY FNPT2
WCNBLD
    LDA PAR2,X
    BEQ TERMX
    CMP #'?
    BNE STWCC
    LDA DATA+2,X
STWCC
    STA PAR3,Y
    CMP #$20    ; space
    BEQ OVWRTC
    INY 
OVWRTC
    INX 
    CPX #8
    BCC WCNBLD
    LDA #'.
    STA PAR3,Y
    INY 
WCEBLD
    LDA PAR2,X
    BEQ TERMX
    CMP #'?
    BNE STWCEC
    LDA DATA+2,X
STWCEC
    STA PAR3,Y
    CMP #$20    ; space
    BEQ OVWRTE
    INY 
OVWRTE
    INX 
    CPX #11
    BCC WCEBLD
TERMX
    LDA #'.
    CMP PAR3-1,Y
    BNE NOTOVP
    DEY 
NOTOVP
    LDA #$9B
    LDX OPT
    CPX #'Q
    BNE NOQUERY
    LDA #'?
NOQUERY
    STA PAR3,Y
    LDA #0
    STA PAR3+1,Y
    LDA CPYTYP
    BNE DOONE
    LDA # <PAR
    LDX # >PAR
    JSR PRTMSG
    JSR PRINT
    .BYTE "--> ",0 ;*
    LDA # <PAR3
    LDX # >PAR3
    JSR PRTMSG
    LDA OPT
    CMP #'Q
    BNE DOONE
    JSR CHRGET
    CMP #'Y
    BNE SKPCOP
DOONE
    LDA ICAX1+5+$10
    STA ICAX1+5+$20
    LDX #$20
    STX CSRC
    LDA #4
    STA ICAX1,X
    LDA # <PAR
    LDY # >PAR
    JSR DEFBUF
    LDA #OPEN
    JSR SCMD
    BMI CPYERR
    LDX #7
CKFDOS
    LDA CKDTST-1,X
    CMP PAR3+2,X
    BNE NOXDOS
    DEX 
    BNE CKFDOS
    LDA PAR3+1
    STA DOSRNM+1
    STA DOSSYS+1
    LDA #$60
    STA PAR3+3
NOXDOS
    LDA # >PAR3
    STA ICBAL+$30+1
    LDA # <PAR3
    STA ICBAL+$30
    LDX #8
    STX ICAX1+$30
    LDX #$30
    STX CDES
    LDA #GETCHR
    JSR COPYF   ; COPY FILE
SKPCOP
    LDA CPYTYP
    BNE TOEXIT
    JMP WCOPY
; 
TOEXIT
    JMP MENUSL
; 
CPYERR
    JMP CIOER1
; 
;  I.  FORMAT A DISK
; 
FMT1050
    LDA #1
    BNE DOFMT
FMTDSK
    .BYTE "Disk to FORMAT:",0
    JSR GETDN   ; GET DRIVE NUMBER OR NAME
    JSR DEFPAR
    LDA # >PAR
    STA ICBAL+$10+1
    LDA # <PAR
    STA ICBAL+$10
    LDY #1
    LDA (FNPTR),Y
    STA FMTDVN
; 
;  MAKE SURE ABOUT DRIVE NUMBER
; 
    JSR PRINT
    .BYTE "(Press "
    .BYTE +$80,"[A]"
    .BYTE " for Enhanced Dns)",155
    .BYTE "Type "
    .BYTE +$80,"[Y]"
    .BYTE " to Format Drive "
FMTDVN
    .BYTE "0:",0
    JSR CHRGET
    CMP #'A
    BEQ FMT1050
    EOR #'Y
    BNE ALFMTD
DOFMT
    STA ICAX1+$10
    LDA #0
    LDX OPT     ; REAL FORMAT?
    CPX #'N
    BNE RELFMT
    ROR A
RELFMT
    STA ICAX1+1+$10
    LDA #FORM
    STA ICCOM+$10
    LDX #$10
    JSR CIOV    ; DO FORMAT OF DISK
    BPL ALFMTD
WBERR
    JMP CIOER1  ; IF ERROR, SAY SO!
; 
ALFMTD
    JMP MENUSL
; 
;  H.  WRITE DOS/DUP TO DISK
; 
DUPFNM
    .BYTE "D1:DUP.SYS",$9B
WBOOT
    .BYTE "Drive to write DOS files to?",0
    JSR GETDN
    LDA DUPSYS+1
    PHA 
    LDA #'1
    STA DUPSYS+1
    STA NMSAV+1
    LDY #1
    LDA (FNPTR),Y
    CMP #':
    BNE CANWB
    LDA DEFAULT+1
CANWB
    STA DOSSYS+1
    STA DUPFNM+1
    DEY         ; SET UP INITIAL VALUES OF PARMS.
    STY OPT
    LDA #$80
    STA STATE
    LDA # <DOSSYS
    LDY # >DOSSYS
    JSR DBUF10
    LDA #8      ; OPEN OUTPUT=WRITE DOS.SYS
    STA ICAX1+$10
    JSR ANYDEN  ; OPEN AND WRITE DOS.SYS (ANY DENSITY)
    JSR CLOS10
    PLA 
    STA NMSAV+1
    STA DUPSYS+1
; 
;  **** WRITE DUP.SYS HERE ****
; 
    LDY #$70
    LDA # <DUPBASE
    LDX # >DUPBASE
    JSR D2B8A
    LDA # >DUPFNM
    STA ICBAL+$10+1
    LDA # <DUPFNM
    STA ICBAL+$10 ; Bugs fixed RP
    LDA # >DUPEND-1
    STA HDBUF+3
    LDA # <DUPEND-1
    STA HDBUF+2
    LDA # >DUPLEN
    STA HDBUF+5
    LDA # <DUPLEN
    STA HDBUF+4
    LDA #0
    STA TEMP    ; CLEAR 'RUN' FLAG
    JMP WRDUP   ; WRITE DUP.SYS
; 
;  J.  DUPLICATE A DISK
; 
DUPDSK
    .BYTE "Source, Destination (Sectors)?",$9B,0
    JSR GETDN
    LDY #1
    LDA (FNPTR),Y
    AND #$0F    ; GET DRIVE NUMBER
    STA CSRC
    STA CDES
    LDA DELIM   ; IF SINGLE DRIVE DUP.
    CMP #'(
    BEQ SETSSZ  ; GO SET SECTOR SIZE
    JSR GETDN2  ; ELSE, GET SECOND DRIVE NAME
    LDY #1
    LDA (FNPTR),Y
    AND #$0F
    STA CDES
    CMP CSRC    ; SAME DRIVE?
    BNE SETSSZ  ; YES, SINGLE DRIVE DUP.
    LDX #$9B
    STX SWPFLG
SETSSZ
    TAX 
    LDY CSRC
    LDA SWPFLG
    ORA #$40    ; SET DUP-DISK FLAG
    STA SWPFLG
    BMI DODKDP
    JSR PRINT
    .BYTE "Insert both disks, type "
    .BYTE +$80,"RETURN"
    .BYTE 0
    JSR CHRGET
DODKDP
    JSR CWFSD
    LDA CSRC    ; POINT TO SOURCE DRIVE
    JSR GETDEN  ; IDENTIFY DENSITY OF SOURCE DISKETTE
    ASL DVSTAT  ;* get ED bit into carry if it's there
    LDA #0      ;* make it a one to signal MyDOS to do 22 or 1050 type
    ADC #0      ;* ED format later on if required
    STA ICAX1+$20 ;* here is where that happens - ED bug fixed, Lee
    LDY CDES    ; ELSE, TWO DRIVE DUP.
    LDX CSRC
    LDA SECSIZ-1,X
    CMP SECSIZ-1,Y
    BEQ SAME
    STY UNNO
    JSR SETDEN
    LDY CDES
    LDX CSRC
    LDA SECSIZ-1,X
    CMP SECSIZ-1,Y
    BEQ SAME
    JSR ERRXIT
    .BYTE "Drives not compatible!",$9B,0
SAME
    ASL WARMST
    LSR A
    STA SIZSEC+1
    ROR A
    STA SIZSEC  ; SET SECTOR SIZE (128 OR 256)
    STX DUNIT   ; READ SOURCE VTOC
    LDA DELIM
    PHA 
    LDA #$FF
    TAX 
INIBMP
    STA DATA+128,X
    STA DATA+256,X
    DEX 
    BNE INIBMP
    PLA         ; BOOT COPY?
    CMP #'(
    BEQ BLDVTOC ; YES, BUILD IMAGINARY VTOC
    CMP #$9B
    BEQ RDVTOC  ; NO, DOS COPY
OOPS
    JSR ERRXIT  ; ELSE, ERROR
    .BYTE "Invalid options!",$9B,0
BLDVTOC
    JSR GETNUM
    CPY #'-
    BNE OOPS
    STA DATA+3
    STX DATA+4
    JSR GETNUM
    CPY #')
    BNE OOPS
    STA DATA+1
    STX DATA+2
    LDY #0
    STY PTR
    STY DATA+6
    STY DATA+5
    LDA # >DATA+10
    STA BUFAD+1
    LDA # <DATA+10
    STA BUFAD
    LDA #$FE
D26BB
    LDX DATA+6
    CPX DATA+4
    BNE D26CB
    LDX DATA+5
    CPX DATA+3
    BCS D26D2
D26CB
  SEC 
  ROL A
  JSR NXTSCT
  BNE D26BB
D26D2
  LDX DATA+2
  CPX DATA+6
  BCC D26EA
  BNE D26E4
  LDX DATA+1
  CPX DATA+5
  BCC D26EA
D26E4
  ASL A
  JSR NXTSCT
  BNE D26D2
D26EA
  SEC 
  ROL A
  BCS D26EA
  STA (BUFAD),Y
RDVTOC
  SEC 
  LDA MEMTOP
  SBC SIZSEC
  STA BUFLEN
  LDA MEMTOP+1
  SBC SIZSEC+1
  STA BUFLEN+1
  LDA BUFLEN
  CMP # <DUPEND
  LDA BUFLEN+1
  SBC # >DUPEND
  BCS ENUF
  JSR ERRXIT
  .BYTE "Not enough memory!",$9B,0
NXTSCT
  BCS D272E
  STA (BUFAD),Y
  LDA #$FE
  INC BUFAD
  BNE D272E
  INC BUFAD+1
D272E
  INC DATA+5
  BNE D2736
  INC DATA+6
D2736
  RTS 
; 
ENUF
  LDA PTR
  BEQ SKRDVT  ; IF POS, SKIP READING VTOC
  LDA # <360
  LDX # >360
  STA DAUX1
  STX DAUX1+1
  LDA # <DATA
  LDX # >DATA
  STA DBUFLO
  STX DBUFLO+1
  JSR RSEC1
  BPL NOERFD
  JMP CIOER1
;
NOERFD
  CLC 
  LDA DATA+1
  ADC #12     ; ADD IN THE BOOT, MAP AND DIR SECTORS
  STA DATA+1
  BCC CK2BIT  ; THEN TAKE CARE OF SECOND BIT MAP IF NEC.
  INC DATA+2  ; ELSE, BUMP UPPER BYTE
CK2BIT
  LDA DATA
  CMP #4
  BCC SKRDVT  ; IF SINGLE SECTOR, SKIP READING SECOND
  INC DATA+1
  CLC 
  LDA DBUFLO
  ADC DBYTLO
  STA DBUFLO
  LDA DBUFLO+1
  ADC DBYTLO+1
  STA DBUFLO+1
  DEC DAUX1
  JSR RSEC1
SKRDVT
  LDA #0
  STA DAUX1+1
  LDA #1
  STA DAUX1
  LDA DATA+10
  STA CBYTE
  LDA #8
  STA IPTR
  LDA # >DATA+10
  STA VECTOR+1
  LDA # <DATA+10
  STA VECTOR
DORD
  LDA VECTOR
  STA PTRSAV
  LDA VECTOR+1
  STA PTR
  LDA IPTR
  STA IPSAV
  LDA CBYTE
  STA CBSAV
  LDA DAUX1
  STA SECTOR
  LDA DAUX1+1
  STA SECTOR+1
  LDA #0
  STA CPYTYP  ; SET OPERATION TO 'READ'
LRS
  LDA # >DUPEND
  STA DBUFLO+1
  LDA # <DUPEND
  STA DBUFLO
LRS1
  ASL CBYTE
  DEC IPTR
  BNE CBIT
  INC VECTOR
  BNE PAGE1
  INC VECTOR+1
PAGE1
  LDY #0
  LDA (VECTOR),Y
  STA CBYTE
  LDX #8
  STX IPTR
CBIT
  BIT CBYTE
  BMI ASPT
  LDA CPYTYP
  ASL A       ; CY=0, READ;  CY=1, WRITE
  LDA CSRC
  BCC RSECIN  ; ACC=DRIVE #
  LDA CDES
RSECIN
  JSR SECTIO  ; READ OR WRITE
IOD
  CLC 
  LDA DBUFLO
  ADC SIZSEC
  STA DBUFLO
  LDA DBUFLO+1
  ADC SIZSEC+1
  STA DBUFLO+1
ASPT
  LDA DAUX1
  CMP DATA+1
  LDA DAUX1+1
  SBC DATA+2
  BCC ASPN
  LDA CPYTYP  ; END OF DRIVE
  BPL STDD2   ; IF READ, DO WRITE
  JMP MENUSL  ; IF WRITE, THEN DONE!
; 
ASPN
  INC DAUX1
  BNE ASPX
  INC DAUX1+1
ASPX
  LDA BUFLEN  ; ELSE, END OF THE BUFFER?
  CMP DBUFLO
  LDA BUFLEN+1
  SBC DBUFLO+1
  BCS LRS1    ; NO, GET NEXT SECTOR
  LDA CPYTYP
  BPL STDD2   ; IF WRITE, DO NEXT READ
  JSR CWFSD
  JMP DORD
; 
STDD2
  BIT SWPFLG
  BPL CKFORM
  JSR PRINT
IDD
  .BYTE "Insert DESTINATION disk, press "
  .BYTE +$80,"RETURN"
  .BYTE 0
  JSR CHRGET
CKFORM
  LDA #'N
  CMP OPT
  BEQ NOFORM
  STA OPT
  LDX #$20    ; IF FORMAT REQ., DO IT
  LDA # <DOSSYS
  LDY # >DOSSYS
  JSR DEFBUF
  LDA #FORM
  STA ICCOM+$20
  LDA CDES
  ORA #'0     ; CONVERT DRIVE NO. TO ASCII
  STA DOSSYS+1
  JSR CIOCL
NOFORM
  LDA #0      ;* ED bug clean up
  STA ICAX1+$20 ;*
  DEC CPYTYP  ; THEN, MAKE A WRITE
  LDA PTRSAV
  STA VECTOR
  LDA PTR
  STA VECTOR+1
  LDA SECTOR
  STA DAUX1
  LDA SECTOR+1
  STA DAUX1+1
  LDA IPSAV
  STA IPTR
  LDA CBSAV
  STA CBYTE
  JMP LRS
; 
;  P.  CHANGE DISK FORMAT
; 
CHDISK
  .BYTE "Drive, new density:",0
  JSR GETDN   ; GET DRIVE NO.
  LDA DELIM
  CMP #$9B    ; DRIVE NUMBER ONLY?
  BNE CHDSK2  ; IF SO, CHANGE DEFAULT
BADPCMD
  JSR ERRXIT
  .BYTE "Drive unchanged.",$9B,0
CHDSK2
  LDY PTR
  LDA (FNPTR),Y
  TAX 
  LDY #1
  LDA (FNPTR),Y
  CMP #'9
  BCS BADPCMD
  SBC #'1-1
  BCC BADPCMD
  TAY 
  INY 
  STY UNNO
  LDA #1
  CPX #'S
  BEQ TOSGL
  CPX #'D
  BNE BADPCMD
  ASL A
TOSGL
  STA SECSIZ-1,Y
  JSR DOFSIN
  JMP SHMEN   ; THEN SHOW CHANGED MENU
; 
;  O.  CONFIGURE SYSTEM OR DISK DRIVE
; 
; This is BOB code, uncommented
; as per usual.... [ChasM]
;
; WE VALIDATE THE MEMORY
; MAPPING ABILITY OF THE BOX WE
; ARE RUNNING IN? [BOB PUFF]
;
; [Don't really understand this
; but thats OK, for now, ChasM]
;
;* Lee will attempt it, but hold
; on to your hat, you won't
; believe it!!
;
CHKBANKS
  SEI         ; stop all ints
  LDY #0      ; from anywhere
  STY $D40E   ; from halting
  STY $D20E   ; the process
  LDA $D301   ; Save Basic etc
  PHA         ; state
  LDX #$FF
CKBL1
  STY $D301   ; Build two
  LDA $4000   ; tables, 1st
  STA MAPBUF,Y ; contains
  STX $4000   ; first byte of
  TXA         ; all 256 poss
  STA MAPBUF+256,Y ; banks'
  INY         ; 1st byte for
  BNE CKBL1   ; later restore
  DEX         ; and store FF
  STX $D301   ; to all banks.
;*  STX 0       ; 2nd table=new
  STX $4000   ; value (FF) of
;*  STX $8000   ; banks for test
;*  STX $C000
  LDX #0      ; prep for test
CKBL2
  STY $D301
  LDA $4000
  CMP #$FF    ; same? no-not
  BNE CKBNOT  ; a working bank
  INX         ; yes-inc bank
  STX $4000   ; count, store
  TXA         ; into bank and
CKBNOT
  STA MAPBUF+256,Y ; 2nd table
  INY         ; when done fall
  BNE CKBL2   ; thru with # of
  STX RDKLMT  ; banks here
;
  LDX #1      ; prep for 2nd
CKBL8
  TXA         ; part....
  LDY #$FF    ; Search for
CKBL6
  CMP MAPBUF+256,Y ; match-2nd
  BEQ CKBFO   ; table and Y...
  DEY         ; If found, Y
  CPY #$FF    ; holds banking
  BNE CKBL6   ; byte-store it
;               ; Wild huh?
CKBL9
  STY $D301   ; Restore all
  LDA MAPBUF,Y ; banks to prev
  STA $4000   ; held data.
  DEY         ; Data remains
  CPY #$FF    ; VALID! Thanks,
  BNE CKBL9   ; Bob
  PLA         ; Restore Basic
  STA $D301   ; state, etc.
  LDA #$C0    ;
  STA $D40E   ; Reset ints for
  LDA $10     ; normal running
  STA $D20E   ;
  CLI         ;
  RTS         ; and done
;
CKBFO
  TYA         ; Store Y offset
  STA MAPAGE-1,X ; into MYDOS
  INX         ; banking table
  CPX #65     ;
  BCC CKBL8   ; Make sure we
  LDY #$FE    ; are not over
  BNE CKBL9   ; 64 bytes total
;               ; as that is our
;               ; limit
GETRDK
  JSR PRINT
  .BYTE "RAM disk present?",0
  JSR CHRGET
  LDY #$00    ;* Fix bad
;*  LDY #$FF    ;* format code Lee
  CMP #'Y     ;* was 'N' & BNE    
  BEQ RAMDSU  ;* made more exclusive
  JMP NOFAST
;
RAMDSU
  JSR PRINT
  .BYTE +$80,"[A]"
  .BYTE "xlon or "
  .BYTE +$80,"[X]"
  .BYTE "E type RAMdisk?",0
  JSR CHRGET
  LDY # <$D301 ;*
  LDX # >$D301 ;*
  CMP #'X     ;*
  BEQ SAVADR  ;*
  LDY # <$CFFF ;*
  LDX # >$CFFF ;*
  CMP #'A     ; *
  BNE RAMDSU  ;*
;* changed above to work
;* exclusively - no default action
;*
;* Axlon does not have a read latch function so sty(x) rdad1 not needed
;* but lda #0 to store back into latch when done is needed to home bank
SAVADR
;* sty rdad1
  STY RDAD2
  STY RDAD3
  STY CKBL1+1 ;*
  STY CKBL1+21 ;* get all
  STY CKBL2+1 ;* RD to use
  STY CKBL9+1 ;* 
;* stx rdad1+1
  STX RDAD2+1
  STX RDAD3+1
  STX CKBL1+2 ;*
  STX CKBL1+22 ;* autotest
  STX CKBL2+2 ;* code - Lee
  STX CKBL9+2 ;* 
  LDY #$EA    ;* get Axlon
  LDX #$EA    ;* to use
  CMP #'X     ;* home bank
  BEQ XETYPE  ;* 
  LDY #$A9    ;* lda #0
  LDX #$00    ;* for Axlon
XETYPE
  STY RDAD1+2 ;*
  STX RDAD1+3 ;*
  JSR CHKBANKS
  LDA RDKLMT
  BNE OKP1
  JSR PRINT
  .BYTE "No extended memory installed!",$9B,0
  LDY #0
  JMP NOFAST
;
OKP1
  LDX #0
;* STX NMLMAP no bit shifting for me, thanks
  STX FR0+1
  ASL A
  ASL A
  ROL FR0+1
  ASL A
  ROL FR0+1
  ASL A
  STA FR0
  ROL FR0+1
  JSR IFP
  JSR FASCII
  JSR PRINT
  .BYTE "Use default config for ",0
  LDY #0
OKP2
  LDA (INBUFF),Y
  BMI OKP3
  INY 
  BNE OKP2
OKP3
  AND #$7F
  STA (INBUFF),Y
  INY 
  LDA #0
  STA (INBUFF),Y
  LDA INBUFF
  LDX INBUFF+1
  JSR PRTMSG
  JSR PRINT
  .BYTE "K?",0
  JSR CHRGET
  CMP #'N
  BEQ RAMDSU2
  JMP DVNOQ
; 
RAMDSU2
  JSR PRINT
  .BYTE "Size(K)?",0
  JSR GETLIN
  JSR GETNUM
  LSR VECTOR+1
  ROR A
  LSR VECTOR+1
  ROR A
  LSR VECTOR+1
  ROR A
  LSR VECTOR+1
  ROR A
  BNE SAVRDS
  LDA #4
SAVRDS
  STA RDKLMT
GETSEQN
  JSR PRINT
  .BYTE "Page sequence?",0
  JSR GETLIN
  JSR GETNO2
  CPY #CR
  BNE FSNUM
  BEQ RSEQ
DVNOQ
  JSR PRINT
  .BYTE "RAM disk drive no?",0
  LDA RDAD2+1 ;* set up
  CMP #$CF    ;* proper Axlon
  BNE GETRDRV ;* banking
  LDX RDKLMT  ;* table
AX1
  TXA         ;*
  STA MAPAGE-1,X ;*
  DEX         ;*
  BNE AX1     ;* Lee
GETRDRV
  JSR CHRGET
  LDY #9      ; ASSUME 9
  CMP #'0
  BCC NOFAST  ; IF DIGIT, CHANGE RAMDISK CODE
  CMP #'9
  BCS NOFAST
  AND #$0F
  TAY 
NOFAST
  STY RAMDKU  ; SET RAMDISK UNIT NO.
  RTS 
; 
RSEQ
  TAY 
  LDX PGMAP,Y
;* STX NMLMAP   just say no to bit shifters
  CPY #3
  BCS CPAXSQ
  LDA SQMAP,Y
  LDX #0
CPY0
  ROL A
  ROL A
  PHA 
  ROL A
  ROL A
  ROL A
  AND #$0C
  TAY 
CPY1
  LDA SQTAB,Y
  STA MAPAGE,X
  INX 
  INY 
  TXA 
  AND #3
  BNE CPY1
  PLA 
  CPX #16
  BNE CPY0
CPSEQ
  LDA SQTAB,X
  STA MAPAGE,X
  INX 
  CPX #64
  BNE CPSEQ
  BEQ DVNOQ
CPAXSQ
  LDX #64
AXSQL
  DEX 
  TXA 
  STA MAPAGE,X
  BNE AXSQL
  BEQ DVNOQ
FSNUM
  LDX #0
  PHA 
  TXA 
FSNCL
  STA DATA+256,X
  INX 
  BNE FSNCL
  PLA 
FSLP1
  STX UNNO
  CPY #CR
  BEQ TONML
  STA DATA+256-64,X
  TAX 
  LDA DATA+256,X
  BNE BADSEQ
  DEC DATA+256,X
  LDY PTR
  LDA (FNPTR),Y
  CMP #CR
  BNE FSLP4
  JSR GETLIN
FSLP4
  JSR GETNO2
  LDX UNNO
  INX 
  CPX #64
  BNE FSLP1
TONML
  CPX RDKLMT
  BNE WRONG
;* STA NMLMAP  last time, no bit shifting
UPDLP1
  DEX 
  LDA DATA+256-64,X
  STA MAPAGE,X
  TXA 
  BNE UPDLP1
  JMP DVNOQ
;
BADSEQ
  JSR PRINT
  .BYTE "Duplicated sequence number!",$9B,0
  JMP GETSEQN
; 
WRONG
  JSR PRINT
  .BYTE "Wrong number of entries!",$9B,0
  JMP GETSEQN
; 
PGMAP
  .BYTE $00,$00,$00,$FF,$FF,$FF
; 
SQMAP
  .BYTE $9C,$D8,$4B,$FF,$FF,$00
; 
SQTAB
  .BYTE $A3,$A7,$AB,$AF
  .BYTE $C3,$C7,$CB,$CF
  .BYTE $E3,$E7,$EB,$EF
  .BYTE $83,$87,$8B,$8F
; 
  .BYTE $A1,$A5,$A9,$AD
  .BYTE $C1,$C5,$C9,$CD
  .BYTE $E1,$E5,$E9,$ED
  .BYTE $81,$85,$89,$8D
; 
  .BYTE $A2,$A6,$AA,$AE
  .BYTE $C2,$C6,$CA,$CE
  .BYTE $E2,$E6,$EA,$EE
  .BYTE $82,$86,$8A,$8E
; 
  .BYTE $A0,$A4,$A8,$AC
  .BYTE $C0,$C4,$C8,$CC
  .BYTE $E0,$E4,$E8,$EC
  .BYTE $80,$84,$88,$8C
; 
CONSYS
  JSR PRINT
  .BYTE "Number of File Buffers?",0
  JSR GETLIN
  JSR GETNUM
  BEQ SKPFCT
  CMP #17
  BCS SKPFCT
  STA FILES   ; SET NUMBER OF FILES (0-16)
SKPFCT
  JSR PRINT   ;* from here...
  .BYTE "3 or 4 digit directory?",0
  JSR GETLIN
  JSR GETNUM
  LDY #0
  CMP #3
  BEQ D3SUB
  CMP #4
  BEQ D4SUB
  BNE SKP34
D34TAB
  CMP #'0+1   ;* first three bytes 3 digit
  PLA         ;* reuse pla for both
  BNE *+9     ;* last three bytes 4 digit
D3SUB
  LDX #0
  BEQ D34COPY
D4SUB
  LDX #2
D34COPY
  LDA D34TAB,X ;* subs 3 or 4 digit code
  STA D34SUB,Y ;* into dos.sys
  INX 
  INY 
  CPY #3
  BNE D34COPY ;* to here - Lee's
SKP34
  JSR GETRDK
  JSR MDINIT  ; REINITIALIZE DOS3
  JMP DOSOS
; 
ZAPDRV
  LDA #$D2
  .BYTE $2C   ; SKIP 2 BYTES
SET52
  LDA #$52
  LDY UNNO
  STA DRVDEF-1,Y
  JSR CLRHDS
CONXIT
  JMP MENUSL
; 
CONFGR
  .BYTE "Drive number or "
  .BYTE +$80,"RETURN"
  .BYTE ":",0
  JSR CHRGET  ; GET DRIVE NUMBER
  CMP #$9B    ; IF RETURN, GO TO SYSTEM CONFIGURATION
  BNE CONDRIV
  JMP CONSYS
;
CONDRIV
  CMP #'9
  BCC SAVDVN
TOBADP
  JMP BADPCMD
; 
SAVDVN
  SBC #'1-1
  BCC TOBADP
  TAY 
  INY 
  STY UNNO
  LDA #0      ; THEN ZERO CONFIGURATION BYTE
  STA DRVDEF-1,Y
  JSR PRINT
  .BYTE "Remove drive?",0
  JSR CHRGET
  CMP #'Y
  BEQ ZAPDRV
  JSR PRINT
  .BYTE "Is drive configurable?",0
  JSR CHRGET
  CMP #'Y     ; IF NO, SET TO $52 AND EXIT
  BNE SET52
  JSR PRINT
  .BYTE "High capacity drive?",0
  JSR CHRGET
  CMP #'Y
  BEQ GETHCD
  JSR PRINT
  .BYTE "Is drive double sided?",0
  JSR CHRGET
  CMP #'Y
  BNE SETSS
  LDA #$01
  JSR ORDRV
SETSS
  JSR PRINT
  .BYTE "Tracks/side?",0
  JSR GETLIN
  JSR GETNUM
  CMP #35
  BEQ SET35
  TAY 
  LDA #$30
  CPY #77
  BEQ SETTKS
  LDA #$20
  CPY #80
  BEQ SETTKS
  LDA #$10
  CPY #40
  BNE SETSS
SETTKS
  JSR ORDRV
SET35
  JSR PRINT
  .BYTE "Step rate?",0
  JSR CHRGET
  CMP #'4
  BCS SET35
  SBC #'0-1
  BCC SET35
  ASL A
  JSR ORDRV
  JSR CLRHDS
  JMP MENUSL
; 
GETHCD
  JSR PRINT
  .BYTE "Drive size (in sectors)?",0
  JSR GETLIN
  JSR GETNUM
  CPX #0
  BEQ GETHCD  ; INVALID SIZE
  PHA 
  LDY UNNO
  LDA #$12    ;   00010010
  STA DRVDEF-1,Y
  LDA #2      ;   00000010
  STA SECSIZ-1,Y
  PLA 
  JSR SETHDS
  JMP MENUSL
; 
;  S.  Set RAMdisk Drive Number
; 
RAMDRV
  .BYTE "RAM disk drive no?",0
  JSR GETRDRV
  JMP MENUSL
; 
;  V.  Set Verify Flag ON or OFF
; 
VERIFY
  .BYTE "Verify WRITEs?",0
  JSR DOVRFY
  JMP MENUSL
; 
DOVRFY
  JSR CHRGET
  LDX #$50    ;* Changed to
  CMP #'Y     ;* default off
  BNE DOVFY
  LDX #$57    ;* Lee
DOVFY
  STX WRCMD   ; SAVE THE WRITE COMMAND IN DOS
  RTS 
; 
ORDRV
  LDY UNNO
  ORA DRVDEF-1,Y
  STA DRVDEF-1,Y
  RTS 
; 
CLRHDS
  LDX #0
  TXA 
SETHDS
  LDY UNNO
  STA HDTAB-1,Y
  TXA 
  STA HDTAB+8-1,Y
  JMP DOFSIN
;
; SAVE#D:MDUP3.M65
; REN100,10
;
;  Permission is granted by the author for any use whatsoever of this
;    code, so long as this notice remains in the source code, and so
;    long as the source to this routine, however modified or unmodified,
;    is made available for a nominal cost.
; 
;  K.  SAVE FILE COMMAND
; 
SAVFIL
    .BYTE "SAVE:filename,start,end(,init(,run))",$9B,0
    JSR GETFN
    STY ICBAL+$10
    STA ICBAL+1+$10
    LDA OPT
    PHA 
    JSR GETNO2
    CPX # >DUPEND
    LDY #$70
    BCS DSLMFG
    LDY #$80    ;* bit 7=$80
;*  LDY #$60    ; mem.sav fix
;*              ; Lee
;  FORCE MEM.SAV TO MEMORY BEFORE SAVING IMAGE
;
DSLMFG
    JSR D2B8A
    JSR GETNO2
    STA HDBUF+2
    STX HDBUF+3
    SEC 
    SBC HDBUF
    STA HDBUF+4
    TXA 
    SBC HDBUF+1
    BPL ADDOK
    JSR ERRXIT
    .BYTE "Invalid START-END range!",$9B,0
ADDOK
    STA HDBUF+5
    INC HDBUF+4
    BNE INCOK
    INC HDBUF+5
INCOK
    LDA #0
    CPY #CR
    BEQ NINTAD
    JSR GETNO2
    STA INITAD
    STX INITAD+1
    ORA INITAD+1
    BEQ NINTAD
    LDA #1      ; SET 'GOT INIT' FLAG
NINTAD
    STA TEMP
    CPY #CR
    BEQ NRUNAD
    JSR GETNO2
    STA RUNAD
    STX RUNAD+1
    ORA RUNAD+1
    BEQ NRUNAD
    INC TEMP
    INC TEMP    ; SET 'GOT RUN' FLAG
NRUNAD
    PLA 
WRDUP
    LDY #0
    STY OPT
    DEY 
    STY VECTOR
    STY VECTOR+1
; 
;  OPEN THE PROGRAM FILE
; 
    LDY #8
    CMP #'A
    BNE OPTOK1
    DEC OPT
    INY 
OPTOK1
    STY ICAX1+$10
    LDX #$10
    JSR ANYDEN  ; OPEN FILE 'OUTPUT/ANY DENSITY'
    BMI KIOERR
    LDA OPT
    BEQ FULHDR  ; IF NO 'APPEND'
    JSR DOIO    ; WRITE SHORT HEADER
    .BYTE $10
    .WORD 4
    .BYTE PUTCHR
    .WORD VECTOR+2
    BMI KIOERR
KEXIT
    LDA HDBUF+4
    STA ICBLL+$10
    LDA HDBUF+5
    STA ICBLL+1+$10
    LDA HDBUF
    STA ICBAL+$10
    LDA HDBUF+1
    STA ICBAL+1+$10
    BIT STATE
    BMI KMSAV
    JMP WDR1
;
KMSAV
    JMP WDR
; 
FULHDR
    JSR WR6BYT
    BPL KEXIT
KIOERR
    JMP CIOER1
; 
D2B8A
    STA HDBUF
    STX HDBUF+1
    STY STATE
    RTS 
; 
;  N.  LOAD PROGRAM INTO MEM.SAV
; 
MEMSAV
    .BYTE "Load MEM.SAV from what file?",$9B,0
    LDA STATE
    ORA #$80    ; TURN ON MEM.SAV FLAG
    BMI LOADIT
TOMEN
    JMP MENUSL
; 
;  L.  LOAD USER FILE FUNCTION
; 
BDLDFL
    LDY #180
BLOWUP
    JMP CIOER1
; 
LDFIL
    .BYTE "Load from what file?",$9B,0
    LDA STATE
    AND #$7F    ; TURN OFF MEM.SAV FLAG
LOADIT
    STA STATE
    JSR GETFN
    STY ICBAL+$10
    STA ICBAL+1+$10
    LDX DATA+3  ; JUST A CR?
    BEQ TOMEN
    LDA #4
    STA ICAX1+$10
    LDX #$10
    JSR ANYDEN
    JSR DOIO
    .BYTE $10
    .WORD 2
    .BYTE GETCHR
    .WORD DATA
    BMI BLOWUP
    LDA DATA
    AND DATA+1
    CMP #$FF
    BNE BDLDFL
    LDA DATA+3
    BEQ TOMEN
    LDA OPT
    EOR #'N
    BEQ GOTN
    LDA #0
    STA WARMST
    LDA #3
GOTN
    EOR #7
    STA ICAX1+$10
    LDA #39
    STA ICCOM+$10
    LDA # <CIOV
    LDX # >CIOV
    BNE BRUN1
; 
;  B.  RUN CARTRIDGE
; 
STCAR
    .BYTE 0
    LDA $BFFD
    EOR #$AA
    STA $BFFD
    CMP $BFFD
    BNE NORAM   ; IF ADDRESS SPACE IS NOT RAM
    EOR #$AA
    STA $BFFD   ; IF RAM, NO CARTRIDGE
NOCART
    JSR ERRXIT
    .BYTE "NO CARTRIDGE!",$9B,0
NORAM
    LDX $BFFC
    BNE NOCART  ; IF NOT ATARI CARTRIDGE
    LDA CARRUN
    LDX CARRUN+1
BRUN1
    STA VECTOR
    STX VECTOR+1
    LDA INISAV
    STA DOSINI
    LDA INISAV+1
    STA DOSINI+1
    LDA STATE
    AND #$BF
    STA STATE
    JMP LDFILE
; 
;  M.  RUN AT ADDRESS
; 
BRUN
    .BYTE "Run from what address?",0
    JSR GETLIN
    LDA (FNPTR),Y
    CMP #$9B    ; NO ADDRESS?
    BEQ BRUN2   ; IF SO, ABORT
    JSR GETNO2
    CPY #$9B
    BNE BRUN2
    LDY #0
    STY WARMST
    BEQ BRUN1
BRUN2
    JSR ERRXIT
    .BYTE "Address must be 1-4 hex digits!",$9B,0
; 
;  PUT A SINGLE CHARACTER ON THE SCREEN
; 
CHRPUT
    LDX #PUTCHR
    STX ICCOM
    LDX #0
    STX ICBLL
    STX ICBLL+1
    JMP CIOV
; 
;  PUT MESSAGE TO THE SCREEN
; 
PRTMSG
    STA BUFADR
    STX BUFADR+1
PRTNXT
    LDX #0
    LDA (BUFADR,X)
    BEQ PRTXIT
    JSR CHRPUT
PRTENT
    INC BUFADR
    BNE PRTNXT
    INC BUFADR+1
    BNE PRTNXT
PRTXIT
    RTS 
; 
;  PRINT AN IN-LINE STRING
; 
PRINT
    PLA 
    STA BUFADR
    PLA 
    STA BUFADR+1
PRTMEN
    JSR PRTENT
    LDA BUFADR+1
    PHA 
    LDA BUFADR
    PHA 
    RTS 
; 
;  READ A BYTE FROM THE KEYBOARD
; 
CHRGET
    JSR XE424   ; FETCH THE BYTE
    CPY #0
    BMI KILLRD  ; IF BREAK OR EOF, ABORT COMMAND
    CMP #'z+1   ; > LOWER CASE Z?
    BCS NCHGCS
    CMP #'a     ; < LOWER CASE A?
    BCC NCHGCS
    SBC #$20    ; CONVERT TO UPPER CASE
NCHGCS
    PHA         ; SAVE IT
    CMP #$9B
    BEQ CHRXIT  ; IF EOL, ECHO IT
    JSR CHRPUT  ; ELSE, ECHO IT
    LDA #$9B    ; FOLLOWED BY EOL
CHRXIT
    JSR CHRPUT
    PLA         ; RESTORE FOR PROGRAM
    RTS         ; THEN EXIT
;
KILLRD
    JSR CHRPUT  ; MOVE TO NEXT LINE AND
    JMP MENUSL  ; EXIT WITHOUT RETURN TO COMMAND
; 
XE424
    JSR CLOSE7  ; get a chr from keyboard
    JSR SOPEN   ; Open #7 for keyboard input
    .BYTE 4,OPEN
    .WORD KDEV
    JSR DOIO    ; get a character
    .BYTE $70,0,0,7,0,0
    PHA         ; save it for a sec
    TYA         ; save error stat
    PHA 
    JSR CLOSE7
    PLA         ; get error stats again
    TAY 
    PLA         ; get character back
    RTS         ; that's all, folks!
;
KDEV
    .BYTE "K:",$9B ; handler addr.
CLOSE7
    JSR DOIO    ; close IOCB #7
    .BYTE $70,0,0,$0C,0,0
    RTS 
; 
;  RAW SECTOR READ/WRITE FUNCTIONS
; 
RSEC1
    LDA CSRC
RSEC2
    CLC 
SECTIO
    STA DUNIT
    LDA #2
    STA RCNT
    PHP 
CLD1
    LDX SIZSEC+1
    INX 
    PLP 
    PHP 
    JSR DKIO2
    BPL DRTS
    CMP #$80
    BEQ TOERR2
    DEC RCNT
    BPL CLD1
TOERR2
    PLP 
    JMP CIOER1
; 
DRTS
    PLP 
    RTS 
; 
;  CHECK FOR 2-COLUMN DIRECTORY LIST
; 
CLEARIT
    LDX CSRC
    LDA ICCOM,X
    CMP #GETCHR
    BEQ CLERXIT
    LDA DATA+512-38
    CMP #'0
    BCS EOFEXIT
    LDY ICBLL,X
    CPY #20
    BCC SHFNL
    DEC ICBLL,X
    LDY #-24
SFTSIZ
    LDA DATA+256,Y
    STA DATA+256-1,Y
    INY 
    BNE SFTSIZ
SHFNL
    LDA COLMN   ;* [D] Alternate 2
    EOR #$17    ;* [D]  column list
    STA COLMN   ;* [D]  between col
    STA $55     ;* [D]  #2 & #21
    LDA TOGGL
    EOR #$BB
    STA TOGGL
    CMP #$9B    ;* [D]  Only bother if
    BEQ SHFNL3  ;* [D]    were on the
    LDA DATA+512-21 ;* [D] 1st column
    CMP #$9B    ;* [D]   3-char sec cnt?
    BNE SHFNL2  ;* [D] Br.=4 char
    LDA #$20    ;* [D] Clear extra CR
    STA DATA+512-21 ;* [D]   w/a space
SHFNL2
    LDA TOGGL   ;* [D] Re-set A reg
SHFNL3
    STA DATA+512-20
;SHFNL          ;* old routines in place
;    LDA TOGGL  ;* for the moment only
;    EOR #$BB
;    STA TOGGL
;    STA DATA+512-20
CLERXIT
    RTS 
; 
EOFEXIT
    LDA #$9B
    CMP TOGGL
    BEQ CLERXIT
    DEC ICBAL,X
    INC ICBLL,X
    STA DATA+512-39
    RTS 
;
TOGGL
    .BYTE $9B
COLMN
    .BYTE $15   ;* [D] Scrn column #21
; 
;  COPY ONE FILE (AS MANY MEMORY LOADS AS NEEDED)
; 
COPYFL
    LDX CSRC
    LDA ICBLL,X
    ORA ICBLL+1,X
    BEQ NOOUTP
    LDA SWPFLG
    BPL WRFILE
    LDA # <IDD
    LDX # >IDD
    JSR PRTMSG
    JSR CHRGET
    LDX CDES
    JSR RESET
WRFILE
    LDX CDES
    BNE DOWRFI
    JSR CLEARIT
    LDX #$00
DOWRFI
    LDA ICHID,X ; OPEN?
    BPL PUTOUT  ; YES, WRITE NEXT BLOCK
    LDX OPT
    LDA #8
    CPX #'A     ; APPEND?
    BNE DOPO1
    LDA #9
DOPO1
    LDX CDES
    STA ICAX1,X
    JSR ANYDEN  ; OPEN THE OUTPUT FILE
    BMI TOCIOR
PUTOUT
    LDX CDES
    LDY CSRC
    LDA ICBLL,Y
    STA ICBLL,X
    LDA ICBLL+1,Y
    STA ICBLL+1,X
    LDA ICBAL,Y
    STA ICBAL,X
    LDA ICBAL+1,Y
    STA ICBAL+1,X
    LDA #PUTCHR
    STA ICCOM,X
    JSR CIOCL   ; WRITE NEXT BLOCK OF DATA
NOOUTP
    LDX CSRC
    LDA ICSTA,X ; EOF?
    CMP #$88
    BEQ CPYXIT
    LDA SWPFLG
    BPL RECOPY
    LDA # <ISD
    LDX # >ISD
    JSR PRTMSG
    JSR CHRGET
    LDX CSRC
    JSR RESET
    JMP RECOPY
; 
COPYF
    LDX CSRC
    STA ICCOM,X
    LDA #$9B
    STA TOGGL
RECOPY
    LDX CSRC
    LDA #0
    STA DATA+512-17
    LDA BUFAD
    LDY BUFAD+1
    JSR DEFBUF
    LDA BUFLEN
    STA ICBLL,X
    LDA BUFLEN+1
    STA ICBLL+1,X
    JSR CIOV    ; READ DIRECTORY DATA
    BPL TOCPFL
    CPY #$88    ; END OF FILE?
    BNE TOCIOR  ; IF ERROR, ABORT
TOCPFL
    JMP COPYFL
;
TOCIOR
    JMP CIOER1
; 
CPYXIT
    LDX CDES
    BEQ NOTCL
    JSR CLOS2
    LDA DOSRNM+1 ; NEED TO RENAME DOS.SYS?
    BEQ NOTCL
    JSR SOPEN   ; IF COPYING DOS.SYS (REALLY 'DIAMOND'OS.SYS)
    .BYTE 0
    .BYTE DEL
    .WORD DOSRNM ; DELETE EXISTING DOS.SYS
    JSR SOPEN
    .BYTE 8
    .BYTE OPEN
    .WORD DOSSYS ; MAKE NEW ONE
    JSR SOPEN   ; and close DOS.SYS
    .BYTE 0,$0C,0,0 ; writing
    LDA #0      ; CLEAR RENAME FLAG
    STA DOSRNM+1
NOTCL
    LDX CSRC
    JMP CLOS2
; 
; 
;  SCAN DIRECTORY AND BUILD THE NEXT FILE NAME
;  EXIT WITH NOT-EQUAL IF AT END
; 
SCNDIR
    LDA # <DATA
    LDY # >DATA
    JSR DBUF10
    LDA #GETREC
    STA ICCOM+$10
    LDA #32
    STA ICBLL+$10
    LDA #0
    STA ICBLL+1+$10
    STA CBYTE   ; ASSUME NOT A DIRECTORY
    JSR CIOCL   ; READ A FILE NAME
    LDA DATA+1
    CMP #':
    BCS NOTDIRD
    CMP #'0
    BCS SCNDX
NOTDIRD
    BEQ GOTSPC
    LDA DATA+10
    CMP CBSAV
    BNE NOTSYS
GOTSPC
    DEC CBYTE
NOTSYS
    LDX FNPT
    LDY #2
MDN1
    LDA DATA,Y
    CMP #$20    ; space
    BEQ MDN2
    STA PAR,X
    INX 
    INY 
    CPY #10
    BCC MDN1
MDN2
    LDA #'.
    STA PAR,X
    INX 
    LDY #10
MDN3
    LDA DATA,Y
    CMP #$20    ; space
    BEQ MDN4
    STA PAR,X
    INY 
    INX 
    CPY #13
    BCC MDN3
MDN4
    LDA #'.
    CMP PAR-1,X
    BNE MDN5
    DEX 
MDN5
    LDA #0      ; TERMINATE FILE NAME
    STA PAR,X
    CLC 
SCNDX
    RTS 
; 
GETLIN
    LDA # <DATA+3
    STA FNPTR
    STA ICBAL
    LDA # >DATA+3
    STA FNPTR+1
    STA ICBAL+1
    LDA #GETREC
    STA ICCOM
    LDX #1
    STX ICBLL+1
    DEX 
    STX ICBLL
    LDY #0
    STY PTR
; 
CIOCL
    JSR CIOV
    TYA 
    BMI CIOER1
    RTS 
;
CIOER1
    STY FR0
    LDA #0
    STA FR0+1
    JSR IFP
    JSR FASCII
    LDY #0
    LDA (INBUFF),Y
    STA CIERC
    INY 
    LDA (INBUFF),Y
    STA CIERC+1
    INY 
    LDA (INBUFF),Y
    AND #$7F
    STA CIERC+2
    JSR ERRXIT
    .BYTE "Error -- "
CIERC
    .BYTE "000",$9B,0
HEXDEF
    LDY DATA+3
    CPY #$9B
    BNE GETNO2
    RTS 
; 
GETNUM
    CLC 
    .BYTE $24   ; SKIP SINGLE BYTE
GETNO2
    SEC 
    ROR TEMP2
    JSR NXTFLD
    STY VECTOR
    STY VECTOR+1
GETND
    LDA (FNPTR),Y
    INY 
    CMP #'F+1   ; IS IT A DIGIT
    BCS GETNDE
    SBC #'0-1   ; NOTE THAT CY=0
    BCC GETND1
    CMP #10     ; 0-9?
    BIT TEMP2
    BPL GOT10
    BCC GOT1    ; YES, SHIFT INTO NUMBER
    CMP #17     ; A-F?
    BCS GOT16   ; YES, HANDLE IT
GETND1
    SEC 
    ADC #'0-1
GETNDE
    STY PTR
    TAY 
    LDA VECTOR
    LDX VECTOR+1
    RTS 
; 
GOT10
    BCS GETND1
    PHA 
    ASL VECTOR
    ROL VECTOR+1
    LDA VECTOR
    LDX VECTOR+1
    ASL VECTOR
    ROL VECTOR+1
    ASL VECTOR
    ROL VECTOR+1
    CLC 
    ADC VECTOR
    STA VECTOR
    PLA 
    PHP 
    CLC 
    ADC VECTOR
    STA VECTOR
    TXA 
    ADC VECTOR+1
    PLP 
    ADC #0
    STA VECTOR+1
    JMP GETND
; 
GOT16
    SBC #7
GOT1
    ASL VECTOR
    ROL VECTOR+1
    ASL VECTOR
    ROL VECTOR+1
    ASL VECTOR
    ROL VECTOR+1
    ASL VECTOR
    ROL VECTOR+1
    ORA VECTOR
    STA VECTOR
    JMP GETND
; 
;  GETFN -- READ A LINE, GET FILENAME FROM IT
; 
GETFN
    LDA #0
    STA DOSRNM+1
    JSR GETLIN
    BEQ WCTSTL
; 
;  GETFN2 -- EXTRACT A FILENAME FROM A LINE ALREADY READ IN
;            X IS THE OFFSET IN THE BUFFER
; 
GETFN2
    JSR NXTFLD
WCTSTL
    LDA (FNPTR),Y
    INY 
    CMP #'?
    BEQ SETWC   ; IF ? OR * FOUND,
    CMP #'*
    BNE CKEOFN  ; SET FLAG, FIND FIRST MATCH
SETWC
    LDA #0
    STA CPYTYP
    BEQ WCTSTL
CKEOFN
    CMP #$9B    ; IF EOL, CONTINUE WIT SINGLE FILE
    BEQ FNSET
    CMP #'.
    BEQ WCTSTL
    CMP #'/
    BCC FNSET
    BNE WCTSTL
SLSHLP
    LDA (FNPTR),Y
    CMP #'S
    BNE NCPSYS
    STA CBSAV
    BEQ SAVED
NCPSYS
    CMP #'X
    BNE NOTSWP
    LDA #$80
    STA SWPFLG
    BMI SAVED
NOTSWP
    STA OPT     ; SAVE OPTION CODE
SAVED
    DEY 
    LDA #0
    STA (FNPTR),Y
    INY 
    INY 
    LDA (FNPTR),Y
    INY 
    CMP #'/
    BEQ SLSHLP
    CMP #'.
    BCC FNSET
    CMP #$9B
    BEQ FNSET
    DEY 
FNSET
    STY PTR     ; SAVE POINTER TO SECOND ARG.
    DEY 
    LDA (FNPTR),Y
    STA DELIM
    LDA #0
    STA (FNPTR),Y
    TAY 
    LDA (FNPTR),Y
    CMP #'0
    BCC DEFDRV
    CMP #':
    BEQ DEFDRV
    INY 
    BCS LKFCOL
    TAX 
    LDA #':
    CMP (FNPTR),Y
    BEQ DBEFOR
    DEY 
    STA (FNPTR),Y
    TXA 
    BNE DGTCOD
LKFCOL
    LDA (FNPTR),Y ; SCAN FOR DRIVE ID
    BEQ DEFDRV
    CMP #':
    BEQ DEVINC  ; DEVICE INCLUDED
    INY 
    LDA (FNPTR),Y
    CMP #':
    BEQ DEVINC
DEFDRV
    LDA #':
DGTCOD
    JSR DECFNP
DBEFOR
    LDA #'D
    JSR DECFNP
DEVINC
    LDY FNPTR
    LDA FNPTR+1
    RTS 
; 
NXTFLD
    CLC 
    LDA PTR     ; MOVE INDEX TO A
    ADC FNPTR
    STA FNPTR
    LDA #0
    TAY 
    ADC FNPTR+1
    STA FNPTR+1
    RTS 
; 
DECFNP
    LDY FNPTR
    BNE DECFP1
    DEC FNPTR+1
DECFP1
    DEC FNPTR
    INC PTR
    LDY #0
    STA (FNPTR),Y
GETDN1
    RTS 
; 
;  REQUIRE A DISK DRIVE (NO FILE SPECIFICATION)
; 
GETDN2
    JSR GETFN2  ; GET NEXT FILE NAME
    JMP GETDNE  ; THEN CHECK FOR DRIVE ONLY
;
GETDN
    JSR GETFN
GETDNE
    STY ICBAL+$10
    STA ICBAL+1+$10
    LDY #$FF
GETDNL
    INY 
    TAX 
    LDA (FNPTR),Y
    BNE GETDNL
    CPX #':     ; ANY FILE NAME INCLUDED?
    BEQ GETDN1  ; NO, THEN RETURN
    JSR ERRXIT
    .BYTE "File name not allowed!",$9B,0
; 
;  UPDATE DENSITY OF DISK IN DRIVE
; 
GETDEN
    CMP #':
    BNE GTDEN2
    LDA DFUNIT
GTDEN2
    AND #$0F    ; MAKE UNIT BINARY
    LDX #0
    STX DAUX1+1
    INX 
    STX DAUX1
    LDX # <DATA+512-128
    STX DBUFLO
    LDX # >DATA+512-128
    STX DBUFLO+1
    JSR RSEC2
    BMI GETDN3
    JMP JSTRD
; 
;  REQUIRE A DISK FILE NAME, SAVING THE POINTER IN IOCB10
; 
CKDSK
    STY ICBAL+$10
    STA ICBAL+1+$10
    LDY #0
    LDA (FNPTR),Y
    CMP #'D
    BEQ GETDN3
    JSR ERRXIT
    .BYTE "Not a disk file!",$9B,0
; 
;  WAIT FOR SOURCE DISK
; 
CWFSD
    LDA SWPFLG
    BMI WFSD
GETDN3
    RTS         ; IF NO WAIT REQUIRED
;
WFSD
    JSR PRINT
ISD
    .BYTE "Insert SOURCE disk, press "
    .BYTE +$80,"RETURN"
    .BYTE 0
    JSR CHRGET
    BIT SWPFLG
    BVS GETDN3  ; IF IN DUP-DISK
    LDX CSRC
RESET
    LDY ICDNO,X
    STY UNNO
    LDA ICAX1+5,X
    BEQ NOCHG
    CMP #3
    BCS NOCHG
SETDEN
    STA SECSIZ-1,Y
    LDX #15
SAVMAP
    LDA MAPBUF,X
    STA SAXMAP,X
    DEX 
    BPL SAVMAP
    JSR DOFSIN
    LDX #15
RSTMAP
    LDA SAXMAP,X
    STA MAPBUF,X
    DEX 
    BPL RSTMAP
NOCHG
    RTS 
; 
SAXMAP
    .BYTE 0,0,0,0,0,0,0,0
    .BYTE 0,0,0,0,0,0,0,0
; 
;  RECONFIGURE DENSITY OR CONFIGURATION
; 
DOFSIN
    LDX #9
DOFLOP
    LDA WOTDCB,X
    STA DUNIT+1,X
    DEX 
    BPL DOFLOP
    LDX #$31
    STX DUNIT-1
    LDX UNNO
    STX DUNIT   ; TELL SIO DRIVE TO CONFIGURE
    LDY SECSIZ-1,X ; GET DENSITY/SECTOR SIZE
    LDA DRVDEF-1,X ; GET DRIVE SPECIFICATION
    JMP SETDRV  ; GO CONFIGURE DRIVE
; 
;  SET UP PAR AND IOCB10 FOR A DIRECTORY SCAN (MULTI-FILE ACTIVITY)
; 
SETSCN
    STA ICCOM+$20
    LDA # <PAR
    LDX # >PAR
    STA ICBAL+$20
    STX ICBAL+1+$20
    JSR SETPTR
    LDX #$10    ; OPEN IOCB10 AS DIRECTORY
OPDIR
    LDA #6      ; OPEN IOCB AS DIRECTORY
    STA ICAX1,X
; 
;  OPEN A FILE INDEPENDENT OF DRIVE DENSITY
; 
ANYDEN
    LDA #0
    STA ICAX1+1,X
    STA ICAX1+5,X
    LDA #OPEN
    JSR SCMD
    BPL SAVDEN
    JMP CIOER1
; 
SAVDEN
    LDY DUNIT
    LDA SECSIZ-1,Y
    STA ICAX1+5,X
    RTS 
; 
;  SET UP 'PAR' FOR A WILD CARD COPY
; 
DEFPAR
  JSR SETPTR
  LDA (FNPTR),Y
  BNE DEFPX
  STA CPYTYP
  STA PAR+2,Y
  LDA #'*
  STA PAR,Y
  STA PAR+1,Y
  LDA #$9B    ; termination!!!
  STA PAR+2,Y
DEFPX
  RTS 
; 
SETPTR
  LDY #$FF
SETLP1
  INY 
  LDA (FNPTR),Y
  STA PAR,Y
  BNE SETLP1
SETLP2
  DEY 
  LDA PAR,Y
  CMP #':
  BEQ SETLP3
  CMP #'>     ; account for sparta type
  BNE SETLP2
SETLP3
  INY 
  STY FNPT
  RTS 
; 
DOSRNM
  .BYTE "D",0,":",$60,"OS.SYS,"
CKDTST
  .BYTE "DOS.SYS",0
; 
;  REPORT ERROR, THEN RETURN TO MENU
; 
ERRXIT
  PLA 
  STA BUFADR
  PLA 
  STA BUFADR+1
  JSR PRTENT  ; WRITE ERROR MESSAGE FOLLOWING 'JSR ERRXIT'
  JMP MENUSL  ; THEN RETURN TO MENU
;