view disk.s @ 0:605ff82c4618

Initial check in with cleaned up sources This is the initial check in the source code in a state where it builds byte accurate copies of all the various ROM versions included.
author William Astle <lost@l-w.ca>
date Sat, 08 Dec 2018 19:57:01 -0700
parents
children
line wrap: on
line source

                *pragma nolist
                include defs.s
; Various references to Color Basic and Extended Color Basic which are listed here to allow this ROM to be built independently.
XBWMST          equ 0x80c0
L813C           equ 0x813c
L8168           equ 0x8168
XVEC3           equ 0x8273
XVEC8           equ 0x8286
XVEC18          equ 0x829c
L8311           equ 0x8311
L8316           equ 0x8316
L836C           equ 0x836c
L8748           equ 0x8748
L880E           equ 0x880e
XVEC15          equ 0x8846
XVEC17          equ 0x88f0
L8955           equ 0x8955
L8C1B           equ 0x8c1b
XVEC4           equ 0x8cf1
XVEC9           equ 0x8e90
L95AC           equ 0x95ac
L962E           equ 0x962e
L9650           equ 0x9650
L96CB           equ 0x96cb
L96EC           equ 0x96ec
L975F           equ 0x975f
L9FB5           equ 0x9fb5
LA0E2           equ 0xa0e2
BAWMST          equ 0xa0e8
LA171           equ 0xa171
LA176           equ 0xa176
PUTCHR          equ 0xa282
LA35F           equ 0xa35f
LA37C           equ 0xa37c
LA3ED           equ 0xa3ed
LA3FB           equ 0xa3fb
LA406           equ 0xa406
LA426           equ 0xa426
LA429           equ 0xa429
LA42D           equ 0xa42d
LA549           equ 0xa549
LA59A           equ 0xa59a
LA5A2           equ 0xa5a2
LA5A5           equ 0xa5a5
LA5AE           equ 0xa5ae
LA5C7           equ 0xa5c7
LA5DA           equ 0xa5da
LA5E4           equ 0xa5e4
LA603           equ 0xa603
LA616           equ 0xa616
LA61C           equ 0xa61c
LA61F           equ 0xa61f
LA928           equ 0xa928
LA951           equ 0xa951
LA7D1           equ 0xa7d1
LA7E9           equ 0xa7e9
LA974           equ 0xa974
LAC37           equ 0xac37
LAC44           equ 0xac44
LAC46           equ 0xac46
LAC60           equ 0xac60
LAC73           equ 0xac73
LAC7C           equ 0xac7c
LACEF           equ 0xacef
LAD19           equ 0xad19
LAD21           equ 0xad21
LAD33           equ 0xad33
LAD9E           equ 0xad9e
LADC6           equ 0xadc6
LADD4           equ 0xadd4
LADEB           equ 0xadeb
LAE15           equ 0xae15
LAF9A           equ 0xaf9a
LAFA4           equ 0xafa4
LAFB1           equ 0xafb1
LB00C           equ 0xb00c
LB01E           equ 0xb01e
LB069           equ 0xb069
LB143           equ 0xb143
LB146           equ 0xb146
LB148           equ 0xb148
LB156           equ 0xb156
LB244           equ 0xb244
LB262           equ 0xb262
LB166           equ 0xb166
SYNCOMMA        equ 0xb26d
LB26F           equ 0xb26f
LB277           equ 0xb277
LB2CE           equ 0xb2ce
LB357           equ 0xb357
LB3E6           equ 0xb3e6
LB44A           equ 0xb44a
LB4F3           equ 0xb4f3
GIVABF          equ 0xb4f4
LB50F           equ 0xb50f
LB516           equ 0xb516
LB654           equ 0xb654
LB657           equ 0xb657
LB659           equ 0xb659
LB69B           equ 0xb69b
LB6A4           equ 0xb6a4
EVALEXPB        equ 0xb70b
LB70E           equ 0xb70e
LB738           equ 0xb738
LB73D           equ 0xb73d
LIST            equ 0xb764
LB958           equ 0xb958
LB95C           equ 0xb95c
STRINOUT        equ 0xb99c
LB99F           equ 0xb99f
LB9A2           equ 0xb9a2
LB9AC           equ 0xb9ac
LB9AF           equ 0xb9af
LB9C5           equ 0xb9c5
LBB91           equ 0xbb91
LBC14           equ 0xbc14
LBC33           equ 0xbc33
LBC35           equ 0xbc35
LBC5F           equ 0xbc5f
INT             equ 0xbcee
LBDCC           equ 0xbdcc
LBDD9           equ 0xbdd9
                pragma noexpandcond
                *pragma list
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; DISK EXTENDED COLOR BASIC
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                ifeq DISKVER
DHITOK          equ 0xe0                        ; highest command token
CYEAR           equ '1                          ; ones digit of copyright year
MINORVER        equ '0
                else
DHITOK          equ 0xe1                        ; highest command token
CYEAR           equ '2                          ; ones digit for copyright year
MINORVER        equ '1
                endc
                org DOSBAS
                fcc 'DK'                        ; magic number Extended Basic uses to identify the presence of a Disk ROM
LC002           bra LC00C                       ; entry point - jump around vector table
DCNVEC          fdb DSKCON                      ; DSKCON indirect entry point
DSKVAR          fdb DCOPC                       ; address of DSKCON parameter block
                ifeq DISKVER-1
DSINIT          fdb DOSINI                      ; vector to an initialization routine, the utility of which is unclear
DOSVEC          fdb DOSCOM                      ; pointer to the actual location of the DOS command
                endc
LC00C           ldx #DBUF0                      ; point to start of Disk Basic memory
LC00F           clr ,x+                         ; clear a byte
                cmpx #DFLBUF                    ; at end of statically allocated Disk Basic memory?
                bne LC00F                       ; brif not
                ldx #LC109                      ; point to initializer for the command interpretation table
                ldu #COMVEC+20                  ; point to command interpretation table location for Disk Basic
                ldb #10                         ; ten bytes in each table entry
                jsr LA59A                       ; initialize interpretation table
                ldd #LB277                      ; syntax error address
                std 3,u                         ; set command handler for "user" table to error
                std 8,u                         ; set function handler for "user" table to error
                clr ,u                          ; mark user table with 0 command keywords
                clr 5,u                         ; mark user table with 0 function keywords
                ldd #DXCVEC                     ; intercept Extended Basic's command handler
                std COMVEC+13
                ldd #DXIVEC                     ; intercept Extended Basic's function handler
                std COMVEC+18
                ldu #RVEC0                      ; point to first RAM vector
LC03B           lda #0x7e                       ; op code of JMP extended
                sta RVEC22                      ; set first byte of GET/PUT vector to JMP
                sta ,u+                         ; set this vector to be a JMP instruction
                ldd ,x++                        ; get vector destination
                std ,u++                        ; set the vector destination
                cmpx #LC139                     ; done the whole list?
                bne LC03B                       ; brif not
                ldx #DVEC22                     ; install handler for GET/PUT vector
                stx RVEC22+1
                ifeq DISKVER-1
                ldx #DVEC20                     ; install replacement interpretation loop handler
                stx RVEC20+1
                endc
                ldx #DUSRVC                     ; relocate USR vector table
                stx USRADR
                ldu #LB44A                      ; default USR address is illegal function call
                ldb #10                         ; there are 10 vectors
LC061           stu ,x++                        ; set a vector
                decb                            ; done all?
                bne LC061                       ; brif not
                ldx #DNMISV                     ; install NMI handler
                stx NMIVEC+1
                lda #0x7e                       ; make it a JMP
                sta NMIVEC
                ldx #DIRQSV                     ; install IRQ handler (ECB and CB already made it a JMP)
                stx IRQVEC+1
                lda #19                         ; initialze the number of changes needed to trigger a FAT write
                sta WFATVL
                clr FATBL0                      ; mark all four FAT images as having no open files
                clr FATBL1
                clr FATBL2
                clr FATBL3
                ldx #DFLBUF                     ; point to the start of the disk "heap"
                stx RNBFAD                      ; set start of random file buffers as the end of the allocated space
                leax 0x100,x                    ; allocate 256 bytes for random file buffers by default
                stx FCBADR                      ; save start of FCBs (and end of random file buffers)
                leax 1,x                        ; leave an empty byte before FCBs (why?)
                stx FCBV1                       ; set address of FCB 1
                clr <<FCBTYP,x                  ; mark it closed
                leax FCBLEN,x                   ; set address of FCB 2 (2 user FCBs allocated at startup)
                stx FCBV1+2
                clr <<FCBTYP,x                  ; mark it closed
                leax FCBLEN,x                   ; set address of FCB 3 (system FCB)
                stx FCBV1+4
                clr <<FCBTYP,x                  ; mark it closed
                lda #2                          ; set 2 active FCBs
                sta FCBACT
                leax FCBLEN,x                   ; point to end of active FCBs
                tfr x,d                         ; put it in D so we can do stuff with it
                tstb                            ; is it a partial memory page?
                ifeq DISKVER
                beq LC0C2                       ; brif not
                else
                beq LC0BD                       ; brif not
                endc
                inca                            ; round up
                ifeq DISKVER-1
LC0BD           bita #1                         ; is it even (multiple of 512)?
                beq LC0C2                       ; brif so
                inca                            ; round up to even 512 byte boundary
                endc
LC0C2           tfr a,b                         ; save start of graphics memory
                addb #24                        ; reserve 4 graphics pages
                stb TXTTAB                      ; set start of program there
                jsr L96EC                       ; do graphics initialization (A is the start of grahpics memory)
                lda BEGGRP                      ; get start of current grahpics page
                adda #6                         ; make one page used
                sta ENDGRP
                ifeq DISKVER-1
                jsr [DSINIT]                    ; do the pointless initialization routine
                endc
                bsr LC0F0                       ; initialize FDC stuff and interrupt any action underway
                andcc #0xaf                     ; enable interrupts
                ldx #LC139-1                    ; point to sign on message
                jsr STRINOUT                    ; show sign on
                ldx #DKWMST                     ; install warm start handler
                stx RSTVEC
                jmp LA0E2                       ; jump into mainline Color Basic
DKWMST          nop                             ; flag warm start routine as valid
                bsr LC0F0                       ; initialize FDC variables and interrupt any action underway
                jsr LD2D2                       ; close files and do some other stuff
                jmp XBWMST                      ; transfer control to ECB's warm start
LC0F0           clr NMIFLG                      ; reset the NMI handler vector
                clr RDYTMR                      ; disable the drive timeout counter
                clr DRGRAM                      ; turn off all drive selects and motors (RAM copy)
                clr DSKREG                      ; turn off all drive selects and motors (real hardware)
                lda #0xd0                       ; send "force interrupt" to controller
                sta FDCREG
                exg a,a                         ; wait for status to stabilize
                exg a,a
                lda FDCREG                      ; clear the status indicator (no error handling - nothing useful to do anyway)
                rts
                ifeq DISKVER
LC109           fcb 19                          ; number of keywords (commands)
                else
LC109           fcb 20                          ; number of keywords (commands)
                endc
                fdb LC192                       ; keyword table (commands)
                fdb LC238                       ; handler (commands)
                fcb 6                           ; number of keywords (functions)
                fdb LC219                       ; keyboard table (functions)
                fdb LC24E                       ; handler (functions)
LC113           fdb DVEC0,DVEC1,DVEC2           ; RAM hook handler addresses
                fdb DVEC3,DVEC4,DVEC5
                fdb DVEC6,DVEC7,DVEC8
                fdb XVEC9,DVEC10,DVEC11
                fdb DVEC12,DVEC13,DVEC14
                fdb DVEC15,DVEC12,DVEC17
                fdb DVEC18
; Sign on message
LC139           fcc 'DISK EXTENDED COLOR BASIC 1.'
                fcb MINORVER
                fcb 0x0d
                fcc 'COPYRIGHT (C) 198'
                fcb CYEAR
                fcc ' BY TANDY'
                fcb 0x0d
                fcc 'UNDER LICENSE FROM MICROSOFT'
                fcb 0x0d,0x0d,0x00
; Keyword list (commands)
LC192           fcs 'DIR'                       ; 0xce
                fcs 'DRIVE'                     ; 0xcf
                fcs 'FIELD'                     ; 0xd0
                fcs 'FILES'                     ; 0xd1
                fcs 'KILL'                      ; 0xd2
                fcs 'LOAD'                      ; 0xd3
                fcs 'LSET'                      ; 0xd4
                fcs 'MERGE'                     ; 0xd5
                fcs 'RENAME'                    ; 0xd6
                fcs 'RSET'                      ; 0xd7
                fcs 'SAVE'                      ; 0xd8
                fcs 'WRITE'                     ; 0xd9
                fcs 'VERIFY'                    ; 0xda
                fcs 'UNLOAD'                    ; 0xdb
                fcs 'DSKINI'                    ; 0xdc
                fcs 'BACKUP'                    ; 0xdd
                fcs 'COPY'                      ; 0xde
                fcs 'DSKI$'                     ; 0xdf
                fcs 'DSKO$'                     ; 0xe0
                ifeq DISKVER-1
                fcs 'DOS'                       ; 0xe1
                endc
; Jump table (commands)
LC1F1           fdb DIR                         ; 0xce DIR
                fdb DRIVE                       ; 0xcf DRIVE
                fdb FIELD                       ; 0xd0 FIELD
                fdb FILES                       ; 0xd1 FILES
                fdb KILL                        ; 0xd2 KILL
                fdb LOAD                        ; 0xd3 LOAD
                fdb LSET                        ; 0xd4 LSET
                fdb MERGE                       ; 0xd5 MERGE
                fdb RENAME                      ; 0xd6 RENAME
                fdb RSET                        ; 0xd7 RSET
                fdb SAVE                        ; 0xd8 SAVE
                fdb WRITE                       ; 0xd9 WRITE
                fdb VERIFY                      ; 0xda VERIFY
                fdb UNLOAD                      ; 0xdb UNLOAD
                fdb DSKINI                      ; 0xdc DSKINI
                fdb BACKUP                      ; 0xdd BACKUP
                fdb COPY                        ; 0xde COPY
                fdb DSKI                        ; 0xdf DSKI$
                fdb DSKO                        ; 0xe0 DSKO$
                ifeq DISKVER-1
                fdb DOS                         ; 0xe1 DOS
                endc
; Keyword list (functions)
LC219           fcs 'CVN'                       ; 0xa2
                fcs 'FREE'                      ; 0xa3
                fcs 'LOC'                       ; 0xa4
                fcs 'LOF'                       ; 0xa5
                fcs 'MKN$'                      ; 0xa6
                fcs 'AS'                        ; 0xa7 (here to avoid conflict with ASC)
; Jump table (functions)
LC22C           fdb CVN                         ; 0xa2 CVN
                fdb FREE                        ; 0xa3 FREE
                fdb LOC                         ; 0xa4 LOC
                fdb LOF                         ; 0xa5 LOF
                fdb MKN                         ; 0xa6 MKN$
                fdb LB277                       ; 0xa7 AS (not actually a function)
; Command handler
LC238           cmpa #DHITOK                    ; is it a Disk Basic valid command?
                bhi LC244                       ; brif not
                ldx #LC1F1                      ; point to jump table
                suba #0xce                      ; normalize Disk Basic tokens to 0
                jmp LADD4                       ; return to mainline to execute command
; The next two instructions are completely pointless. If we get here, the comparison has already
; been done and the branch condition is the exact opposite of what brought us here.
LC244           cmpa #DHITOK                    ; is it a Disk Basic token?
                lbls LB277                      ; brif not
                jmp [COMVEC+33]                 ; transfer control to user command handler
; Function handler
LC24E           cmpb #(0xa7-0x80)*2             ; is it a Disk Basic function token?
                bls LC256                       ; brif so
                jmp [COMVEC+38]                 ; transfer control to user handler if not
LC256           subb #(0xa2-0x80)*2             ; normalize Disk Basic tokens to 0
                pshs b                          ; save jump table offset
                jsr LB262                       ; evaluate parenthetical expression
                puls b                          ; get back jump table offset
                ldx #LC22C                      ; point to jump table
                jmp LB2CE                       ; rejoin mainline code to transfer control
; Error handler
DVEC17          puls y                          ; get back original caller
                jsr LAD33                       ; reset some stuff like CONT
                jsr LD2D2                       ; clean up some Disk Basic stuff
                pshs y,b                        ; put return address back and save error code
                jsr DVEC7                       ; close all files
                puls b                          ; get back error code
                cmpb #2*27                      ; is it a Disk Basic error code?
                lblo XVEC17                     ; brif not - pass it to Extended Basic
                leas 2,s                        ; dump the return address
                jsr LA7E9                       ; stop tape
                jsr LA974                       ; stop sound
                clr DEVNUM                      ; reset output to screen
                jsr LB95C                       ; do a newline
                jsr LB9AF                       ; do a ?
                ldx #LC290-2*27                 ; point to error message table
                jmp LAC60                       ; rejoin mainline error handler
; Error strings (note that NE error is provided by Extended Basic)
LC290           fcc 'BR'                        ; 27 Bad record
                fcc 'DF'                        ; 28 Disk full
                fcc 'OB'                        ; 29 Out of buffer space
                fcc 'WP'                        ; 30 Write protected
                fcc 'FN'                        ; 31 Bad file name
                fcc 'FS'                        ; 32 Bad file structure
                fcc 'AE'                        ; 33 File already exists
                fcc 'FO'                        ; 34 Field overflow
                fcc 'SE'                        ; 35 Set to non-fielded string
                fcc 'VF'                        ; 36 Verify error
                fcc 'ER'                        ; 37 Input or write past end of record
BASEXT          fcc 'BAS'                       ; default Basic program file extension
DEFEXT          fcc '   '                       ; default blank extension (three spaces)
DATEXT          fcc 'DAT'                       ; default extension for data files
BINEXT          fcc 'BIN'                       ; default extension for binary files
; "CLS" vector handler. Extended Basic also chose to use this vector as a way to hook into
; the GET/PUT commands, the RENUM token check, and the Extended Basic "functions as commands"
; interpretation scheme. Only the GET/PUT hook is used. Checking the caller address is hacky
; but unavoidable here.
DVEC22          pshs x,cc                       ; save scratch register and flags
                ldx 3,s                         ; get caller address
                cmpx #L975F                     ; is it coming from GET/PUT?
                bne LC2BF                       ; brif not
                cmpa #'#                        ; is it GET # or PUT # (disk file operations)?
                beq LC2C1                       ; brif so - don't return to mainline
LC2BF           puls cc,x,pc                    ; restore scratch register, flags, and return to mainline
; GET/PUT handler for random file access
LC2C1           leas 5,s                        ; remove saved state from above and don't return to mainline
                jsr LC82E                       ; evaluate device number and get FCB pointer
                stx FCBTMP                      ; save the FCB pointer
                clr FCBGET,x                    ; reset the get data pointer
                clr FCBGET+1,x
                clr FCBPUT,x                    ; reset the put data pointer
                clr FCBPUT+1,x
                clr FCBPOS,x                    ; reset print position
                lda FCBDRV,x                    ; get drive number for the file
                sta DCDRV                       ; set it as the DSKCON drive number
                jsr GETCCH                      ; end of statement?
                beq LC2EA                       ; brif so - use current record
                jsr SYNCOMMA                    ; insist on a comma
                ifeq DISKVER
                jsr LB3E6                       ; evaluate expression to D
                else
                jsr LB73D                       ; get unsigned 16 bit number to X
                tfr x,d                         ; stash it in D so we can use X as a pointer
                endc
LC2E6           ldx FCBTMP                      ; get back FCB pointer
                std FCBREC,x                    ; set the current record number
                ifeq DISKVER
LC2EA           jsr LC685                       ; bump record number
                else
LC2EA           ldd FCBREC,x                    ; get desired record number
                beq LC30B                       ; brif 0 - records start at 1
                jsr LC685                       ; bump record number
                endc
                ldd FCBRLN,x                    ; get record length
                ldx FCBBUF,x                    ; point to FCB data buffer
                pshs x,b,a                      ; save them
                leax -2,u                       ; point to record number (but zero based)
                jsr L9FB5                       ; do unsigned multiply of record length and record number
                pshs u,y                        ; save product (this is the file offset to the record)
                lda ,s+                         ; is MSB 0?
                bne LC30B                       ; brif not - record number too big
                puls x                          ; middle two bytes are sector number in file - retrieve it
                puls b                          ; LSB is offset into the sector - retrieve it
LC306           cmpx #(35-1)*18                 ; is it more than the maximum number of sectors a file can have?
                blo LC310                       ; brif so
LC30B           ldb #2*27                       ; code for bad record
                jmp LAC46                       ; raise error
LC310           ldu FCBTMP                      ; get pointer to FCB
                cmpx FCBSOF,u                   ; is it the same sector we're already handling?
                lbeq LC3CF                      ; brif so
                pshs x,b                        ; save sector number and sector offset
                lda FCBFLG,u                    ; were we doing get or put?
                beq LC324                       ; brif we were doing get
                clr FCBFLG,u                    ; flag doing get
                ldb #3                          ; write operation code for DSKCON
                bsr LC357                       ; write the sector data
LC324           ldd 1,s                         ; get sector number
                jsr LC784                       ; convert to a granule offset
                pshs b                          ; save granule offset
                jsr LC779                       ; calculate starting sector of granule number
                negb                            ; make negative
                addb 3,s                        ; add LS byte of sector number
                incb                            ; add one - sectors in FCB start at 1
                stb FCBSEC,u                    ; set sector
                ldb FCBFGR,u                    ; get first granule in file
                jsr LC755                       ; fetch FAT pointer
                leau FATCON,x                   ; point to actual granule table
                lda ,s                          ; get number of granules offset to the record
                inca                            ; bump it (compensate for deca below)
LC33E           leax ,u                         ; point X to entry for this granule
                abx
                deca                            ; are we at the correct one?
                beq LC37B                       ; bif not
                stb ,s                          ; save granule offset on stack
                ldb ,x                          ; get next granule in file
                cmpb #0xc0                      ; is it "end of file" flag?
                blo LC33E                       ; brif not
                ldb ,s                          ; get offset to previous granule
                tst VD8                         ; get or put?
                bne LC366                       ; brif put
LC352           ldb #2*23                       ; code for input past end of file
                jmp LAC46                       ; raise error
LC357           leax FCBCON,u                   ; point to data buffer for FCB
LC35A           stb DCOPC                       ; set operation code for DSKCON
                stx DCBPT                       ; set buffer pointer for DSKCON
                leax ,u                         ; point to FCB
                jsr LC763                       ; convert FCB track and sector to DSKCON parameters
                jmp LD6F2                       ; read or write the sector
LC366           pshs x,a                        ; save granule counter and pointer to last used granule
                jsr LC7BF                       ; find a free granule
                tfr a,b                         ; save allocated granule
                puls a,u                        ; get last granule pointer and counter off stack
                stb ,u                          ; add it to the file's granule chain
                deca                            ; do we have enough of them?
                bne LC366                       ; brif not - allocate another
                pshs x,b                        ; save alocated granule and pointer
                jsr LC71E                       ; write the FAT out
                puls b,x                        ; get back allocated granule and pointer
LC37B           leas 1,s                        ; remove granule number
                ldu FCBTMP                      ; point to FCB
                stb FCBCGR,u                    ; save current granule
                lda #0xff                       ; set to illegal sector offset to force sector data to be read
                sta FCBSOF,u
                lda ,x                          ; get next granule pointer
                cmpa #0xc0                      ; last granule?
                blo LC3B2                       ; brif not
                anda #0x3f                      ; get only the number of sectors used
                cmpa FCBSEC,u                   ; compare calculated sector to current sector
                bhs LC3B2                       ; brif sector is <= last one in file
                lda VD8                         ; GET or PUT?
                beq LC352                       ; brif GET - do IE error
                lda FCBSEC,u                    ; get sector number from FCB
                ora #0xc0                       ; add "last granule" flag bits
                sta ,x                          ; update FAT
                jsr LC5A9                       ; write FAT if needed
                ldx FCBRLN,u                    ; get record length
                cmpx #SECLEN                    ; exactly one sector?
                bne LC3AD                       ; brif not
                cmpx FCBLST,u                   ; is number of bytes in last sector a full sector?
                beq LC3B2                       ; brif so
                lda #0x81                       ; set "presaved" flag and force number of bytes to be 256
                skip1                           ; skip next byte ("BRN")
LC3AD           clra                            ; set number of bytes in last sector to 0
                clrb                            ; clear LS byte of D
                std FCBLST,u                    ; set number of bytes used in last sector
LC3B2           ldb #2                          ; DSKCON read operation
                ldx FCBRLN,u                    ; get record length
                cmpx #SECLEN                    ; exactly one sector?
                bne LC3C8                       ; brif not exactly
                leas 7,s                        ; clean up stack
                ldx FCBBUF,u                    ; point to start of random file buffer
                lda VD8                         ; is it GET or PUT?
                beq LC3C5                       ; brif GET
                ldb #3                          ; DSKCON write opreation
LC3C5           jmp LC35A                       ; go read or write a sector
LC3C8           jsr LC357                       ; read a sector into data buffer
                puls b,x                        ; get back byte offset to record
                stx FCBSOF,u                    ; save sector offset
LC3CF           pshs b                          ; save sector byte offset
                jsr LC755                       ; point to FAT
                leax FATCON,x                   ; point to FAT data
                ldb FCBCGR,u                    ; get current granulenumber
                abx                             ; point to granule data
                lda ,x                          ; get this granule's next pointer
                cmpa #0xc0                      ; end of file flag?
                blo LC40A                       ; brif not
                anda #0x3f                      ; convert to number of sectors in final granule
                cmpa FCBSEC,u                   ; are we asking for the last sector?
                bne LC40A                       ; brif not
                ldd FCBLST,u                    ; get number of bytes in last sector
                anda #0x7f                      ; lose pre-saved flag
                pshs d                          ; save number of bytes in last sector
                clra                            ; zero extend byte offset
                ldb 2,s                         ; get byte offset
                addd 3,s                        ; add in record length
                cmpd ,s++                       ; is it more than last sector?
                bls LC40A                       ; brif the whole record fits
                tst VD8                         ; is it GET?
                lbeq LC352                      ; brif so - IE error if file doesn't have a whole record available
                ifeq DISKVER
                anda #1                         ; keep only bit 0 of byte count
                ora #0x80                       ; set pre-saved flag bit
                else
                cmpd #SECLEN                    ; is it a whole sector we need?
                bls LC405                       ; brif not
                ldd #SECLEN                     ; force one sector length
LC405           ora #0x80                       ; set pre-saved flag bit
                endc
                std FCBLST,u                    ; save number of bytes in last sector
LC40A           puls b                          ; get byte offset
                leax FCBCON,u                   ; point to data buffer
                abx                             ; offset into data buffer
                ldu 2,s                         ; point to position in random file buffer
                pshs b                          ; save byte offset
                lda #-1                         ; convert D into a negative 2 byte number representing unused bytes in sector
                addd 1,s
                bhs LC421                       ; brif there are enough bytes to finish record
                std 1,s                         ; save new temporary record length counter
                puls b                          ; restore byte counter
                negb                            ; negate it (B is number of bytes available to a record in this sector)
                bra LC429                       ; move the data
LC421           ldb 2,s                         ; get remaining record length
                clr 1,s                         ; clear the temporary record length counter
                clr 2,s
                leas 1,s                        ; we no longer need byte offset
LC429           lda VD8                         ; GET?
                beq LC42F                       ; brif so
                exg x,u                         ; swap pointers so we write to data buffer
LC42F           jsr LA59A                       ; copy data
                stu 2,s                         ; save new record pointer
                ldu FCBTMP                      ; get pointer to FCB
                lda VD8                         ; GET?
                beq LC43E                       ; brif so
                sta FCBFLG,u                    ; flag as PUT
                stx 2,s                         ; save buffer pointer
LC43E           ldx FCBSOF,u                    ; get sector offset count
                leax 1,x                        ; bump it
                clrb                            ; byte offset in this new sector is 0
                ldu ,s                          ; get length of record needed
                lbne LC306                      ; brif not already completed ar ecord
                puls a,b,x,pc                   ; clean up stack and return
; OPEN handler
DVEC0           leas 2,s                        ; don't return mainline
                jsr LB156                       ; evaluate mode expression
                jsr LB6A4                       ; get first character in the mode string
                pshs b                          ; save it
                jsr LA5A2                       ; parse device number
                tstb                            ; disk file?
                lble LA603                      ; return mainline if not disk file
                puls a                          ; get mode
                pshs a,b                        ; save mode and file number
                clr DEVNUM                      ; reset device to screen
                jsr SYNCOMMA                    ; insist on a comma
                ldx #DATEXT                     ; point to "DAT" extension as default for data file
                jsr LC938                       ; parse file name
                ldd #0x01ff                     ; file type is "data" (1) and ASCII
                std DFLTYP                      ; save file type
                ldx #SECLEN                     ; default record length - one whole sector
                jsr GETCCH                      ; is there a record length specifier?
                beq LC481                       ; brif not
                jsr SYNCOMMA                    ; insist on comma
                jsr LB3E6                       ; evaluate record length
                ldx FPA0+2                      ; get evaluated length
LC481           stx DFFLEN
                lbeq LB44A                      ; record length of 0 makes no sense of error if so
                jsr LA5C7                       ; raise error if more stuff
                puls a,b                        ; get mode and fil enumber
LC48D           pshs a                          ; save mode
                jsr LC749                       ; point to FCB for this file
                lbne LA61C                      ; brif the file is already open
                stx FCBTMP                      ; save FCB pointer
                jsr LC79D                       ; make sure FAT is valid
                jsr LC68C                       ; search for requested file
                puls b                          ; get mode
                lda #INPFIL                     ; input file flag
                pshs a                          ; save it
                cmpb #'I                        ; input mode?
                bne LC4C7                       ; brif not
                jsr LC6E5                       ; see if match was found
                jsr LC807                       ; check if it's already open
                ldx V974                        ; point to directory data
                ldd DIRTYP,x                    ; get file type and ASCII flag
                std DFLTYP                      ; save it
                bsr LC52D                       ; initialize FCB
                jsr LC627                       ; go read first sector from file
LC4BB           jsr LC755                       ; point to FAT
                inc <<FAT0,x                    ; bump number of open files on this disk
                ldx FCBTMP                      ; get back FCB pointer
                puls a                          ; get file type
                sta <<FCBTYP,x                  ; save file type
                rts
LC4C7           asl ,s                          ; set type to output
                cmpb #'O                        ; output requested?
                bne LC4E8                       ; brif not
                tst V973                        ; did file exist?
                beq LC4E1                       ; brif not
                jsr LC6FC                       ; kill the old file
                lda V973                        ; get directory sector number of old file
                sta V977                        ; save as first free directory entry
                ldx V974                        ; get directory image of old file
                stx V978                        ; asve it as first free entry
                ifeq DISKVER
LC4E1           bsr LC567                       ; set up new directory entry on disk
                else
LC4E1           jsr LC567                       ; set up new directory entry on disk
                endc
                bsr LC538                       ; initialize the file buffer
                bra LC4BB                       ; finish setting up FCB
LC4E8           cmpb #'R                        ; random file?
                beq LC4F2                       ; brif so
                cmpb #'D                        ; direct file?
                lbne LA616                      ; brif not - bad file mode
LC4F2           asl ,s                          ; set file type to random
                ldd RNBFAD                      ; get address of random file buffer area
                pshs d                          ; save it
                addd DFFLEN                     ; add in record length
                bcs LC504                       ; brif we overflowed memory
                cmpd FCBADR                     ; is it more than FCB data area?
                bls LC509                       ; brif not
LC504           ldb #2*29                       ; code for out of buffer space
                jmp LAC46                       ; raise error
LC509           pshs d                          ; save new end of buffer area
                tst V973                        ; did the file exist?
                bne LC514                       ; brif so
                bsr LC567                       ; set up directory
                ifeq DISKVER
LC514           bsr LC52D                       ; inistialize FCB
                else
                bra LC519                       ; initialize FCB
LC514           lda #0xff                       ; set file type match = 0xff (all types)
                jsr LC807                       ; see if any open file matches and AO error if so
LC519           bsr LC52D                       ; initialize FCB
                endc
                com FCBSOF,x                    ; set FCBSOF to 0xff (illegal offset) to force new sector to be read
                inc FCBREC+1,x                  ; set record number to 1
                puls a,b,u                      ; D = end of buffer, U = start of buffer
                std RNBFAD                      ; save start of free buffer space
                stu FCBBUF,x                    ; save buffer pointer in FCB
                ldu DFFLEN                      ; get record length
                stu FCBRLN,x                    ; save in FCB
                bra LC4BB                       ; finish setting things up
LC52D           bsr LC538                       ; initialize FCB
                ldu V974                        ; get directory image
                ldu DIRLST,u                    ; get number of bytes in last sector
                stu FCBLST,x                    ; save it
                rts
LC538           ldx FCBTMP                      ; get FCB pointer
                ldb #FCBCON                     ; number of control bytes
LC53C           clr ,x+                         ; clear a control byte
                decb                            ; done all?
                bne LC53C                       ; brif not
                ldx FCBTMP                      ; get back FCB pointer
                lda DCDRV                       ; set drive number
                sta FCBDRV,x
                lda V976                        ; get first granule
                sta FCBFGR,x                    ; save it in FCB
                sta FCBCGR,x                    ; also set as current granule
                ldb V973                        ; get directory sector offset
                subb #3                         ; directory sectors start at 3
                aslb                            ; 8 directory entries per sector
                aslb
                aslb
                pshs b                          ; save sector offset
                ldd V974                        ; get directory pointer
                subd #DBUF0                     ; calculate offset in sector buffer
                lda #8                          ; 8 directory entries per sector
                mul                             ; now A contains 0 to 7
                adda ,s+                        ; add to directory sector offset
                sta FCBDIR,x                    ; save directory entry number in FCB
                rts
LC567           ldb #28*2                       ; code for disk full
                lda V977                        ; get sector number of first empty entry
                lbeq LAC46                      ; brif none found
                sta V973                        ; save sector number of first entry
                sta DSEC                        ; set DSKCON sector parameter
                ldb #2                          ; DSKCON read operation
                stb DCOPC
                jsr LD6F2                       ; read sector
                ldx V978                        ; get address of RAM image of unused directory
                stx V974                        ; save as current entry
                leau ,x                         ; point to directory image
                ldb #DIRLEN                     ; set counter to clear the entry
LC586           clr ,x+                         ; clear a byte
                decb                            ; done all?
                bne LC586                       ; brif not
                ldx #DNAMBF                     ; point to file name
                ldb #11                         ; 8.3 total number of characters
                jsr LA59A                       ; copy file name into directory
                ldd DFLTYP                      ; get file type and ASCII flag
                std <<0,u                       ; save in directory
                ldb #33                         ; first granule to check
                jsr LC7BF                       ; find first gree granule
                sta V976                        ; save granule found
                sta 2,u                         ; save as first granule in file
                ldb #3                          ; DSKCON write operation
                stb DCOPC
                jsr LD6F2                       ; write out directory entry
LC5A9           pshs u,x,b,a                    ; save registers
                jsr LC755                       ; point to FAT
                inc FAT1,x                      ; mark FAT as changed
                lda FAT1,x                      ; have enough things changed?
                cmpa WFATVL
                blo LC5BA                       ; brif not
                jsr LC71E                       ; write FAT out
LC5BA           puls a,b,x,u,pc                 ; restore registers and return
; Generic input handler
DVEC4           lda DEVNUM                      ; get device number
                lble XVEC4                      ; brif not disk file
                leas 2,s                        ; don't return mainline if disk
LC5C4           pshs x,b                        ; save registers
                clr CINBFL                      ; clear EOF flag
                ldx #FCBV1-2                    ; point to input file buffer table (-2 here to avoid decrementing device)
                ldb DEVNUM                      ; get device number
                aslb                            ; two bytes per pointer
                ldx b,x                         ; get pointer to FCB
                ldb FCBTYP,x                    ; get type of file
                cmpb #RANFIL                    ; random file?
                bne LC5EC                       ; brif not
                ldd FCBGET,x                    ; get record counter
                cmpd FCBRLN,x                   ; compare to size of record
                bhs LC5FE                       ; brif pointer is after end of record - handle empty buffer
                addd #1                         ; move pointer forward
                std FCBGET,x                    ; save new read pointer
                ldx FCBBUF,x                    ; point to data buffer
                leax d,x                        ; offset to buffer location
                lda -1,x                        ; get the character (before the increment)
                puls b,x,pc                     ; return the character from the record
LC5EC           ldb FCBCFL,x                    ; has a character been "ungot"?
                beq LC5F9                       ; brif not
                lda FCBCDT,x                    ; get ungot character
                clr FCBCFL,x                    ; clear ungot flag
                puls b,x,pc                     ; restore registers and return
LC5F9           ldb FCBDFL,x                    ; is there any data left to read?
                beq LC602                       ; brif so
LC5FE           com CINBFL                      ; flag EOF
                puls b,x,pc                     ; restore registers and return
LC602           ldb FCBCPT,x                    ; get character pointer
                inc FCBCPT,x                    ; bump saved pointer
                dec FCBLFT,x                    ; anything left?
                beq LC611                       ; brif buffer is empty
                abx                             ; add offset into buffer
                lda FCBCON,x                    ; get actual character (offset over the FCB control structure)
                puls b,x,pc                     ; restore registers and return
LC611           pshs u,y                        ; save register
                clra                            ; zero extend offset
                leau d,x                        ; now U has buffer offset
                lda FCBCON,u                    ; get character to return (offset over FCB control structure)
                pshs a                          ; save return value
                clr FCBCPT,x                    ; reset character pointer
                lda FCBDRV,x                    ; set DSKCON to the correct drive
                sta DCDRV
                bsr LC627                       ; read a sector
                puls a,y,u                      ; restore registers and get back return value
                puls b,x,pc                     ; restore registers and return
LC627           lda FCBSEC,x                    ; get current sector number
LC629           inca                            ; bump sector counter
                pshs a                          ; save sector counter for later
                cmpa #9                         ; end of granule?
                bls LC631                       ; brif not
                clra                            ; reset granule sector offset
LC631           sta FCBSEC,x                    ; save sector offset
                ldb FCBCGR,x                    ; get granule number
                leau ,x                         ; save FCB pointer
                jsr LC755                       ; point to correct FAT image
                abx                             ; now X points to granule data
                ldb FATCON,x                    ; get next granule pointer (offset past control data structure)
                leax ,u                         ; reset FCB pointer
                cmpb #0xc0                      ; is the current granule the last one?
                bhs LC64D                       ; brif so
                puls a                          ; get sector number
                suba #10                        ; did it overflow the granule?
                bne LC65E                       ; brif not
                stb FCBCGR,x                    ; save new granule number
                bra LC629                       ; set variables for new granule
LC64D           andb #0x3f                      ; get number of sectors in the granule
                cmpb #9                         ; is it more than a granule has?
                bls LC658                       ; brif not
LC653           ldb #2*32                       ; code for bad file structure
                jmp LAC46                       ; raise error
LC658           subb ,s+                        ; subtract current sector number and also clean stack
                bcs LC67D                       ; brif past last sector
                tfr b,a
LC65E           pshs a                          ; save sector number difference
                bsr LC685                       ; bump record number
                lda #2                          ; set up for read
                sta DCOPC
                jsr LC763                       ; set DSKCON variables for correct track and sector
                leau FCBCON,x                   ; point past control structure to actual buffer
                stu DCBPT                       ; set read destination
                jsr LD6F2                       ; go ahead and read the sector
                clr FCBLFT,x                    ; set buffer left to full sector
                ldb ,s+                         ; get sector number back
                bne LC684                       ; brif not last sector
                ldd FCBLST,x                    ; get bytes in last sector
                bne LC681                       ; brif bytes in last sector is nonzero
LC67D           clrb                            ; set remaining bytes to 256
                com FCBDFL,x                    ; flag buffer empty
LC681           stb FCBLFT,x                    ; save number of bytes in buffer
LC684           rts
LC685           ldu FCBREC,x                    ; get current record number
                leau 1,u                        ; bump it
                stu FCBREC,x                    ; save new record number
                rts
; Scan directory for file name; return sector number in V973, granule in V976,
; and pointer to directory data in V974. If disk is full, pointer in V978,
; and first unused sector in V977 (and V973 is 0)
LC68C           clr V973                        ; clear sector number (for not found)
                clr V977                        ; clear temp sector number
                ldd #0x1102                     ; set up to read track 17
                sta DCTRK
                stb DCOPC
                ldb #3                          ; start with sector 3
LC69B           stb DSEC                        ; set DSKCON sector
                ldu #DBUF0                      ; read to global buffer
                stu DCBPT
                jsr LD6F2                       ; read directory sector
LC6A5           stu V974                        ; set pointer to directory entry data
                leay ,u                         ; save start of directory entry
                lda ,u                          ; NUL (for a deleted entry)?
                bne LC6D6                       ; brif not
                bsr LC6D9                       ; set unused pointers
LC6B0           ldx #DNAMBF                     ; point to desired file name
LC6B3           lda ,x+                         ; does a character match?
                cmpa ,u+
                bne LC6C7                       ; brif not
                cmpx #DNAMBF+11                 ; end of file name?
                bne LC6B3                       ; brif not
                stb V973                        ; save sector number for match
                lda FCBFGR,u                    ; set first granule in file
                sta V976
                rts
LC6C7           leau DIRLEN,y                   ; point to next directory entry
                cmpu #DBUF0+SECLEN              ; end of sector?
                bne LC6A5                       ; brif not - search another
                incb                            ; move to next sector
                cmpb #11                        ; 11 sectors in directory - checked all of them?
                bls LC69B                       ; brif more sectors
                rts
LC6D6           coma                            ; is first byte of file name 0xff?
                bne LC6B0                       ; brif not - actually do a search
LC6D9           lda V977                        ; have we already found an unused entry?
                bne DVEC12                      ; brif so
                stb V977                        ; save sector number for unused entry
                stu V978                        ; save pointer to unused entry
DVEC12          rts                             ; NOTE: this is used as a dummy do-nothing RAM hook handler
LC6E5           ldb #2*26                       ; code for NE error
                tst V973                        ; was entry found?
                bne DVEC12                      ; brif so
                jmp LAC46                       ; raise error
; KILL command
KILL            jsr LC935                       ; parse file name
                jsr LA5C7                       ; brif something after file name
                jsr LC79D                       ; load FAT data
                bsr LC68C                       ; look up file
                bsr LC6E5                       ; raise error if not found
LC6FC           lda #0xff                       ; file type to match (all types)
                jsr LC807                       ; find any file that matches type
                ldx V974                        ; get directory entry pointer
                clr ,x                          ; mark it as unused
                ldb #3                          ; set up to write
                stb DCOPC
                jsr LD6F2                       ; write out the updated directory sector
                ldb DIRGRN,x                    ; get starting granule of file
LC70F           bsr LC755                       ; point to correct FAT
                leax FATCON,x                   ; skip control structure
                abx                             ; now X points to next granule
                ldb ,x                          ; get next granule pointer
                lda #0xff                       ; mark granule free
                sta ,x
                cmpb #0xc0                      ; was it last one?
                blo LC70F                       ; brif not
; Write FAT to drive
LC71E           ldu #DBUF0                      ; point to global sector buffer
                stu DCBPT                       ; point DSKCON there
                ldd #0x1103                     ; set up to write track 17
                sta DCTRK
                stb DCOPC
                ldb #2                          ; FAT is in sector 2
                stb DSEC
                bsr LC755                       ; point to proper FAT entry
                clr FAT1,x                      ; mark FAT as having no outstanding changes
                leax FATCON,x                   ; move past control structure
                ldb #GRANMX                     ; get total granule count in a FAT
                jsr LA59A                       ; copy the FAT data to buffer
                ifeq DISKVER
LC739           clr ,x+                         ; clear a byte
                cmpx #DBUF0+SECLEN              ; end of sector?
                else
LC739           clr ,u+                         ; clear out the rest of the sector (to avoid junk going into it)
                cmpu #DBUF0+SECLEN              ; end of sector?
                endc
                ifeq DISKVER-1
                bne LC739                       ; brif not
                endc
                jmp LD6F2                       ; go write the FAT sector out
; Point X to the correct FCB based on DEVNUM (or B if entering at LC749)
LC744           pshs b                          ; save register
                ldb DEVNUM                      ; get device number
                skip2
LC749           pshs b                          ; save register
                lslb                            ; two bytes per pointer
                ldx #FCBV1-2                    ; point to FCB table (-2 to adjust for 1-based file numbers)
                ldx b,x                         ; get pointer
                ldb <<FCBTYP,x                  ; set flags for file type
                puls b,pc                       ; restore register and return
; Point X to FAT image for the selected drive
LC755           pshs b,a                        ; save registers
                lda DCDRV                       ; get drive number
                ldb #FATLEN                     ; get size of FAT mirror
                mul                             ; calculate offset from first FAT image
                ldx #FATBL0                     ; point to first FAT image
                leax d,x                        ; offset to correct one
                puls a,b,pc                     ; restore registers and return
; Set up DSKCON variables to point to the correct sector and track for the current file position
LC763           ldb FCBCGR,x                    ; get granule number
                lsrb                            ; two granules per track
                stb DCTRK                       ; save track
                cmpb #17                        ; is it below the directory?
                blo LC76E                       ; brif so
                inc DCTRK                       ; skip directory track if not
LC76E           aslb                            ; double track number
                negb                            ; subtract from actual granule number: -(TRK*2)+CGR
                addb FCBCGR,x
                bsr LC779                       ; set B=9 for odd granule, B=0 for even
                addb FCBSEC,x                   ; add granule sector offset
                stb DSEC                        ; set DSKCON sector
                rts
LC779           pshs b,a                        ; temp store original
                aslb                            ; times 2
                rola
                aslb                            ; times 4
                rola
                aslb                            ; times 8
                rola
                addd ,s++                       ; times 9
                rts
; Convert sector offset in D to a granule offset (0-67) in B (lose fractional part)
LC784           clr ,-s                         ; make a temporary counter
LC786           inc ,s                          ; bump division counter
                subd #90                        ; does 90 go?
                bpl LC786                       ; brif so
                lda ,s                          ; get quotient (+1)
                stb ,s                          ; save remainder (negative)
                ldb #10                         ; multiply result by 10 (we divided by 90)
                mul
                puls a                          ; get back remainder
LC796           decb                            ; decrement granule count
                adda #9                         ; have we used up the remainder?
                bmi LC796                       ; brif not
                clra                            ; zero extend result
LC79C           rts
; Make sure FAT data is valid
LC79D           bsr LC755                       ; point to correct FAT
                tst <<FAT0,x                    ; any open files?
                bne LC79C                       ; brif so
                clr FAT1,x                      ; reset change count
                leau FATCON,x                   ; point past control structure
                ldx #DBUF0                      ; point DSKCON to sector buffer
                stx DCBPT
                ldd #0x1102                     ; read track 17
                sta DCTRK
                stb DCOPC
                ldb #2                          ; read sector 2 (FAT)
                stb DSEC
                jsr LD6F2                       ; go read FAT
                ldb #GRANMX                     ; get total FAT data size
                jmp LA59A                       ; copy FAT data from sector buffer to FAT image
; Find free granule; enter with B containing the start location; mark granule with 0xc0 in the
; FAT to indicate last granule in file. Return granule number in A
LC7BF           bsr LC755                       ; get pointer to FAT
                leax FATCON,x                   ; move past controls structure
                clra                            ; reset granule counter
                andb #0xfe                      ; start at first granule on track
                clr ,-s                         ; initialize direction counter to down
LC7C8           com b,x                         ; is this granule free
                beq LC7FD                       ; brif so
                com b,x                         ; restore granule data
                inca                            ; bump counter
                cmpa #GRANMX                    ; searched whole FAT?
                bhs LC7F8                       ; brif so - disk full
                incb                            ; bump granule counter
                bitb #1                         ; odd?
                bne LC7C8                       ; brif so
                pshs b,a                        ; save granule counter and current granule
                subb #2                         ; move back one track
                com 2,s                         ; flip direction
                bne LC7EC                       ; brif we're switching to "up"
                subb ,s+                        ; subtract out granule counter (moves other side of start)
                bpl LC7E8                       ; brif below lower bound
                ldb ,s                          ; get original granule number
LC7E6           com 1,s                         ; restore direction flag
LC7E8           leas 1,s                        ; remove saved granule number
                bra LC7C8                       ; see if we found a free granule yet
LC7EC           addb ,s+                        ; move to the top side of starting position
                cmpb #GRANMX                    ; did we overflow upward?
                blo LC7E8                       ; brif not
                ldb ,s                          ; get original granule number
                subb #4                         ; move an extra track in the other direction if overflowed up
                bra LC7E6                       ; go see if we found a free one yet
LC7F8           ldb #2*28                       ; code for disk full
                jmp LAC46                       ; raise error
LC7FD           leas 1,s                        ; clean up direction flag
                tfr b,a                         ; put granule number in A
                abx                             ; point X to granule data
                ldb #0xc0                       ; set granule to "used 0, last of file"
                stb ,x
LC806           rts
; Check active files to see if a file is already open; drive number and granule number
; AO will not be generated if the current status matches *exactly* the requested type in A.
LC807           pshs a                          ; save desired file type
                ldb FCBACT                      ; get number of active FCBs
                incb                            ; include the system FCB in the check
LC80D           jsr LC749                       ; point to FCB
                beq LC829                       ; brif not open at all
                lda DCDRV                       ; get desired drive
                cmpa FCBDRV,x                   ; match?
                bne LC829                       ; brif not
                ldu V974                        ; get directory entry pointer
                lda DIRGRN,u                    ; get first granule in file
                cmpa FCBFGR,x                   ; does it match?
                bne LC829                       ; brif not
                lda <<FCBTYP,x                  ; get file type
                cmpa ,s                         ; does it match the type we want?
                lbne LA61C                      ; brif not - raise AO error
LC829           decb                            ; checked all FCBs?
                bne LC80D                       ; brif not
                puls a,pc                       ; clean stack and return
; Parse device number and make sure it's open in random mode
LC82E           jsr LA5A5                       ; evaluate device number
                clr DEVNUM                      ; reset device number to screen
                tstb                            ; set flags on device number
                lble LB44A                      ; brif not a disk file
                jsr LC749                       ; fetch FCB pointer
                lda <<FCBTYP,x                  ; is file open?
                lbeq LA3FB                      ; brif not
                cmpa #RANFIL                    ; random file?
                beq LC806                       ; brif so
LC845           jmp LA616                       ; raise bad file mode
; Input device number check handler
DVEC5           lda #INPFIL                     ; set to check for input file
                skip2
; Output device number check handler
DVEC6           lda #OUTFIL                     ; set to check for output file
                tst DEVNUM                      ; set flags on device number
                ble LC806                       ; brif not a disk file (return)
                stx ,s                          ; save X and lose return address
                jsr LC744                       ; point to FCB
                ifeq DISKVER
                pshs a                          ; save file type requested
                else
                pshs d                          ; save b and file type requested
                endc
                lda <<FCBTYP,x                  ; get file type
                lbeq LA3FB                      ; brif not open
                cmpa #RANFIL                    ; random file?
                ifeq DISKVER
                beq LC866                       ; brif so - it's good (both input and output)
                else
                beq LC868                       ; brif so - it's good (both input and output)
                endc
                cmpa ,s                         ; is it the right type?
                bne LC845                       ; brif not - bad file mode
                ifeq DISKVER
LC866           puls a,x,pc                     ; restore registers and return
                else
LC866           puls a,b,x,pc                   ; clean up stack, restore registers, and return to caller
; This code is required to work around the dumbosity in the INPUT command which outputs the
; prompt string uncondionally so it would cause the prompt string to end up being output to
; a random file.
LC868           ldx 4,s                         ; are we coming from INPUT?
                cmpx #LB00C
                bne LC866                       ; brif not
                jsr SYNCOMMA                    ; make sure there's a comma after device
                cmpa #'"                        ; is there a prompt string?
                bne LC881                       ; brif not
                jsr LB244                       ; parse prompt string
                jsr LB657                       ; fetch string details (and discard them)
                ldb #';                         ; make sure there's a semicolon after the prompt string
                jsr LB26F
LC881           ldx #LB01E                      ; return after the prompt string check
                stx 4,s
                puls a,b,x,pc                   ; return to mainline flow
                endc
; Device number validity check handler
                ifeq DISKVER
DVEC1           ble LC806                       ; brif not a disk file
                else
DVEC1           ble LC8AF                       ; brif not a disk file
                endc
                cmpb FCBACT                     ; is it in range for open files?
                lbhi LA61F                      ; brif not - device number error
                puls x,pc                       ; purge RAM hook call return and return to original caller
; Set print parameters handler
DVEC2           tst DEVNUM                      ; is it disk file?
                ifeq DISKVER
                ble LC806                       ; brif not
                else
                ble LC8AF                       ; brif not
                endc
                leas 2,s                        ; don't return to mainline code
                pshs x,b,a                      ; save registers
                clr PRTDEV                      ; set print device to "display"
                jsr LC744                       ; point to correct FCB
                ldb FCBPOS,x                    ; get print position
                clra                            ; line width (256)
                ldx #0x1000                     ; tab width of 16, no last tab position
                jmp LA37C                       ; go save print parameters
; LIST break check handler
DVEC11          tst DEVNUM                      ; is it disk file?
                ble LC8AF                       ; brif not
                leas 2,s                        ; purge return - don't do break check if disk file
LC8AF           rts
                ifeq DISKVER-1
; Command interpreation handler
; This code replaces the main command interpretation loop completely. It includes a check
; to see if any keys are down before doing a break check. This is unneeded with Color Basic
; 1.2, but earlier versions of Color Basic benefit from it. This is the only change compared
; to plain ECB.
DVEC20          leas 2,s                        ; don't return to mainline code
LC8B2           andcc #0xaf                     ; enable interrupts
                clr PIA0+2                      ; strobe all keyboard columns
                lda PIA0                        ; get row data
                coma                            ; invert bits so 1 means pressed
                anda #0x7f                      ; lose the comparator input
                beq LC8C2                       ; brif no keys down - don't check for BREAK
                jsr LADEB                       ; do a break check
LC8C2           ldx CHARAD                      ; get input pointer
                stx TINPTR                      ; save it so things can find the start of this statement
                lda ,x+                         ; get current character
                beq LC8D1                       ; brif end of line
                cmpa #':                        ; is it end of statement?
                beq LC8F3                       ; brif so
                jmp LB277                       ; raise syntax error if not end of statement
LC8D1           lda ,x++                        ; get MSB of next line address
                sta ENDFLG                      ; this sets ENDFLG to "END" (unless program code is above 0x7FFF)
                bne LC8DA                       ; brif not end of program
                jmp LAE15                       ; go do "END" If we fell off the end of the program
LC8DA           ldd ,x+                         ; get line number for this line (and leave pointer one before line text)
                std CURLIN                      ; set current line number
                stx CHARAD                      ; set input pointer to start of line text
                lda TRCFLG                      ; are we doing "TRON"?
                beq LC8F3                       ; brif not
                lda #'[                         ; show [
                jsr PUTCHR
                lda CURLIN                      ; restore MSB of line number
                jsr LBDCC                       ; show line number
                lda #']                         ; show ]
                jsr PUTCHR
LC8F3           jsr GETNCH                      ; get starting character of next statement
                tfr cc,b                        ; save flags
                cmpa #0x98                      ; CSAVE?
                bne LC8FE                       ; brif not
                jmp L8316                       ; go handle ECB's CSAVE extensions (CSAVEM)
LC8FE           cmpa #0x97                      ; CLOAD?
                bne LC905                       ; brif not
                jmp L8311                       ; go handle ECB's CLOAD extensions (multi-origin binaries)
LC905           tfr b,cc                        ; restore flags for input byte
                jsr LADC6                       ; go interpret command token
                bra LC8B2                       ; process next statement
                endc
; EOF handler
DVEC14          leas 2,s                        ; dont return to mainline code
                lda DEVNUM                      ; get device number
                pshs a                          ; save it
                jsr LA5AE                       ; evaluate device number
                jsr LA3ED                       ; make sure it's open for input
                tst DEVNUM                      ; set flags on device
                lble LA5DA                      ; brif not disk file - go to mainline code
                jsr LC744                       ; point to correct FCB
                ldb <<FCBTYP,x                  ; get file type
                cmpb #RANFIL                    ; is it random file? (have to check since random is valid for input)
                ifeq DISKVER
                beq LC845                       ; bad file mode if so
                else
                lbeq LA616                      ; bad file mode if so
                endc
                clrb                            ; set flag to not EOF (false)
                lda FCBCFL,x                    ; is there an "ungot" character?
                bne LC932                       ; brif so
                ldb FCBDFL,x                    ; is there anything in the buffer? Will be 0xff if not
LC932           jmp LA5E4                       ; return status
; Parse a disk file name. Enter at LC938 with a pointer to the default extension in X.
; Valid file name patterns are:
; N:FILENAME[.EXT]
; N:FILENAME[/EXT]
; FILENAME[.EXT][:N]
; FILENAME[/EXT][:N]
; where N is a drive number.
LC935           ldx #DEFEXT                     ; point to blank default extension
LC938           clr ,-s                         ; set a flag for whether drive number was seen
                lda DEFDRV                      ; set drive number to default (as set by DRIVE)
                sta DCDRV
                ldu #DNAMBF                     ; point to file name buffer
                ldd #0x2008                     ; space character and 8 characters to set
LC945           sta ,u+                         ; blank a character
                decb                            ; done all?
                bne LC945                       ; brif not
                ldb #3                          ; three characters in extension
                jsr LA59A                       ; set default extension
                jsr L8748                       ; evaluate file name string
                leau ,x                         ; point to start of the string
                cmpb #2                         ; is string less than 2 characters?
                blo LC96A                       ; brif so - can't be N:FILENAME.EXT pattern
                lda 1,u                         ; get second character
                cmpa #':                        ; is it colon?
                bne LC96A                       ; brif not - no leading drive number
                lda ,u                          ; get leading character
                cmpa #'0                        ; is it below ASCII 0?
                blo LC96A                       ; brif so - not a drive number
                cmpa #'3                        ; is it above ASCII 3?
                bhi LC96A                       ; brif so - not a drive number
                bsr LC99D                       ; get drive number
LC96A           ldx #DNAMBF                     ; point to start of file name buffer
                incb                            ; compensate for DECB below
LC96E           decb                            ; end of string?
                bne LC97D                       ; brif so
                leas 1,s                        ; clean up drive number seen flag
LC973           cmpx #DNAMBF                    ; was there a file name?
                bne LC9DF                       ; brif not
LC978           ldb #2*31                       ; bad file name error code
                jmp LAC46                       ; raise error
LC97D           lda ,u+                         ; get character from string
                cmpa #'.                        ; is it extension?
                beq LC9B0                       ; brif so
                cmpa #'/                        ; is it other extension introducer?
                beq LC9B0                       ; brif so
                cmpa #':                        ; drive number introducer?
                beq LC994                       ; brif so
                cmpx #DEXTBF                    ; are we at the end of the file name buffer?
                beq LC978                       ; brif so - name too long
                bsr LC9D0                       ; put character in file name
                bra LC96E                       ; process another
LC994           bsr LC973                       ; bad file name if no name yet
                bsr LC99D                       ; parse drive number
                tstb                            ; is there anything left?
                bne LC978                       ; brif so
LC99B           puls a,pc                       ; clean up strack and return
LC99D           com 2,s                         ; toggle drive number seen flag
                beq LC978                       ; brif we've seen drive number already
                lda ,u++                        ; get drive number and skip trailing : if leading
                subb #2                         ; take two characters from string
                suba #'0                        ; remove ASCII bias
                blo LC978                       ; brif not a digit
                cmpa #3                         ; is it in range?
                bhi LC978                       ; brif not
                sta DCDRV                       ; save drive number
                rts
LC9B0           bsr LC973                       ; error if no file name yet
                ldx #DFLTYP                     ; point to end of extension buffer
                lda #0x20                       ; space (for padding extension)
LC9B7           sta ,-x                         ; insert padding character
                cmpx #DEXTBF                    ; done yet?
                bne LC9B7                       ; brif not
LC9BE           decb                            ; are we at the end of the string?
                beq LC99B                       ; brif so
                lda ,u+                         ; get character
                cmpa #':                        ; drive number?
                beq LC994                       ; brif so
                cmpx #DFLTYP                    ; is extension full?
                beq LC978                       ; brif so - bad fil ename
                bsr LC9D0                       ; put character in buffer
                bra LC9BE                       ; process another character
LC9D0           sta ,x+                         ; put character in buffer
                beq LC978                       ; brif NUL - don't allow it (first character NUL is deleted file)
                cmpa #'.                        ; dot?
                beq LC978                       ; brif not - don't allow extension separator
                cmpa #'/                        ; ditto for slash
                beq LC978
                inca                            ; is if 0xff?
                beq LC978                       ; brif so - first character 0xff means never used entry
LC9DF           rts
; SAVE command
SAVE            cmpa #'M                        ; is it SAVEM?
                lbeq LCF68                      ; brif so
                bsr LCA33                       ; parse file name
                ldx ZERO                        ; set to BASIC program and binary
                stx DFLTYP
                jsr GETCCH                      ; is there something after the file name?
                beq LCA12                       ; brif not
                jsr SYNCOMMA                    ; make sure we have a comma
                ldb #'A                         ; only valid flag is "A" for ASCII
                jsr LB26F
                bne LC9DF                       ; brif more stuff follows - error
                com DASCFL                      ; set to ASCII type
                bsr LCA04                       ; open sequential file for output
                clra                            ; set Z to cause whole program to be listed
                jmp LIST                        ; let LIST do the heavy lifting
LCA04           lda #'O                         ; output file type
                skip2
LCA07           lda #'I                         ; iput file type
                ldb FCBACT                      ; get number of active FCBs
                incb                            ; bump to system FCB
                stb DEVNUM                      ; use the system FCB
                jmp LC48D                       ; open file and initialize FCB
LCA12           bsr LCA04                       ; open file for output
                lda #0xff                       ; send basic file flag
                jsr LCC24
                ldd VARTAB                      ; get end of program address
                subd TXTTAB                     ; now we have length of program
                jsr LCC24                       ; output length MS byte
                tfr b,a                         ; output length LS byte
                jsr LCC24
                ldx TXTTAB                      ; point to start of program text
LCA27           lda ,x+                         ; output byte from program
                jsr LCC24
                cmpx VARTAB                     ; end of program?
                bne LCA27                       ; brif not
                jmp LA42D                       ; close the file
LCA33           ldx #BASEXT                     ; point to BAS extension (for basic programs)
                jmp LC938                       ; parse file name
; MERGE command
MERGE           clra                            ; run flag: 0 = don't run
                ldb #0xff                       ; merge flag: 0xff = merge
                bra LCA50
; RUN handler
DVEC18          cmpa #'"                        ; do we have a file name?
                lbne XVEC18                     ; brif not
                lda #2                          ; RUN flag - run after loading
                bra LCA4F                       ; load file
; LOAD command
LOAD            cmpa #'M                        ; is it LOADM?
                lbeq LCFC1                      ; brif so
                clra                            ; set not to RUN
LCA4F           clrb                            ; set not to MERGE
LCA50           sta DRUNFL                      ; save RUN flag
                stb DMRGFL                      ; save MERGE flag
                bsr LCA33                       ; parse file name
                jsr GETCCH                      ; is there anything after the file name?
                beq LCA6C                       ; brif not
                jsr SYNCOMMA                    ; make sure comma
                ldb #'R                         ; make sure the flag is "R"
                jsr LB26F
                jsr LA5C7                       ; error if anything else
                lda #3                          ; set flags to RUN and not close files
                sta DRUNFL
LCA6C           bsr LCA07                       ; open file for input
                lda DASCFL                      ; is it ASCII?
                beq LCA7E                       ; brif not
                tst DMRGFL                      ; is it merge?
                bne LCA7B                       ; brif so
                jsr LAD19                       ; do a "NEW" - erase existing program
LCA7B           jmp LAC7C                       ; let immediate mode do the heavy lifting now
LCA7E           lda DFLTYP                      ; get type
                ora DMRGFL                      ; mix with merge flag
                lbne LA616                      ; if either of the above was nonzero, raise bad file mode
                jsr LAD19                       ; erase existing program
                com DLODFL                      ; flag that we're loading a program
                jsr LCDBC                       ; get initial character (discard it, should be 0xff)
                jsr LCDBC                       ; get MSB of length
                pshs a                          ; save it
                jsr LCDBC                       ; get LSB of length
                tfr a,b                         ; save length in D
                puls a
                addd TXTTAB                     ; add to start of program text
                jsr LAC37                       ; make sure it fits
                ldx TXTTAB                      ; point to start of program
LCAA4           jsr LC5C4                       ; get a character
                ldb CINBFL                      ; EOF?
                bne LCAAF                       ; brif so
                sta ,x+                         ; save character
                bra LCAA4                       ; process more
LCAAF           clr DLODFL                      ; clear load flag - no errors
                stx VARTAB                      ; set new end of program
                ldb #3                          ; make sure the last three bytes were 0
LCAB6           lda ,-x                         ; do we have a 0?
                bne LCABD                       ; brif not
                decb                            ; done all three?
                bne LCAB6                       ; brif not
LCABD           ldx VARTAB                      ; get end of program
LCABF           stx VARTAB                      ; save new end of program
                clr ,x+                         ; blank a byte
                decb                            ; done enough?
                bpl LCABF                       ; brif not
LCAC6           jsr LA42D                       ; close the file
                jsr LAD21                       ; clear variables, reset stack, etc.
                jsr XVEC18                      ; initalize graphics stuff
                jsr LACEF                       ; recalculate line pointers
                asr DRUNFL                      ; are we supposed to close all files?
                bcs LCADA                       ; brif not
                jsr LA426                       ; close all open files
LCADA           asr DRUNFL                      ; are we supposed to run the program/
                lbcs LAD9E                      ; brif so - launch program
                jmp LAC73                       ; return to immediate mode
; EOF handler for main loop
DVEC13          tst DEVNUM                      ; is it disk file?
                bgt LCAC6                       ; brif so - run it if required
                rts                             ; return to mainline otherwise
; Close all files handler
DVEC7           ldb FCBACT                      ; get number of reserved FCBs
                incb                            ; include system FCB
LCAED           pshs b                          ; save file count
                stb DEVNUM                      ; set device to close
                bsr LCB01                       ; close it
                puls b                          ; get back file count
                decb                            ; move to next one
                bne LCAED                       ; brif not done all disk files
LCAF8           rts
; Close one file handler
DVEC8           tst DEVNUM                      ; is it a disk file?
                lble XVEC8                      ; brif not
                leas 2,s                        ; don't return to mainline
LCB01           jsr LC744                       ; get FCB pointer
                clr DEVNUM                      ; reset device number
LCB06           stx FCBTMP                      ; save FCB pointer
                lda <<FCBTYP,x                  ; get file type
                beq LCAF8                       ; brif file isn't open - we don't have to do anything
                pshs a                          ; save file type
                clr <<FCBTYP,x                  ; mark file closed
                ldb FCBDRV,x                    ; tell DSKCON which drive the file is on
                stb DCDRV
                cmpa #OUTFIL                    ; output file?
                bne LCB31                       ; brif not
                ldb FCBLFT,x                    ; get number of characters in output buffer
                lda #0x80                       ; set pre-saved bit to indicate data already saved
                ifeq DISKVER-1
                ora FCBCPT,x                    ; merge with full sector flag
                endc
                std FCBLST,x                    ; save number of bytes used in last sector
                inc FCBSEC,x                    ; bump sector counter
                ldb FCBCGR,x                    ; get current granule
                jsr LC755                       ; point to FAT
                sta FAT1,x                      ; mark FAT data invalid
                abx                             ; add granule offset to pointer
                inc FATCON,x                    ; add one to sector count for last granule (skip control bytes)
                ifeq DISKVER
LCB2E           bra LCBC3                       ; update FAT and directory, write out any final data
                else
LCB2E           jmp LCBC3                       ; update FAT and directory, write out any final data
                endc
LCB31           cmpa #RANFIL                    ; random file?
                ifeq DISKVER
                bne LCBC3                       ; brif not
                else
                bne LCB2E                       ; brif not - update FAT and directory for input file
                endc
                ldd FCBRLN,x                    ; get record length
                ldx FCBBUF,x                    ; get buffer pointer
                leay d,x                        ; point to end of random file buffer
                pshs y,x,b,a                    ; save pointers and length
                ifeq DISKVER-1
                leay ,s                         ; save stack pointer
                endc
                ldu VARTAB                      ; get start of variables
LCB41           cmpu ARYTAB                     ; end of scalars?
                beq LCB54                       ; brif so
                lda 1,u                         ; get second byte of variable name
                leau 2,u                        ; move past variable name
                bpl LCB4E                       ; brif numeric
                bsr LCB76                       ; adjust string variable if in random file buffer
LCB4E           leau 5,u                        ; move to next variable entry
                bra LCB41                       ; process next variable entry
LCB52           puls u                          ; get address of next array
LCB54           cmpu ARYEND                     ; end of arrays?
                ifeq DISKVER
                beq LCB91                       ; brif so
                else
                beq LCB93                       ; brif so
                endc
                tfr u,d                         ; save array start
                addd 2,u                        ; add length of array
                pshs d                          ; save address of next array
                lda 1,u                         ; is it string?
                bpl LCB52                       ; brif not - do next array
                ldb 4,u                         ; get number of dimensions
                aslb                            ; two bytes per dimension size
                addb #5                         ; 5 bytes constant per array header
                clra                            ; zero extend
                leau d,u                        ; point to start of array data
LCB6B           cmpu ,s                         ; end of this array?
                beq LCB52                       ; brif so
                bsr LCB76                       ; adjust string variable if in random file buffer
                leau 5,u                        ; move to next entry
                bra LCB6B                       ; process next entry
LCB76           ldx 2,u                         ; get pointer to start of string
                cmpx RNBFAD                     ; is it above top of random buffer area?
                bhs LCB8B                       ; brif so
                ifeq DISKVER
                cmpx 4,s                        ; is it below this file's buffer area?
                blo LCB8C                       ; brif so
                cmpx 6,s                        ; is it above this file's buffer?
                else
                cmpx 2,y                        ; is it above start of this file's buffer area?
                blo LCB8B                       ; brif not
                cmpx 4,y                        ; is it below end of this file's buffer area?
                endc
                blo LCB8C                       ; brif so - we have to adjust it
                tfr x,d                         ; save pointer in D
                ifeq DISKVER
                subd 2,s                        ; adjust pointer down by length of buffer area for this file
                else
                subd ,y                         ; adjust pointer down by length of buffer area for this file
                endc
                std 2,u                         ; save new start of string
LCB8B           rts
LCB8C           clr ,u                          ; mark string empty
                clr 2,u                         ; NULL out string address
                clr 3,u
                rts
                ifeq DISKVER
LCB91           puls a,b,x,u                    ; clean up stack
                else
LCB93           ldb FCBACT                      ; get number of active files
                incb                            ; include system FCB
LCB97           pshs b                          ; save files count
                jsr LC749                       ; point to FCB number in B
                lda <<FCBTYP,x                  ; open as random file?
                cmpa #RANFIL
                bne LCBAD                       ; brif not
                ldd FCBBUF,x                    ; get buffer pointer
                cmpd 4,y                        ; is it above this file's buffer?
                blo LCBAD                       ; brif not
                subd ,y                         ; subtract out length for this file's buffer
                std FCBBUF,x                    ; save new buffer area pointer
LCBAD           puls b                          ; get files counter back
                decb                            ; done all?
                bne LCB97                       ; brif not
                puls a,b,x,u                    ; get back pointers and buffer length
                endc
LCBB4           cmpu RNBFAD                     ; at top of buffers?
                beq LCBC0                       ; brif so
                lda ,u+                         ; copy a byte down
                sta ,x+
                bra LCBB4                       ; see if we're done yet
LCBC0           stx RNBFAD                      ; save new start of free buffer area
LCBC3           jsr LC755                       ; point to proper FAT
                dec <<FAT0,x                    ; remove one active file
                tst FAT1,x                      ; new data in FAT image?
                beq LCBCF                       ; brif not
                jsr LC71E                       ; save modified FAT
LCBCF           ldx FCBTMP                      ; get FCB pointer back
                puls a                          ; get file type
                cmpa #OUTFIL                    ; output?
                beq LCBDF                       ; brif so
                cmpa #RANFIL                    ; random?
                bne LCB8B                       ; brif not
                lda FCBFLG,x                    ; doing GET?
                beq LCBE9                       ; brif so
LCBDF           jsr LC763                       ; set up track and sector parameters
                leau FCBCON,x                   ; point to data buffer
                stu DCBPT
                bsr LCC15                       ; write out the sector data
LCBE9           lda FCBLST,x                    ; data pre-saved?
                bpl LCB8B                       ; brif it has already been saved
                ldb FCBDIR,x                    ; get directory number for this file
                andb #7                         ; 8 entries per sector
                lda #DIRLEN                     ; calculate offset into directory sector
                mul
                ldu #DBUF0                      ; point to global buffer
                stu DCBPT                       ; set DSKCON buffer address
                leay d,u                        ; Y points to directory entry now
                ldb FCBDIR,x                    ; get directory entry number
                lsrb                            ; divide by 8 (gives sector number)
                lsrb
                lsrb
                addb #3                         ; first directory sector is 3
                stb DSEC                        ; tell DSKCON
                ldd #0x1102                     ; set up to read track 17
                sta DCTRK
                bsr LCC17                       ; read directory sector
                ldd FCBLST,x                    ; get number of bytes in last sector
                anda #0x7f                      ; remove pre-saved flag
                std DIRLST,y                    ; update directory entry
LCC15           ldb #3                          ; write operation
LCC17           stb DCOPC                       ; tell DSKCON what to do
                jmp LD6F2                       ; go read or write sector
; Generic output handler
DVEC3           tst DEVNUM                      ; disk file?
                lble XVEC3                      ; brif not
                leas 2,s                        ; don't return to mainline
LCC24           pshs x,b,a                      ; save registers
                ldx #FCBV1-2                    ; point to FCB list (-2 for 1-based file numbers)
                ldb DEVNUM                      ; get device number
                aslb                            ; two bytes per pointer
                ldx b,x                         ; get FCB pointer
                ldb ,x                          ; get file type
                cmpb #INPFIL                    ; input?
                beq LCC6A                       ; brif so - bail
                cmpa #0x0d                      ; carriage return?
                bne LCC3A                       ; brif so
                clr FCBPOS,x                    ; reset print position if CR
LCC3A           cmpa #0x20                      ; control code?
                blo LCC40                       ; brif so
                inc FCBPOS,x                    ; bump print position if printing character
LCC40           cmpb #RANFIL                    ; random file?
                bne LCC5E                       ; brif not
                ldd FCBPUT,x                    ; get put pointer
                addd #1                         ; bump it
                cmpd FCBRLN,x                   ; did we overflow the record?
                lbhi LCDCB                      ; brif so - raise error
                std FCBPUT,x                    ; save updated pointer
                ldx FCBBUF,x                    ; get buffer pointer
                leax d,x                        ; add in offset
                puls a                          ; get back output character
                sta -1,x                        ; save in buffer (-1 because we already bumped pointer)
                puls b,x,pc                     ; restore registers and return
LCC5E           inc FCBLFT,x                    ; bump character count
                ldb FCBLFT,x                    ; did we max out a sector?
                beq LCC6C                       ; brif so
                abx                             ; add offset into sector
                sta FCBCON-1,x                  ; save output character in buffer, offset past control structure
LCC6A           puls a,b,x,pc                   ; restore registers and return
LCC6C           pshs u,y                        ; save registers
                sta SECLEN+FCBCON-1,x           ; save last character in buffer
                ifeq DISKVER
                jsr LC685
                endc
                ldb FCBDRV,x                    ; tell DSKCON which drive
                stb DCDRV
                inc FCBSEC,x                    ; bump sector counter (in granule)
                jsr LCBDF                       ; write file buffer to disk
                leay ,x                         ; save FCB pointer
                ldb FCBCGR,x                    ; get granule number
                jsr LC755                       ; get pointer to FAT
                abx                             ; offset into granule data
                leau FATCON,x                   ; now U points to granule data (offset past control structure)
                lda FCBSEC,y                    ; get current sector offset
                cmpa #9                         ; end of granule?
                blo LCC99                       ; brif not
                ifeq DISKVER-1
                dec FCBSEC,y                    ; decrement sector number and bump error flag in case error occurs
                inc FCBCPT,y
                else
                clr FCBSEC,y
                endc
                jsr LC7BF                       ; allocate granule
                ifeq DISKVER-1
                clr FCBSEC,y                    ; clear sector number
                clr FCBCPT,y                    ; clear error flag - disk not full
                endc
                sta FCBCGR,y                    ; save new granule in FCB
                skip2
LCC99           ora #0xc0                       ; mark granule as end of file
                sta ,u                          ; save in granule map
                ifeq DISKVER-1
                leax ,y                         ; get back FCB pointer
                jsr LC685                       ; bump record number
                endc
                jsr LC5A9                       ; update FAT
                puls y,u                        ; restore registers
                puls a,b,x,pc                   ; restore registers and return
; DIR command
DIR             jsr LD24F                       ; parse drive number
                jsr LC79D                       ; fetch FAT for drive
                jsr LB958                       ; do a linefeed
                ldd #0x1102                     ; set up to read track 17
                sta DCTRK
                stb DCOPC
                ldb #3                          ; start at sector 3 for the directory
LCCBB           stb DSEC                        ; set sector to read
                ldx #DBUF0                      ; use the global sector buffer
                stx DCBPT
                jsr LD6F2                       ; read directory sector
LCCC5           puls u                          ; do some stack games due to break check requirements
                jsr LA549
                pshs u
                lda ,x                          ; is this entry used?
                beq LCD08                       ; brif not
                coma                            ; is it the start of never entries?
                beq LCD17                       ; brif so - we're done
                pshs x                          ; save directory data pointer
                ldb #8                          ; print out 8 characters for the filename
                jsr LB9A2                       ; display file name
                bsr LCD1B                       ; put a blank
                ldb #3                          ; show 3 characters in extension
                jsr LB9A2                       ; display extension
                bsr LCD1B                       ; put a blank
                ldb <<0,x                       ; get file type
                cmpb #10                        ; is it one digit?
                bhs LCCEB                       ; brif so
                bsr LCD1B                       ; put another blank
LCCEB           clra                            ; zero extend type
                jsr LBDCC                       ; show file type
                bsr LCD1B                       ; another blank
                ldx ,s                          ; get directory entry back
                lda #'B                         ; set to binary
                adda DIRASC,x                   ; add ASCII flag - will subtract 1 (to A) if ASCII
                bsr LCD18                       ; show character and a blank
                ldb DIRGRN,x                    ; point to first granule in file
                bsr LCD1E                       ; count granules
                tfr a,b                         ; zero extend into D
                clra
                jsr LBDCC                       ; show granule count
                jsr LB958                       ; do a newline
                puls x                          ; get back directory pointer
LCD08           leax DIRLEN,x                   ; move to next entry
                cmpx #DBUF0+SECLEN              ; end of sector?
                blo LCCC5                       ; brif not
                ldb DSEC                        ; get sector number
                incb                            ; move to next one
                cmpb #SECMAX                    ; end of track?
                bls LCCBB                       ; brif not
LCD17           rts
LCD18           jsr PUTCHR                      ; display character
LCD1B           jmp LB9AC                       ; display a space
; Count granule chain starting at granule number in B
LCD1E           jsr LC755                       ; get FAT pointer
                leau FATCON,x                   ; point past control structure
                clra                            ; reset count to 0
LCD24           inca                            ; bump granule count
                cmpa #GRANMX                    ; at maximum size of disk?
                lbhi LC653                      ; do FS error if so
                leax ,u                         ; point to base FAT data
                abx                             ; offset to granule number
                ldb ,x                          ; get next granule pointer
                cmpb #0xc0                      ; end of file marker?
                blo LCD24                       ; brif not
                rts
; INPUT handler; this whole mess is requried because the disk data format varies from that used
; by tape files.
DVEC10          tst DEVNUM                      ; are we reading from a disk file?
                ble LCD97                       ; brif not
                ldx #LB069                      ; change return address to skip ? prompt
                stx ,s
                ldx #LINBUF+1                   ; point to input buffer
                ldb #',                         ; set item separator to ,
                stb CHARAC
                lda VALTYP                      ; get type wanted
                bne LCD4B                       ; brif string
                ldb #0x20                       ; space is the numeric delimiter
LCD4B           bsr LCDBC                       ; fetch input character
                cmpa #0x20                      ; space?
                beq LCD4B                       ; brif so
                cmpa #'"                        ; quote?
                bne LCD5F                       ; brif not
                cmpb #',                        ; delim is ,?
                bne LCD5F                       ; brif not - numeric
                tfr a,b                         ; save quote as search character
                stb CHARAC
                bra LCD81                       ; save quote as first item in buffer
LCD5F           cmpb #'"                        ; string value?
                beq LCD74                       ; brif so
                cmpa #0x0d                      ; end of line?
                bne LCD74                       ; brif not
                cmpx #LINBUF+1                  ; at start of buffer?
                beq LCDB0                       ; brif so - check for LF
                lda -1,x                        ; get back input character
                cmpa #0x0a                      ; was it LF?
                bne LCDB0                       ; brif not
                lda #0x0d                       ; restore CR as input character
LCD74           tsta                            ; NUL?
                beq LCD8E                       ; brif so - ignore it
                cmpa CHARAC                     ; hit a delimiter?
                beq LCD98                       ; brif so
                pshs b                          ; does it match the other delimiter?
                cmpa ,s+
                beq LCD98                       ; brif so
LCD81           sta ,x+                         ; save character in buffer
                cmpx #LINBUF+LBUFMX             ; end of buffer?
                bne LCD8E                       ; brif not
                bsr LCDD0                       ; fetch character
                bne LCD92                       ; brif buffer empty
                bra LCDAC                       ; check for CR/CRLF
LCD8E           bsr LCDD0                       ; get input character
                beq LCD5F                       ; brif we have something
LCD92           clr ,x                          ; put NUL at end of buffer
                ldx #LINBUF                     ; point to input buffer
LCD97           rts
LCD98           cmpa #'"                        ; quote?
                beq LCDA0                       ; brif so
                cmpa #0x20                      ; space?
                bne LCD92                       ; brif not
LCDA0           bsr LCDD0                       ; get character
                bne LCD92                       ; brif end
                cmpa #0x20                      ; space?
                beq LCDA0                       ; brif so - skip it
                cmpa #',                        ; item separator?
                beq LCD92                       ; brif so - done
LCDAC           cmpa #0x0d                      ; carriage return?
                bne LCDB8                       ; brif not
LCDB0           bsr LCDD0                       ; fetch character
                bne LCD92                       ; brif end
                cmpa #0x0a                      ; line feed?
                beq LCD92                       ; brif so - skip it
LCDB8           bsr LCDD6                       ; unget character
                bra LCD92                       ; handle exit
LCDBC           bsr LCDD0                       ; fetch character
                beq LCDD5                       ; brif not end of file
                jsr LC744                       ; point to FCB
                ldb <<FCBTYP,x                  ; get file type
                cmpb #RANFIL                    ; random file?
                lbne LC352                      ; brif not - do input past end of file
LCDCB           ldb #2*37                       ; code for input past end of record
                jmp LAC46                       ; raise error
LCDD0           jsr LA176                       ; read character
                tst CINBFL                      ; set Z if not EOF
LCDD5           rts
LCDD6           pshs x,b                        ; save registers
                jsr LC744                       ; point to FCB
                ldb <<FCBTYP,x                  ; random file?
                cmpb #RANFIL
                bne LCDEC                       ; brif not
                ldd FCBGET,x                    ; get input pointer
                subd #1                         ; move it back (no error check!)
                std FCBGET,x                    ; save new pointer
                puls b,x,pc                     ; restore registers and return
LCDEC           sta FCBCDT,x                    ; save unget character
                com FCBCFL,x                    ; flag that we have an ungot character
                puls b,x,pc                     ; restore registers and return
; CVN function
CVN             jsr LB654                       ; evaluate argument string
                cmpb #5                         ; is it at least 5 bytes (packed FP number)?
                lblo LB44A                      ; brif not - raise error
                clr VALTYP                      ; result is numeric
                jmp LBC14                       ; unpack string into return value
; MKN$ function
MKN             jsr LB143                       ; make sure we have a number
                ldb #5                          ; string will be 5 bytes long
                jsr LB50F                       ; reserve space for it
                jsr LBC35                       ; pack argument into the string
                jmp LB69B                       ; return the newly created string
; LOC function
LOC             bsr LCE19                       ; get pointer to correct FCB
                ldd FCBREC,x                    ; get record number (random file) or sector counter
                ifeq DISKVER
LCE14           jmp GIVABF                      ; return result as integer
                else
LCE14           std FPA0+2                      ; return result as an unsigned integer
                jmp L880E
                endc
; Evaluate device number, set print parameters, and point to FCB
LCE19           lda DEVNUM                      ; save current device number
                pshs a
                jsr LB143                       ; make sure we have a number
                jsr LA5AE                       ; check device and set print params
                tst DEVNUM                      ; is it a disk file?
                lble LB44A                      ; brif not
                jsr LC744                       ; point to FCB
                puls a                          ; restore original device number
                sta DEVNUM
                tst <<FCBTYP,x                  ; is file open?
                lbeq LA3FB                      ; brif not, do NO error
                rts
; LOF function
LOF             bsr LCE19                       ; point to FCB
                lda FCBDRV,x                    ; tell DSKCON the drive number
                sta DCDRV
                ldb FCBFGR,x                    ; get first granule of file
                pshs x                          ; save FCB pointer
                jsr LCD1E                       ; count granules in file
                deca                            ; subtract out last granule
                andb #0x3f                      ; get number of sectors in last granule
                pshs b                          ; save it
                tfr a,b                         ; zero extend granule number to D
                clra
                jsr LC779                       ; multiply by 9 for total sector count
                addb ,s+                        ; add in sectors in last granule
                adca #0
                puls x                          ; get back FCB pointer
                pshs a                          ; temp save
                lda <<FCBTYP,x                  ; is it random file?
                cmpa #RANFIL
                puls a                          ; restore register
                bne LCE14                       ; brif not random file - return number of sectors
                pshs x                          ; save FCB pointer
                subd ZERO                       ; "tstd"
                beq LCE68                       ; brif file is empty
                subd #1                         ; don't count last sector as fully used
LCE68           bsr LCE14                       ; put D into FPA0
                ldb FP0EXP                      ; is it 0?
                beq LCE72                       ; brif so
                addb #8                         ; multiply by 256
                stb FP0EXP
LCE72           jsr LBC5F                       ; save result in FPA1
                ldx ,s                          ; get back FCB pointer
                ldd FCBLST,x                    ; get number of bytes in last sector
                anda #0x7f                      ; clear out pre-save flag
                bsr LCE14                       ; stuff that number in FPA0
                clr RESSGN                      ; result will be positive
                lda FP1EXP                      ; get exponents
                ldb FP0EXP
                jsr LB9C5                       ; add number of bytes in last sector
                jsr LBC5F                       ; save total in FPA1
                puls x                          ; get FCB
                ldd FCBRLN,x                    ; get record length
                bsr LCE14                       ; turn it into a FP number
                clr RESSGN                      ; make result positive
                lda FP1EXP                      ; get exponents
                ldb FP0EXP
                jsr LBB91                       ; divide total by record size
                jmp INT                         ; return the result as an integer
; FREE function
FREE            jsr LB143                       ; make sure we have a number
                jsr LB70E                       ; get value in B
                cmpb #3                         ; valid drive?
                lbhi LA61F                      ; brif not
                stb DCDRV                       ; set drive
                jsr LC79D                       ; read FAT
                jsr LC755                       ; point to FAT
                leax FATCON,x                   ; point to actual granule data
                clr ,-s                         ; initialize free count
                ldb #GRANMX                     ; total granules to check
LCEB6           lda ,x+                         ; get granule data
                coma                            ; is it free?
                bne LCEBD                       ; brif not
                inc ,s                          ; bump free count
LCEBD           decb                            ; checked them all?
                bne LCEB6                       ; brif not
                puls b                          ; get free count
                jmp LB4F3                       ; return free count
; DRIVE command
DRIVE           jsr EVALEXPB                    ; evaluate drive number to B
                cmpb #3                         ; valid?
                lbhi LA61F                      ; brif not
                stb DEFDRV                      ; set default drive
                rts
; Expression evaluation handler; this is needed so we can move strings into string space
; if regular assignment to a FIELDed string is done. There really isn't a better place to
; intercept this, unfortunately.
DVEC15          lda 4,s                         ; is it end of operation?
                bne LCEE9                       ; brif not
                ldx 5,s                         ; are we comming from LET?
                cmpx #LAF9A
                bne LCEE9                       ; brif not
                ldx 2,s
                cmpx #LB166
                bne LCEE9                       ; and brif not again
                ldx #LCEEC                      ; install intercept for LET
                stx 5,s
LCEE9           jmp XVEC15                      ; let ECB do its thing
; LET modifier
LCEEC           puls a                          ; get variable type
                rora                            ; set C if string
                jsr LB148                       ; make sure things match
                lbeq LBC33                      ; brif numeric - we can go back to mainline
                ldx FPA0+2                      ; get string descriptor
                ldd 2,x                         ; get data pointer
                cmpd #DFLBUF                    ; is it below random buffers?
                blo LCF07                       ; brif so
                subd FCBADR                     ; is it within the random buffers?
                lblo LAFB1                      ; brif so - move string to string space
LCF07           jmp LAFA4                       ; return to mainline code
; ECB interpretation handler intercept; the PMODE intercept fixes a stupid usage of a constant 6 for the
; start of graphics memory in PMODE.  The DLOAD intercept fixes the problem where DLOADM couldn't be
; detected due to A being clobbered before it was checked. Both of those bugs were fixed in ECB 1.1.
DXCVEC          cmpa #0xca                      ; DLOAD?
                beq LCF2A                       ; brif so
                cmpa #0xc8                      ; PMODE?
                lbne L813C                      ; brif not - return to ECB's handler
                jsr GETNCH                      ; get input character
                cmpa #',                        ; no PMODE argument?
                lbeq L9650                      ; brif not - return to mainline
                jsr EVALEXPB                    ; evaluate PMODE number
                cmpb #4                         ; valid?
                lbhi LB44A                      ; brif not
                lda GRPRAM                      ; fetch start of grahpics memory (work around usage of constant 6 in ECB 1.0)
                jmp L962E                       ; return to mainline PMODE
LCF2A           jsr LA429                       ; close files 
                jsr GETNCH                      ; fetch input character
                jmp L8C1B                       ; return to mainlnie
; ECB function interpetation handler intercept; this is needed to patch into the POS() function.
DXIVEC          cmpb #(0x9a-0x80)*2             ; is it POS?
                lbne L8168                      ; brif not - return to ECB mainline
                jsr LB262                       ; evaluate argument
                lda DEVNUM                      ; get device number
                pshs a                          ; save it
                jsr LA5AE                       ; evaluate device number
                jsr LA406                       ; make sure it's open
                tst DEVNUM                      ; disk file?
                ble LCF5C                       ; brif not
                jsr LC744                       ; point to FCB
                ldb <<FCBTYP,x                  ; get file type
                cmpb #RANFIL                    ; random file?
                bne LCF5C                       ; brif not
                puls a                          ; get back saved device number
                sta DEVNUM
                ldd FCBPUT,x                    ; get "put" position
                jmp GIVABF                      ; return that as the position
LCF5C           jsr LA35F                       ; set print parameters
                puls a                          ; restore device number
                sta DEVNUM
                ldb DEVPOS                      ; get print position
                jmp LB4F3                       ; return B as unsigned
; SAVEM command (comes from SAVE command)
LCF68           jsr GETNCH                      ; eat the "M"
                bsr LCFBB                       ; parse filename
                jsr L836C                       ; evaluate start address
                jsr L836C                       ; evaluate end address
                cmpx 2,s                        ; is start > end?
                lblo LB44A                      ; brif so - throw an error
                jsr L836C                       ; evaluate execution address
                jsr LA5C7                       ; make sure there's nothing more
                ldd #0x200                      ; file type 2 (M/L) and binary
                std DFLTYP
                jsr LCA04                       ; open file for output
                clra                            ; write preamble header
                bsr LCFB5
                ldd 2,s                         ; get end address
                subd 4,s                        ; subtract start - gets length
                addd #1                         ; length is inclusive
                tfr d,y                         ; set data counter
                bsr LCFB3                       ; output the length of the block
                ldd 4,s                         ; output the load address
                bsr LCFB3
                ldx 4,s                         ; point to start of block
LCF9B           lda ,x+                         ; grab output byte
                jsr LCC24                       ; write it
                leay -1,y                       ; done yet?
                bne LCF9B                       ; brif not
                lda #0xff                       ; write header for postamble
                bsr LCFB5
                clra                            ; write dummy 16 bits (would be block length)
                clrb
                bsr LCFB3
                puls d,x,y                      ; get back execution address and clean stack
                bsr LCFB3                       ; write out execution address
                jmp LA42D                       ; close file
LCFB3           bsr LCFB5                       ; write MSB of word; fall through for LSB
LCFB5           jsr LCC24                       ; write byte out
                exg a,b                         ; swap bytes in word
                rts
LCFBB           ldx #BINEXT                     ; set default extension to "BIN"
                jmp LC938                       ; parse filename
; LOADM command (comes from LOAD command)
LCFC1           jsr GETNCH                      ; eat the "M"
                bsr LCFBB                       ; parse filename
                jsr LCA07                       ; open file for input
                ldd DFLTYP                      ; get type of file
                subd #0x200                     ; is it M/L and binary?
                lbne LA616                      ; bad file mode if not
                ldx ZERO                        ; set default offset value
                jsr GETCCH                      ; is there a load offset?
                beq LCFDE                       ; brif not
                jsr SYNCOMMA                    ; insist on a comma
                jsr LB73D                       ; evaluate offset to X
LCFDE           stx VD3                         ; save offset
                jsr LA5C7                       ; insist on end of statement
LCFE3           jsr LCDBC                       ; read "amble" header
                pshs a                          ; save "amble" type
                bsr LD013                       ; read block length
                tfr d,y                         ; save it (in counter)
                bsr LD013                       ; read block address
                addd VD3                        ; add load offset
                std EXECJP                      ; set execution address
                tfr d,x                         ; put it also in a pointer
                lda ,s+                         ; set flags on "amble" type
                lbne LA42D                      ; brif postamble - stop reading
LCFFA           jsr LC5C4                       ; read a byte
                ldb CINBFL                      ; EOF?
                beq LD004                       ; brif not
                jmp LC352                       ; raise "IE" error
LD004           sta ,x                          ; save byte in memory
                cmpa ,x+                        ; does the byte match?
                beq LD00D                       ; brif so
                jmp LD709                       ; bad store - throw I/O error
LD00D           leay -1,y                       ; done whole block?
                bne LCFFA                       ; brif not
                bra LCFE3                       ; process another "amble"
LD013           bsr LD015                       ; read MSB then fall through for LSB
LD015           jsr LCDBC                       ; read a byte from the file
                exg a,b                         ; swap bytes in word
                rts
; RENAME command
RENAME          ldx CHARAD                      ; get input pointer
                pshs x                          ; save it
                bsr LD056                       ; evaluate source file name
                lda DCDRV                       ; save drive for first file
                pshs a
                bsr LD051                       ; evaluate TO and destination file
                puls a                          ; get back original drive number
                cmpa DCDRV                      ; does it match?
                lbne LB44A                      ; brif not - we can't rename across drives
                bsr LD059                       ; make sure new file does not already exist
                puls x                          ; get back input pointer
                stx CHARAD
                bsr LD056                       ; re-evaluate source file
                jsr LC68C                       ; find the source file
                jsr LC6E5                       ; throw error if not found
                bsr LD051                       ; evaluate destination file name
                ldx #DNAMBF                     ; point to destinatoin file name
                ldu V974                        ; point to directory entry
                ldb #11                         ; 8 characters file name and 3 characters extension
                jsr LA59A                       ; replace file name
                ldb #3                          ; operation code for write
                stb DCOPC
                jmp LD6F2                       ; write updated directory sector
LD051           ldb #0xa5                       ; insist on "TO"
                jsr LB26F
LD056           jmp LC935                       ; evaluate file name with default blank extension
LD059           jsr LC68C                       ; find file
                ldb #33*2                       ; code for already exists
                tst V973                        ; does it exist?
                lbne LAC46                      ; brif so - raise error
                rts
; WRITE command
WRITE           lbeq LB958                      ; do CR if end of statement
                bsr LD06F                       ; write an item list
                clr DEVNUM                      ; reset device to screen
LD06E           rts
LD06F           cmpa #'#                        ; device number?
                bne LD082                       ; brif not
                jsr LA5A5                       ; evaluate device number
                jsr LA406                       ; check for output
                jsr GETCCH                      ; end of statement?
                lbeq LB958                      ; brif so - do newline
LD07F           jsr SYNCOMMA                    ; need a comma after device
LD082           jsr LB156                       ; evaluate expression
                lda VALTYP                      ; number or string?
                bne LD0A7                       ; brif string
                jsr LBDD9                       ; convert number to strng
                jsr LB516                       ; stash it as the current value
                jsr LB99F                       ; output the string
LD092           jsr GETCCH                      ; is there more?
                lbeq LB958                      ; brif not - do newline
                lda #',                         ; comma for non-tape separator
                jsr LA35F                       ; set print parameters
                tst PRTDEV                      ; tape?
                beq LD0A3                       ; brif not
                lda #0x0d                       ; carriage return for tape separator
LD0A3           bsr LD0B9                       ; send separator
                bra LD07F                       ; process another item
LD0A7           bsr LD0B0                       ; print leading string delimiter
                jsr LB99F                       ; print string
                bsr LD0B0                       ; print ending string delimiter
                bra LD092                       ; handle separator or next item
LD0B0           jsr LA35F                       ; set print parameters
                tst PRTDEV                      ; tape?
                bne LD06E                       ; brif so
                lda #'"                         ; string delimiter
LD0B9           jmp PUTCHR                      ; send character out
; FIELD command
FIELD           jsr LC82E                       ; evaluate device number and make sure it's a random file
                clra                            ; clear total field length counter
                clrb
                pshs x,b,a                      ; save field length and FCB pointer
LD0C3           jsr GETCCH                      ; are we at the end of the statement?
                bne LD0C9                       ; brif not
                puls a,b,x,pc                   ; clean up stack and return
LD0C9           jsr LB738                       ; evaluate comma and expression
                pshs x,b                        ; save field length (B) and make a hole for a temp
                clra                            ; zero extend length
                addd 3,s                        ; add in current accumulated size
                bcs LD0DA                       ; brif we overflowed
                ldx 5,s                         ; point to FCB
                cmpd FCBRLN,x                   ; have we overflowed the record?
                bls LD0DF                       ; brif not
LD0DA           ldb #34*2                       ; code for field overflow
                jmp LAC46                       ; raise error
LD0DF           ldu 3,s                         ; get old accumulated length
                std 3,s                         ; save new accumulated length
                ldd FCBBUF,x                    ; get start of random buffer
                leau d,u                        ; now U is the start of the field in the buffer
                stu 1,s                         ; save it so we can set string descriptor
                ldb #0xff                       ; insist on two byte "AS" token
                jsr LB26F
                ldb #0xa7
                jsr LB26F
                jsr LB357                       ; evaluate variable
                jsr LB146                       ; error if it's a number
                puls b,u                        ; get back field length and buffer address
                stb ,x                          ; put those in the string descriptor
                stu 2,x
                bra LD0C3                       ; look for another entry
; RSET command
RSET            skip1lda                        ; set nonzero for right justify and fall through
; LSET command
LSET            clra                            ; set zero to flag left justify
                pshs a                          ; save justification type
                jsr LB357                       ; evaluate variable
                jsr LB146                       ; make sure it's a string
                pshs x                          ; save descriptor address
                ldx 2,x                         ; get address of string data
                cmpx #DFLBUF                    ; is it below random buffer area?
                blo LD119                       ; brif below - throw error
                cmpx FCBADR                     ; is it above the random buffer area?
                blo LD11E                       ; brif not - it's good
LD119           ldb #2*35                       ; code for "set to non-fielded string"
                jmp LAC46                       ; raise error
LD11E           ldb #0xb3                       ; insist on =
                jsr LB26F
                jsr L8748                       ; evaluate string expression; return details
                puls y                          ; get back destination descriptor pointer
                lda ,y                          ; get length of field string
                beq LD15A                       ; brif empty destination
                pshs b                          ; save length of new string
                ldb #0x20                       ; pad characteris space
                ldu 2,y                         ; point to destination string
LD132           stb ,u+                         ; blank out string
                deca                            ; done yet?
                bne LD132                       ; brif not
                ldb ,s+                         ; get length of data string
                beq LD15A                       ; brif that one is NULL
                cmpb ,y                         ; is data string smaller than destination?
                blo LD143                       ; brif not
                ldb ,y                          ; get length of destination string as the copy length
                clr ,s                          ; we'll do left justify if string is longer
LD143           ldu 2,y                         ; get address of the destination
                tst ,s+                         ; left or right justify?
                beq LD157                       ; brif left set
                pshs b                          ; save number of bytes to move into field string
                clra                            ; get negation of that in D (do -DLEN+FLEN)
                negb
                sbca #0
                addb ,y                         ; then add string length of destination to it
                adca #0
                leau d,u                        ; now U points to destination offset
                puls b                          ; get back destination size
LD157           jmp LA59A                       ; copy data and return
LD15A           puls a,pc                       ; clean up stack and return
; FILES command
FILES           jsr L95AC                       ; reset video display
                ldd FCBADR                      ; get current size of buffer space
                subd #DFLBUF
                pshs d                          ; save it as the default size
                ldb FCBACT                      ; get number of available disk files
                pshs b                          ; save it as the default number
                jsr GETCCH                      ; get input character
                cmpa #',                        ; is numer of files specified?
                beq LD181                       ; brif not
                jsr EVALEXPB                    ; evaluate the number of files wanted
                cmpb #15                        ; we only allow 15
                lbhi LB44A                      ; raise error if too many
                stb ,s                          ; save number of FCBs to allocate
                jsr GETCCH                      ; see what's after the number
                beq LD189                       ; brif no buffer size specified
LD181           jsr SYNCOMMA                    ; insist on a comma
                jsr LB3E6                       ; evaluate buffer size
                ifeq DISKVER
                addd #1
                endc
                std 1,s                         ; save buffer size
LD189           jsr DVEC7                       ; close all disk files
                ldb ,s                          ; get number of files
                pshs b                          ; initialize the file number count
                ldd #DFLBUF                     ; point to start of random buffers
                addd 2,s                        ; add in size requested for buffer space
                bcs LD208                       ; raise error if we carry
                std 2,s                         ; save start of FCBs
LD199           addd #FCBLEN                    ; add size of one FCB
                bcs LD208                       ; brif we overflowed
                dec ,s                          ; added on for all files?
                bpl LD199                       ; brif not yet (BPL so we set up the system one as well)
                tstb                            ; are we at an even page boundary?
                ifeq DISKVER
                beq LD1AF                       ; brif so
                else
                beq LD1A8                       ; brif so
                endc
                inca                            ; round up
                beq LD208                       ; brif we overflowed
                ifeq DISKVER-1
LD1A8           bita #1                         ; on an even 512 byte boundary?
                beq LD1AF                       ; brif so
                inca                            ; round up
                beq LD208                       ; brif we overflowed
                endc
LD1AF           sta ,s                          ; save MSB of graphics memory
                ldd VARTAB                      ; get end of program
                suba GRPRAM                     ; subtract out start of graphics (D is now size of program and graphics)
                adda ,s                         ; add in the new start of graphics
                bcs LD208                       ; brif overflow
                tfr d,x                         ; save new top of program
                inca                            ; add some extra room for the stack
                beq LD208                       ; brif overflow
                cmpd FRETOP                     ; does it fit in memory?
                bhs LD208                       ; brif not
                deca                            ; restore actual top of program
                subd VARTAB                     ; get difference compared to the original top of program
                addd TXTTAB                     ; add that to the program start
                tfr d,y                         ; now Y is the new start of the program
                lda ,s                          ; get back start of graphics memory
                suba GRPRAM                     ; this gives difference between old graphics start and new grahpics start
                tfr a,b                         ; we need this twice
                adda BEGGRP                     ; set new start of active page
                sta BEGGRP
                addb ENDGRP                     ; set new end of active page
                stb ENDGRP
                puls a,b,u                      ; get back graphics start, number of files, and start of buffers
                sta GRPRAM                      ; set graphics memory start
                stb FCBACT                      ; set number of active FCBs
                stu FCBADR                      ; set start of FCBs
                ifeq DISKVER-1
                lda CURLIN                      ; in immediate mode?
                inca
                beq LD1EF                       ; brif so
                tfr y,d                         ; calculate how much the program is moving
                subd TXTTAB
                addd CHARAD                     ; adjust input pointer for the change
                std CHARAD
                endc
LD1EF           ldu VARTAB                      ; get old end of program
                stx VARTAB                      ; save new end of program
                cmpu VARTAB                     ; which way did it move?
                bhi LD20B                       ; brif it moved up
LD1F8           lda ,-u                         ; move a byte down
                sta ,-x
                cmpu TXTTAB                     ; at start?
                bne LD1F8                       ; brif not
                sty TXTTAB                      ; set new start of program
                clr -1,y                        ; make sure there's a NUL before the program
                bra LD21B                       ; clean up
LD208           jmp LAC44                       ; raise OM error
LD20B           ldu TXTTAB                      ; get old start of program
                sty TXTTAB                      ; save new start of program
                clr -1,y                        ; make sure there's a NUL before the program
LD212           lda ,u+                         ; move a byte up
                sta ,y+
                cmpy VARTAB                     ; at end yet?
                bne LD212                       ; brif not
LD21B           ldu #FCBV1                      ; point to FCB pointers
                ldx FCBADR                      ; point to start of FCBs
                clrb                            ; file counter
LD222           stx ,u++                        ; set FCB pointer
                clr <<FCBTYP,x                  ; mark FCB as closed
                leax FCBLEN,x                   ; point to next FCB
                incb                            ; bump file counter
                cmpb FCBACT                     ; do we have enough of them yet?
                bls LD222                       ; brif not (BLS so we include system FCB)
                jmp L96CB                       ; fix up line pointers, etc.
; UNLOAD command
UNLOAD          bsr LD24F                       ; get drive number
                clrb                            ; clear file counter
LD236           incb                            ; bump file counter
                jsr LC749                       ; point to FCB
                beq LD249                       ; brif file not open
                lda FCBDRV,x                    ; is it on the right drive?
                cmpa DCDRV
                bne LD249                       ; brif not
                pshs b                          ; save file counter
                jsr LCB06                       ; close the file
                puls b                          ; restore file counter
LD249           cmpb FCBACT                     ; done all files?
                bls LD236                       ; brif not (includes system FCB)
                rts
; Parse drive number; use default if none given
LD24F           ldb DEFDRV                      ; set default drive
                jsr GETCCH                      ; is there something there?
                beq LD25F                       ; brif not
LD256           jsr EVALEXPB                    ; evaluate drive number
                cmpb #3                         ; valid?
                lbhi LA61F                      ; brif not
LD25F           stb DCDRV                       ; set drive number
                rts
; BACKUP command
BACKUP          lbeq LA61F                      ; raise error if no drive numbers
                jsr L95AC                       ; reset display
                jsr LD256                       ; get source drive number
                stb DBUF0+255                   ; save it (we're going to put our stack in DBUF0)
                jsr GETCCH                      ; is there something else?
                beq LD27B                       ; brif not
                ldb #0xa5                       ; insist on TO
                jsr LB26F
                jsr LD256                       ; fetch destination drive
LD27B           lds #DBUF0+255                  ; put the stack somewhere safe (source drive number already there)
                pshs b                          ; save destination drive number
                jsr LA5C7                       ; bail of there's more
                jsr DVEC7                       ; close files
                clr ,-s                         ; initialize track counter
                ldx #DFLBUF-1                   ; point to start of the heap
LD28C           inc ,s                          ; bump track counter
                leax SECMAX*SECLEN,x            ; add a whole track to the count
                cmpx MEMSIZ                     ; does it fit in memory?
                bls LD28C                       ; brif so
                dec ,s                          ; decrement track counter
                lbeq LAC44                      ; error if less than one track memory available
                lda #TRKMAX                     ; get maximum number of tracks
                clrb                            ; set tracks copied to 0
                pshs a,b                        ; save track counters
                com DRESFL                      ; force a "reset" of the disk system
LD2A4           clrb                            ; initialize write counter
LD2A5           incb                            ; add one to track counter
                dec ,s                          ; whole disk done?
                beq LD2AE                       ; brif not
                cmpb 2,s                        ; will it fit in memory?
                bne LD2A5                       ; brif so
LD2AE           stb TMPLOC                      ; save number of tracks to copy
                ldb 4,s                         ; get source drive number
                bsr LD2FC                       ; read TMPLOC tracks
                lda #0xff                       ; set source/dest flag to dest
                jsr LD322                       ; show prompt if needed
                ldb 3,s                         ; get destination drive
                bsr LD2FF                       ; write TMPLOC tracks
                tst ,s                          ; is there anything left?
                beq LD2CD                       ; brif not - we're done
                clra                            ; set source/desetination to source
                jsr LD322                       ; show prompt
                ldb 1,s                         ; get tracks written
                addb TMPLOC                     ; account for the ones we just wrote
                stb 1,s                         ; save new written counter
                bra LD2A4                       ; go copy some more tracks
LD2CD           bsr LD2D2                       ; check for re-init
                jmp LAC73                       ; return to immediate mode
LD2D2           puls u                          ; get return address (we might be resetting the stack)
                lda DRESFL                      ; reset desired?
                beq LD2EF                       ; brif not
                ldx #FCBV1                      ; point to FCB addresses
                clra                            ; set file counter to 0
LD2DD           clr [,x++]                      ; mark FCB as closed
                inca                            ; bump file counter
                cmpa FCBACT                     ; end of allocated FCBs?
                bls LD2DD                       ; brif not
                ldx TXTTAB                      ; get start of program
                clr -1,x                        ; make sure there's a NUL there
                jsr LAD19                       ; do a "NEW"
                clr DRESFL                      ; mark reset as not needed
LD2EF           lda DLODFL                      ; were we loading something?
                beq LD2FA                       ; brif not
                clr DLODFL                      ; clear out the loading state
                jsr LAD19                       ; empty out the program
LD2FA           jmp ,u                          ; return to caller
LD2FC           lda #2                          ; opcode for read
                skip2
LD2FF           lda #3                          ; opcode for write
                std DCOPC                       ; save operation and drive number
                lda 3,s                         ; get number of the first track to write
                sta DCTRK                       ; tell DSKCON
                ldx #DFLBUF                     ; put track buffer at the start of the heap
                stx DCBPT
                lda TMPLOC                      ; get track counter
LD30E           ldb #1                          ; start at sector 1
LD310           stb DSEC                        ; set sector
                jsr LD6F2                       ; read or write a sector
                inc DCBPT                       ; bump buffer pointer
                incb                            ; bump sector number
                cmpb #SECMAX                    ; end of track?
                bls LD310                       ; brif not
                inc DCTRK                       ; bump track
                deca                            ; done all the tracks?
                bne LD30E                       ; brif not
                rts
LD322           ldb 5,s                         ; get destination drive number
                cmpb 6,s                        ; compare to source
LD326           bne LD35E                       ; brif no prompt needed
                clr RDYTMR                      ; reset drive motor
                clr DSKREG
                clr DRGRAM
                pshs a                          ; save source/dest flag
                jsr LA928                       ; clear screen
                ldx #LD35F                      ; point to "source"
                ldb #13                         ; 13 bytes
                lda ,s+                         ; set flags on source/dest flag
                beq LD344                       ; brif source
                ldx #LD36C                      ; point to "dest"
                ldb #18                         ; 18 bytes
LD344           jsr LB9A2                       ; display message
                ldx #LD37E                      ; point to remainder of message
                ldb #27                         ; 27 bytes
                jsr LB9A2                       ; display it
                ldd #0x6405                     ; set up SOUND parameters
                sta SNDTON
                jsr LA951                       ; do a beep
LD357           jsr LA171                       ; read generic input (shows cursor)
                cmpa #0x0d                      ; carriage return?
                bne LD357                       ; bri fnot
LD35E           rts
LD35F           fcc 'INSERT SOURCE'
LD36C           fcc 'INSERT DESTINATION'
LD37E           fcc ' DISKETTE AND'
                fcb 0x0d
                fcc "PRESS 'ENTER'"
; Save file name and extension on stack, and also the current drive number
LD399           puls y                          ; get return address
                ldb #11                         ; 11 characters for both name and extension
                ldx #DNAMBF+11                  ; point to end of buffer
LD3A0           lda ,-x                         ; fetch a file name character
                pshs a                          ; stuff it on the stack
                decb                            ; done yet?
                bne LD3A0                       ; brif not
                lda DCDRV                       ; save drive number
                pshs a
                jmp ,y                          ; return to caller
; Copy drive, filename, and extension from X to state
LD3AD           lda ,x+                         ; set drive number
                sta DCDRV
                ldb #11                         ; 11 characters in file name and extension
                ldu #DNAMBF                     ; point to disk file name buffer
                jmp LA59A                       ; copy the file name
; COPY command
; NOTE: an error during COPY will cause the system to hang due to the FCB's buffer pointer
; being moved out of normal buffer space.
COPY            jsr LC935                       ; get source file name
                bsr LD399                       ; save it on the stack
                clr ,-s                         ; set flag for "single disk" copy
                jsr GETCCH                      ; is there a destination?
                beq LD3CE                       ; brif not - single disk (swapping)
                com ,s                          ; set to "two parameter" copy
                ldb #0xa5                       ; insist on TO
                jsr LB26F
                jsr LC935                       ; parse the destination file name
LD3CE           bsr LD399                       ; save destination file name
                jsr LA5C7                       ; bail if more stuff
                jsr DVEC7                       ; close everything
                clr ,-s                         ; clear sector counter
                ifeq DISKVER
                leax -100,s                     ; leave a buffer below the stack
                else
                leax -SECLEN,s                  ; point one sector below the stack
                endc
LD3DC           inc ,s                          ; bump sector counter
                leax -SECLEN,x                  ; move back a sector
                cmpx ARYEND                     ; did we hit the top of variables?
                bhs LD3DC                       ; brif not
                dec ,s                          ; decrement off the last one that didn't fit
                lbeq LAC44                      ; brif not at least one sector free memory
                leax 14,s                       ; set up for source file name/drive
                bsr LD3AD
                jsr LC68C                       ; find file
                jsr LC6E5                       ; error if not found
                ldx V974                        ; get directory data pointer
                ldu DIRLST,x                    ; get file type and last sector data
                ldx DIRTYP,x
                pshs u,x                        ; save them
                jsr LC79D                       ; read FAT data
                ldb V976                        ; get first granule in file
                jsr LCD1E                       ; count granules in chain
                pshs a                          ; save number of granules in file
                deca                            ; subtract off last granule (may be partial)
                andb #0x3f                      ; get number of sectors in last granule
                pshs b                          ; save sectors in last granule
                tfr a,b                         ; zero extend to granule count to D
                clra
                jsr LC779                       ; get number of sectors in complete granules
                addb ,s                         ; add in partial sector count
                adca #0
                ldx #1                          ; initialize record counter to 1
                pshs x,b,a                      ; save record counter and sector counter
LD41E           clrb                            ; set sector counter to 0
                ldx ,s                          ; get number of sectors remaining in the file
                beq LD42C                       ; brif none left
LD423           incb                            ; add a sector to counter
                leax -1,x                       ; at bottom of file?
                beq LD42C                       ; brif so
                cmpb 10,s                       ; at maximum memory space?
                bne LD423                       ; brif not
LD42C           stx ,s                          ; save number of sectors that will be left after this iteration
                stb 4,s                         ; save number of sectors to be copied this time
                bsr LD482                       ; get sectors to buffer
                lda #0xff                       ; show swap message for dest
                bsr LD476
                tst 5,s                         ; do we need to test for enough free space?
                beq LD45F                       ; brif not
                leax 11,s                       ; retrieve destination file parameters
                jsr LD3AD
                jsr LD059                       ; find the file, AE error if it exists
                jsr LC79D                       ; get FAT data
                jsr LC755                       ; point to FAT
                leax FATCON,x                   ; point to granuledata
                lda 5,s                         ; get number of granules in file
                ldb #GRANMX                     ; maximum granules to check
LD44E           com ,x                          ; is granule free?
                bne LD455                       ; brif not
                deca                            ; found enough?
                beq LD45D                       ; brif not
LD455           com ,x+                         ; restore FAT data
                decb                            ; run through whole fat?
                bne LD44E                       ; brif not
                jmp LC7F8                       ; do "disk full"
LD45D           com ,x                          ; restore FAT data
LD45F           bsr LD47C                       ; put data from memory to destination file
                ldx ,s                          ; get number of sectors left
                beq LD472                       ; brif none - we're done
                ldd 2,s                         ; get current recordcounter
                addb 4,s                        ; add in number of sectors
                adca #0
                std 2,s                         ; save new record counter
                clra                            ; show source message if needed
                bsr LD476
                bra LD41E                       ; copy some more stuff
LD472           leas 36,s                       ; clean up stack
                rts
LD476           tst 25,s                        ; doing a "single disk" copy?
                jmp LD326                       ; show message if needed
; put or get data for copy
LD47C           lda #0xff                       ; put flag
                leax 13,s                       ; point to destination file
                bra LD486                       ; go do the write
LD482           clra                            ; get flag
                leax 26,s                       ; point to source file
LD486           sta VD8                         ; save get/put flag
                jsr LD3AD                       ; fetch file parameters from stack
                ldx 8,s                         ; get file type and ASCII flag
                stx DFLTYP                      ; save it
                ldx #SECLEN                     ; set record length to one sector
                stx DFFLEN
                lda #'R                         ; set type to "random"
                ldb FCBACT                      ; point to system FCB
                incb
                jsr LC48D
                ldx FCBTMP                      ; get FCB pointer
                ldd #SECLEN                     ; set number of bytes in last sector to one sector
                std FCBLST,x
                ldb 6,s                         ; get number of sectors to read/write
                beq LD4D4                       ; brif none
                ldb VD8                         ; get or put?
                andb 7,s                        ; is it first time on put?
                beq LD4BA                       ; brif not
                ldd 2,s                         ; get number of sectors remaining
                addb 6,s                        ; add to number copied this time
                adca #0
                jsr LC2E6                       ; put the last record in the file (this allocates the file)
LD4BA           ldx FCBTMP                      ; point to FCB
                ldu 4,s                         ; get current record number
                stu FCBREC,x                    ; save in FCB
                ldb 6,s                         ; get number of sectors to move
                ldu ARYEND                      ; point to start of free memory
LD4C4           pshs u,b                        ; save buffer pointer and counter
                ldx FCBTMP                      ; fetch FCB pointer
                stu FCBBUF,x                    ; set buffer to free memory (will cause hang on error)
                jsr LC2EA                       ; do get or put
                inc 1,s                         ; bump buffer pointer
                puls b,u                        ; get back buffer pointer and sector count
                decb                            ; done all yet?
                bne LD4C4                       ; brif not
LD4D4           ldx FCBTMP                      ; get FCB pointer
                ldu #DFLBUF                     ; reset buffer pointer to bottom of buffer area
                stu FCBBUF,x
                ldb VD8                         ; first time through on PUT?
                andb 7,s
                beq LD4EA                       ; brif not
                clr 7,s                         ; reset the "first time" flag
                ldd 10,s                        ; get bytes in last sector
                ora #0x80                       ; set "pre-save" flag
                std FCBLST,x                    ; set correct last sector size
LD4EA           jmp LCB06                       ; close the file
; DSKI$ command
DSKI            bsr LD527                       ; get drive, track, and sector
                bsr LD51C                       ; evaluate frist string sand save descriptor address
                pshs x
                bsr LD51C                       ; evaluate second string and save descriptor address
                pshs x
                ldb #2                          ; read operation
                jsr LD58F                       ; read sector
                ldu #DBUF0+128                  ; point to second half
                puls x                          ; get descriptor for second string
                bsr LD508                       ; stow second string
                ldu #DBUF0                      ; point to first half
                puls x                          ; get descriptor for first string
LD508           pshs u,x                        ; save source data and descriptor
                ldb #128                        ; do 128 bytes exactly
                jsr LB50F                       ; reserve space
                leau ,x                         ; point to reserved space
                puls x                          ; get string descriptor address
                stb ,x                          ; save length in descriptor
                stu 2,x                         ; save data pointer
                puls x                          ; get buffer pointer
LD519           jmp LA59A                       ; copy bytes to string
LD51C           jsr SYNCOMMA                    ; make sure there's a comma
                ldx #LB357                      ; point to variable evaluation routine
                bsr LD553                       ; evaluate variable
LD524           jmp LB146                       ; make sure we have a string
LD527           jsr EVALEXPB                    ; evaluate 8 bit expression
                cmpb #3                         ; valid drive?
                bhi LD54A                       ; brif not
                pshs b                          ; save it
                jsr LB738                       ; evaluate track expression (after a comma)
                cmpb #TRKMAX-1                  ; valid track?
                bhi LD54A                       ; brif not
                pshs b                          ; save track number
                jsr LB738                       ; evaluate comma followed by sector number
                stb DSEC                        ; set DSKCON variable
                decb                            ; zero-base it
                cmpb #SECMAX-1                  ; is it a valid sector?
                bhi LD54A                       ; brif not
                puls a,b                        ; get drive and track
                sta DCTRK                       ; set DSKCON
                stb DCDRV
                rts
LD54A           jmp LB44A                       ; raise FC error
LD54D           jsr SYNCOMMA                    ; insist on a comma
                ldx #LB156                      ; evaluate expression pointer
LD553           ldb DCDRV                       ; save drive, track, and sector values
                ldu DCTRK
                pshs u,b                        ; save them
                jsr ,x                          ; evaluate variable or expression
                puls b,u                        ; restore DSKCON
                stb DCDRV
                stu DCTRK
                rts
; DSKO$ command
DSKO            bsr LD527                       ; evaluate drive, track, and sector
                bsr LD54D                       ; evaluate string 1
                bsr LD524                       ; make sure it's a string
                ldx FPA0+2                      ; get descriptor address
                pshs x                          ; save it
                bsr LD54D                       ; evaluate string 2
                jsr LB654                       ; get string details
                pshs x,b                        ; save them
                clrb                            ; clear full sector (so junk doesn't get in if strings are short)
                ldx #DBUF0                      ; point to sector buffer
LD577           clr ,x+                         ; clear a byte
                decb                            ; done whole sector?
                bne LD577                       ; brif not
                puls b,x                        ; get string data
                ldu #DBUF0+128                  ; point to second half of sector
                bsr LD519                       ; copy string data (anything over 128 will go in second I/O buffer so harmless)
                puls x                          ; get first string
                jsr LB659                       ; fetch string details
                ldu #DBUF0                      ; point to start of sector buffer
                bsr LD519                       ; copy string data (this will overwrite up to 255 bytes!)
                ldb #3                          ; write operation
LD58F           ldx #DBUF0                      ; point to sector buffer
                stx DCBPT
                stb DCOPC                       ; set read/write
                jmp LD6F2                       ; go read/write sector
; DSKINI command
DSKINI          lbeq LA61F                      ; error if no drive number specified
                jsr LD256                       ; parse driven umber
                ldb #4                          ; default skip factor is 4
                jsr GETCCH                      ; is there a skip factor?
                beq LD5B2                       ; brif not
                jsr LB738                       ; evaluate comma followed by skip factor
                cmpb #17                        ; max value is 16
                lbhs LB44A                      ; brif too high
                jsr LA5C7                       ; carp if there's anything else
LD5B2           pshs b                          ; save skip factor
                ldx #DBUF1+SECMAX               ; poitn to end of sector number scratch area
                ldb #SECMAX                     ; get the maximum sector number
LD5B9           clr ,-x                         ; mark sector number unset
                decb                            ; done all of them?
                bne LD5B9                       ; brif not
                clra                            ; reset sector counter
                bra LD5CE                       ; start assigning sector numbers
LD5C1           addb ,s                         ; add in skip factor
LD5C3           incb                            ; bump sector number
LD5C4           subb #SECMAX                    ; remove a whole track worth
                bhs LD5C4                       ; brif we can still do more
                addb #SECMAX                    ; undo extra subtraction
                tst b,x                         ; has this sector been numbered?
                bne LD5C3                       ; brif so - try again on next one
LD5CE           inca                            ; bump sector number
                sta b,x                         ; set actual sector number
                cmpa #SECMAX                    ; done all?
                blo LD5C1                       ; brif not
                leas 1,s                        ; remove skip factor - we don't need it
                ldx #DFLBUF+0x1888-2            ; point to top of memory used by DSKINI (for track image)
                cmpx MEMSIZ                     ; does it fit?
                lbhi LAC44                      ; brif not
                jsr DVEC7                       ; close files
                com DRESFL                      ; cause reset of things
                lds #DBUF1+SECLEN               ; put stack somewhere safe
                jsr L95AC                       ; reset display
                lda #0                          ; restore head to track 0
                sta DCOPC
                ifeq DISKVER-1
                clr DCTRK                       ; set track number to 0 (used as a track counter for the format)
                endc
                jsr LD6F2                       ; restorehead to track 0
                clr RDYTMR                      ; don't allow motor to turn off
                lda #0xc0                       ; FDC read address code
                sta FDCREG                      ; instruct FDC
                jsr LD7D1                       ; wait until drive ready
                ifeq DISKVER
                lbne LD688                      ; brif drive not ready
                clr DCTRK                       ; reset track counter
                bra LD620                       ; go format tracks
                else
                beq LD620                       ; brif drive ready
                jmp LD688                       ; raise error if not ready
                endc
LD606           cmpa #22                        ; precomp?
                blo LD612                       ; brif not
                lda DRGRAM                      ; enable precomp
                ora #0x10
                sta DSKREG
LD612           lda #0x53                       ; "step in"
                sta FDCREG                      ; go do a step
                exg a,a                         ; wait for FDC status to stabilize
                exg a,a
                jsr LD7D1                       ; wait for ready
                bne LD688                       ; bri fnot ready - raise error
LD620           jsr LD7F0                       ; wait for a bit
                bsr LD691                       ; build formatted track
                ldy #FDCREG+3                   ; point to data register
                orcc #0x50                      ; disable interrupts
                ldx #LD64F                      ; where to return to
                stx DNMIVC                      ; set up NMI escaper
                ldx #DFLBUF                     ; point to track image
                lda FDCREG                      ; reset status of FDC
                lda #0xff                       ; enable NMI escaper
                sta NMIFLG
                ldb #0xf4                       ; write track command
                stb FDCREG                      ; instruct FDC
                lda DRGRAM                      ; enable HALT
                ora #0x80
                sta DSKREG
LD649           ldb ,x+                         ; fetch track byte
                stb ,y                          ; stuff it out to FDC
                bra LD649                       ; do another ASAP (HALT will clock this)
LD64F           lda FDCREG                      ; fetch status
                andcc #0xaf                     ; restore interrupts
                anda #0x44                      ; keep only write protect and lost data
                sta DCSTA                       ; save status
                bne LD688                       ; brif error
                inc DCTRK                       ; bump track number
                lda DCTRK                       ; done all tracks?
                cmpa #TRKMAX
                bne LD606                       ; brif not
                lda #2                          ; DSKCON read operation
                sta DCOPC
                ldx #DBUF0                      ; point to disk buffer
                stx DCBPT
                ldu #DBUF1                      ; point to sector numbers
                clra                            ; reset track counter
LD66F           sta DCTRK                       ; set track
                clrb                            ; reset sector counter
LD672           lda b,u                         ; get real sector number
                sta DSEC                        ; tell DSKCON
                jsr LD6F2                       ; read a sector
                incb                            ; bump sector counter
                cmpb #SECMAX                    ; done whole track?
                blo LD672                       ; brif not
                lda DCTRK                       ; get track number
                inca                            ; bump it
                cmpa #TRKMAX                    ; done all?
                blo LD66F                       ; brif not
                jmp LD2CD                       ; do the reset thing if needed
LD688           clr DRGRAM                      ; stop drive motors and selects
                clr DSKREG
                jmp LD701                       ; wait for ready signal
LD691           ldx #DFLBUF                     ; point to track buffer
                ldd #0x204e                     ; write out 32 * 0x4e
                bsr LD6C2
                clrb                            ; reset sector counter
LD69A           pshs b                          ; save sector counter
                ldu #DBUF1                      ; point to sector numbers
                ldb b,u                         ; get real sector number
                stb DSEC                        ; save it
                ldu #LD6D4                      ; point to format table for a sector
                ldb #3                          ; process three blocks
                bsr LD6C8
                lda DCTRK                       ; save track number
                sta ,x+
                clr ,x+                         ; set side number to 0
                lda DSEC                        ; set sector number
                sta ,x+
                ldb #9                          ; process 9 blocks
                bsr LD6C8
                puls b                          ; get sector counter
                incb                            ; bump it
                cmpb #SECMAX                    ; done all?
                blo LD69A                       ; brif not - do another sector
                ldd #0xc84e                     ; write 200 times 0x4e for track trailer
LD6C2           stb ,x+                         ; stow a byte
                deca                            ; done enough?
                bne LD6C2                       ; brif not
                rts
LD6C8           pshs b                          ; save item counter
                ldd ,u++                        ; get count and data byte
                bsr LD6C2                       ; process it
                puls b                          ; get item count back
                decb                            ; done all?
                bne LD6C8                       ; brif not
                rts
LD6D4           fcb 8,0                         ; SYNC field
                fcb 3,0xf5
                fcb 1,0xfe                      ; address mark
                ; track, side, sector here
                fcb 1,1                         ; sector size flag
                fcb 1,0xf7                      ; CRC request
                fcb 22,0x4e                     ; post-ID gap
                fcb 12,0                        ; sync field
                fcb 3,0xf5
                fcb 1,0xfb                      ; data address mark
                fcb 0,0xff                      ; default track data
                fcb 1,0xf7                      ; CRC request
                fcb 24,0x4e                     ; post data gap
                ifeq DISKVER-1
; DOS command
DOS             bne LD742                       ; brif argument given
                jmp [DOSVEC]                    ; transfer control to DOS command
                endc
; General sector read/write routine; this implements VERIFY on write and does several retries
LD6F2           pshs b                          ; save register
                ldb #5                          ; we'll try 5 times on VERIFY failure
                stb ATTCTR
                puls b                          ; restore register
LD6FB           bsr DSKCON                      ; execute command
                tst DCSTA                       ; success?
                beq LD70E                       ; brif so
LD701           lda DCSTA                       ; get status
                ldb #2*30                       ; code for write protect
                bita #0x40                      ; was it write protected?
                bne LD70B                       ; brif so
LD709           ldb #2*20                       ; I/O error code
LD70B           jmp LAC46                       ; raise error
LD70E           pshs a                          ; save A
                lda DCOPC                       ; was it write?
                cmpa #3
                puls a                          ; restore register
                bne LD742                       ; brif not
                tst DVERFL                      ; verify?
                beq LD742                       ; brif not
                pshs u,x,b,a                    ; save registers
                lda #2                          ; set for read
                sta DCOPC
                ldu DCBPT                       ; get original buffer pointer
                ldx #DBUF1                      ; point to secondary buffer
                stx DCBPT
                bsr DSKCON                      ; read the sector
                stu DCBPT                       ; restore buffer pointer
                lda #3                          ; restore write operation
                sta DCOPC
                lda DCSTA                       ; did we have a problem?
                bne LD743                       ; brif so
                clrb                            ; check 256 bytes
LD737           lda ,x+                         ; compare two bytes
                cmpa ,u+
                bne LD743                       ; brif no match - error
                decb                            ; done all?
                bne LD737                       ; brif not
                puls a,b,x,u                    ; restore registers
LD742           rts
LD743           puls a,b,x,u                    ; restore registers
                dec ATTCTR                      ; tried enough times?
                bne LD6FB                       ; brif not - try again
                ldb #2*36                       ; code for verify error
                bra LD70B                       ; raise error
; VERIFY command
VERIFY          clrb                            ; off flag
                cmpa #0xaa                      ; OFF?
                beq LD75A                       ; brif so
                comb                            ; set to on flag
                cmpa #0x88                      ; ON?
                lbne LB277                      ; brif not - raise error
LD75A           stb DVERFL                      ; set verify state
                jmp GETNCH                      ; eat the ON/OFF and return
; DSKCON - the main disk I/O driver
DSKCON          pshs u,y,x,b,a                  ; save registers
                lda #5                          ; retry 5 times
                pshs a                          ; save retry counter
LD765           clr RDYTMR                      ; reset drive timeout (so drive won't turn off if it's already on)
                ldb DCDRV                       ; get drive number
                ldx #LD89D                      ; point to drive enable masks
                lda DRGRAM                      ; get control register value
                anda #0xa8                      ; keep only motor, halt, double density
                ora b,x                         ; set drive select lines
                ora #0x20                       ; set double density
                ldb DCTRK                       ; get desired track
                cmpb #22                        ; precomp?
                blo LD77E                       ; brif not
                ora #0x10                       ; enable precomp
LD77E           tfr a,b                         ; save image prior to enabling motors
                ora #8                          ; turn on motors
                sta DRGRAM                      ; actuall do all that stuff above
                sta DSKREG
                bitb #8                         ; were motors already on?
                bne LD792                       ; brif so - don't wait
                jsr LA7D1                       ; wait quite a while
                jsr LA7D1                       ; wait quite a while longer
LD792           bsr LD7D1                       ; wait until read
                bne LD7A0                       ; brif timed out
                clr DCSTA                       ; clear status (set no error)
                ldx #LD895                      ; point to command jump table
                ldb DCOPC                       ; get operation code
                aslb                            ; two bytes per routine address
                jsr [b,x]                       ; do operation
LD7A0           puls a                          ; get back retry count
                ldb DCSTA                       ; get status
                beq LD7B1                       ; brif no error
                deca                            ; retried enough?
                beq LD7B1                       ; brif so
                pshs a                          ; save retry counter again
                bsr LD7B8                       ; restore head to track 0
                bne LD7A0                       ; brif error
                bra LD765                       ; try command again
LD7B1           lda #120                        ; drive timeout is 120 VSYNC ticks (2 seconds for 60Hz)
                sta RDYTMR
                puls a,b,x,y,u,pc               ; restore registers and return
LD7B8           ldx #DR0TRK                     ; point to track table
                ldb DCDRV                       ; get drive number
                clr b,x                         ; mark drive on track 0
                lda #3                          ; restore head to track 0, unloaded, 30ms step
                sta FDCREG                      ; go do it
                exg a,a                         ; wait for status to stabilize
                exg a,a
                bsr LD7D1                       ; wait for ready
                bsr LD7F0                       ; wait somemore
                anda #0x10                      ; keep only seek error
                sta DCSTA                       ; set result
LD7D0           rts
LD7D1           ldx ZERO                        ; get timeout counter
LD7D3           leax -1,x                       ; count down
                beq LD7DF                       ; brif timed out
                lda FDCREG                      ; get status
                bita #1                         ; is it ready?
                bne LD7D3                       ; brif not
                rts
LD7DF           lda #0xd0                       ; force interrupt
                sta FDCREG
                exg a,a                         ; wait for status to stabilize
                exg a,a
                lda FDCREG                      ; clear status
                lda #0x80                       ; return not ready status
                sta DCSTA
                rts
LD7F0           ldx #8750                       ; delay for about half of a long while
LD7F3           leax -1,x                       ; count down
                bne LD7F3                       ; brif not done
                rts
LD7F8           lda #0x80                       ; code for read sector
                skip2
LD7FB           lda #0xa0                       ; code for write sector
                pshs a                          ; save operation
                ldx #DR0TRK                     ; point to track state table
                ldb DCDRV                       ; get drive number
                abx                             ; point to correct drive table
                ldb ,x                          ; get current track number
                stb FDCREG+1                    ; tell FDC about it
                cmpb DCTRK                      ; is it the one we want?
                beq LD82C                       ; brif so - no stepping needed
                lda DCTRK                       ; get desired track
                sta FDCREG+3                    ; tell the FDC that too
                sta ,x                          ; record that drive is there
                lda #0x17                       ; seek to desired track, unloaded, 30ms step, verify destination
                sta FDCREG
                exg a,a                         ; wait for status to be stable
                exg a,a
                bsr LD7D1                       ; wait for ready
                bne LD82A                       ; brif timed out
                bsr LD7F0                       ; wait some more
                anda #0x18                      ; keep only seek error or CRC error in ID
                beq LD82C                       ; brif no errors
                sta DCSTA                       ; save error state
LD82A           puls a,pc                       ; clean up stack and return
LD82C           lda DSEC                        ; get desired sector
                sta FDCREG+2                    ; tell FDC
                ldx #LD88B                      ; point to escape routine
                stx DNMIVC                      ; set up NMI escaper
                ldx DCBPT                       ; point to I/O buffer
                lda FDCREG                      ; reset FDC status
                lda DRGRAM                      ; get control register image
                ora #0x80                       ; enable HALT
                puls b                          ; get operation code
                ldy ZERO                        ; timeout value
                ldu #FDCREG                     ; point to FDC
                com NMIFLG                      ; enable escaper
                orcc #0x50                      ; disable interrupts
                stb FDCREG                      ; give FDC its marching orders
                exg a,a                         ; wait for stable status
                exg a,a
                cmpb #0x80                      ; read?
                beq LD875                       ; brif so
                ldb #2                          ; DRQ mask
LD85B           bitb ,u                         ; is it ready for a byte?
                bne LD86B                       ; brif not
                leay -1,y                       ; timed out?
                bne LD85B                       ; brif not
LD863           clr NMIFLG                      ; disable NMI escaper
                andcc #0xaf                     ; enable interrupts
                jmp LD7DF                       ; force interrupt, etc.
LD86B           ldb ,x+                         ; get byte from buffer
                stb FDCREG+3                    ; send it out
                sta DSKREG                      ; reprogram control register
                bra LD86B                       ; send more
LD875           ldb #2                          ; DRQ mask bit
LD877           bitb ,u                         ; is a byte ready?
                bne LD881                       ; brif not
                leay -1,y                       ; timed out?
                bne LD877                       ; brif not
                bra LD863                       ; bail out
LD881           ldb FDCREG+3                    ; get input data
                stb ,x+                         ; put in buffer
                sta DSKREG                      ; reprogram control register
                bra LD881                       ; read more
LD88B           andcc #0xaf                     ; enable interrupts
                lda FDCREG                      ; get status from FDC
                anda #0x7c                      ; keep write protect, write fault, not found, CRC, or lost data
                sta DCSTA                       ; set status
                rts
LD895           fdb LD7B8                       ; reset head to track 0
                fdb LD7D0                       ; no-op - just spin up drives
                fdb LD7F8                       ; read sector
                fdb LD7FB                       ; write sector
LD89D           fcb 0x01                        ; drive select 0
                fcb 0x02                        ; drive select 1
                fcb 0x04                        ; drive select 2
                fcb 0x40                        ; drive select 3/side select
; NMI handler
DNMISV          lda NMIFLG                      ; is the escaper enabled?
                beq LD8AE                       ; brif not
                ldx DNMIVC                      ; set return to escape hatch
                stx 10,s
                clr NMIFLG                      ; disable escaper now that we used it
LD8AE           rti
; Disk IRQ handler
DIRQSV          lda PIA0+3                      ; is it VSYNC?
                bpl LD8AE                       ; brif HSYNC
                lda PIA0+2                      ; clear interrupt status
                lda RDYTMR                      ; are drives waiting to stop?
                beq LD8CD                       ; brif not
                deca                            ; count down a tick
                sta RDYTMR                      ; save new count
                bne LD8CD                       ; brif they haven't timed out yet
                lda DRGRAM                      ; get control register image
                anda #0xb0                      ; turn off motors and drive selects
                sta DRGRAM
                sta DSKREG
LD8CD           jmp L8955                       ; transfer control to Extended Basic's handler
                ifeq DISKVER-1
; From here to the DOS command is unused
                fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
                fcb 0x13,0x34,0x06,0x9D,0xA5,0x27,0x03,0xBD,0x95,0x81,0x96,0xB5,0x97,0xD8,0x35,0x06
                fcb 0xDD,0xB4,0x4F,0x34,0x56,0xBD,0x95,0x22,0xBD,0x92,0x8F,0xDF,0xD9,0xBD,0x99,0xDF
                fcb 0x27,0x0F,0xBD,0x99,0xCB,0x86,0x01,0x97,0xD7,0xBD,0x99,0xBA,0x00,0xD7,0xBD,0x99
                fcb 0xBA,0x10,0xDF,0xDC,0x0D,0xDB,0x26,0x03,0x10,0xDE,0xDC,0x35,0x56,0x0F,0xDB,0x10
                fcb 0xDF,0xDC,0x30,0x01,0x9F,0xBD,0xDF,0xD1,0x97,0xD7,0x27,0x9F,0x2B,0x06,0x5C,0xD1
                fcb 0xD6,0x23,0x05,0x5F,0x5D,0x27,0xDD,0x5A,0xD7,0xC0,0xBD,0x99,0xDF,0x27,0x0F,0x10
                fcb 0x83,0x00,0x03,0x25,0x04,0x30,0x1E,0x8D,0x38,0xBD,0x99,0xCB,0x8D,0x4C,0x43,0x53
                fcb 0xD3,0xD1,0xDD,0xD1,0x2F,0x16,0xBD,0x95,0x06,0xBD,0x9A,0x12,0x26,0x05,0xCC,0xFF
                fcb 0xFF,0x20,0xED,0xBD,0x95,0x14,0x8D,0x3E,0x8D,0x5E,0x20,0xE0,0xBD,0x95,0x06,0x30
                fcb 0x8B,0x9F,0xBD,0x43,0x53,0x83,0x00,0x01,0x2F,0x04,0x1F,0x01,0x8D,0x03,0x7E,0x99
                fcb 0x34,0xDD,0xCB,0x35,0x20,0xDC,0xBD,0x34,0x16,0x96,0xD7,0x40,0xD6,0xC0,0x34,0x06
                fcb 0x34,0x20,0xC6,0x02,0xBD,0xAC,0x33,0xDC,0xCB,0x39,0xDD,0xCB,0x35,0x20,0xDC,0xC3
                fcb 0x34,0x16,0x96,0xD7,0x20,0xE6,0x9E,0xBD,0x9F,0xC3,0x39,0xDD,0xCD,0x10,0x9E,0xC3
                fcb 0x8D,0xF4,0x10,0x9F,0xBD,0x8D,0x11,0x9E,0xCD,0x30,0x8B,0xC3,0x00,0x01,0x39,0xBD
                fcb 0x99,0xC6,0x10,0x8E,0x95,0x14,0x20,0x06,0x10,0x8E,0x95,0x06,0xAD,0xA4,0xDE,0x8A
                fcb 0x9E,0xBD,0x2B,0x17,0x9C,0xD3,0x22,0x13,0x34,0x60,0x8D,0x16,0x27,0x0B,0xBD,0x93
                fcb 0x77,0x35,0x60,0x33,0x41,0xAD,0xA4,0x20,0xE9,0x35,0x60,0x1F,0x30,0x1F,0x01,0x93
                fcb 0x8A,0x39,0xAD,0x9F,0x00,0xD9,0x1F,0x89,0xD4,0xD8,0x34,0x06,0xA4,0x84,0xA1,0x61
                fcb 0x35,0x86,0x9E,0x8A,0xC6,0x01,0x34,0x14,0xBD,0xB1,0x56,0x5F,0xBD,0xA9,0xA2,0xBD
                fcb 0xA9,0x76,0xBD,0xB6,0x54,0x20,0x02,0x35,0x14,0xD7,0xD8,0x27,0xFA,0x9F,0xD9,0x10
                fcb 0x27,0x0F,0x31,0x0D,0xD8,0x27,0xF0,0xBD,0x9B,0x98,0x81,0x3B,0x27,0xF5,0x81,0x27
                fcb 0x27,0xF1,0x81,0x58,0x10,0x27,0x01,0xB2,0x8D,0x02,0x20,0xE7,0x81,0x4F,0x26,0x0D
                fcb 0xD6,0xDE,0x5C,0x8D,0x5B,0x5A,0xC1,0x04,0x22,0x63,0xD7,0xDE,0x39,0x81,0x56,0x26
                fcb 0x1A,0xD6,0xDF,0x54,0x54,0xC0,0x1F,0x8D,0x47,0xC1,0x1F,0x22,0x50,0x58,0x58,0x34
                fcb 0x04,0xCC,0x7E,0x7E,0xAB,0xE4,0xE0,0xE0,0xDD,0xDF,0x39,0x81,0x4C,0x26,0x23,0xD6
                fcb 0xE1,0x8D,0x2D,0x5D,0x27,0x37,0xD7,0xE1,0x0F,0xE5,0x8D,0x03,0x24,0xFC,0x39,0x0D
                fcb 0xD8,0x27,0x0A,0xBD,0x9B,0x98,0x81,0x2E,0x27,0x05,0xBD,0x9B,0xE2,0x43,0x39,0x0C
                fcb 0xE5,0x39,0x81,0x54,0x26,0x0D,0xD6,0xE2,0x8D,0x06,0x5D,0x27,0x10,0xD7,0xE2,0x39
                fcb 0x7E,0x9B,0xAC,0x81,0x50,0x26,0x24,0xBD,0x9C,0xCB,0x5D,0x26,0x03,0x7E,0xB4,0x4A
                fcb 0x96,0xE5,0x9E,0xDF,0x34,0x12,0x86,0x7E,0x97,0xDF,0x97,0xE0,0x0F,0xE5,0x8D,0x07
                fcb 0x35,0x12,0x97,0xE5,0x9F,0xDF,0x39,0x6F,0xE2,0x20,0x40,0x81,0x4E,0x26,0x03,0xBD
                fcb 0x9B,0x98,0x81,0x41,0x25,0x04,0x81,0x47,0x23,0x05,0xBD,0x9B,0xBE,0x20,0x23,0x80
                fcb 0x41,0x8E,0x9C,0x5B,0xE6,0x86,0x0D,0xD8,0x27,0x18,0xBD,0x9B,0x98,0x81,0x23,0x27
                fcb 0x04,0x81,0x2B,0x26,0x03,0x5C,0x20,0x0A,0x81,0x2D,0x26,0x03,0x5A,0x20,0x03,0xBD
                fcb 0x9B,0xE2,0x5A,0xC1,0x0B,0x22,0xA6,0x34,0x04,0xD6,0xE1,0x96,0xE2,0x3D,0xDD,0xD5
                fcb 0x33,0x61,0x96,0xDE,0x81,0x01,0x22,0x2C,0x8E,0x9C,0x62,0xC6,0x18,0x3D,0x3A,0x35
                fcb 0x04,0x58,0x3A,0x31,0x84,0x8D,0x45,0xDD,0xE3,0x8D,0x0C,0x96,0xDF,0x8D,0x0B,0x8D
                fcb 0x06,0x96,0xE0,0x8D,0x05,0x20,0xF2,0x86,0x7E,0x12,0xB7,0xFF,0x20,0xAE,0xA4,0x30
                fcb 0x1F,0x26,0xFC,0x39,0x8E,0x9C,0x7A,0xC6,0x0C,0x3D,0x3A,0x35,0x04,0x3A,0x8D,0x1C
                fcb 0xDD,0xE3,0x8D,0x0C,0x96,0xDF,0x8D,0x0B,0x8D,0x06,0x96,0xE0,0x8D,0x05,0x20,0xF2
                fcb 0x86,0x7E,0x12,0xB7,0xFF,0x20,0xA6,0x84,0x4A,0x26,0xFD,0x39,0xC6,0xFF,0x96,0xE5
                fcb 0x27,0x05,0x8B,0x02,0x3D,0x44,0x56,0x39,0x34,0x10,0x0D,0xD8,0x27,0x4D,0x9E,0xD9
                fcb 0xA6,0x80,0x9F,0xD9,0x0A,0xD8,0x81,0x20,0x27,0xF0,0x35,0x90,0x8D,0xEA,0x81,0x2B
                fcb 0x27,0x3C,0x81,0x2D,0x27,0x3C,0x81,0x3E,0x27,0x42,0x81,0x3C,0x27,0x39,0x81,0x3D
                fcb 0x27,0x3F,0xBD,0x90,0xAA,0x25,0x24,0x5F,0x80,0x30,0x97,0xD7,0x86,0x0A,0x3D,0x4D
                fcb 0x26,0x19,0xDB,0xD7,0x25,0x15,0x0D,0xD8,0x27,0x17,0xBD,0x9B,0x98,0xBD,0x90,0xAA
                fcb 0x24,0xE6,0x0C,0xD8,0x9E,0xD9,0x30,0x1F,0x9F,0xD9,0x39,0x7E,0xB4,0x4A,0x5C,0x27
                fcb 0xFA,0x39,0x5D,0x27,0xF6,0x5A,0x39,0x5D,0x27,0xF1,0x54,0x39,0x5D,0x2B,0xEC,0x58
                fcb 0x39,0x34,0x60,0x8D,0x16,0xBD,0xB7,0x0E,0x35,0xE0,0xBD,0x9C,0x1B,0xC6,0x02,0xBD
                fcb 0xAC,0x33,0xD6,0xD8,0x9E,0xD9,0x34,0x14,0x7E,0x9A,0x32,0x9E,0xD9,0x34,0x10,0xBD
                fcb 0x9B,0x98,0xBD,0xB3,0xA2,0x25,0xC4,0xBD,0x9B,0x98,0x81,0x3B,0x26,0xF9,0x35,0x10
                fcb 0xDE,0xA6,0x34,0x40,0x9F,0xA6,0xBD,0xB2,0x84,0x35,0x10,0x9F,0xA6,0x39,0x4F,0x1F
                fcb 0x8B,0xDC,0xE3,0x10,0x27,0x0D,0x74,0x93,0xD5,0xDD,0xE3,0x22,0x0D,0x0F,0xE3,0x0F
                fcb 0xE4,0x35,0x02,0x10,0xEE,0x67,0x84,0x7F,0x34,0x02,0x3B,0x0A,0x0C,0x01,0x03,0x05
                fcb 0x06,0x08,0x01,0xA8,0x01,0x90,0x01,0x7A,0x01,0x64,0x01,0x50,0x01,0x3D,0x01,0x2B
                fcb 0x01,0x1A,0x01,0x0A,0x00,0xFB,0x00,0xED,0x00,0xDF,0x00,0xD3,0x00,0xC7,0x00,0xBB
                fcb 0x00,0xB1,0x00,0xA6,0x00,0x9D,0x00,0x94,0x00,0x8B,0x00,0x83,0x00,0x7C,0x00,0x75
                fcb 0x00,0x6E,0xA6,0x9C,0x93,0x8B,0x83,0x7B,0x74,0x6D,0x67,0x61,0x5B,0x56,0x51,0x4C
                fcb 0x47,0x43,0x3F,0x3B,0x37,0x34,0x31,0x2E,0x2B,0x28,0x26,0x23,0x21,0x1F,0x1D,0x1B
                fcb 0x19,0x18,0x16,0x14,0x13,0x12,0x9E,0x8A,0xC6,0x01,0x34,0x14,0xD7,0xC2,0x9F,0xD5
                fcb 0xBD,0x95,0x9A,0xBD,0xB1,0x56,0xBD,0xB6,0x54,0x20,0x08,0xBD,0x9B,0x98,0x7E,0x9B
                fcb 0xBE,0x35,0x14,0xD7,0xD8,0x27,0xFA,0x9F,0xD9,0x10,0x27,0x00,0xEA,0x0D,0xD8,0x27
                fcb 0xF0,0xBD,0x9B,0x98,0x81,0x3B,0x27,0xF5,0x81,0x27,0x27,0xF1,0x81,0x4E,0x26,0x04
                fcb 0x03,0xD5,0x20,0xE9,0x81,0x42,0x26,0x04,0x03,0xD6,0x20,0xE1,0x81,0x58,0x10,0x27
                fcb 0x00,0x96,0x81,0x4D,0x10,0x27,0x01,0x2A,0x34,0x02,0xC6,0x01,0x0D,0xD8,0x27,0x11
                fcb 0xBD,0x9B,0x98,0xBD,0xB3,0xA2,0x34,0x01,0xBD,0x9B,0xE2,0x35,0x01,0x24,0x02,0x8D
                fcb 0xAA,0x35,0x02,0x81,0x43,0x27,0x28,0x81,0x41,0x27,0x2E,0x81,0x53,0x27,0x32,0x81
                fcb 0x55,0x27,0x5C,0x81,0x44,0x27,0x55,0x81,0x4C,0x27,0x4C,0x81,0x52,0x27,0x43,0x80
                fcb 0x45,0x27,0x2F,0x4A,0x27,0x27,0x4A,0x27,0x32,0x4A,0x27,0x1D,0x7E,0xB4,0x4A,0xBD
                fcb 0x95,0x5D,0xD7,0xB2,0xBD,0x95,0x9A,0x20,0x84,0xC1,0x04,0x24,0xEF,0xD7,0xE8,0x20
                fcb 0xF6,0xC1,0x3F,0x24,0xE7,0xD7,0xE9,0x20,0xEE,0x4F,0x8D,0x58,0x21,0x4F,0x1F,0x01
                fcb 0x20,0x59,0x4F,0x1F,0x01,0x8D,0x4D,0x1E,0x01,0x20,0x50,0x4F,0x1F,0x01,0x8D,0x44
                fcb 0x20,0x49,0x4F,0x9E,0x8A,0x20,0x44,0x4F,0x8D,0x3A,0x20,0xF7,0x4F,0x20,0x03,0x4F
                fcb 0x8D,0x32,0x9E,0x8A,0x1E,0x10,0x20,0x33,0xBD,0x9C,0x1B,0xC6,0x02,0xBD,0xAC,0x33
                fcb 0xD6,0xD8,0x9E,0xD9,0x34,0x14,0x7E,0x9C,0xC6,0xD6,0xE9,0x27,0x1B,0x4F,0x1E,0x01
                fcb 0xA7,0xE2,0x2A,0x02,0x8D,0x0D,0xBD,0x9F,0xB5,0x1F,0x30,0x44,0x56,0x44,0x56,0x6D
                fcb 0xE0,0x2A,0x04,0x40,0x50,0x82,0x00,0x39,0x1F,0x10,0x39,0x34,0x06,0x8D,0xDA,0x35
                fcb 0x10,0x34,0x06,0x8D,0xD4,0x35,0x10,0x10,0x9E,0xE8,0x34,0x20,0x6D,0xE4,0x27,0x08
                fcb 0x1E,0x10,0x8D,0xDF,0x6A,0xE4,0x20,0xF4,0x35,0x20,0xDE,0x8A,0xD3,0xC7,0x2B,0x02
                fcb 0x1F,0x03,0x1F,0x10,0x9E,0x8A,0xD3,0xC9,0x2B,0x02,0x1F,0x01,0x11,0x83,0x01,0x00
                fcb 0x25,0x03,0xCE,0x00,0xFF,0x8C,0x00,0xC0,0x25,0x03,0x8E,0x00,0xBF,0xDC,0xC7,0xDD
                fcb 0xBD,0xDC,0xC9,0xDD,0xBF,0x9F,0xC5,0xDF,0xC3,0x0D,0xD5,0x26,0x04,0x9F,0xC9,0xDF
                fcb 0xC7,0xBD,0x94,0x20,0x0D,0xD6,0x26,0x03,0xBD,0x94,0xA1,0x0F,0xD5,0x0F,0xD6,0x7E
                fcb 0x9C,0xDD,0xBD,0x9B,0x98,0x34,0x02,0xBD,0x9E,0x5E,0x34,0x06,0xBD,0x9B,0x98,0x81
                fcb 0x2C,0x10,0x26,0xFF,0x07,0xBD,0x9E,0x5B,0x1F,0x01,0x35,0x40,0x35,0x02,0x81,0x2B
                fcb 0x27,0x04,0x81,0x2D,0x26,0xA6,0x1F,0x30,0x7E,0x9D,0xCB,0xBD,0x9B,0x98,0x81,0x2B
                fcb 0x27,0x07,0x81,0x2D,0x27,0x04,0xBD,0x9B,0xE2,0x4F,0x34,0x02,0xBD,0x9C,0xCB,0x35
                fcb 0x02,0x4D,0x27,0x04,0x4F,0x50,0x82,0x00,0x39,0x00,0x00,0x00,0x01,0xFE,0xC5,0x19
                fcb 0x19,0xFB,0x16,0x31,0xF2,0xF4,0xFB,0x4A,0x51,0xEC,0x84,0x61,0xF9,0xE1,0xC7,0x78
                fcb 0xAE,0xD4,0xDC,0x8E,0x3B,0xC5,0xE5,0xA2,0x69,0xB5,0x06,0xB5,0x06,0x81,0x40,0x26
                fcb 0x02,0x9D,0x9F,0xBD,0x95,0x22,0xBD,0x93,0xB2,0xBD,0x93,0x1D,0xAE,0xC4,0x9F,0xCB
                fcb 0xAE,0x42,0x9F,0xCD,0xBD,0xB2,0x6D,0xBD,0xB7,0x3D,0xCE,0x00,0xCF,0xAF,0xC4,0xBD
                fcb 0x93,0x20,0x86,0x01,0x97,0xC2,0xBD,0x95,0x81,0x8E,0x01,0x00,0x9D,0xA5,0x27,0x0F
                fcb 0xBD,0xB2,0x6D,0xBD,0xB1,0x41,0x96,0x4F,0x8B,0x08,0x97,0x4F,0xBD,0xB7,0x40,0x96
                fcb 0xB6,0x85,0x02,0x27,0x04,0x1F,0x10,0x30,0x8B,0x9F,0xD1,0xC6,0x01,0xD7,0xC2,0xD7
                fcb 0xD8,0xBD,0x9F,0xE2,0x34,0x06,0xBD,0x9F,0xE2,0xDD,0xD9,0x35,0x06,0x34,0x06,0x9E
; The actual implementation of the DOS command follows; presumably this is here because it was
; implemented by a different group of people given that it doesn't call DSKCON directly and uses
; the DSKCON variables pointer as well.
DOSCOM          swi3                            ; do a software interrupt for some reason (why?)
                clr TMPLOC                      ; reset sector counter
                ldd #DOSBUF                     ; initialize load address for boot track
                pshs d                          ; save buffer address
LDF09           ldx DSKVAR                      ; point to DSKCON variables
                inc TMPLOC                      ; bump sector counter
                lda TMPLOC                      ; get current sector
                cmpa #SECMAX                    ; loaded whole track?
                bhi LDF36                       ; brif so
                sta 3,x                         ; tell DSKCON the sector number
                ldd #0x0200                     ; read code and drive 0
                sta ,x                          ; set operation code (should be std to set drive)
                lda #34                         ; track 34
                sta 2,x                         ; tell DSKCON
                puls a,b                        ; get buffer pointer
                std 4,x                         ; tell DSKCON
                adda #1                         ; bump buffer pointer by one sector
                pshs a,b                        ; save it again
                jsr [DCNVEC]                    ; call DSKCON to read a sector
                tst 6,x                         ; error?
                beq LDF09                       ; brif not - read another
                puls a,b                        ; clean stack
                ldb #2*20                       ; I/O error code
                jmp LAC46                       ; raise error
LDF36           puls a,b                        ; clear up stack
                ldd DOSBUF                      ; get start of loaded track
                cmpd #'O*256+'S                 ; is it the "OS" tag?
                lbeq DOSBUF+2                   ; brif so - transfer control to it
                clr DOSBUF                      ; clear first two bytes (why?)
                clr DOSBUF+1
                jmp BAWMST                      ; do a warm start
DOSINI          ldd #0x3b3b                     ; set up SWI3 and SWI2 with RTIs (kind of pointless)
                std SW3VEC
                std SW3VEC+2
                std SW2VEC+1
                rts
; The remainder to the end is unused garbage bytes
                fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x10,0x93,0xD3,0x25,0x02,0xDC,0xD3,0xDD
                fcb 0xC3,0xA6,0xE4,0x81,0x04,0x25,0x0A,0xDC,0xCD,0x93,0xC5,0x24,0x11,0x4F,0x5F,0x20
                fcb 0x0D,0xDC,0xCD,0xD3,0xC5,0x25,0x05,0x10,0x93,0xD5,0x25,0x02,0xDC,0xD5,0xDD,0xC5
                fcb 0x0D,0xD8,0x26,0x02,0x8D,0x50,0x35,0x06,0x04,0xD8,0x25,0x05,0x10,0x93,0xD9,0x27
                fcb 0x0C,0x5C,0xC1,0x08,0x26,0x04,0x4C,0x5F,0x84,0x07,0x7E,0x9E,0xFD,0x39,0x9E,0xCF
                fcb 0xEC,0xC4,0x27,0x07,0x83,0x00,0x01,0x8D,0x03,0x1F,0x21,0x39,0x34,0x76,0x6F,0x64
                fcb 0xA6,0x63,0x3D,0xED,0x66,0xEC,0x61,0x3D,0xEB,0x66,0x89,0x00,0xED,0x65,0xE6,0xE4
                fcb 0xA6,0x63,0x3D,0xE3,0x65,0xED,0x65,0x24,0x02,0x6C,0x64,0xA6,0xE4,0xE6,0x62,0x3D
                fcb 0xE3,0x64,0xED,0x64,0x35,0xF6,0x7E,0x94,0xA1,0x5F,0x9D,0xA5,0x27,0x11,0xBD,0xB2
                fcb 0x6D,0xBD,0xB1,0x41,0x96,0x4F,0x8B,0x06,0x97,0x4F,0xBD,0xB7,0x0E,0xC4,0x3F,0x1F
                fcb 0x98,0xC4,0x07,0x44,0x44,0x44,0x39
                else
; From here to the end of the ROM is unused garbage bytes
	fcb 0x00,0x00,0x00
	fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
	fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
	fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
	fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
	fcb 0xa7,0xfc,0x8f,0xec,0x94,0xbc,0x8c,0xf5
	fcb 0xbc,0xf8,0xd1,0xfa,0xfd,0xfd,0xac,0xe5
	fcb 0xec,0xf8,0x8a,0xea,0xad,0xec,0xb9,0xff
	fcb 0xbc,0xfd,0xcc,0xed,0x8c,0xe5,0x9c,0xf4
	fcb 0xa2,0xa6,0xe8,0xfc,0xae,0xe5,0x94,0xec
	fcb 0xbe,0xee,0x8c,0xed,0xea,0xe5,0xed,0x7c
	fcb 0xbe,0xfc,0x8e,0xed,0xfe,0xec,0x9c,0xac
	fcb 0xdc,0xfd,0xfb,0xf5,0xad,0xfd,0xaf,0xe9
	fcb 0xa0,0x30,0x24,0x8a,0x14,0x84,0x2c,0xc4
	fcb 0x24,0x08,0xe0,0x21,0x20,0x80,0x28,0x00
	fcb 0x20,0x88,0xa4,0xa0,0xa4,0x80,0xac,0x11
	fcb 0x30,0x90,0x24,0xd4,0x01,0xa1,0xa0,0x84
	fcb 0x64,0x80,0x34,0x04,0x34,0x80,0x20,0x21
	fcb 0xa1,0x81,0xa4,0x80,0x20,0x90,0x88,0xc0
	fcb 0x00,0x9a,0xa0,0xa0,0xe0,0x80,0xb6,0xa4
	fcb 0x20,0xa2,0x20,0x98,0x20,0x88,0x7c,0xae
	fcb 0xbd,0xee,0xee,0xfe,0xf1,0xec,0xad,0xbc
	fcb 0xed,0xec,0xdd,0xf9,0xec,0x75,0xb5,0xbd
	fcb 0xef,0xfd,0xa9,0xe4,0x96,0xfc,0x94,0xe4
	fcb 0xae,0xad,0xda,0xb4,0xac,0x7c,0xc3,0xec
	fcb 0xbd,0xfc,0xae,0xfd,0xee,0xfd,0x85,0xf4
	fcb 0xad,0xef,0x76,0xfc,0xd6,0x6e,0xef,0xed
	fcb 0xf6,0xbd,0xed,0xfe,0x58,0xed,0xf7,0xfd
	fcb 0x85,0xec,0xfc,0xe8,0xf2,0xe4,0xbf,0xa8
	fcb 0x30,0x80,0xa0,0x05,0xa4,0x20,0xb0,0x80
	fcb 0x20,0x84,0x04,0x80,0x30,0x8e,0xe0,0xa4
	fcb 0xb0,0x02,0x04,0x80,0x61,0x84,0x20,0x00
	fcb 0xa0,0x80,0x20,0x88,0x24,0x94,0x24,0xa4
	fcb 0x80,0x04,0x00,0x84,0x24,0x84,0x28,0x9c
	fcb 0x44,0x28,0xa0,0x80,0x80,0x90,0x30,0x80
	fcb 0xe8,0x80,0xa4,0x88,0x30,0x94,0x20,0x80
	fcb 0x00,0x8c,0x68,0xac,0xa4,0x84,0x30,0x06
	fcb 0x86,0xe4,0xbc,0xfc,0xae,0xec,0x87,0xbd
	fcb 0x9c,0xfd,0xec,0xbc,0xfd,0xb5,0xa9,0xed
	fcb 0xa7,0xac,0x8b,0x7c,0xa5,0xfc,0xcc,0xbc
	fcb 0xaa,0xb6,0xc9,0xfc,0xa5,0xfc,0x47,0xfc
	fcb 0xdd,0x6d,0x84,0xfe,0xac,0xee,0x20,0xf4
	fcb 0xc5,0xff,0xf4,0xee,0xf7,0xf4,0xaa,0xfc
	fcb 0xef,0xff,0x9c,0xfd,0xee,0xe4,0xaf,0xfc
	fcb 0xbe,0xbc,0xdf,0xa5,0xeb,0xec,0xee,0xa4
	fcb 0x34,0x86,0xac,0x84,0xa4,0x21,0x90,0x88
	fcb 0xa0,0xa0,0x24,0xc0,0xe0,0x80,0x70,0xe5
	fcb 0x3c,0xa5,0xa1,0x8c,0x34,0xa4,0xe4,0x84
	fcb 0x24,0x80,0xf8,0x81,0xa0,0x8d,0xec,0x4a
	fcb 0x2c,0xe2,0xa4,0x93,0x20,0x88,0xb0,0xc0
	fcb 0x34,0x10,0x20,0x91,0xa4,0x84,0xa4,0xae
	fcb 0x0c,0x92,0xb0,0xcd,0xb0,0xaa,0x74,0xe8
	fcb 0xa0,0x12,0xb9,0x85,0x21,0xf5,0xe0,0x8e
	fcb 0x9e,0xbd,0x81,0xf5,0xcf,0xe4,0xcc,0x66
	fcb 0xa7,0xad,0x98,0xbd,0xbc,0xbc,0x88,0xbc
	fcb 0x8e,0xed,0xa4,0xa8,0xad,0x88,0xee,0xfe
	fcb 0xcd,0xfc,0xac,0xfd,0x8c,0xfc,0x9a,0xf5
	fcb 0xb4,0xe4,0x8e,0xfc,0xfe,0xe4,0xcc,0xac
	fcb 0x9d,0xfc,0x97,0xe4,0x8b,0xec,0xea,0xec
	fcb 0xdb,0xec,0xdf,0xec,0xac,0xe4,0xae,0xfc
	fcb 0xd4,0xf4,0xcd,0xec,0xb4,0xec,0xef,0xee
	fcb 0xb2,0x24,0x28,0x20,0xac,0xd0,0x24,0x1c
	fcb 0x30,0x81,0xac,0x84,0x80,0x01,0xa4,0xa4
	fcb 0x70,0x88,0xa4,0xc4,0xa4,0x84,0x24,0x60
	fcb 0x08,0x04,0xa0,0x88,0x20,0x98,0x64,0xa8
	fcb 0x24,0x10,0xd4,0x90,0xa0,0x81,0x30,0xec
	fcb 0xac,0x09,0x64,0xe0,0x60,0x18,0x30,0xb0
	fcb 0x24,0x80,0x6c,0x88,0xa4,0x8c,0xa4,0x8c
	fcb 0xa8,0x10,0x21,0xa8,0x68,0x84,0xa8,0xa0
	fcb 0x8d,0xe5,0xa4,0x66,0x98,0xfd,0x87,0xfc
	fcb 0xde,0xac,0x9c,0xf4,0x8c,0xf5,0xb5,0xf5
	fcb 0xb6,0xf5,0xa9,0xf8,0xaf,0xed,0xe6,0xe5
	fcb 0xb8,0xf1,0xb1,0xfc,0xfc,0xe9,0x8c,0xec
	fcb 0x86,0xf9,0xb5,0xf7,0xcd,0xbc,0x84,0xe6
	fcb 0x8c,0xfc,0x81,0xe4,0xbc,0xe4,0x4f,0xfc
	fcb 0x8c,0xfc,0xae,0xe7,0xbd,0xfc,0xdc,0xfc
	fcb 0xf4,0xe8,0x9f,0xec,0xea,0xfc,0xef,0x6c
	fcb 0x20,0x82,0xa4,0x40,0xa8,0x8c,0xac,0x08
	fcb 0x60,0x82,0xa1,0x95,0xe0,0x30,0x60,0x80
	fcb 0x64,0x48,0x20,0x04,0x20,0x84,0xa4,0x82
	fcb 0xa0,0x04,0x20,0x94,0x44,0xa0,0xe0,0x80
	fcb 0x04,0xc8,0x2c,0x82,0x24,0x04,0x30,0xb8
	fcb 0x24,0x00,0x20,0xa0,0xa4,0x82,0xa0,0x80
	fcb 0x84,0x81,0x2c,0x84,0x20,0x80,0x24,0x8c
	fcb 0x80,0x80,0x24,0x02,0x64,0xa8,0x24,0x88
	fcb 0xed,0xbd,0xd1,0xff,0xb4,0xe4,0xaa,0xec
	fcb 0x80,0xf1,0x8c,0xed,0x89,0xac,0xb6,0xfc
	fcb 0x6e,0xfd,0xae,0xed,0x89,0xec,0xb6,0xec
	fcb 0xae,0xfd,0xee,0xf0,0x9f,0x7e,0x9f,0xfe
	fcb 0xd9,0xec,0xae,0xed,0xc6,0xec,0xfe,0x7d
	fcb 0xbc,0xfc,0xb9,0xac,0xda,0xfc,0xa5,0xbd
	fcb 0xcc,0xfd,0xad,0xe6,0xae,0xf4,0xcd,0xf4
	fcb 0xf2,0xed,0x84,0x78,0xcc,0xec,0xab,0x74
	fcb 0xa4,0x94,0x20,0x84,0x20,0x00,0xa0,0x00
	fcb 0xa4,0x05,0x28,0x0c,0x24,0x04,0x24,0x00
	fcb 0xa0,0x84,0x80,0x80,0x18,0x80,0x24,0x0c
	fcb 0xe0,0x88,0x04,0x8a,0x2c,0x88,0x0c,0x84
	fcb 0x00,0x80,0xe0,0x04,0x20,0xa1,0x20,0x85
	fcb 0x20,0x90,0x80,0x9c,0x24,0xc0,0xe0,0x8d
	fcb 0xa0,0x80,0x20,0x82,0xa0,0xa2,0x20,0x40
	fcb 0x80,0x82,0x10,0xb8,0x00,0x84,0x60,0x92
	fcb 0xdf,0xef,0xd1,0xec,0xa4,0xec,0xc9,0xfd
	fcb 0xe6,0xad,0xc6,0xe5,0xd4,0xfd,0x9a,0xed
	fcb 0xae,0xe4,0xac,0xbc,0x9f,0xec,0x8a,0xed
	fcb 0x0f,0xe5,0x8f,0xec,0xd7,0xe4,0xac,0xec
	fcb 0xce,0xef,0x9e,0xf4,0xd7,0xe4,0xcf,0xf5
	fcb 0xce,0xf4,0xe6,0x6c,0x81,0xec,0x9b,0xee
	fcb 0x9f,0x7c,0xbc,0xf7,0xcc,0x6d,0xfe,0xef
	fcb 0x8e,0x6e,0xef,0xbd,0xbe,0xbd,0x8f,0xe4
	fcb 0xa0,0x04,0x20,0xe0,0xb4,0x82,0xb4,0x82
	fcb 0x20,0x8c,0xb0,0x90,0xb0,0x90,0xb8,0x84
	fcb 0x24,0x90,0x6a,0x86,0x28,0x84,0xa0,0xa8
	fcb 0x24,0xcf,0xb8,0x88,0xa0,0xa0,0xb1,0x81
	fcb 0x10,0xb6,0xe0,0x98,0xc8,0xb4,0x34,0xaf
	fcb 0x34,0x00,0xb0,0x82,0x20,0x90,0xe4,0xac
	fcb 0x28,0x84,0x84,0x88,0x24,0xac,0xac,0xa4
	fcb 0x25,0x98,0x20,0xa0,0x20,0x80,0x32,0x00
	fcb 0xae,0xec,0x8d,0xbd,0x9f,0xf7,0xff,0xa1
	fcb 0xca,0xbe,0x8d,0x7c,0x8e,0x74,0xef,0xec
	fcb 0xd4,0xf5,0x9e,0xb8,0x8e,0x35,0xc6,0xe4
	fcb 0x90,0xed,0xed,0xfc,0x8c,0x25,0xbe,0xa4
	fcb 0xfc,0x6c,0x89,0xee,0xec,0xad,0xae,0x78
	fcb 0xee,0xec,0xad,0xed,0xad,0xec,0xbc,0xbd
	fcb 0x2e,0x76,0xae,0xec,0x8e,0xbd,0xef,0xfd
	fcb 0xac,0xec,0xef,0xb5,0xbe,0xa4,0xbf,0xe8
	fcb 0x04,0x00,0x24,0x08,0x04,0x84,0x24,0x80
	fcb 0x28,0x82,0x60,0x04,0x24,0x94,0x28,0x00
	fcb 0x2c,0x84,0x20,0x80,0xb5,0x86,0x30,0x04
	fcb 0x23,0x84,0xa0,0x80,0xa0,0x06,0x24,0xad
	fcb 0xa4,0x80,0xa6,0x86,0x80,0x00,0xe0,0x80
	fcb 0x66,0x90,0x20,0x8c,0x00,0x8c,0x04,0x82
	fcb 0xa4,0x46,0x00,0x01,0x20,0x98,0xa0,0x88
	fcb 0x20,0x2a,0x24,0xe0,0x00,0x08,0x64,0x02
	fcb 0x8d,0xa5,0xb5,0xe5,0xad,0xf7,0xcd,0xf4
	fcb 0xa8,0x29,0xbc,0x64,0xf8,0xec,0xad,0xae
	fcb 0xa8,0xf5,0x8c,0xa7,0xe7,0xe5,0xa9,0xf4
	fcb 0xf4,0xfd,0x94,0xed,0x5c,0xe4,0xc0,0xbe
	fcb 0x8c,0xfd,0xcd,0xa4,0x94,0xff,0xa5,0xec
	fcb 0xfc,0xe5,0xac,0xe4,0xae,0xbd,0x9d,0xbd
	fcb 0xa8,0xec,0x84,0x68,0xc9,0xad,0x8e,0xac
	fcb 0xea,0xed,0x8f,0xec,0xbf,0xaf,0xf7,0xed
	fcb 0x24,0x91,0xa0,0x04,0xb4,0x04,0x82,0x90
	fcb 0xac,0x08,0xb0,0xa0,0xc0,0x08,0x34,0xa0
	fcb 0x65,0x88,0x73,0x80,0x20,0x80,0x2c,0x04
	fcb 0x20,0x84,0x21,0x26,0x20,0x94,0x00,0x20
	fcb 0xa4,0x96,0xa4,0x80,0xb0,0x84,0x24,0x82
	fcb 0x25,0x86,0xa0,0x00,0x7c,0x30,0xa2,0x25
	fcb 0x24,0x9e,0xa0,0x88,0x20,0x80,0x20,0x00
	fcb 0x20,0xa9,0x20,0xa2,0xc0,0xb2,0xa1,0x0e
	fcb 0xae,0xec,0xa8,0xee,0xac,0xf8,0xfa,0xb4
	fcb 0xa4,0xfe,0xfc,0xf4,0x1c,0xed,0xae,0xf4
	fcb 0xd7,0xf8,0xfd,0xed,0x8e,0xfe,0xdc,0xe8
	fcb 0xfe,0xed,0xfc,0xed,0x9f,0xfc,0x9c,0xed
	fcb 0xb0,0xe7,0xbe,0xfe,0x84,0xe4,0xa7,0xfe
	fcb 0xad,0xe4,0xbc,0x64,0x8d,0xbf,0xaf,0xfd
	fcb 0xaa,0x2c,0xcd,0xed,0x8f,0xe4,0xfc,0xbd
	fcb 0xbf,0xef,0xe5,0xed,0xbf,0xfe,0xe5,0xfd
	fcb 0x84,0x82,0xa4,0x83,0xa4,0x08,0xa0,0x80
	fcb 0x00,0x84,0x30,0x86,0x08,0x20,0xb0,0x90
	fcb 0x14,0xb4,0xa0,0x80,0x20,0x90,0xa4,0x88
	fcb 0xec,0x80,0xa4,0x84,0xa0,0x84,0x28,0x80
	fcb 0xb4,0x81,0xf0,0xa0,0xe4,0x80,0x00,0x84
	fcb 0x34,0xb1,0xe4,0x80,0x24,0x5d,0x20,0xd2
	fcb 0x44,0x83,0xb0,0x88,0x20,0x14,0x30,0xbc
	fcb 0x20,0xa0,0xc4,0x9d,0x68,0x00,0xa0,0x20
	fcb 0xcf,0xec,0xaa,0x66,0xb8,0x75,0x9e,0xfc
	fcb 0xfe,0xb4,0xbc,0xff,0xac,0xfd,0x9a,0xbc
	fcb 0xba,0xec,0x8e,0xf4,0xec,0xfc,0x96,0xfd
	fcb 0xd2,0xea,0x84,0xfc,0xae,0xe4,0xe5,0xfd
	fcb 0xbd,0xec,0xdc,0xac,0xa5,0xb0,0xcf,0xec
	fcb 0x7a,0xb5,0xe4,0xea,0xef,0xec,0xa4,0xfe
	fcb 0xe5,0xff,0xf8,0xbc,0x86,0xe4,0xff,0xe5
	fcb 0xaf,0x6c,0xee,0xec,0xee,0x6c,0x2a,0x6c
	fcb 0x28,0xa0,0x64,0x84,0xb4,0x92,0x04,0x94
	fcb 0x80,0x00,0xb8,0x0c,0x20,0x88,0xa0,0x84
	fcb 0xa0,0x40,0xb0,0x00,0xa0,0x84,0xa0,0xca
	fcb 0x00,0x14,0x24,0xc0,0xa0,0x64,0x24,0x88
	fcb 0x00,0x18,0xed,0x88,0x28,0x80,0xa1,0x80
	fcb 0x00,0x85,0x20,0x80,0xa4,0x34,0x00,0x04
	fcb 0x24,0xa4,0xac,0x8c,0x34,0x88,0x2c,0x04
	fcb 0x24,0x84,0x60,0x88,0xa0,0xa0,0xa0,0x9c
	fcb 0xb9,0xf4,0x97,0xec,0x68,0xad,0xe4,0xf0
	fcb 0xf4,0xec,0xcb,0xfc,0xa8,0xf5,0xfd,0x3e
	fcb 0xfc,0xee,0x9d,0xec,0x5e,0xfc,0x9c,0xf6
	fcb 0x80,0xed,0xa2,0xe4,0xad,0xb6,0xbf,0xf4
	fcb 0xed,0xfe,0xb3,0xfc,0xdc,0xb5,0xb3,0xed
	fcb 0xef,0xfc,0xbf,0xfc,0xbc,0xfe,0xea,0xf4
	fcb 0xc5,0xe4,0x89,0xfc,0x7c,0xbd,0xde,0xfd
	fcb 0x87,0xe4,0x9e,0xec,0xaf,0xe4,0xfe,0xe4
	fcb 0x34,0xc6,0x30,0x26,0x24,0x80,0x20,0x1c
	fcb 0xb4,0x04,0xb4,0x28,0x24,0x98,0x20,0x00
	fcb 0xa4,0xa4,0xa0,0x80,0x21,0x48,0xb9,0x24
	fcb 0x20,0x80,0x28,0x00,0x20,0x80,0x84,0x1e
	fcb 0x60,0xbc,0x28,0x88,0xac,0x74,0xe0,0x04
	fcb 0x24,0xa6,0x00,0x20,0x70,0x85,0xa0,0x89
	fcb 0x30,0x0b,0xa0,0x80,0x20,0x10,0xa0,0x14
	fcb 0x24,0x04,0x20,0x82,0xa0,0x80,0x35,0xa0
	fcb 0xee,0xbc,0xbe,0xfd,0xbe,0xb9,0x89,0xe4
	fcb 0xfd,0x3d,0x13,0xe4,0x9e,0xec,0x8d,0xec
	fcb 0xde,0xfc,0x8e,0xe5,0x8f,0xf4,0xbe,0xff
	fcb 0xe6,0xe6,0x8c,0xe6,0xcd,0xae,0xee,0xed
	fcb 0xfe,0xec,0xdc,0xec,0x8e,0xfc,0x96,0xfd
	fcb 0xa6,0xfc,0xce,0xcd,0xbe,0xfe,0xee,0xfc
	fcb 0x9e,0xf4,0xee,0x6e,0xcf,0xed,0xee,0xe0
	fcb 0xfc,0xee,0xae,0xa0,0xfd,0xed,0xa6,0x6c
	fcb 0xa8,0x04,0x20,0x00,0x30,0x80,0xa0,0x90
	fcb 0x20,0x80,0x60,0x00,0x20,0x82,0x90,0x40
	fcb 0x24,0x10,0x04,0x00,0x84,0x00,0x24,0x18
	fcb 0xe0,0x00,0x00,0x02,0x20,0xb4,0x24,0x00
	fcb 0x22,0x80,0x04,0x04,0xa0,0x80,0x84,0x0a
	fcb 0x28,0x14,0xa0,0x80,0x00,0x86,0x40,0x86
	fcb 0x20,0x90,0x10,0x30,0x84,0x84,0x00,0x00
	fcb 0x74,0x80,0x30,0x00,0x20,0x08,0x20,0x80
	fcb 0xfb,0xfd,0xc9,0xe6,0x91,0xfd,0xc8,0xee
	fcb 0xb4,0x7c,0xbe,0xec,0x89,0xec,0xbd,0xfc
	fcb 0xa5,0xfd,0xd9,0xec,0x8a,0xfd,0xae,0xec
	fcb 0xad,0xfc,0xae,0xec,0x8d,0xec,0x8f,0xf4
	fcb 0xbf,0x6d,0xac,0xbd,0xea,0xed,0xaf,0xac
	fcb 0xfd,0xfc,0xea,0xfd,0xf0,0xf9,0xb3,0xee
	fcb 0x8e,0xe4,0xfd,0xec,0xff,0xe0,0x8e,0xe4
	fcb 0xfd,0xad,0xdc,0x6c,0xa0,0xe4,0x8e,0xe4
	fcb 0x28,0x00,0xb4,0x00,0x22,0x00,0xb4,0x00
	fcb 0x6c,0x00,0xa4,0x1b,0xb2,0x9c,0x20,0x84
	fcb 0x24,0xc4,0x24,0xa8,0xa0,0x80,0x64,0x88
	fcb 0x80,0xac,0x30,0x85,0x20,0x9c,0x74,0xf2
	fcb 0x88,0x88,0x38,0x80,0x2c,0xa0,0x20,0x04
	fcb 0xb8,0x80,0x24,0x90,0xa8,0xf8,0xbc,0x88
	fcb 0x20,0x20,0xa0,0xe0,0x6c,0x80,0x00,0xe8
	fcb 0x20,0x80,0x24,0xc0,0x23,0x9c,0x24,0x82
	fcb 0xb5,0xe0,0xa4,0xed,0x8e,0xe4,0xa9,0xfc
	fcb 0xf8,0xee,0xce,0xfc,0x89,0xe4,0x98,0xf5
	fcb 0xa1,0xec,0xa1,0xe0,0xb8,0xec,0xd0,0xfc
	fcb 0xcf,0xf9,0xae,0xec,0x8a,0xfd,0x6b,0x6e
	fcb 0x94,0xa8,0xb8,0xe4,0xce,0xa6,0x8c,0xf4
	fcb 0xee,0xbd,0x8d,0xec,0xed,0xf4,0xcf,0x6c
	fcb 0x99,0x6c,0xc8,0xf9,0xf9,0xa5,0xb6,0x79
	fcb 0x8c,0xc1,0xe4,0xf5,0xaa,0x24,0xf7,0x64
	fcb 0x24,0xa8,0xa4,0x80,0xa0,0x96,0x20,0x09
	fcb 0x20,0x18,0xa8,0x08,0xb0,0xc0,0x7c,0xcd
	fcb 0x24,0xdc,0x20,0x98,0x64,0x84,0xe0,0x82
	fcb 0x34,0xa0,0xea,0x88,0x60,0xc4,0x70,0xe8
	fcb 0x30,0x06,0xe5,0x1c,0x20,0x84,0x20,0x9c
	fcb 0xa0,0x80,0xa0,0x1c,0xa8,0x80,0x88,0x22
	fcb 0x24,0x80,0x24,0xb0,0xe4,0x14,0xe4,0x80
	fcb 0xe0,0x86,0x00,0xd6,0x8c,0x80,0xb8,0xab
	fcb 0xaf,0xa2,0x84,0xe8,0x86,0x2f,0x8a,0xf5
	fcb 0xd4,0xff,0x86,0xef,0x8e,0xf4,0xc8,0x6c
	fcb 0xf5,0xf4,0x4c,0xf4,0xe8,0x74,0x04,0xee
	fcb 0xee,0xe0,0x26,0x2c,0x9f,0xec,0x90,0xe5
	fcb 0xbc,0xe5,0xf8,0xe0,0xfb,0xf4,0xb4,0xed
	fcb 0x4e,0xe4,0xe6,0xec,0x8c,0xe4,0xbf,0xed
	fcb 0x9f,0xe0,0xcc,0x7c,0xbf,0xed,0x9d,0xed
	fcb 0xad,0xf8,0xaf,0x64,0xef,0xed,0xed,0xe4
	fcb 0xa0,0x8c,0x20,0x95,0x30,0x38,0xa0,0x84
	fcb 0x64,0x80,0xe0,0x76,0x2c,0x20,0xb4,0x04
	fcb 0x3f,0xb1,0xa4,0x24,0x24,0x80,0x24,0xa9
	fcb 0x31,0x97,0xac,0x28,0x64,0x50,0xa0,0x04
	fcb 0x38,0x80,0xb4,0x8e,0x20,0xcc,0xbc,0x38
	fcb 0x64,0x8c,0xa0,0x90,0xe4,0xa0,0x64,0x99
	fcb 0x64,0xaf,0x24,0xe5,0x60,0x80,0xa4,0x3c
	fcb 0x2c,0x8e,0xb4,0xbc,0xa4,0xcc,0x24,0xcc
                endc