diff --git a/Makefile b/Makefile index c912e476e..53b1ca040 100644 --- a/Makefile +++ b/Makefile @@ -27,10 +27,10 @@ dsk: md asm cp res/_FileInformation.txt build/ $(CADIUS) ADDFILE build/"$(DISK)" "/${VOLUME}/" "res/PRODOS" >/dev/null $(CADIUS) ADDFILE build/"$(DISK)" "/${VOLUME}/" "build/LAUNCHER.SYSTEM" >/dev/null + $(CADIUS) CREATEFOLDER build/"$(DISK)" "/${VOLUME}/X/" >/dev/null $(CADIUS) ADDFILE build/"$(DISK)" "/${VOLUME}/" "res/GAMES.CONF" >/dev/null $(CADIUS) ADDFILE build/"$(DISK)" "/${VOLUME}/" "res/COVER" >/dev/null $(CADIUS) ADDFILE build/"$(DISK)" "/${VOLUME}/" "res/COVER.A2FC" >/dev/null - $(CADIUS) CREATEFOLDER build/"$(DISK)" "/${VOLUME}/X/" >/dev/null # bin/do2po.py res/dsk/ build/po/ # rsync -a res/dsk/*.po build/po/ # bin/extract.py build/po/ | sh >/dev/null diff --git a/src/glue.prorwts2.a b/src/glue.prorwts2.a index 067dd9f79..1545fcd63 100644 --- a/src/glue.prorwts2.a +++ b/src/glue.prorwts2.a @@ -1,15 +1,17 @@ ;license:MIT -;(c) 2017-8 by 4am +;(c) 2018 by 4am & qkumba ; ; ProRWTS2 glue functions ; ; Public functions ; - LoadFile +; - LoadDHRFile ; ;------------------------------------------------------------------------------ ; LoadFile ; load a file into memory all at once, using ProRWTS2 +; supports files in subdirectories, delimited by '/' like ProDOS ; uses file's load address ; ; in: stack contains 2 bytes of parameters: @@ -22,13 +24,114 @@ LoadFile +PARAMS_ON_STACK 2 +LDPARAM 1 +STAY namlo ; set filename - lda #$FF ; read entire file (ProRWTS2 will figure out exact size) + + ;search for '/' character in filename + + ldx #0 + ldy #0 + lda (namlo), y + tay +- inx + dey + bmi @go ; no '/', just do the read + lda (namlo), y + cmp #'/' + bne - + sty sizelo + txa + pha + +@myreadblock +@myx80_parms + ldx #2 + lda #0 + jsr hddreaddirsel + lda #NAME_LENGTH + sta bloklo + lda #>(hdddirbuf - 1) + sta blokhi + + ;there can be only one page crossed, so we can increment here + +@mynextent1 + inc blokhi +@mynextent + ldy #0 + lda (bloklo), y + pha + and #$0f + tax +-- iny + lda (bloklo), y + cmp (namlo), y + beq @myfoundname + + ;match failed, move to next directory in this block, if possible + +- pla + +@myskiphdr + clc + lda bloklo + adc #ENTRY_SIZE + sta bloklo + bcs @mynextent1 + cmp #$ff ;4 + ($27 * $0d) + bne @mynextent + + ;read next directory block when we reach the end of this block + + lda readbuff + NEXT_BLOCK_LO + ldx readbuff + NEXT_BLOCK_HI + bcs + + +@myfoundname + dex + bne -- + + ;parse path until last directory is seen + + iny + lda (namlo), y + cmp #'/' + bne - + pla + and #$20 ;Volume Directory Header XOR subdirectory + bne @myskiphdr + tya + eor #$ff + adc sizelo sta sizelo - sta sizehi - lda #0 ; 0 = read into main memory - sta auxreq + clc + tya + adc namlo + sta namlo + + ;cache block number of current directory + ;as starting position for subsequent searches + + ldy #(KEY_POINTER + 1) + lda (bloklo), y + tax + dey + lda (bloklo), y + sta (reloc + unrhddblocklo - unrelochdd) + 1 + stx (reloc + unrhddblockhi - unrelochdd) + 1 ++ sta @myx80_parms + 1 + stx @myx80_parms + 3 +++ lda sizelo + bne @myreadblock + tay + + pla + sta (namlo), y +@go lda #cmdread ; read (instead of write) sta reqcmd + lda #0 ; 0 = read into main memory + sta auxreq + lda #$FF ; read entire file (ProRWTS2 will figure out exact size) + sta sizehi jmp hddopendir ; exit via ProRWTS2 ;------------------------------------------------------------------------------ diff --git a/src/prorwts2.a b/src/prorwts2.a index 488158c7b..fd19255d2 100644 --- a/src/prorwts2.a +++ b/src/prorwts2.a @@ -1,2856 +1,2864 @@ -;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 - -;place no code before init label below. - - ;user-defined options - verbose_info = 0 ;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 = 1 ;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 = 1 ;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 = 1 ;enable support for reading sparse files - bounds_check = 1 ;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 { - } ;fast_trees - iny - lda (bloklo), y - sta hdddirbuf + 256 - !if fast_trees = 0 { - } ;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 +;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 + +;place no code before init label below. + + ;user-defined options + verbose_info = 0 ;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 = 1 ;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 = 1 ;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=1 ;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 = 1 ;enable support for reading sparse files + ;recommended if enable_write is enabled, to prevent writing to sparse blocks + bounds_check = 1 ;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 + + sec + php + +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 + +skiphdr 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 - + pla + and #$20 ;Volume Directory Header XOR subdirectory + beq adjpath + pla + clc + php + lsr + bcc skiphdr + inx + +adjpath tya + eor #$ff + adc sizelo + sta sizelo + clc + tya + adc namlo + sta namlo + dex + beq ++ + + ;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 + pla + + ;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 + +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 + +readdir ;note that calling this location directly limits subdirectories to 14 entries! + lda #NAME_LENGTH + ENTRY_SIZE +firstent sta bloklo + lda #>(dirbuf - 1) + sta blokhi + + !if might_exist = 1 { + lda dirbuf + FILE_COUNT ;assuming only 256 files per subdirectory + sta entries + } ;might_exist + + ;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 + lda #NAME_LENGTH + 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 (allow_trees + (fast_trees xor 1)) > 1 { + sta treeblklo + } ;allow_trees = 1 and fast_trees = 0 + iny + lda (bloklo), y + sta dirbuf + 256 + !if (allow_trees + (fast_trees xor 1)) > 1 { + sta treeblkhi + } ;allow_trees = 1 and fast_trees = 0 + !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 +;;; jsr poll + +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 + 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 + +hddreaddir ;note that calling this location directly limits subdirectories to 14 entries! + lda #NAME_LENGTH + ENTRY_SIZE +hddfirstent sta bloklo + lda #>(hdddirbuf - 1) + sta blokhi + + !if might_exist = 1 { + lda hdddirbuf + FILE_COUNT ;assuming only 256 files per subdirectory + sta entries + } ;might_exist + + ;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 + jsr hddreaddirsec + lda #NAME_LENGTH + bne hddfirstent + +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 (allow_trees + (fast_trees xor 1)) > 1 { + sta treeblklo + } ;allow_trees = 1 and fast_trees = 0 + iny + lda (bloklo), y + sta hdddirbuf + 256 + !if (allow_trees + (fast_trees xor 1)) > 1 { + sta treeblkhi + } ;allow_trees = 1 and fast_trees = 0 + !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