Re: Adventures in FAT32 with 65c02
Posted: Sat Feb 14, 2026 6:42 am
Heh. My late mother, who was born in Yorkshire but moved to Scotland forty years ago, could famously spend a penny twice and still have change!
Neil
Neil
Code: Select all
Free cluster count $0001E553
Next free cluster $000000B0
Code: Select all
7EB0 AD 00 00 00 AE 00 00 00 AF 00 00 00 B0 00 00 00 ................
7EC0 FF FF FF 0F FF FF FF 0F 00 00 00 00 00 00 00 00 ................
Code: Select all
7FE0 00 00 00 00 72 72 41 61 52 E5 01 00 B1 00 00 00 ....rrAaR.......
7FF0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA ..............U.
Code: Select all
;-----------------------------------------------------------------------
; f_alloc
; Allocate a new cluster if one is available.
; Return new cluster number, or E_NO_SPACE if disc is full
; New cluster is returned in fsi_next_free
f_alloc:
LYA fsi_free_count
jsr u32_iszero
bne f_all_01
; disc is full
lda #E_NO_SPACE
jmp f_all_x
f_all_01:
; free count is not zero, so seek next cluster
; start looking at fsi_next_free
LYA fsi_next_free
jsr u32_tolba ; cluster is in lba
jsr clus_to_fat_sector ; replace cluster # with the fat 1 sector
LYA tmpq1
jsr u32_fromlba ; tmpq1 holds address of fat 1 sector
; but lba still holds it
LYA transient
jsr cf_read ; get the FAT sector into transient
lda fsi_next_free ; pass the low byte of cluster
and #$7f ; there are 128 records in a sector
f_all_05:
tax ; save record count
jsr clus_to_fat_rec ; fat_record points to record in transient
ldy #1
lda (fat_record)
ora (fat_record),y
iny
ora (fat_record),y
iny
ora (fat_record),y ; is this a zero?
beq f_all_10 ; yes!
; if non-zero, we have to try the next location
inx
txa
bpl f_all_05 ; 128 records per sample
; else we need a new sector. By checking for zeros until either
; we find one, or we get to the cluster start, we first check
; for empty space at the end of the disk and if that fails, at
; the beginning (finding the oldest deallocated cluster first).
LYA tmpq1 ; increment the fat sector
jsr u32_inc
jsr u32_tolba ; into lba
LYA cluster_begin_lba
jsr u32_cmp ; are we at the clusters yet?
bne f_all_06 ; no, carry on looking
; else disc is full
lda #E_NO_SPACE
jmp f_all_x
f_all_06:
LYA tmpq1
jsr u32_tolba
LYA transient
jsr cf_read ; read this next FAT sector
bra f_all_05 ; and back for more
f_all_10:
; if we get here, then we have found a zero.
; first we calculate the new cluster number. We need to know which
; FAT we're in
; tmpq1 contains the sector and fat_record the offset in transient
PRINT "Found a zero "
LYA fat_begin_lba
jsr u32_tolba
LYA sectors_per_fat
jsr u32_add ; the start of the second FAT
LYA tmpq1 ; check against current FAT
jsr u32_cmp ; are we less than that?
php
LYA tmpq1
jsr u32_tolba ; put the FAT sector in lba
plp ; retrieve the flags from the comparison
bcs f_all_12
; ah, we're in FAT 2
LYA sectors_per_fat
jsr u32_sub ; so move back to FAT1
f_all_12:
; convert the current fat sector and fat_record to the cluster
lda fat_record
pha
lda fat_record+1 ; save sector_ptr; pointer_to_clus
pha ; thumps it
jsr pointer_to_clus
LYA fsi_next_free ; save the result as next free cluster
jsr u32_fromlba
; change the fat entry to end-of-cluster
; we currently have the address of the FAT 1 sector in lba
pla
sta fat_record+1
pla
sta fat_record ; retrieve sector_ptr
ldy #0
lda #$ff ; set record to end-of-chain
sta (fat_record),y
iny
sta (fat_record),y
iny
sta (fat_record),y
iny
lda #$0f
sta (fat_record),y ; record = $0fffffff
; transient should now have the modified chain, so get it back in
; the two FAT copies
SHOWTRANS
LYA transient
;jsr cf_write ; FAT 1
LYA sectors_per_fat
jsr u32_add
LYA transient
;jsr cf_write ; FAT 2
;but there's still stuff to do
sec ; decrement fsi_free_count
lda fsi_free_count
sbc #1
sta fsi_free_count
lda fsi_free_count+1
sbc #0
sta fsi_free_count+1
lda fsi_free_count+2
sbc #0
sta fsi_free_count+2
lda fsi_free_count+3
sbc #0
sta fsi_free_count+3
LYA fsi_sector
jsr u32_tolba
LYA transient
jsr cf_read ; load FSI to transient
LYA fsi_free_count
jsr u32_tolba
LYA free_count_ptr
jsr u32_fromlba ; set updated free count
LYA fsi_next_free
jsr u32_tolba
LYA next_free_ptr
jsr u32_fromlba ; and updated next pointer
LYA fsi_sector ; get the FSI sector back
jsr u32_tolba
SHOWTRANS
LYA transient
;jsr cf_write ; and write it to disk
lda #E_NOERR ; ASSUME it worked
f_all_x:
rts
Code: Select all
f_alloc:
LYA fsi_free_count
jsr u32_iszero
bne f_all_01
; disc is full
lda #E_NO_SPACE
jmp f_all_x
f_all_01:
; free count is not zero, so seek next cluster
; start looking at fsi_next_free
LYA fsi_next_free
jsr u32_tolba ; cluster is in lba
jsr clus_to_fat_sector ; replace cluster # with the fat 1 sector
LYA tmpq1
jsr u32_fromlba ; tmpq1 holds address of fat 1 sector
; but lba still holds it
LYA transient
jsr cf_read ; get the FAT sector into transient
lda fsi_next_free ; pass the low byte of cluster
and #$7f ; there are 128 records in a sector
f_all_05:
tax ; save record count
jsr clus_to_fat_rec ; fat_record points to record in transient
ldy #1
lda (fat_record)
ora (fat_record),y
iny
ora (fat_record),y
iny
ora (fat_record),y ; is this a zero?
beq f_all_10 ; yes!
; if non-zero, we have to try the next location
inx
txa
bpl f_all_05 ; 128 records per sample
; else we need a new sector. By checking for zeros until either
; we find one, or we get to the cluster start, we first check
; for empty space at the end of the disk and if that fails, at
; the beginning (finding the oldest deallocated cluster first).
LYA tmpq1 ; increment the fat sector
jsr u32_inc
jsr u32_tolba ; into lba
LYA cluster_begin_lba
jsr u32_cmp ; are we at the clusters yet?
bne f_all_06 ; no, carry on looking
; else disc is full
lda #E_NO_SPACE
jmp f_all_x
f_all_06:
LYA tmpq1
jsr u32_tolba
LYA transient
jsr cf_read ; read this next FAT sector
bra f_all_05 ; and back for more
f_all_10:
; if we get here, then we have found a zero.
; first we calculate the new cluster number. We need to know which
; FAT we're in
; tmpq1 contains the sector and fat_record the offset in transient
;PRINT "Found a zero "
LYA fat_begin_lba
jsr u32_tolba
LYA sectors_per_fat
jsr u32_add ; the start of the second FAT
LYA tmpq1 ; check against current FAT
jsr u32_cmp ; are we less than that?
php
LYA tmpq1
jsr u32_tolba ; put the FAT sector in lba
plp ; retrieve the flags from the comparison
bcs f_all_12
; ah, we're in FAT 2
LYA sectors_per_fat
jsr u32_sub ; so move back to FAT1
f_all_12:
; convert the current fat sector and fat_record to the cluster
lda fat_record
pha
lda fat_record+1 ; save sector_ptr; pointer_to_clus
pha ; thumps it
jsr pointer_to_clus
LYA fsi_next_free ; save the result as next free cluster
jsr u32_fromlba
; change the fat entry to end-of-cluster
; we currently have the address of the FAT 1 sector in lba
pla
sta fat_record+1
pla
sta fat_record ; retrieve sector_ptr
ldy #0
lda #$ff ; set record to end-of-chain
sta (fat_record),y
iny
sta (fat_record),y
iny
sta (fat_record),y
iny
lda #$0f
sta (fat_record),y ; record = $0fffffff
; transient should now have the modified chain, so get it back in
; the two FAT copies
LYA tmpq1 ; <<<<<<<<<<<<<<<<<
jsr u32_tolba ; <<<<<<<<<<<<<<<<<
LYA transient
jsr cf_write ; FAT 1
LYA sectors_per_fat
jsr u32_add
LYA transient
jsr cf_write ; FAT 2
;but there's still more stuff to do
sec ; decrement fsi_free_count
lda fsi_free_count
sbc #1
sta fsi_free_count
lda fsi_free_count+1
sbc #0
sta fsi_free_count+1
lda fsi_free_count+2
sbc #0
sta fsi_free_count+2
lda fsi_free_count+3
sbc #0
sta fsi_free_count+3
LYA fsi_sector
jsr u32_tolba
LYA transient
jsr cf_read ; load FSI to transient
LYA fsi_free_count
jsr u32_tolba
LYA free_count_ptr
jsr u32_fromlba ; set updated free count
LYA fsi_next_free
jsr u32_tolba
LYA next_free_ptr
jsr u32_fromlba ; and updated next pointer
LYA fsi_sector ; get the FSI sector back
jsr u32_tolba
LYA transient
jsr cf_write ; and write it to disk
lda #E_NOERR ; ASSUME it worked
f_all_x:
rts
Code: Select all
fs_find_first:
LYA cwd
jsr u32_tolba ; cluster of current working directory
jsr clus_to_1st_sec
LYA transient ; set the current directory
jsr cf_read ; and load the first sector
stz fs_dir_number ; start with record zero
stz fs_dir_sector ; and the first sector
Code: Select all
LYA rootclus_ptr
jsr u32_tolba
LYA root_clus
jsr u32_fromlba ; save the root cluster
LYA cwd
jsr u32_fromlba ; and also to cwd