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