Getting closer to the treasure - two steps forward, one step back
( I should point out that the code I've been writing has undergone major changes, mostly factoring, isolating 32 bit arithmetic and helper, and the like, in the interest of code size. And sanity. I'm not going to go through all the gory details here, but I will post a finished listing at the end of this series. Which is looking as far away as it was when I started!)
Our hero has been cheerfully following the yellow bricks in the road, but he's run into a problem. He's got to the end of a cluster before he's reached the end of the directory. There are more files but he doesn't know anything about them. Somehow, in
fs_find_next he has to advance to the next cluster.
The problem is, it almost certainly isn't the _next_ cluster. By the time the first directory cluster is filled up, there are potentially dozens of files written before the new directory cluster is required, each using at least one cluster.
We could, potentially, log every cluster of interest as we go along, but that sounds a painful way to do it (though it might be worth it). Instead, we'll use a generic routine to get the next cluster. Other routines will find this handy.
The only thing we know is the sector we're currently in. That's in LBA when we need it, filled in by each iteration through
fs_get_next. In there, we're keeping track of how many records we've looked at, grabbing a new sector whenever we get to the end of one (the sectors in a cluster are always sequential). When we get to the eighth sector, we need a new cluster... which is where we left things last time.
Here's the bit that's doing the work:
Code: Select all
fs_find_next:
; else get the next record
inc fs_dir_number ; have we reached record $10?
lda fs_dir_number
cmp #$10
bne fs_ff_01 ; try the next entry
inc fs_dir_sector ; otherwise we need the next sector
lda fs_dir_sector
cmp #$8 ; have we run out of cluster?
bne fs_fn_12
jsr fs_next_cluster ; if so, we need more cluster in lba
stz fs_dir_number ; clear the record and sector count
stz fs_dir_sector
bra fs_fn_15 ; and round we go
fs_fn_12:
; increment the lba
which it does by handing the problem to
fs_next_cluster...
Code: Select all
bss
fat_record: ds 2
code
fs_next_cluster: ; the current sector is in lba
jsr sec_to_cluster ; so find out the sector number
jsr clus_to_fat_rec ; convert it to a FAT record
; remembering the offset by two!
; so now we have the FAT sector and an index into transient pointing
; to the FAT record we need, so get the sector on board
jsr cf_set_lba
jsr cf_read
; now we can read the FAT record from Transient
ldy #0
fs_nc_1:
lda (fat_record),y
sta lba,y
iny
cpy #4
bne fs_nc_1
; we're on the home straight, all we have to do is convert this
; record number to a sector number
jsr clus_to_1st_sec ; leaving the sector number in lba
rts
That takes a deep breath and gets on with things. First it asks
sec_to_cluster to tell it which cluster it's in. That it does by applying this equation:
Code: Select all
cluster = (sector - cluster_begin_lba) / sectors_per_cluster
(and in my lazy code, it assumes that sectors_per_cluster is always 8 ).
Now it knows the cluster, it can find its entry in the FAT. It needs to get the correct sector into transient, and an offset into the transient area to see the right data.
clus_to_fat_record is moderately complex:
Code: Select all
clus_to_fat_rec:
LYA two
jsr u32_add ; lba = lba + 2 = record number, but that
; could be more than fits in a sector
; there are 128 records per sector (four bytes each)
stz fat_record+1
lda lba
and #$7f ; extract lower seven bits
; multiply by four
asl a ; this doesn't affect the high byte
asl a ; but this does
sta fat_record
rol fat_record+1
clc ; now add transient to it
lda fat_record
adc # lo transient
sta fat_record
lda fat_record+1
adc # hi transient
sta fat_record+1 ; so we're pointing to the right place in
; transient, even though we haven't loaded
; the sector
; now sort out the sector where the record is
; sector = (lba >> 7) + fat_begin_lba
ldy #7
fs_sf_1:
lsr lba+3
ror lba+2
ror lba+1
ror lba+0
dey
bne fs_sf_1 ; not the speediest, but small
LYA fat_begin_lba
jsr u32_add
rts
We start by adding two - remember the offset between the clusters and their pointers in the FAT, and then, as we have four bytes per entry, multiply by four. Then we add the address of transient to generate a pointer to the record (though it's not valid yet; we haven't loaded the sector).
To decide the correct sector to load, we divide the current contents of the LBA (the cluster plus 2) by 128, and add
fat_begin_lba. Then we can return with LBA holding a sector number and
fat_record containing an offset into the FAT.
When we return, we can load the sector directly, read the value of the FAT record, and from there use
clus_to_1st_sec to convert our cluster number to the first sector:
Code: Select all
sector = ((record - 2) * sectors_per_cluster) + cluster_begin_lba
And when we finally find our way back
fs_get_next, we already have the directory sector's next clusters' first sector loaded, and it can proceed as normal.
And here's what we get. I haven't done anything significant about the actual data in the directory yet; that will be next time. But this output shows the sector number between each block of entries; you can see where it suddenly leaps from 00000FC7 to 00046650; that's how far away the second cluster of the root directory is.
Code: Select all
00000800
00000820
00000FC0
$0220 45 43 55 20 20 20 20 20 43 20 20 20 00 8A 21 60 ECU C ..!`
$0240 E5 4E 54 49 54 4C 7E 31 20 20 20 10 00 3E 08 60 .NTITL~1 ..>.`
$0280 54 45 53 54 20 20 20 20 20 20 20 10 00 3E 08 60 TEST ..>.`
$02C0 45 45 50 52 4F 4D 20 20 43 20 20 20 00 96 21 60 EEPROM C ..!`
$0300 47 52 41 50 48 49 43 53 43 20 20 20 00 A1 21 60 GRAPHICSC ..!`
$0340 49 31 38 4E 20 20 20 20 43 20 20 20 00 AC 21 60 I18N C ..!`
$0380 4D 41 49 4E 20 20 20 20 43 20 20 20 00 B8 21 60 MAIN C ..!`
$03C0 53 45 52 49 41 4C 20 20 43 20 20 20 00 C3 21 60 SERIAL C ..!`
00000FC1
$0200 53 53 44 31 33 30 39 20 43 20 20 20 00 07 22 60 SSD1309 C .."`
$0240 53 59 53 4D 45 4D 20 20 43 20 20 20 00 12 22 60 SYSMEM C .."`
$02A0 46 41 54 5F 46 49 7E 31 50 44 46 20 00 7B 1D 77 FAT_FI~1PDF .{.w
$0300 53 4C 49 44 45 53 7E 31 50 44 46 20 00 87 1D 77 SLIDES~1PDF ...w
$0380 55 4E 49 54 31 30 7E 31 50 44 46 20 00 9C 1D 77 UNIT10~1PDF ...w
$03E0 53 4C 49 44 45 53 7E 32 50 44 46 20 00 AD 1D 77 SLIDES~2PDF ...w
00000FC2
$0260 55 4E 49 54 31 30 7E 32 50 44 46 20 00 C1 1D 77 UNIT10~2PDF ...w
$02E0 53 52 41 4D 5F 42 7E 31 50 44 46 20 00 0A 20 77 SRAM_B~1PDF .. w
$0340 43 46 5F 34 34 5F 7E 31 50 44 46 20 00 22 20 77 CF_44_~1PDF ." w
$03A0 43 46 5F 34 34 5F 7E 32 50 44 46 20 00 2E 20 77 CF_44_~2PDF .. w
00000FC3
$0200 36 35 30 32 5F 43 7E 31 50 44 46 20 00 3A 20 77 6502_C~1PDF .: w
$0260 43 46 5F 42 4F 41 7E 31 50 44 46 20 00 4E 20 77 CF_BOA~1PDF .N w
$02E0 36 35 30 32 41 4E 7E 31 50 44 46 20 00 5E 20 77 6502AN~1PDF .^ w
$0340 4E 45 4F 4E 36 35 7E 31 41 53 4D 20 00 6A 20 77 NEON65~1ASM .j w
$0380 49 44 45 20 20 20 20 20 50 44 46 20 00 74 20 77 IDE PDF .t w
$03E0 46 41 54 33 32 46 7E 31 50 44 46 20 00 82 20 77 FAT32F~1PDF .. w
00000FC4
$0220 46 20 20 20 20 20 20 20 50 44 46 20 00 95 20 77 F PDF .. w
$0280 48 45 58 43 4F 4E 7E 31 50 44 46 20 00 AA 20 77 HEXCON~1PDF .. w
$02C0 31 20 20 20 20 20 20 20 50 44 46 20 00 C0 20 77 1 PDF .. w
$0320 36 35 30 32 5F 43 7E 32 50 44 46 20 00 04 21 77 6502_C~2PDF ..!w
$0380 5A 38 30 2D 44 4F 7E 31 50 44 46 20 00 18 21 77 Z80-DO~1PDF ..!w
$03C0 57 36 35 43 32 32 20 20 50 44 46 20 00 27 21 77 W65C22 PDF .'!w
00000FC5
$0200 49 53 36 32 43 32 35 36 50 44 46 20 00 3E 21 77 IS62C256PDF .>!w
$0260 53 59 4E 45 52 54 7E 31 50 44 46 20 00 4A 21 77 SYNERT~1PDF .J!w
$02A0 53 4E 37 34 48 43 7E 31 50 44 46 20 00 7D 21 77 SN74HC~1PDF .}!w
$0320 56 49 56 41 4C 44 7E 31 44 45 42 20 00 B5 21 77 VIVALD~1DEB ..!w
$0360 38 31 34 30 34 39 20 20 50 44 46 20 00 92 2B 77 814049 PDF ..+w
$03C0 41 50 58 38 32 33 7E 31 50 44 46 20 00 A8 2B 77 APX823~1PDF ..+w
00000FC6
$0200 42 55 34 38 58 58 7E 31 50 44 46 20 00 C4 2B 77 BU48XX~1PDF ..+w
$0260 44 41 54 41 53 48 7E 31 50 44 46 20 00 19 2C 77 DATASH~1PDF ..,w
$02E0 44 41 54 41 53 48 7E 32 50 44 46 20 00 3D 2C 77 DATASH~2PDF .=,w
$0360 36 35 30 32 2D 4B 7E 31 5A 49 50 20 00 5B 2C 77 6502-K~1ZIP .[,w
$03C0 31 30 31 44 53 45 7E 31 50 44 46 20 00 67 2C 77 101DSE~1PDF .g,w
00000FC7
$0220 31 30 31 44 2D 54 7E 31 50 44 46 20 00 78 2C 77 101D-T~1PDF .x,w
$0280 46 43 49 2D 31 30 7E 31 50 44 46 20 00 88 2C 77 FCI-10~1PDF ..,w
$02E0 31 30 31 44 53 45 7E 32 50 44 46 20 00 96 2C 77 101DSE~2PDF ..,w
$0360 4E 45 57 53 4C 45 7E 31 50 44 46 20 00 A6 2C 77 NEWSLE~1PDF ..,w
$03E0 5A 47 36 35 30 32 7E 31 50 44 46 20 00 0C 2D 77 ZG6502~1PDF ..-w
00046650
$0260 48 49 52 4F 53 45 7E 31 50 44 46 20 00 18 2D 77 HIROSE~1PDF ..-w
$02C0 36 39 33 31 32 30 7E 31 50 44 46 20 00 2C 2D 77 693120~1PDF .,-w
$0320 4A 41 45 49 53 30 7E 31 50 44 46 20 00 49 2D 77 JAEIS0~1PDF .I-w
$0360 4D 49 32 30 2D 32 7E 31 50 44 46 20 00 59 2D 77 MI20-2~1PDF .Y-w
$03A0 54 53 32 30 38 33 20 20 50 44 46 20 00 6A 2D 77 TS2083 PDF .j-w
$03E0 43 32 30 34 31 35 7E 31 50 44 46 20 00 92 2D 77 C20415~1PDF ..-w
00046651
$0240 31 30 31 44 2D 54 7E 32 50 44 46 20 00 9F 2D 77 101D-T~2PDF ..-w
$0280 43 46 53 20 20 20 20 20 50 44 46 20 00 AF 2D 77 CFS PDF ..-w
$+
We are close to the treasure, but before that, next time I'll take a look at the directory entry in more detail.
Neil