Mercurial > hg > index.cgi
diff 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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/disk.s Sat Dec 08 19:57:01 2018 -0700 @@ -0,0 +1,3566 @@ + *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