;license:BSD-3-Clause ;extended open/read/write binary file in ProDOS filesystem, with random access ;copyright (c) Peter Ferrie 2013-18 ver_02 = 1 !if ver_02 = 1 { !cpu 6502 } else { ;ver_02 = 0 !cpu 65c02 } ;ver_02 !to "build/prorwts2",plain *=$800 ;place no code before init label below. ;user-defined options verbose_info = 1 ;set to 1 to enable display of memory usage enable_floppy = 0 ;set to 1 to enable floppy drive support poll_drive = 0 ;set to 1 to check if disk is in drive, recommended if allow_multi is enabled override_adr = 0 ;set to 1 to require an explicit load address aligned_read = 1 ;set to 1 if all reads can be a multiple of block size enable_write = 1 ;set to 1 to enable write support ;file must exist already and its size cannot be altered ;writes occur in multiples of block size enable_seek = 0 ;set to 1 to enable seek support ;seeking with aligned_read=1 requires non-zero offset allow_multi = 0 ;set to 1 to allow multiple floppies check_chksum = 0 ;set to 1 to enforce checksum verification for floppies allow_subdir = 0 ;set to 1 to allow opening subdirectories to access files might_exist = 0 ;set to 1 if file is not known to always exist already ;makes use of status to indicate success or failure allow_aux = 0 ;set to 1 to allow read/write directly to/from aux memory ;requires load_high to be set for arbitrary memory access ;else driver must be running from same memory target ;i.e. running from main if accessing main, running from aux if accessing aux allow_saplings=0 ;enable support for saplings allow_trees = 0 ;enable support for tree files, as opposed to only seedlings and saplings fast_trees = 0 ;keep tree block in memory, requires an additional 512 bytes of RAM always_trees = 0 ;set to 1 if the only file access involves tree files ;not compatible with allow_subdir, allow_saplings detect_treof = 0 ;detect EOF during read of tree files allow_sparse = 0 ;enable support for reading sparse files bounds_check = 0 ;set to 1 to prevent access beyond the end of the file ;but limits file size to 64k-2 bytes. no_interrupts= 0 ;set to 1 to disable interrupts across calls detect_err = 0 ;set to 1 to to detect errors in no_interrupt mode swap_zp = 0 ;set to 1 to include code to preserve zpage ;used only by rwts_mode rwts_mode = 0 ;set to 1 to enable emulation of DOS RWTS when running from hard disk ;uses a one-time open of a tree file, no other file access allowed ;use unique volume numbers to distinguish between images in the same file ;requires override_adr, enable_seek, allow_trees, always_trees ;not compatible with enable_floppy, aligned_read, allow_subdir, might_exist, bounds_check load_high = 1 ;set to 1 to load to top of RAM (either main or banked, enables a himem check) load_aux = 0 ;load to aux memory load_banked = 1 ;set to 1 to load into banked RAM instead of main RAM (can be combined with load_aux for aux banked) lc_bank = 1 ;load into specified bank (1 or 2) if load_banked=1 one_page = 1 ;set to 1 if verbose mode says that you should (smaller code) ;user-defined driver load address !if load_banked = 1 { !if load_high = 1 { !ifdef PASS2 { } else { ;PASS2 not defined reloc = $ff00 ;page-aligned, as high as possible, the ideal value will be shown on mismatch } ;PASS2 } else { ;load_high = 0 reloc = $d000 ;page-aligned, but otherwise wherever you want } ;load_high } else { ;load_banked = 0 !if load_high = 1 { !ifdef PASS2 { } else { ;PASS2 not defined reloc = $bf00 ;page-aligned, as high as possible, the ideal value will be shown on mismatch } ;PASS2 } else { ;load_high = 0 reloc = $bc00 ;page-aligned, but otherwise wherever you want ($BC00 is common for rwts_mode) } ;load_high } ;load_banked ;there are also buffers that can be moved if necessary: ;dirbuf, encbuf, treebuf (and corresponding hdd* versions that load to the same place) ;they are independent of each other so they can be placed separately ;see near EOF for those ;note that hddencbuf must be even-page-aligned in RWTS-mode ;zpage usage, arbitrary selection except for the "ProDOS constant" ones ;feel free to move them around !if (might_exist + poll_drive) > 0 { status = $50 ;returns non-zero on error } ;might_exist or poll_drive !if allow_aux = 1 { auxreq = $51 ;set to 1 to read/write aux memory, else main memory is used } ;allow_aux sizelo = $52 ;set if enable_write=1 and writing, or reading, or if enable_seek=1 and seeking sizehi = $53 ;set if enable_write=1 and writing, or reading, or if enable_seek=1 and seeking !if (enable_write + enable_seek + allow_multi + rwts_mode) > 0 { reqcmd = $54 ;set (read/write/seek) if enable_write=1 or enable_seek=1 ;if allow_multi=1, bit 7 selects floppy drive in current slot (clear=drive 1, set=drive 2) during open call ;bit 7 must be clear for read/write/seek on opened file } ;enable_write or enable_seek or allow_multi ldrlo = $55 ;set to load address if override_adr=1 ldrhi = $56 ;set to load address if override_adr=1 namlo = $57 ;name of file to access namhi = $58 ;name of file to access !if enable_floppy = 1 { tmpsec = $3c ;(internal) sector number read from disk reqsec = $3d ;(internal) requested sector number curtrk = $40 ;(internal) track number read from disk } ;enable_floppy command = $42 ;ProDOS constant unit = $43 ;ProDOS constant adrlo = $44 ;ProDOS constant adrhi = $45 ;ProDOS constant bloklo = $46 ;ProDOS constant blokhi = $47 ;ProDOS constant entries = $3f ;(internal) total number of entries in directory !if rwts_mode = 1 { lasttree = $59 ;(internal) last used index in tree buffer lastvol = $5a ;(internal) last used volume number } ;rwts_mode !if allow_trees = 1 { treeidx = $5b ;(internal) index into tree block !if always_trees = 0 { istree = $5c ;(internal) flag to indicate tree file } ;always_trees !if fast_trees = 0 { treeblklo = $5d treeblkhi = $5e } ;fast_trees } ;allow_trees blkidx = $5f ;(internal) index into sapling block list !if rwts_mode = 1 { lastblk = $60 ;(internal) previous index into sapling block list } ;rwts_mode !if bounds_check = 1 { bleftlo = $61 ;(internal) bytes left in file blefthi = $62 ;(internal) bytes left in file } ;bounds_check !if (aligned_read + rwts_mode) = 0 { blkofflo = $63 ;(internal) offset within cache block blkoffhi = $64 ;(internal) offset within cache block } ;not aligned_read and not rwts_mode !if enable_floppy = 1 { step = $65 ;(internal) state for stepper motor tmptrk = $66 ;(internal) temporary copy of current track phase = $67 ;(internal) current phase for seek } ;enable_floppy ;constants cmdseek = 0 ;requires enable_seek=1 cmdread = 1 ;requires enable_write=1 cmdwrite = 2 ;requires enable_write=1 SETKBD = $fe89 SETVID = $fe93 DEVNUM = $bf30 PHASEOFF = $c080 MOTOROFF = $c088 MOTORON = $c089 DRV0EN = $c08a Q6L = $c08c Q6H = $c08d Q7L = $c08e Q7H = $c08f MLI = $bf00 NAME_LENGTH = $4 ;ProDOS constant MASK_SUBDIR = $d0 ;ProDOS constant MASK_ALL = $f0 ;ProDOS constant KEY_POINTER = $11 ;ProDOS constant EOF_LO = $15 ;ProDOS constant EOF_HI = $16 ;ProDOS constant AUX_TYPE = $1f ;ProDOS constant ENTRY_SIZE = $27 ;ProDOS constant NEXT_BLOCK_LO = $2 ;ProDOS constant NEXT_BLOCK_HI = $3 ;ProDOS constant SAPLING = $20 ;ProDOS constant FILE_COUNT = $25 ;ProDOS constant DEVADR01HI = $bf11 ;ProDOS constant ROMIN = $c081 LCBANK2 = $c089 CLRAUXRD = $c002 CLRAUXWR = $c004 SETAUXWR = $c005 CLRAUXZP = $c008 SETAUXZP = $c009 first_zp = $40 ;lowest address to save if swap_zp enabled last_zp = $60 ;highest address to save if swap_zp enabled (max 127 entries later) D1S1 = 1 ;disk 1 side 1 volume ID if rwts_mode enabled init jsr SETKBD jsr SETVID lda DEVNUM sta x80_parms + 1 sta unrunit + 1 and #$70 !if (enable_floppy + enable_write) > 1 { sta unrslot1 + 1 sta unrslot2 + 1 sta unrslot3 + 1 sta unrslot4 + 1 } ;enable_floppy and enable_write pha !if enable_floppy = 1 { ora # 0 { sta unrdrvoff2 + 1 } ;might_exist or poll_drive sta unrdrvoff3 + 1 tax inx ;MOTORON !if allow_multi = 1 { stx unrdrvon1 + 1 } ;allow_multi stx unrdrvon2 + 1 stx unrdrvon3 + 1 stx unrdrvon4 + 1 inx ;DRV0EN !if allow_multi = 1 { stx unrdrvsel2 + 1 } ;allow_multi inx !if allow_multi = 1 { stx unrdrvsel1 + 1 } ;allow_multi inx ;Q6L stx unrread1 + 1 !if (poll_drive + allow_multi) > 0 { stx unrread2 + 1 stx unrread3 + 1 } ;poll_drive or allow_multi stx unrread4 + 1 stx unrread5 + 1 !if check_chksum = 1 { stx unrread6 + 1 } ;check_chksum } ;enable_floppy ldx #1 stx namlo inx stx namhi ;fetch path, if any jsr MLI !byte $c7 !word c7_parms ldx $200 dex stx sizelo bmi +++ ;find current directory name in directory readblock jsr MLI !byte $80 !word x80_parms lda #<(readbuff + NAME_LENGTH) sta bloklo lda #>(readbuff + NAME_LENGTH) sta blokhi inextent ldy #0 lda (bloklo), y pha and #$0f tax -- iny lda (bloklo), y cmp (namlo), y beq ifoundname ;match failed, move to next directory in this block, if possible - pla clc lda bloklo adc #ENTRY_SIZE sta bloklo bcc + ;there can be only one page crossed, so we can increment instead of adc inc blokhi + cmp #<(readbuff + $1ff) ;4 + ($27 * $0d) lda blokhi sbc #>(readbuff + $1ff) bcc inextent ;read next directory block when we reach the end of this block lda readbuff + NEXT_BLOCK_LO ldx readbuff + NEXT_BLOCK_HI bcs + ifoundname dex bne -- ;parse path until last directory is seen iny lda (namlo), y cmp #'/' bne - tya eor #$ff adc sizelo sta sizelo clc tya adc namlo sta namlo pla and #$20 ;Volume Directory Header XOR subdirectory bne ++ ;cache block number of current directory ;as starting position for subsequent searches ldy #(KEY_POINTER + 1) lda (bloklo), y tax dey lda (bloklo), y !if enable_floppy = 1 { sta unrblocklo + 1 stx unrblockhi + 1 } ;enable_floppy sta unrhddblocklo + 1 stx unrhddblockhi + 1 + sta x80_parms + 4 stx x80_parms + 5 ++ lda sizelo bne readblock ;unit to slot for SmartPort interface +++ pla lsr lsr lsr tay ldx DEVADR01HI, y cpx #$c8 bcc set_slot ldx #$c8 - dex stx blokhi ldy #0 sty bloklo iny lda (bloklo), y cmp #$20 bne - iny iny lda (bloklo), y bne - iny iny lda (bloklo), y cmp #3 bne - ldy #$ff lda (bloklo), y beq - set_slot stx slot + 2 stx unrentry + 2 !if load_banked = 1 { lda LCBANK2 - ((lc_bank - 1) * 8) lda LCBANK2 - ((lc_bank - 1) * 8) } ;load_banked !if load_aux = 1 { sta SETAUXWR + (load_banked * 4) ;SETAUXWR or SETAUXZP } ;load_aux !if enable_floppy = 1 { ldx #>unrelocdsk ldy #unrelochdd ldy #((codeend - rdwrpart) + $ff) ldy #0 - lda (bloklo), y reladr sta reloc, y iny bne - inc blokhi inc reladr + 2 dex bne - plp bne ++ ;build 6-and-2 denibbilisation table ldx #$16 -- stx bloklo txa asl bit bloklo beq + ora bloklo eor #$ff and #$7e - bcs + lsr bne - tya sta nibtbl - $16, x !if enable_write = 1 { ;and 6-and-2 nibbilisation table if writing txa ora #$80 sta xlattbl, y } ;enable_write iny + inx bpl -- unrdrvon1 lda MOTORON jsr readadr lda curtrk sta trackd1 !if allow_multi = 1 { unrdrvsel1 lda DRV0EN + 1 jsr spinup jsr poll bcs + lda #$c8 ;iny sta twodrives inc driveind + 1 jsr readadr lda curtrk sta trackd2 + } ;allow_multi unrdrvoff1 lda MOTOROFF ++ } else { ;enable_floppy = 0 slot lda $cfff sta unrentry + 1 ldy #0 - lda unrelochdd, y sta reloc, y !if one_page = 0 { ;hack to avoid address overflow when load_high and load_banked ;and code is less than two pages long (e.g. aligned_read, no write) ;can't insert code during pass two because it breaks existing offsets !ifdef PASS2 { !if >(hddcodeend - reloc) > 0 { !set hack=$100 } ;hddcodeend } else { ;PASS2 not defined !set hack=0 } ;PASS2 lda unrelochdd + hack, y sta reloc + hack, y } ;one_page iny bne - } ;enable_floppy !if load_aux = 1 { sta CLRAUXWR + (load_banked * 4) ;CLRAUXWR or CLRAUXZP } ;load_aux !if rwts_mode = 1 { ;read volume directory key block ;self-modified by init code hddopendir unrhddblocklo = * ldx #2 unrhddblockhi = * lda #0 hddreaddir1 jsr hddreaddirsel ;include volume directory header in count hddreaddir hddfirstent lda #NAME_LENGTH sta bloklo lda #>(hdddirbuf - 1) sta blokhi ;there can be only one page crossed, so we can increment here hddnextent1 inc blokhi hddnextent ldy #0 ;match name lengths before attempting to match names lda (bloklo), y and #$0f tax inx - cmp filename, y beq hddfoundname ;match failed, move to next entry in this block, if possible + clc lda bloklo adc #ENTRY_SIZE sta bloklo bcs hddnextent1 cmp #$ff ;4 + ($27 * $0d) bne hddnextent ;read next directory block when we reach the end of this block ldx hdddirbuf + NEXT_BLOCK_LO lda hdddirbuf + NEXT_BLOCK_HI bcs hddreaddir1 hddfoundname iny lda (bloklo), y dex bne - !if swap_zp = 0 { !if allow_trees = 1 { stx treeidx sty lasttree ;guarantee no match } ;allow_trees stx blkidx sty lastblk ;guarantee no match } else { ;swap_zp = 1 !if allow_trees = 1 { stx zp_array + treeidx - first_zp sty zp_array + lasttree - first_zp ;guarantee no match } ;allow_trees stx zp_array + blkidx - first_zp sty zp_array + lastblk - first_zp ;guarantee no match } ;swap_zp ;fetch KEY_POINTER ldy #KEY_POINTER lda (bloklo), y tax iny lda (bloklo), y jsr hddreaddirsect ldx #2 stx sizehi dex stx reqcmd dex stx sizelo stx ldrlo lda #$b6 sta ldrhi jsr hddrdfile jmp $b700 filename !byte filename_e-filename_b filename_b !text "diskimage.dsk" filename_e } else { ;rwts_mode = 0 rts } ;rwts_mode c7_parms !byte 1 !word $200 x80_parms !byte 3, $d1 !word readbuff, 2 !if enable_floppy = 1 { unrelocdsk !pseudopc reloc { rdwrpart !if (override_adr + allow_subdir) > 0 { ;only available when load address is specified jmp rdwrfile } ;override_adr or allow_subdir opendir !if no_interrupts = 1 { !if detect_err = 1 { clc } ;detect_err php sei jsr + !if detect_err = 1 { pla adc #0 pha } ;detect_err plp rts + } ;no_interrupts ;read volume directory key block ;self-modified by init code unrblocklo = unrelocdsk + (* - reloc) ldx #2 unrblockhi = unrelocdsk + (* - reloc) lda #0 jsr readdirsel ;include volume directory header in count readdir !if might_exist = 1 { ldx dirbuf + FILE_COUNT ;assuming only 256 files per subdirectory inx stx entries } ;might_exist firstent lda #NAME_LENGTH sta bloklo lda #>(dirbuf - 1) sta blokhi ;there can be only one page crossed, so we can increment here nextent1 inc blokhi nextent ldy #0 !if (might_exist + allow_subdir + allow_saplings + (allow_trees and (always_trees xor 1))) > 0 { lda (bloklo), y !if might_exist = 1 { sty status ;skip deleted entries without counting and #MASK_ALL beq + } ;might_exist !if (allow_subdir + allow_saplings + (allow_trees and (always_trees xor 1))) > 0 { ;remember type ;now bits 5-4 are represented by carry (subdirectory), sign (sapling) asl asl !if allow_trees = 1 { ;now bits 5-3 are represented by carry (subdirectory), sign (sapling), ;overflow (seedling), and sign+overflow (tree) sta treeidx bit treeidx } ;allow_trees php } ;allow_subdir or allow_saplings or (allow_trees and not always_trees) } ;might_exist or allow_subdir or allow_saplings or (allow_trees and not always_trees) ;match name lengths before attempting to match names lda (bloklo), y and #$0f tax inx - cmp (namlo), y beq foundname ;match failed, check if any directory entries remain !if (allow_subdir + allow_saplings + (allow_trees and (always_trees xor 1))) > 0 { plp } ;allow_subdir or allow_saplings or (allow_trees and not always_trees) !if might_exist = 1 { dec entries bne + } ;might_exist !if (might_exist + poll_drive) > 0 { nodisk unrdrvoff2 = unrelocdsk + (* - reloc) lda MOTOROFF inc status rts } ;might_exist or poll_drive ;move to next entry in this block, if possible + clc lda bloklo adc #ENTRY_SIZE sta bloklo bcs nextent1 cmp #$ff ;4 + ($27 * $0d) bne nextent ;read next directory block when we reach the end of this block ldx dirbuf + NEXT_BLOCK_LO lda dirbuf + NEXT_BLOCK_HI jsr readdirsec bne firstent foundname iny lda (bloklo), y dex bne - ;initialise essential variables !if allow_trees = 1 { stx treeidx !if always_trees = 0 { stx istree } ;always_trees } ;allow_trees stx blkidx !if aligned_read = 0 { stx blkofflo stx blkoffhi } ;aligned_read !if enable_write = 1 { ldy reqcmd cpy #cmdwrite ;control carry instead of zero bne + ;round requested size up to nearest block if writing lda sizelo adc #$fe lda sizehi adc #1 and #$fe sta sizehi !if aligned_read = 0 { stx sizelo !if bounds_check = 1 { sec } ;bounds_check } ;aligned_read + } ;enable_write !if bounds_check = 1 { ;cache EOF (file size, loaded backwards) ldy #EOF_HI lda (bloklo), y !if (enable_write + aligned_read) > 0 { tax dey ;EOF_LO lda (bloklo), y ;round file size up to nearest block if writing without aligned reads ;or always if using aligned reads !if aligned_read = 0 { bcc + } else { ;aligned_read = 1 !if enable_write = 1 { sec } ;enable_write } ;aligned_read adc #$fe txa adc #1 and #$fe !if aligned_read = 0 { tax lda #0 + stx blefthi sta bleftlo } else { ;aligned_read = 1 sta blefthi } ;aligned_read } else { ;enable_write = 0 and aligned_read = 0 sta blefthi dey ;EOF_LO lda (bloklo), y sta bleftlo } ;enable_write or aligned_read } ;bounds_check ;cache AUX_TYPE (load offset for binary files) !if override_adr = 0 { ldy #AUX_TYPE lda (bloklo), y !if (allow_subdir + allow_saplings + allow_trees + (aligned_read xor 1)) > 0 { sta ldrlo iny lda (bloklo), y sta ldrhi } else { ;allow_subdir = 0 and allow_saplings = 0 and allow_trees = 0 and aligned_read = 1 pha iny lda (bloklo), y pha } ;allow_subdir or allow_saplings or allow_trees or not aligned_read } ;override_adr ;cache KEY_POINTER ldy #KEY_POINTER lda (bloklo), y tax !if (allow_subdir + allow_saplings + allow_trees) > 0 { sta dirbuf !if fast_trees = 0 { sta treeblklo } ;fast_trees iny lda (bloklo), y sta dirbuf + 256 !if fast_trees = 0 { sta treeblkhi } ;fast_trees !if (allow_trees and always_trees) = 0 { plp bpl ++ !if allow_subdir = 1 { php } ;allow_subdir !if allow_trees = 1 { ldy #>dirbuf bvc + !if fast_trees = 1 { ldy #>treebuf } ;fast_trees sty istree + } ;allow_trees } else { ;allow_trees = 0 or always_trees = 1 !if (allow_trees + always_trees) > 1 { ldy #>treebuf } ;allow_trees and always_trees } ;allow_trees or always_trees } else { ;allow_subdir = 0 and allow_saplings = 0 and allow_trees = 0 iny lda (bloklo), y } ;allow_subdir or allow_saplings or allow_trees ;read index block in case of sapling or tree jsr readdirsect !if allow_subdir = 1 { plp } ;allow_subdir ++ ;skip some stuff ;drive is on already ;and interrupt control is in place jmp rdwrfilei rdwrfile unrdrvon2 = unrelocdsk + (* - reloc) lda MOTORON !if no_interrupts = 1 { !if detect_err = 1 { clc } ;detect_err php sei jsr + !if detect_err = 1 { pla adc #0 pha } ;detect_err plp rts + } ;no_interrupts rdwrfilei !if (allow_subdir + allow_saplings + allow_trees + (aligned_read xor 1)) > 0 { ;restore load offset ldx ldrhi lda ldrlo !if allow_subdir = 1 { ;check file type and fake size and load address for subdirectories bcc + ldy #2 sty sizehi ldx #>dirbuf lda #0 !if aligned_read = 0 { sta sizelo } ;aligned_read + } ;allow_subdir sta adrlo stx adrhi } else { ;allow_subdir = 0 and allow_saplings = 0 and allow_trees = 0 and aligned_read = 1 pla sta adrhi pla sta adrlo } ;allow_subdir or allow_saplings or allow_trees ;set requested size to min(length, requested size) !if aligned_read = 0 { !if bounds_check = 1 { ldy bleftlo cpy sizelo lda blefthi tax sbc sizehi bcs copyblock sty sizelo stx sizehi } ;bounds_check copyblock !if allow_aux = 1 { ldx auxreq jsr setaux } ;allow_aux !if enable_write = 1 { lda reqcmd lsr bne rdwrloop } ;enable_write lda blkofflo tax ora blkoffhi beq rdwrloop lda sizehi pha lda sizelo pha lda adrhi sta blokhi lda adrlo sta bloklo stx adrlo lda #>encbuf clc adc blkoffhi sta adrhi ;determine bytes left in block lda #1 sbc blkofflo tay lda #2 sbc blkoffhi tax ;set requested size to min(bytes left, requested size) cpy sizelo sbc sizehi bcs + sty sizelo stx sizehi + !if enable_seek = 1 { lda sizehi } else { ;enable_seek = 0 ldy sizehi } ;enable_seek jsr copycache unrdrvon3 = unrelocdsk + (* - reloc) lda MOTORON ;copycache turns it off lda ldrlo adc sizelo sta ldrlo lda ldrhi adc sizehi sta ldrhi sec pla sbc sizelo sta sizelo pla sbc sizehi sta sizehi ora sizelo bne rdwrfilei !if allow_aux = 0 { rts } else { ;allow_aux = 1 beq rdwrdone } ;allow_aux } else { ;aligned_read = 1 !if bounds_check = 1 { lda blefthi cmp sizehi bcs + sta sizehi + } ;bounds_check !if allow_aux = 1 { ldx auxreq jsr setaux } ;allow_aux } ;aligned_read rdwrloop !if aligned_read = 0 { !if (enable_write + enable_seek) > 0 { ldx reqcmd } ;enable_write or enable_seek ;set read/write size to min(length, $200) lda sizehi cmp #2 bcs + pha lda #2 sta sizehi ;redirect read to private buffer for partial copy lda adrhi pha lda adrlo pha lda #>encbuf sta adrhi !if ver_02 = 1 { ldx #0 stx adrlo !if (enable_write + enable_seek) > 0 { inx ;ldx #cmdread } ;enable_write or enable_seek } else { ;ver_02 = 0 stz adrlo !if (enable_write + enable_seek) > 0 { ldx #cmdread } ;enable_write or enable_seek } ;ver_02 + } ;aligned_read !if allow_trees = 1 { ;read tree data block only if tree and not read already ;the indication of having read already is that at least one sapling/seed block entry has been read, too ldy blkidx bne + !if always_trees = 0 { lda istree beq + } ;always_trees lda adrhi pha lda adrlo pha !if ((aligned_read xor 1) + (enable_write or enable_seek)) > 1 { !if ver_02 = 1 { txa pha } else { ;ver_02 = 0 phx } ;ver_02 } ;(not aligned_read) and (enable_write or enable_seek) lda #>dirbuf sta adrhi sty adrlo ;fetch tree data block and read it ldy treeidx inc treeidx ldx treebuf, y lda treebuf + 256, y !if aligned_read = 0 { php } ;aligned_read jsr seekrd !if aligned_read = 0 { plp !if (enable_write + enable_seek) > 0 { !if ver_02 = 1 { pla tax } else { ;ver_02 = 0 plx } ;ver_02 } ;enable_write or enable_seek } ;aligned_read pla sta adrlo pla sta adrhi } ;allow_trees ;fetch data block and read/write it ldy blkidx + inc blkidx !if aligned_read = 0 { !if enable_seek = 1 { txa ;cpx #cmdseek, but that would require php at top beq + } ;enable_seek !if enable_write = 1 { stx command } ;enable_write } ;aligned_read ldx dirbuf, y lda dirbuf + 256, y !if allow_sparse = 1 { pha ora dirbuf, y tay pla dey iny ;don't affect carry } ;allow_sparse !if aligned_read = 0 { php } ;aligned_read !if allow_sparse = 1 { beq issparse } ;allow_sparse !if (aligned_read + (enable_write or enable_seek)) > 1 { ldy reqcmd !if enable_seek = 1 { beq + } ;enable_seek } ;aligned_read and (enable_write or enable_seek) !if enable_write = 1 { jsr seekrdwr } else { ;enable_write = 0 jsr seekrd } ;enable_write resparse !if aligned_read = 0 { plp !if bounds_check = 1 { + bcc + dec blefthi dec blefthi } ;bounds_check } ;aligned_read + dec sizehi dec sizehi bne rdwrloop unrdrvoff3 = unrelocdsk + (* - reloc) lda MOTOROFF !if aligned_read = 0 { bcc + lda sizelo bne rdwrloop } ;aligned_read rdwrdone !if allow_aux = 1 { ldx #0 setaux sta CLRAUXRD, x sta CLRAUXWR, x } ;allow_aux rts !if allow_sparse = 1 { issparse - sta (adrlo), y iny bne - inc adrhi - sta (adrlo), y iny bne - dec adrhi bne resparse } ;allow_sparse !if aligned_read = 0 { ;cache partial block offset + pla sta bloklo pla sta blokhi pla sta sizehi dec adrhi dec adrhi !if enable_seek = 1 { copycache ldy reqcmd ;cpy #cmdseek beq ++ tay } else { ;enable_seek = 0 tay copycache } ;enable_seek beq + dey - lda (adrlo), y sta (bloklo), y iny bne - inc blokhi inc adrhi bne + - lda (adrlo), y sta (bloklo), y iny + cpy sizelo bne - ++ !if bounds_check = 1 { lda bleftlo sec sbc sizelo sta bleftlo lda blefthi sbc sizehi sta blefthi } ;bounds_check clc !if enable_seek = 1 { lda sizelo } else { ;enable_seek = 0 tya } ;enable_seek adc blkofflo sta blkofflo lda sizehi adc blkoffhi and #$fd sta blkoffhi bcc rdwrdone ;always } ;aligned_read spinup ldy #6 - jsr delay dey bpl - delay -- ldx #$11 - dex bne - sec sbc #1 bne -- rts ;no tricks here, just the regular stuff seek ldy #0 sty step asl phase txa asl copy_cur tax sta tmptrk sec sbc phase beq +++ bcs + !if ver_02 = 1 { eor #$ff } else { ;ver_02 = 0 inc } ;ver_02 inx bcc ++ + !if ver_02 = 1 { sbc #1 } else { ;ver_02 = 0 dec } ;ver_02 dex ++ cmp step bcc + lda step + cmp #8 bcs + tay sec + !if ver_02 = 1 { txa pha } else { ;ver_02 = 0 phx } ;ver_02 ldx step1, y +++ php bne + --- clc lda tmptrk ldx step2, y + stx tmpsec and #3 rol tax lsr unrseek = unrelocdsk + (* - reloc) lda PHASEOFF, x -- ldx #$12 - dex bpl - dec tmpsec bne -- bcs --- plp beq seekret pla inc step bne copy_cur step1 !byte 1, $30, $28, $24, $20, $1e, $1d, $1c step2 !byte $70, $2c, $26, $22, $1f, $1e, $1d, $1c readadr - jsr readd5aa cmp #$96 bne - ldy #3 - sta curtrk jsr readnib rol sta tmpsec jsr readnib and tmpsec dey bne - seekret rts readd5aa -- jsr readnib - cmp #$d5 bne -- jsr readnib cmp #$aa bne - tay ;we need Y=#$AA later readnib unrread1 = unrelocdsk + (* - reloc) - lda Q6L bpl - rts !if (poll_drive + allow_multi) > 0 { poll ldy #0 unrread2 = unrelocdsk + (* - reloc) - lda Q6L jsr seekret pha pla unrread3 = unrelocdsk + (* - reloc) cmp Q6L clc bne + dey bne - sec + rts } ;poll_drive or allow_multi readdirsel !if ver_02 = 1 { pha txa pha } else { ;ver_02 pha phx } ;ver_02 unrdrvon4 = unrelocdsk + (* - reloc) lda MOTORON !if (ver_02 + allow_multi) > 0 { ldy #0 sty adrlo !if poll_drive = 1 { sty status } ;poll_drive } else { ;ver_02 = 0 and allow_multi = 0 stz adrlo !if poll_drive = 1 { stz status } ;poll_drive } ;ver_02 or allow_multi !if allow_multi = 1 { asl reqcmd bcc seldrive twodrives nop ;replace with INY if drive exists seldrive lsr reqcmd unrdrvsel2 = unrelocdsk + (* - reloc) lda DRV0EN, y cpy driveind + 1 sty driveind + 1 beq nodelay jsr spinup nodelay } ;allow_multi !if poll_drive = 1 { jsr poll bcc + pla pla pla pla jmp nodisk + } ;poll_drive !if ver_02 = 1 { pla tax pla } else { ;ver_02 plx pla } ;ver_02 readdirsec !if allow_trees = 0 { readdirsect ldy #>dirbuf } else { ;allow_trees = 1 ldy #>dirbuf readdirsect } ;allow_trees sty adrhi seekrd ldy #cmdread !if (aligned_read + enable_write) > 1 { seekrdwr sty command } else { ;aligned_read = 0 or enable_write = 0 sty command seekrdwr } ;aligned_read and enable_write ;convert block number to track/sector lsr txa ror lsr lsr sta phase txa and #3 php asl plp rol sta reqsec driveind ldy #0 ldx trackd1, y ;if track does not match, then seek cpx phase beq checksec lda phase sta trackd1, y jsr seek ;match or read/write sector checksec jsr cmpsecrd inc reqsec inc reqsec cmpsecrd jsr readadr !if enable_write = 1 { ldy command cpy #cmdwrite ;we need Y=2 below beq encsec } ;enable_write cmp reqsec bne cmpsecrd ;read sector data jsr readd5aa eor #$ad ;zero A if match ;; bne * ;lock if read failure unrread4 = unrelocdsk + (* - reloc) - ldx Q6L bpl - eor nibtbl - $96, x sta bit2tbl - $aa, y iny bne - unrread5 = unrelocdsk + (* - reloc) - ldx Q6L bpl - eor nibtbl - $96, x sta (adrlo), y ;the real address iny bne - !if check_chksum = 1 { unrread6 = unrelocdsk + (* - reloc) - ldx Q6L bpl - eor nibtbl - $96, x bne cmpsecrd } ;check_chksum -- ldx #$a9 - inx beq -- lda (adrlo), y lsr bit2tbl - $aa, x rol lsr bit2tbl - $aa, x rol sta (adrlo), y iny bne - inc adrhi rts !if enable_write = 1 { encsec -- ldx #$aa - dey lda (adrlo), y lsr rol bit2tbl - $aa, x lsr rol bit2tbl - $aa, x sta encbuf, y lda bit2tbl - $aa, x and #$3f sta bit2tbl - $aa, x inx bne - tya bne -- cmpsecwr jsr readadr cmp reqsec bne cmpsecwr ;skip tail #$DE #$AA #$EB some #$FFs ... ldy #$24 - dey bpl - ;write sector data unrslot1 = unrelocdsk + (* - reloc) ldx #$d1 lda Q6H, x ;prime drive lda Q7L, x ;required by Unidisk tya sta Q7H, x ora Q6L, x ;40 cycles ldy #4 ;2 cycles cmp $ea ;3 cycles cmp ($ea, x) ;6 cycles - jsr writenib1 ;(29 cycles) ;+6 cycles dey ;2 cycles bne - ;3 cycles if taken, 2 if not ;36 cycles ;+10 cycles ldy #(prolog_e - prolog) ;2 cycles cmp $ea ;3 cycles - lda prolog - 1, y ;4 cycles jsr writenib2 ;(17 cycles) ;32 cycles if branch taken ;+6 cycles dey ;2 cycles bne - ;3 cycles if taken, 2 if not ;36 cycles on first pass ;+10 cycles tya ;2 cycles ldy #$56 ;2 cycles - eor bit2tbl - 1, y ;5 cycles tax ;2 cycles lda xlattbl, x ;4 cycles unrslot2 = unrelocdsk + (* - reloc) ldx #$d1 ;2 cycles sta Q6H, x ;5 cycles lda Q6L, x ;4 cycles ;32 cycles if branch taken lda bit2tbl - 1, y ;5 cycles dey ;2 cycles bne - ;3 cycles if taken, 2 if not ;32 cycles ;+9 cycles clc ;2 cycles -- eor encbuf, y ;4 cycles - tax ;2 cycles lda xlattbl, x ;4 cycles unrslot3 = unrelocdsk + (* - reloc) ldx #$d1 ;2 cycles sta Q6H, x ;5 cycles lda Q6L, x ;4 cycles bcs + ;3 cycles if taken, 2 if not ;32 cycles if branch taken lda encbuf, y ;4 cycles iny ;2 cycles bne -- ;3 cycles if taken, 2 if not ;32 cycles ;+10 cycles sec ;2 cycles bcs - ;3 cycles ;32 cycles ;+3 cycles + ldy #(epilog_e - epilog) ;2 cycles cmp ($ea, x) ;6 cycles - lda epilog - 1, y ;4 cycles jsr writenib2 ;(17 cycles) ;32 cycles if branch taken ;+6 cycles dey ;2 cycles bne - ;3 cycles if branch taken, 2 if not lda Q7L, x lda Q6L, x ;flush final value inc adrhi rts writenib1 jsr writeret ;6 cycles writenib2 unrslot4=unrelocdsk+(*-reloc) ldx #$d1 ;2 cycles sta Q6H, x ;5 cycles ora Q6L, x ;4 cycles writeret rts ;6 cycles prolog !byte $ad, $aa, $d5 prolog_e epilog !byte $ff, $eb, $aa, $de epilog_e } ;enable_write codeend trackd1 !byte 0 trackd2 !byte 0 bit2tbl = (* + 255) & -256 nibtbl = bit2tbl + 86 !if enable_write = 1 { xlattbl = nibtbl + 106 dataend = xlattbl + 64 } else { ;enable_write = 0 dataend = nibtbl + 106 } ;enable_write } ;enable_floppy } ;reloc unrelochdd !pseudopc reloc { !if rwts_mode = 1 { !if swap_zp = 1 { jsr swap_zpg } ;swap_zp sta namhi sty namlo !if ver_02 = 1 { ldx #0 stx reqcmd ;seek stx sizehi stx adrhi } else { ;ver_02 stz reqcmd ;seek stz sizehi stz adrhi } ;ver_02 ldy #$0c ;command lda (namlo),y cmp #2 ;write (or format if greater) php bcc skipinit ;read beq skipinit ;write ldy #5 ;sector !if ver_02 = 1 { txa } else { ;ver_02 lda #0 } ;ver_02 sta (namlo),y dey ;track sta (namlo),y skipinit ldy #3 ;volume lda (namlo),y bne + lda lastvol + cmp lastvol sta lastvol bne + ror adrhi ;bit 7 set if same volume + ldy #$0e ;returned volume sta (namlo),y ldx #vollist_e-vollist_b - dex cmp vollist_b,x bne - ldy #4 ;track lda (namlo),y asl asl asl rol sizehi asl rol sizehi iny ;sector ora (namlo),y ldy sizehi - dex bmi ++ clc adc #$30 bcc + iny + iny iny bne - ++ tax tya lsr sta treeidx tay txa ror php + bit adrhi bpl newtree cpy lasttree beq newblock ;volume or tree changed, so tree changed newtree sty lasttree tax beq newblock ;block zero will automatically read tree pha lda #0 jsr seek1 pla ;block changed, read it newblock jsr seek1 plp bcc + inc adrhi + ldy #9 ;adrhi lda (namlo),y sta blokhi dey ;adrlo lda (namlo),y sta bloklo ldy #0 plp bcs runinit !if swap_zp = 0 { jmp hddcopycache } else { ;swap_zp jsr hddcopycache beq swap_zpg } ;swap_zp runinit php dec blkidx bne + dec treeidx + ldx #0 plp bne format - lda (bloklo),y sta (adrlo),y iny bne - lda #1 bne writesec clrcarry clc inc adrhi format lda blanksec,x sta (adrlo),y inx txa and #7 tax iny bne format bcs clrcarry dex stx lasttree iny lda #$18 ;blocks writesec sta namlo sty namhi lda adrhi and #$fe sta adrhi - lda #cmdwrite ;also size sta sizehi sta reqcmd jsr hddrdwrloop dec adrhi dec adrhi dec namlo bne - dec namhi bpl - clc !if swap_zp = 1 { swap_zpg pha tya pha ldx #(last_zp - first_zp) - lda first_zp,x ldy hddcodeend,x sta hddcodeend,x sty first_zp,x dex bpl - pla tay pla } ;swap_zp rts blanksec !text "SAN INC." seek1 sta blkidx lda #1 sta sizehi } else { ;rwts_mode !if (override_adr + allow_subdir) > 0 { hddrdwrpart jmp hddrdwrfile } ;override_adr or allow_subdir hddopendir !if no_interrupts = 1 { !if detect_err = 1 { clc } ;detect_err php sei jsr + !if detect_err = 1 { pla adc #0 pha } ;detect_err plp rts + } ;no_interrupts ;read volume directory key block ;self-modified by init code unrhddblocklo = unrelochdd + (* - reloc) ldx #2 unrhddblockhi = unrelochdd + (* - reloc) lda #0 hddreaddir1 jsr hddreaddirsel !if enable_floppy = 1 { !if (* - hddopendir) < (readdir - opendir) { ;essential padding to match offset with floppy version !fill (readdir - opendir) - (* - hddopendir), $ea } } ;enable_floppy ;include volume directory header in count hddreaddir !if might_exist = 1 { ldx hdddirbuf + FILE_COUNT ;assuming only 256 files per subdirectory inx stx entries } ;might_exist hddfirstent lda #NAME_LENGTH sta bloklo lda #>(hdddirbuf - 1) sta blokhi ;there can be only one page crossed, so we can increment here hddnextent1 inc blokhi hddnextent ldy #0 !if (might_exist + allow_subdir + allow_saplings + (allow_trees and (always_trees xor 1))) > 0 { lda (bloklo), y !if might_exist = 1 { sty status ;skip deleted entries without counting and #MASK_ALL beq + } ;might_exist !if (allow_subdir + allow_saplings + (allow_trees and (always_trees xor 1))) > 0 { ;remember type ;now bits 5-4 are represented by carry (subdirectory), sign (sapling) asl asl !if allow_trees = 1 { ;now bits 5-3 are represented by carry (subdirectory), sign (sapling), ;overflow (seedling), and sign+overflow (tree) sta treeidx bit treeidx } ;allow_trees php } ;allow_subdir or allow_saplings or allow_trees } ;might_exist or allow_subdir or allow_saplings or allow_trees ;match name lengths before attempting to match names lda (bloklo), y and #$0f tax inx - cmp (namlo), y beq hddfoundname ;match failed, check if any directory entries remain !if (allow_subdir + allow_saplings + (allow_trees and (always_trees xor 1))) > 0 { plp } ;allow_subdir or allow_saplings or (allow_trees and not always_trees) !if might_exist = 1 { dec entries bne + inc status rts } ;might_exist ;move to next entry in this block, if possible + clc lda bloklo adc #ENTRY_SIZE sta bloklo bcs hddnextent1 cmp #$ff ;4 + ($27 * $0d) bne hddnextent ;read next directory block when we reach the end of this block ldx hdddirbuf + NEXT_BLOCK_LO lda hdddirbuf + NEXT_BLOCK_HI !if might_exist = 1 { jsr hddreaddirsec bcc hddfirstent } else { ;might_exist = 0 bcs hddreaddir1 } ;might_exist hddfoundname iny lda (bloklo), y dex bne - ;initialise essential variables !if allow_trees = 1 { stx treeidx !if always_trees = 0 { stx istree } ;always_trees } ;allow_trees stx blkidx !if aligned_read = 0 { stx blkofflo stx blkoffhi } ;aligned_read !if enable_write = 1 { ldy reqcmd cpy #cmdwrite ;control carry instead of zero bne + ;round requested size up to nearest block if writing lda sizelo adc #$fe lda sizehi adc #1 and #$fe sta sizehi !if aligned_read = 0 { stx sizelo !if bounds_check = 1 { sec } ;bounds_check } ;aligned_read + } ;enable_write !if bounds_check = 1 { ;cache EOF (file size, loaded backwards) ldy #EOF_HI lda (bloklo), y !if (enable_write + aligned_read) > 0 { tax dey ;EOF_LO lda (bloklo), y ;round file size up to nearest block if writing without aligned reads ;or always if using aligned reads !if aligned_read = 0 { bcc + } else { ;aligned_read = 1 !if enable_write = 1 { sec } ;enable_write } ;aligned_read adc #$fe txa adc #1 and #$fe !if aligned_read = 0 { tax lda #0 + stx blefthi sta bleftlo } else { ;aligned_read = 1 sta blefthi } ;aligned_read } else { ;enable_write = 0 and aligned_read = 0 sta blefthi dey ;EOF_LO lda (bloklo), y sta bleftlo } ;enable_write or aligned_read } ;bounds_check ;cache AUX_TYPE (load offset for binary files) !if override_adr = 0 { ldy #AUX_TYPE lda (bloklo), y !if (allow_subdir + allow_saplings + allow_trees + (aligned_read xor 1)) > 0 { sta ldrlo iny lda (bloklo), y sta ldrhi } else { ;allow_subdir = 0 and allow_saplings = 0 and allow_trees = 0 and aligned_read = 1 pha iny lda (bloklo), y pha } ;allow_subdir or allow_saplings or allow_trees or not aligned_read } ;override_adr ;cache KEY_POINTER ldy #KEY_POINTER lda (bloklo), y tax !if (allow_subdir + allow_saplings + allow_trees) > 0 { sta hdddirbuf !if fast_trees = 0 { sta treeblklo } ;fast_trees iny lda (bloklo), y sta hdddirbuf + 256 !if fast_trees = 0 { sta treeblkhi } ;fast_trees !if (allow_trees and always_trees) = 0 { plp bpl ++ !if allow_subdir = 1 { php } ;allow_subdir !if allow_trees = 1 { ldy #>hdddirbuf bvc + !if fast_trees = 1 { ldy #>hddtreebuf } ;fast_trees sty istree + } ;allow_trees } else { ;allow_trees = 0 or always_trees = 1 !if (allow_trees + always_trees) > 1 { ldy #>hddtreebuf } ;allow_trees and always_trees } ;allow_trees or always_trees } else { ;allow_subdir = 0 and allow_saplings = 0 and allow_trees = 0 iny lda (bloklo), y } ;allow_subdir or allow_saplings or allow_trees ;read index block in case of sapling jsr hddreaddirsect !if allow_subdir = 1 { plp } ;allow_subdir ++ } ;rwts_mode hddrdfile hddrdwrfile !if no_interrupts = 1 { !if detect_err = 1 { clc } ;detect_err php sei jsr + !if detect_err = 1 { pla adc #0 pha } ;detect_err plp rts + } ;no_interrupts hddrdwrfilei !if rwts_mode = 0 { !if (allow_subdir + allow_saplings + allow_trees + (aligned_read xor 1)) > 0 { ;restore load offset ldx ldrhi lda ldrlo !if allow_subdir = 1 { ;check file type and fake size and load address for subdirectories bcc + ldy #2 sty sizehi ldx #>hdddirbuf lda #0 !if aligned_read = 0 { sta sizelo } ;aligned_read + } ;allow_subdir sta adrlo stx adrhi } else { ;allow_subdir = 0 and allow_saplings = 0 and allow_trees = 0 and aligned_read = 1 pla sta adrhi pla sta adrlo } ;allow_subdir or allow_saplings or allow_trees ;set requested size to min(length, requested size) !if aligned_read = 0 { !if bounds_check = 1 { ldy bleftlo cpy sizelo lda blefthi tax sbc sizehi bcs hddcopyblock sty sizelo stx sizehi } ;bounds_check hddcopyblock !if allow_aux = 1 { ldx auxreq jsr hddsetaux } ;allow_aux !if enable_write = 1 { lda reqcmd lsr bne hddrdwrloop } ;enable_write ;if offset is non-zero then we return from cache lda blkofflo tax ora blkofflo beq hddrdwrloop lda sizehi pha lda sizelo pha lda adrhi sta blokhi lda adrlo sta bloklo stx adrlo lda #>hddencbuf clc adc blkoffhi sta adrhi ;determine bytes left in block lda #1 sbc blkofflo tay lda #2 sbc blkoffhi tax ;set requested size to min(bytes left, requested size) cpy sizelo sbc sizehi bcs + sty sizelo stx sizehi + !if enable_seek = 1 { lda sizehi } else { ;enable_seek = 0 ldy sizehi } ;enable_seek jsr hddcopycache ;align to next block and resume read lda ldrlo adc sizelo sta ldrlo lda ldrhi adc sizehi sta ldrhi sec pla sbc sizelo sta sizelo pla sbc sizehi sta sizehi ora sizelo bne hddrdwrfilei !if allow_aux = 0 { rts } else { ;allow_aux beq hddrdwrdone } ;allow_aux } else { ;aligned_read = 1 !if bounds_check = 1 { lda blefthi cmp sizehi bcs + sta sizehi + } ;bounds_check !if allow_aux = 1 { ldx auxreq jsr hddsetaux } ;allow_aux } ;aligned_read } ;rwts_mode hddrdwrloop !if aligned_read = 0 { !if rwts_mode = 0 { !if (enable_write + enable_seek) > 0 { ldx reqcmd } ;enable_write or enable_seek ;set read/write size to min(length, $200) lda sizehi cmp #2 bcs + pha ;redirect read to private buffer for partial copy lda adrhi pha lda adrlo pha lda #2 sta sizehi } ;rwts_mode lda #>hddencbuf sta adrhi !if ver_02 = 1 { ldx #0 stx adrlo !if ((enable_write + enable_seek) and (rwts_mode - 1)) > 0 { inx ;ldx #cmdread } ;(enable_write or enable_seek) and not rwts_mode } else { ;ver_02 = 0 stz adrlo !if ((enable_write + enable_seek) and (rwts_mode - 1)) > 0 { ldx #cmdread } ;(enable_write or enable_seek) and not rwts_mode } ;ver_02 + } ;aligned_read !if allow_trees = 1 { ;read tree data block only if tree and not read already ;the indication of having read already is that at least one sapling/seed block entry has been read, too !if rwts_mode = 0 { ldy blkidx bne + !if always_trees = 0 { lda istree beq + } ;always_trees } else { ;rwts_mode = 1 ldy istree } ;rwts_mode lda adrhi pha lda adrlo pha !if rwts_mode = 0 { !if ((aligned_read xor 1) + (enable_write or enable_seek)) > 1 { !if ver_02 = 1 { txa pha } else { ;ver_02 = 0 phx } ;ver_02 } ;(not aligned_read) and (enable_write or enable_seek) !if aligned_read = 0 { php } ;aligned_read lda #>hdddirbuf sta adrhi sty adrlo } else { ;rwts_mode = 1 ;or in this case, read whenever tree index changes sty adrhi ldy treeidx cpy lasttree beq skiptree sty lasttree ldx blkidx inx stx lastblk } ;rwts_mode ;fetch tree data block and read it !if fast_trees = 0 { ldx treeblklo lda treeblkhi jsr hddseekrd ldy treeidx !if rwts_mode = 0 { inc treeidx } ;rwts_mode ldx hdddirbuf, y lda hdddirbuf + 256, y } else { ;fast_trees = 1 ldy treeidx !if rwts_mode = 0 { inc treeidx } ;rwts_mode ldx hddtreebuf, y lda hddtreebuf + 256, y } ;fast_trees !if detect_treof = 1 { bne noteof1 tay txa bne fixy1 pla pla sec rts fixy1 tya noteof1 } ;detect_treof !if aligned_read = 0 { php } ;aligned_read jsr hddseekrd skiptree !if rwts_mode = 0 { !if aligned_read = 0 { plp } ;aligned_read !if ((aligned_read xor 1) + (enable_write or enable_seek)) > 1 { !if ver_02 = 1 { pla tax } else { ;ver_02 = 0 plx } ;ver_02 } ;(not aligned_read) and (enable_write or enable_seek) } ;rwts_mode pla sta adrlo pla sta adrhi } ;allow_trees ;fetch data block and read/write it !if rwts_mode = 1 { + } ;rwts_mode ldy blkidx !if rwts_mode = 0 { + inc blkidx !if aligned_read = 0 { !if enable_seek = 1 { txa ;cpx #cmdseek, but that would require php at top beq + } ;enable_seek !if enable_write = 1 { stx command } ;enable_write } ;aligned_read } else { ;rwts_mode = 1 ;read whenever block index changes cpy lastblk beq skipblk sty lastblk } ;rwts_mode ldx hdddirbuf, y lda hdddirbuf + 256, y !if detect_treof = 1 { bne noteof2 tay txa bne fixy2 sec rts fixy2 tya noteof2 } ;detect_treof !if allow_sparse = 1 { pha ora hdddirbuf, y tay pla dey iny ;don't affect carry } ;allow_sparse !if (aligned_read + rwts_mode) = 0 { php } ;aligned_read or rwts_mode !if allow_sparse = 1 { !if rwts_mode = 0 { beq hddissparse } else { ;rwts_mode = 1 bne hddseekrd } ;rwts_mode } ;allow_sparse !if rwts_mode = 0 { !if (aligned_read and (enable_write or enable_seek)) = 1 { ldy reqcmd !if enable_seek = 1 { beq + } ;enable_seek } ;aligned_read and (enable_write or enable_seek) !if enable_write = 1 { jsr hddseekrdwr } else { ;enable_write = 0 jsr hddseekrd } ;enable_write hddresparse !if aligned_read = 0 { plp !if bounds_check = 1 { + bcc + dec blefthi dec blefthi } ;bounds_check } ;aligned_read inc adrhi inc adrhi + dec sizehi dec sizehi bne hddrdwrloop !if aligned_read = 0 { !if bounds_check = 0 { bcc + } ;bounds_check lda sizelo bne hddrdwrloop } ;aligned_read hddrdwrdone !if allow_aux = 1 { ldx #0 hddsetaux sta CLRAUXRD, x sta CLRAUXWR, x } ;allow_aux rts } ;rwts_mode !if allow_sparse = 1 { hddissparse - sta (adrlo), y inc adrhi sta (adrlo), y dec adrhi iny bne - !if rwts_mode = 0 { beq hddresparse } ;rwts_mode } ;allow_sparse !if rwts_mode = 1 { skipblk rts } ;rwts_mode !if aligned_read = 0 { ;cache partial block offset + pla sta bloklo pla sta blokhi pla sta sizehi !if bounds_check = 0 { dec adrhi dec adrhi } ;bounds_check !if enable_seek = 1 { !if rwts_mode = 0 { hddcopycache } ;rwts_mode ldy reqcmd ;cpy #cmdseek !if rwts_mode = 0 { beq ++ tay } else { ;rwts_mode beq hddrdwrdone hddcopycache } ;rwts_mode } else { ;enable_seek = 0 tay hddcopycache } ;enable_seek !if rwts_mode = 0 { beq + dey } ;rwts_mode - lda (adrlo), y sta (bloklo), y iny bne - !if rwts_mode = 0 { inc blokhi inc adrhi bne + - lda (adrlo), y sta (bloklo), y iny + cpy sizelo bne - ++ !if bounds_check = 1 { lda bleftlo sec sbc sizelo sta bleftlo lda blefthi sbc sizehi sta blefthi } ;bounds_check clc !if enable_seek = 1 { lda sizelo } else { ;enable_seek = 0 tya } ;enable_seek adc blkofflo sta blkofflo lda sizehi adc blkoffhi and #$fd sta blkoffhi bcc hddrdwrdone ;always } else { ;rwts_mode = 1 rts } ;rwts_mode } ;aligned_read hddreaddirsel !if ver_02 = 1 { ldy #0 sty adrlo !if might_exist = 1 { sty status } ;might_exist } else { ;ver_02 = 0 stz adrlo !if might_exist = 1 { stz status } ;might_exist } ;ver_02 !if allow_multi = 1 { asl reqcmd lsr reqcmd } ;allow_multi hddreaddirsec !if allow_trees = 0 { hddreaddirsect ldy #>hdddirbuf } else { ;allow_trees = 1 ldy #>hdddirbuf hddreaddirsect } ;allow_trees sty adrhi hddseekrd ldy #cmdread !if (aligned_read + enable_write) > 1 { hddseekrdwr sty command } else { ;aligned_read = 0 or enable_write = 0 sty command hddseekrdwr } ;aligned_read and enable_write stx bloklo sta blokhi unrunit=unrelochdd+(*-reloc) lda #$d1 sta unit unrentry=unrelochdd+(*-reloc) jmp $d1d1 !if rwts_mode = 1 { vollist_b !byte D1S1 vollist_e } ;rwts_mode hddcodeend !if swap_zp = 1 { zp_array !fill last_zp - first_zp } ;swap_zp hdddataend } ;reloc ;[music] you can't touch this [music] ;math magic to determine ideal loading address, and information dump !ifdef PASS2 { } else { ;PASS2 not defined !set PASS2=1 !if enable_floppy = 1 { !if reloc < $c000 { !if ((dataend + $ff) & -256) > $c000 { !serious "initial reloc too high, adjust to ", $c000 - (((dataend + $ff) & -256) - reloc) } ;dataend !if load_high = 1 { !if ((dataend + $ff) & -256) != $c000 { !warn "initial reloc too low, adjust to ", $c000 - (((dataend + $ff) & -256) - reloc) } ;dataend dirbuf = reloc - $200 encbuf = dirbuf - $200 !if allow_trees = 1 { treebuf = encbuf - $200 } ;allow_trees } else { ;load_high = 0 !pseudopc ((dataend + $ff) & -256) { dirbuf = * } encbuf=dirbuf + $200 !if allow_trees = 1 { treebuf = encbuf + $200 } ;allow_trees } ;load_high } else { ;reloc > $c000 !if ((dataend + $ff) & -256) < reloc { !serious "initial reloc too high, adjust to ", (0 - (((dataend + $ff) & -256) - reloc)) & $ffff } ;dataend !if load_high = 1 { !if (((dataend + $ff) & -256) & $ffff) != 0 { !warn "initial reloc too low, adjust to ", (0 - (((dataend + $ff) & -256) - reloc)) & $ffff } ;dataend dirbuf = reloc - $200 encbuf = dirbuf - $200 !if allow_trees = 1 { treebuf = encbuf - $200 } ;allow_trees } else { ;load_high = 0 !pseudopc ((dataend + $ff) & -256) { dirbuf = * } encbuf = dirbuf + $200 !if allow_trees = 1 { treebuf = encbuf + $200 } ;allow_trees } ;load_high } ;reloc !if verbose_info = 1 { !warn "floppy code: ", reloc, "-", codeend - 1 !warn "floppy data: ", bit2tbl, "-", dataend - 1 !warn "floppy dirbuf: ", dirbuf, "-", dirbuf + $1ff !if aligned_read = 0 { !warn "floppy encbuf: ", encbuf, "-", encbuf + $1ff } ;aligned_read !if (allow_trees + fast_trees) > 1 { !warn "floppy treebuf: ", treebuf, "-", treebuf + $1ff } ;allow_trees and fast_trees !warn "floppy driver start: ", unrelocdsk - init } ;verbose_info } ;enable_floppy !if reloc < $c000 { !if ((hdddataend + $ff) & -256) > $c000 { !serious "initial reloc too high, adjust to ", $c000 - (((hdddataend + $ff) & -256) - reloc) } ;hdddataend !if load_high = 1 { !if ((hdddataend + $ff) & -256) != $c000 { !warn "initial reloc too low, adjust to ", $c000 - (((hdddataend + $ff) & -256) - reloc) } ;hdddataend hdddirbuf = reloc - $200 !if aligned_read = 0 { hddencbuf = hdddirbuf - $200 } ;aligned_read !if allow_trees = 1 { !if aligned_read = 0 { hddtreebuf = hddencbuf - $200 } else { ;aligned_read = 1 hddtreebuf = hdddirbuf - $200 } ;aligned_read } ;allow_trees } else { ;load_high = 0 !pseudopc ((hdddataend + $ff) & -256) { hdddirbuf = * } !if aligned_read = 0 { hddencbuf = hdddirbuf + $200 !if hddencbuf >= $c000 { !if hddencbuf < $d000 { !set hddencbuf = reloc - $200 } } } ;aligned_read !if allow_trees = 1 { !if aligned_read = 0 { hddtreebuf = hddencbuf + $200 !if hddtreebuf >= reloc { !if hddencbuf < hddcodeend { !set hddtreebuf = hddencbuf - $200 } } } else { ;aligned_read = 1 hddtreebuf = hdddirbuf + $200 } ;aligned_read } ;allow_trees } ;load_high } else { ;reloc > $c000 !if ((hdddataend + $ff) & -256) < reloc { !serious "initial reloc too high, adjust to ", (0 - (((hdddataend + $ff) & -256) - reloc)) & $ffff } ;hdddataend !if load_high = 1 { !if enable_floppy = 0 { !if (((hdddataend + $ff) & -256) & $ffff) != 0 { !warn "initial reloc too low, adjust to ", (0 - (((hdddataend + $ff) & -256) - reloc)) & $ffff } ;hdddataend } ;enable_floppy hdddirbuf = reloc - $200 !if aligned_read = 0 { hddencbuf = hdddirbuf - $200 } ;aligned_read !if allow_trees = 1 { !if aligned_read = 0 { hddtreebuf = hddencbuf - $200 } else { ;aligned_read = 1 hddtreebuf = hdddirbuf - $200 } ;aligned_read } ;allow_trees } else { ;load_high = 0 !pseudopc ((hdddataend + $ff) & -256) { hdddirbuf = * } !if aligned_read = 0 { hddencbuf = hdddirbuf + $200 } ;aligned_read !if allow_trees = 1 { !if aligned_read = 0 { hddtreebuf = hddencbuf + $200 } else { ;aligned_read = 1 hddtreebuf = hdddirbuf + $200 } ;aligned_read } ;allow_trees } ;load_high } ;reloc !if verbose_info = 1 { !warn "hdd code: ", reloc, "-", hddcodeend - 1 !if hddcodeend != hdddataend { !warn "hdd data: ", hddcodeend, "-", hdddataend - 1 } !warn "hdd dirbuf: ", hdddirbuf, "-", hdddirbuf + $1ff !if aligned_read = 0 { !warn "hdd encbuf: ", hddencbuf, "-", hddencbuf + $1ff } ;aligned_read !if (allow_trees + fast_trees) > 1 { !warn "hdd treebuf: ", hddtreebuf, "-", hddtreebuf + $1ff } ;allow_trees and fast_trees !warn "hdd driver start: ", unrelochdd - init !if (one_page + enable_floppy) = 0 { !if ((hddcodeend - hddopendir) < $100) { !warn "one_page can be enabled, code is small enough" } ;hddcodeend } ;not one_page and not enable_floppy } ;verbose_info } ;PASS2 readbuff !byte $D3,$C1,$CE,$A0,$C9,$CE,$C3,$AE