lawless-legends/Platform/Apple/tools/ProRWTS/prorwts2.s

2104 lines
58 KiB
ArmAsm
Executable File

;license:BSD-3-Clause
;extended open/read/write binary file in ProDOS filesystem, with random access
;copyright (c) Peter Ferrie 2013-17
!cpu 6502
*=$4000
;place no code before init label below.
;user-defined options
verbose_info = 0 ;set to 1 to enable display of memory usage
enable_floppy = 1 ;set to 1 to enable floppy drive support
poll_drive = 1 ;set to 1 to check if disk is in drive
override_adr = 1 ;set to 1 to require an explicit load address
aligned_read = 0 ;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 (256 bytes for floppy, 512 bytes for HDD)
enable_seek = 1 ;set to 1 to enable seek support
allow_multi = 1 ;set to 1 to allow multiple floppies
check_chksum = 1 ;set to 1 to enforce checksum verification for floppies
allow_subdir = 0 ;set to 1 to allow opening subdirectories to access files
might_exist = 1 ;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
save_auxscr = 1 ;set to 1 to save and restore the I/O scratchpad registers in aux
;e.g. $478,x $4f8,x ... $7f8,x (where x = slot
;needed if using the aux text page, and possibly some hard drive controller
;cards will be confused if run in aux mem without this
allow_trees = 1 ;enable support for tree files, as opposed to only seedlings and saplings
;requires an additional 512 bytes of RAM
bounds_check = 0 ;set to 1 to prevent access beyond the end of the file
;but limits file size to 64k-2 bytes.
load_high = 0 ;set to 1 to load to top of RAM (either main or banked, enables a himem check)
load_aux = 1 ;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
;user-defined driver load address
!if load_banked = 1 {
!if load_high = 1 {
!ifdef PASS2 {
} else { ;PASS2
reloc = $fb00 ;page-aligned, as high as possible, the ideal value will be shown on mismatch
} ;PASS2
} else { ;load_high
reloc = $d000 ;page-aligned, but otherwise wherever you want
} ;load_high
} else { ;load_banked
!if load_high = 1 {
!ifdef PASS2 {
} else { ;PASS2
reloc = $bf00 ;page-aligned, as high as possible, the ideal value will be shown on mismatch
} ;PASS2
} else { ;load_high
reloc = $1000 ;page-aligned, but otherwise wherever you want
} ;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
;zpage usage, arbitrary selection except for the "ProDOS constant" ones
;feel free to move them around
!if (might_exist + poll_drive) > 0 {
status = $3 ;returns non-zero on error
} ;might_exist or poll_drive
!if allow_aux = 1 {
auxreq = $a ;set to 1 to read/write aux memory, else main memory is used
} ;allow_aux
sizelo = $6 ;set if enable_write=1 and writing, or reading, or if enable_seek=1 and seeking
sizehi = $7 ;set if enable_write=1 and writing, or reading, or if enable_seek=1 and seeking
!if (enable_write + enable_seek + allow_multi) > 0 {
reqcmd = $2 ;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 = $E ;set to load address if override_adr=1
ldrhi = $F ;set to load address if override_adr=1
namlo = $C ;name of file to access
namhi = $D ;name of file to access
!if enable_floppy = 1 {
tmpsec = $15 ;(internal) sector number read from disk
reqsec = $16 ;(internal) requested sector number
curtrk = $17 ;(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
!if allow_trees = 1 {
treeidx = $1b ;(internal) index into tree block
;MH: must be just after blkoffhi for proper seek reset in LegendOS
istree = $1c ;(internal) flag to indicate tree file
} ;allow_trees
entries = $18 ;(internal) total number of entries in directory
!if bounds_check = 1 {
bleftlo = $13 ;(internal) bytes left in file
blefthi = $14 ;(internal) bytes left in file
} ;bounds_check
blkofflo = $19 ;(internal) offset within cache block
blkoffhi = $1a ;(internal) offset within cache block
!if enable_floppy = 1 {
step = $1d ;(internal) state for stepper motor
tmptrk = $1e ;(internal) temporary copy of current track
phase = $1f ;(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
ROMIN = $c081
LCBANK2 = $c089
CLRAUXRD = $c002
SETAUXRD = $c003
CLRAUXWR = $c004
SETAUXWR = $c005
CLRAUXZP = $c008
SETAUXZP = $c009
init jsr SETVID
jsr SETKBD
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 #<PHASEOFF
sta unrseek + 1
ora #<MOTOROFF
!if might_exist = 1 {
sta unrdrvoff1 + 1
} ;might_exist
sta unrdrvoff2 + 1
tax
inx ;MOTORON
!if poll_drive = 1 {
stx unrdrvon1 + 1
} ;poll_drive
stx unrdrvon2 + 1
inx ;DRV0EN
!if allow_multi = 1 {
stx unrdrvsel + 1
} ;allow_multi
inx
inx ;Q6L
stx unrread1 + 1
!if poll_drive = 1 {
stx unrread2 + 1
} ;poll_drive
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 #MASK_SUBDIR
;watch for subdirectory entries
cmp #MASK_SUBDIR
bne +
lda (bloklo), y
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 iny
dex
bne --
;parse path until last directory is seen
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
tax
lsr
ora #$c0
ldy $bf11, x
cpy #$c8 ;max slot+1
bcs set_slot
tya
set_slot sta slot + 2
sta 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 #<unrelocdsk
slot lda $cfff
sta unrentry + 1
php
beq copydrv
ldx #>unrelochdd
ldy #<unrelochdd
copydrv stx blokhi
sty bloklo
ldx #>((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 --
++
} else { ;enable_floppy
slot lda $cfff
sta unrentry + 1
ldy #0
- lda unrelochdd, y
sta reloc, y
;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
!set hack=0
} ;PASS2
lda unrelochdd + hack, y
sta reloc + hack, y
iny
bne -
} ;enable_floppy
!if load_aux = 1 {
sta CLRAUXWR + (load_banked * 4) ;CLRAUXWR or CLRAUXZP
} ;load_aux
rts
c7_parms !byte 1
!word $200
x80_parms !byte 3, $d1
!word readbuff, 2
!if enable_floppy = 1 {
unrelocdsk
!pseudopc reloc {
!if override_adr = 1 {
;only available when load address is specified
rdwrpart jmp rdwrfile
} ;override_adr
;read volume directory key block
;self-modified by init code
opendir
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 #<(dirbuf + NAME_LENGTH)
sta bloklo
lda #>(dirbuf + NAME_LENGTH)
sta blokhi
nextent ldy #0
!if might_exist = 1 {
sty status
} ;might_exist
lda (bloklo), y
!if might_exist = 1 {
;skip deleted entries without counting
and #MASK_ALL
beq ++
} ;might_exist
;remember type
;now bits 5-4 are represented by carry (subdirectory), sign (sapling)
savetype
asl
asl
;now bits 5-3 are represented by carry (subdirectory), sign (sapling),
;overflow (seedling), and sign+overflow (tree)
!if allow_trees = 1 {
sta treeidx
bit treeidx
} ;allow_trees
php
;match name lengths before attempting to match names
lda (bloklo), y
and #$0f
tax
inx
!byte $2c ;mask lda, y on first pass
- lda (bloklo), y
cmp (namlo), y
beq foundname
;match failed, check if any directory entries remain
plp
+
!if might_exist = 1 {
dec entries
bne ++
} ;might_exist
!if (might_exist + poll_drive) > 0 {
nodisk
unrdrvoff1=unrelocdsk+(*-reloc)
lda MOTOROFF
inc status
rts
} ;might_exist or poll_drive
;move to next directory in this block, if possible
++ 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 #<(dirbuf + $1ff) ;4 + ($27 * $0d)
lda blokhi
sbc #>(dirbuf + $1ff)
bcc 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
dex
bne -
!if allow_trees = 1 {
stx treeidx
stx istree
} ;allow_trees
stx entries
stx blkofflo
stx blkoffhi
!if enable_write = 1 {
ldy reqcmd
cpy #cmdwrite ;control carry instead of zero
bne +
;round requested size up to nearest block if writing
!if aligned_read = 0 {
php
} ;aligned_read
lda sizelo
ldx sizehi
jsr round
sta sizehi
!if aligned_read = 0 {
plp
} ;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
} else { ;enable_write or aligned_read
sta blefthi
} ;enable_write or aligned_read
dey ;EOF_LO
lda (bloklo), y
!if (enable_write + aligned_read) > 0 {
;round file size up to nearest sector if writing without aligned reads
;or nearest block if using aligned reads
!if aligned_read = 0 {
bcc +
} ;aligned_read
jsr round
tax
lda #0
!if aligned_read = 0 {
sta sizelo
} ;aligned_read
+ stx blefthi
} ;enable_write or aligned_read
!if aligned_read = 0 {
sta bleftlo
} ;aligned_read
} else { ;bounds_check
!if enable_write = 1 {
!if aligned_read = 0 {
bcc +
lda #0
sta sizelo
+
} ;aligned_read
} ;enable_write
} ;bounds_check
;cache AUX_TYPE (load offset for binary files)
!if override_adr = 0 {
pla
tax
ldy #AUX_TYPE
lda (bloklo), y
pha
iny
lda (bloklo), y
pha
txa
pha
} ;override_adr
;cache KEY_POINTER
ldy #KEY_POINTER
lda (bloklo), y
tax
sta dirbuf
iny
lda (bloklo), y
sta dirbuf + 256
;read index block in case of sapling
plp
!if (allow_subdir + allow_trees) > 0 {
bpl rdwrfile
!if allow_subdir = 1 {
php
} ;allow_subdir
!if allow_trees = 1 {
ldy #>dirbuf
bvc +
ldy #>treebuf
sty istree
+
} ;allow_trees
jsr readdirsect
!if allow_subdir = 1 {
plp
} ;allow_subdir
} ;allow_subdir
;restore load offset
rdwrfile
!if override_adr = 1 {
ldx ldrhi
lda ldrlo
} else { ;override_adr
pla
tax
pla
} ;override_adr
!if allow_subdir = 1 {
;check file type and fake size and load address for subdirectories
bcc +
ldy #2
sty sizehi
ldx #>dirbuf
lda #<dirbuf
+
} ;allow_subdir
sta adrlo
stx adrhi
;set requested size to min(length, requested size)
!if aligned_read = 0 {
!if bounds_check = 1 {
lda bleftlo
tay
cmp sizelo
lda blefthi
tax
sbc sizehi
bcs copyblock
sty sizelo
stx sizehi
} ;bounds_check
copyblock
!if (enable_write + enable_seek) > 0 {
ldy reqcmd
;cpy #cmdseek
beq +
} ;enable_write or enable_seek
!if allow_aux = 1 {
ldx auxreq
jsr setaux
} ;allow_aux
!if (enable_write + enable_seek) > 0 {
dey ;cpy #cmdread
!if enable_write = 1 {
bne rdwrloop
} ;enable_write
} ;enable_write or enable_seek
+
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
!if (enable_write + enable_seek) > 0 {
tya
} else { ;enable_write or enable_seek
lda #0
} ;enable_write or enable_seek
sec
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
+
lda sizehi
jsr copycache
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 rdwrfile
beq rdwrdone
} else { ;aligned_read
!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 (enable_write + enable_seek) > 0 {
ldx reqcmd
} ;enable_write or enable_seek
!if aligned_read = 0 {
;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
lda #0
sta adrlo
!if (enable_write + enable_seek) > 0 {
ldx #cmdread
} ;enable_write or enable_seek
+
} ;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 entries
bne +
lda istree
beq +
lda adrhi
pha
lda adrlo
pha
lda #>dirbuf
sta adrhi
lda #0
sta adrlo
txa
pha
lda #cmdread
sta command
;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 seekrdwr
!if aligned_read = 0 {
plp
} ;aligned_read
pla
tax
pla
sta adrlo
pla
sta adrhi
} ;allow_trees
;fetch data block and read/write it
ldy entries
+ inc entries
!if enable_seek = 1 {
txa ;cpx #cmdseek, but that would require php at top
beq +
} ;enable_seek
stx command
ldx dirbuf, y
lda dirbuf + 256, y
!if aligned_read = 0 {
php
} ;aligned_read
jsr seekrdwr
!if aligned_read = 0 {
plp
+ bcc +
} ;aligned_read
!if bounds_check = 1 {
dec blefthi
dec blefthi
} ;bounds_check
+ dec sizehi
dec sizehi
bne rdwrloop
unrdrvoff2 = 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 aligned_read = 0 {
;cache partial block offset
+ pla
sta bloklo
pla
sta blokhi
pla
sta sizehi
dec adrhi
dec adrhi
copycache
!if enable_seek = 1 {
ldy reqcmd
;cpy #cmdseek
beq ++
} ;enable_seek
tay
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
lda blkofflo
adc sizelo
sta blkofflo
lda blkoffhi
adc sizehi
and #$fd
sta blkoffhi
bcc rdwrdone ;always
} ;aligned_read
!if (enable_write + (bounds_check & aligned_read)) > 0 {
round clc
adc #$ff
txa
adc #1
and #$fe
rts
} ;enable_write or (bounds_check and aligned_read)
;no tricks here, just the regular stuff
seek sty step
asl phase
txa
asl
copy_cur tax
sta tmptrk
sec
sbc phase
beq +++
bcs +
eor #$ff
inx
bcc ++
+ sbc #1
dex
++ cmp step
bcc +
lda step
+ cmp #8
bcs +
tay
sec
+ txa
pha
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 #$13
- dex
bne -
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 = 1 {
checkpoll pla
sbc #1
bcs pollinv
failpoll pla
pla
pla
jmp nodisk
} ;poll_drive
readdirsel ldy #0
sty adrlo
!if allow_multi = 1 {
asl reqcmd
bcc seldrive
iny
seldrive lsr reqcmd
unrdrvsel = unrelocdsk + (* - reloc)
cmp DRV0EN, y
} ;allow_multi
!if poll_drive = 1 {
pha
lda #$FF
sec
unrdrvon1 = unrelocdsk + (* - reloc)
ldy MOTORON
pollinv pha
;watch for a real data prolog
--- ldy #(prolog_e - prolog - 1)
-- inc status
beq checkpoll ;loop max 65281+ times as worst-case
unrread2 = unrelocdsk + (* - reloc)
- lda Q6L
bpl --
eor prolog,y
bne ---
dey
bpl -
pla
pla
} ;poll_drive
readdirsec
!if allow_trees = 0 {
readdirsect
} ;allow_trees
ldy #>dirbuf
!if allow_trees = 1 {
readdirsect
} ;allow_trees
sty adrhi
ldy #cmdread
sty command
;convert block number to track/sector
seekrdwr
unrdrvon2 = unrelocdsk + (* - reloc)
ldy MOTORON
lsr
txa
ror
lsr
lsr
sta phase
txa
and #3
php
asl
plp
rol
sta reqsec
jsr readadr
;if track does not match, then seek
ldx curtrk
cpx phase
beq checksec
jsr seek
;force sector mismatch
lda #$ff
;match or read/write sector
checksec jsr cmpsec
inc reqsec
inc reqsec
;force sector mismatch
cmpsecrd lda #$ff
cmpsec
!if enable_write = 1 {
ldy command
cpy #cmdwrite ;we need Y=2 below
beq encsec
} ;enable_write
cmpsec2 cmp reqsec
beq readdata
jsr readadr
beq cmpsec2
;read sector data
readdata 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
!if check_chksum = 1 {
bne -
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 -
readret 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 writenib3 ;(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 writenib3 ;(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 cmp ($ea, x) ;6 cycles
writenib2 cmp ($ea, x) ;6 cycles
writenib3
unrslot4=unrelocdsk+(*-reloc)
ldx #$d1 ;2 cycles
writenib4 sta Q6H, x ;5 cycles
ora Q6L, x ;4 cycles
rts ;6 cycles
prolog !byte $ad, $aa, $d5
prolog_e
epilog !byte $ff, $eb, $aa, $de
epilog_e
} ;enable_write
codeend
bit2tbl = (* + 255) & -256
nibtbl = bit2tbl + 86
!if enable_write = 1 {
xlattbl = nibtbl + 106
dataend = xlattbl + 64
} else { ;enable_write
dataend = nibtbl + 106
} ;enable_write
} ;enable_floppy
} ;reloc
unrelochdd
!pseudopc reloc {
hddrdwrpart
!if override_adr = 1 {
!if save_auxscr = 1 {
jmp svhddrdwrfile
} else { ;save_auxscr
jmp hddrdwrfile
} ;save_auxscr
} ;override_adr
;read volume directory key block
;self-modified by init code
hddopendir
!if save_auxscr = 1 {
jsr flipscratch
jsr +
jmp flipscratch
+
}
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
;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 #<(hdddirbuf + NAME_LENGTH)
sta bloklo
lda #>(hdddirbuf + NAME_LENGTH)
sta blokhi
hddnextent ldy #0
!if might_exist = 1 {
sty status
} ;might_exist
lda (bloklo), y
!if might_exist = 1 {
;skip deleted entries without counting
and #MASK_ALL
beq ++
} ;might_exist
;remember type
;now bits 5-4 are represented by carry (subdirectory), sign (sapling)
hddsavetype
asl
asl
;now bits 5-3 are represented by carry (subdirectory), sign (sapling),
;overflow (seedling), and sign+overflow (tree)
!if allow_trees = 1 {
sta treeidx
bit treeidx
} ;allow_trees
php
;match name lengths before attempting to match names
lda (bloklo), y
and #$0f
tax
inx
!byte $2c ;mask lda, y on first pass
- lda (bloklo), y
cmp (namlo), y
beq hddfoundname
;match failed, check if any directory entries remain
plp
+
!if might_exist = 1 {
dec entries
bne ++
inc status
rts
} ;might_exist
;move to next directory in this block, if possible
++ 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 #<(hdddirbuf + $1ff) ;4 + ($27 * $0d)
lda blokhi
sbc #>(hdddirbuf + $1ff)
bcc 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
bcc hddfirstent
hddfoundname iny
dex
bne -
!if allow_trees = 1 {
stx treeidx
stx istree
} ;allow_trees
stx entries
stx blkofflo
stx blkoffhi
!if enable_write = 1 {
ldy reqcmd
cpy #cmdwrite ;control carry instead of zero
bne +
;round requested size up to nearest block if writing
!if aligned_read = 0 {
php
} ;aligned_read
lda sizelo
ldx sizehi
jsr hddround
sta sizehi
!if aligned_read = 0 {
plp
} ;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
} else { ;enable_write or aligned_read
sta blefthi
} ;enable_write or aligned_read
dey ;EOF_LO
lda (bloklo), y
!if (enable_write + aligned_read) > 0 {
;round file size up to nearest block if writing without aligned reads
;or always if using aligned reads
!if aligned_read = 0 {
bcc +
} ;aligned_read
jsr hddround
tax
lda #0
!if aligned_read = 0 {
sta sizelo
} ;aligned_read
+ stx blefthi
} ;enable_write or aligned_read
!if aligned_read = 0 {
sta bleftlo
} ;aligned_read
} else { ;bounds_check
!if enable_write = 1 {
!if aligned_read = 0 {
bcc +
lda #0
sta sizelo
+
} ;aligned_read
} ;enable_write
} ;bounds_check
;cache AUX_TYPE (load offset for binary files)
!if override_adr = 0 {
pla
tax
ldy #AUX_TYPE
lda (bloklo), y
pha
iny
lda (bloklo), y
pha
txa
pha
} ;override_adr
;cache KEY_POINTER
ldy #KEY_POINTER
lda (bloklo), y
tax
sta hdddirbuf
iny
lda (bloklo), y
sta hdddirbuf + 256
;read index block in case of sapling
plp
!if (allow_subdir + allow_trees) > 0 {
bpl hddrdwrfile
!if allow_subdir = 1 {
php
} ;allow_subdir
!if allow_trees = 1 {
ldy #>hdddirbuf
bvc +
ldy #>hddtreebuf
sty istree
+
} ;allow_trees
jsr hddreaddirsect
!if allow_subdir = 1 {
plp
} ;allow_subdir
} ;allow_subdir
;restore load offset
hddrdwrfile
!if override_adr = 1 {
ldx ldrhi
lda ldrlo
} else { ;override_adr
pla
tax
pla
} ;override_adr
!if allow_subdir = 1 {
;check file type and fake size and load address for subdirectories
bcc +
ldy #2
sty sizehi
ldx #>hdddirbuf
lda #<hdddirbuf
+
} ;allow_subdir
sta adrlo
stx adrhi
;set requested size to min(length, requested size)
!if aligned_read = 0 {
!if bounds_check = 1 {
lda bleftlo
tay
cmp sizelo
lda blefthi
tax
sbc sizehi
bcs hddcopyblock
sty sizelo
stx sizehi
} ;bounds_check
hddcopyblock
!if (enable_write + enable_seek) > 0 {
ldy reqcmd
;cpy #cmdseek
beq +
} ;enable_write or enable_seek
!if allow_aux = 1 {
ldx auxreq
jsr hddsetaux
} ;allow_aux
!if (enable_write + enable_seek) > 0 {
dey ;cpy #cmdread
!if enable_write = 1 {
bne hddrdwrloop
} ;enable_write
} ;enable_write or enable_seek
+
lda blkofflo
tax
ora blkoffhi
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
!if (enable_write + enable_seek) > 0 {
tya
} else { ;enable_write or enable_seek
lda #0
} ;enable_write or enable_seek
sec
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
+
lda sizehi
jsr hddcopycache
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 hddrdwrfile
beq hddrdwrdone
} else { ;aligned_read
!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
hddrdwrloop
!if (enable_write + enable_seek) > 0 {
ldx reqcmd
} ;enable_write or enable_seek
!if aligned_read = 0 {
;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 #>hddencbuf
sta adrhi
lda #0
sta adrlo
!if (enable_write + enable_seek) > 0 {
ldx #cmdread
} ;enable_write or enable_seek
+
} ;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 entries
bne +
lda istree
beq +
lda adrhi
pha
lda adrlo
pha
lda #>hdddirbuf
sta adrhi
lda #0
sta adrlo
txa
pha
lda #cmdread
sta command
;fetch tree data block and read it
ldy treeidx
inc treeidx
ldx hddtreebuf, y
lda hddtreebuf + 256, y
!if aligned_read = 0 {
php
} ;aligned_read
jsr hddseekrdwr
!if aligned_read = 0 {
plp
} ;aligned_read
pla
tax
pla
sta adrlo
pla
sta adrhi
} ;allow_trees
;fetch data block and read/write it
ldy entries
+ inc entries
!if enable_seek = 1 {
txa ;cpx #cmdseek, but that would require php at top
beq +
} ;enable_seek
stx command
ldx hdddirbuf, y
lda hdddirbuf + 256, y
!if aligned_read = 0 {
php
} ;aligned_read
jsr hddseekrdwr
!if aligned_read = 0 {
plp
+ bcc +
} ;aligned_read
inc adrhi
inc adrhi
!if bounds_check = 1 {
dec blefthi
dec blefthi
} ;bounds_check
+ dec sizehi
dec sizehi
bne hddrdwrloop
!if aligned_read=0 {
bcc +
lda sizelo
bne hddrdwrloop
} ;aligned_read
hddrdwrdone
!if allow_aux = 1 {
ldx #0
hddsetaux sta CLRAUXRD, x
sta CLRAUXWR, x
} ;allow_aux
rts
!if save_auxscr = 1 {
svhddrdwrfile
jsr flipscratch
jsr hddrdwrfile
flipscratch ldx auxreq
beq flipdone
dex
stx adrlo
lda #4
flipouter sta adrhi
pha
ldy #$F8
flipinner lda (adrlo),y
tax
sta SETAUXRD
sta SETAUXWR
lda (adrlo),y
pha
txa
sta (adrlo),y
sta CLRAUXWR
sta CLRAUXRD
pla
sta (adrlo),y
iny
bne flipnext
ldy #$78
flipnext cpy #$80
bne flipinner ; if eq, sets carry
pla
adc #0 ; carry set above
cmp #8
bne flipouter
flipdone rts
}
!if aligned_read = 0 {
;cache partial block offset
+ pla
sta bloklo
pla
sta blokhi
pla
sta sizehi
hddcopycache
!if enable_seek = 1 {
ldy reqcmd
;cpy #cmdseek
beq ++
} ;enable_seek
tay
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
lda blkofflo
adc sizelo
sta blkofflo
lda blkoffhi
adc sizehi
and #$fd
sta blkoffhi
bcc hddrdwrdone
} ;aligned_read
!if (enable_write + (bounds_check & aligned_read)) > 0 {
hddround clc
adc #$ff
txa
adc #1
and #$fe
rts
} ;enable_write or (bounds_check and aligned_read)
hddreaddirsel ldy #0
sty adrlo
!if might_exist = 1 {
sty status
} ;might_exist
!if allow_multi = 1 {
asl reqcmd
lsr reqcmd
} ;allow_multi
hddreaddirsec
!if allow_trees = 0 {
hddreaddirsect
} ;allow_trees
ldy #>hdddirbuf
!if allow_trees = 1 {
hddreaddirsect
} ;allow_trees
sty adrhi
ldy #cmdread
sty command
hddseekrdwr stx bloklo
sta blokhi
unrunit=unrelochdd+(*-reloc)
lda #$d1
sta unit
!if (allow_aux + save_auxscr) > 1 {
ldx auxreq
jsr hddsetaux
} ;allow_aux
unrentry=unrelochdd+(*-reloc)
jmp $d1d1
hddcodeend
hdddataend
} ;reloc
;[music] you can't touch this [music]
;math magic to determine ideal loading address, and information dump
!ifdef PASS2 {
} else { ;PASS2
!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
!pseudopc ((dataend + $ff) & -256) {
dirbuf = *
}
encbuf=dirbuf + $200
!if allow_trees = 1 {
treebuf = encbuf + $200
} ;allow_trees
} ;load_high
} else { ;reloc
!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
!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
!warn "floppy encbuf: ", encbuf, "-", encbuf + $1ff
!if allow_trees = 1 {
!warn "floppy treebuf: ", treebuf, "-", treebuf + $1ff
} ;allow_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
hddtreebuf = hdddirbuf - $200
} ;aligned_read
} ;allow_trees
} else { ;load_high
!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
hddtreebuf = hdddirbuf + $200
} ;aligned_read
} ;allow_trees
} ;load_high
} else { ;reloc
!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
hddtreebuf = hdddirbuf - $200
} ;aligned_read
} ;allow_trees
} else { ;load_high
!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
hddtreebuf = hdddirbuf + $200
} ;aligned_read
} ;allow_trees
} ;load_high
} ;reloc
!if verbose_info = 1 {
!warn "hdd code: ", reloc, "-", hddcodeend - 1
!warn "hdd dirbuf: ", hdddirbuf, "-", hdddirbuf + $1ff
!if aligned_read = 0 {
!warn "hdd encbuf: ", hddencbuf, "-", hddencbuf + $1ff
} ;aligned_read
!if allow_trees = 1 {
!warn "hdd treebuf: ", hddtreebuf, "-", hddtreebuf + $1ff
} ;allow_trees
!warn "hdd driver start: ", unrelochdd - init
} ;verbose_info
} ;PASS2
readbuff
!byte $D3,$C1,$CE,$A0,$C9,$CE,$C3,$AE