diff options
| author | user <user@clank> | 2026-07-16 12:20:57 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-07-16 12:20:57 +0200 |
| commit | 4f2d40ca35e0e39886dc881d06256fc25ba27a77 (patch) | |
| tree | 368474d3d24a2480b45c0efd8ffe0b7ee018b879 /src/fs.asm | |
| parent | fs rewrite stage 1: persistent block device (bounce buffer, cart SRAM) (diff) | |
| download | gbos-4f2d40ca35e0e39886dc881d06256fc25ba27a77.tar.gz gbos-4f2d40ca35e0e39886dc881d06256fc25ba27a77.tar.xz gbos-4f2d40ca35e0e39886dc881d06256fc25ba27a77.zip | |
fs rewrite stage 2: inodes + root directory (block-based, persistent)
- fs.asm: a real block filesystem on the persistent block device - superblock,
block/inode bitmaps, a 32-entry inode table (type, size, 8 direct block
pointers -> files up to 2 KiB), and a root directory of 16-byte entries.
Metadata cached in WRAMX; one-block data cache streams file/dir blocks.
- same syscall interface (open/getb/putb/list/remove) -> tools unchanged;
ls now enumerates until flist() runs out (16 files, was hardcoded 8).
- old 8-slot WRAM FS removed; cart RAM partitioned: process banks 0-7, disk 8-11.
- two register-clobber bugs fixed: alloc_block/alloc_inode returned the
bitmap-block number (write_bitmap clobbers C); db_use loaded the wrong block
on a transition (db_flush->write_block clobbers C) -> multi-block files broke.
- verified: 10+ files, multi-block (300-byte) files, delete, and persistence
across reboots. Debug 'blk' disk tool retained (fill/peek).
- README: document the block filesystem.
Diffstat (limited to 'src/fs.asm')
| -rw-r--r-- | src/fs.asm | 804 |
1 files changed, 599 insertions, 205 deletions
@@ -1,193 +1,568 @@ ; ============================================================================= -; fs.asm - a tiny RAM filesystem in WRAMX ($D000-$DFFF, 4 KiB). +; fs.asm - a small block-based filesystem (inodes + a root directory) on the +; persistent block device (blk.asm). Same syscall interface as before +; (open/close/getb/putb/list/remove) so the tools and libc are unchanged. ; -; 8 fixed slots of 512 bytes: name[8] (first byte 0 = free) + len[2] + data[502]. -; Slot i base = $D000 + i*512 -> high = $D0 + i*2, low = $00. -; Because WRAMX is always mapped (DMG) and the caller's buffers live in the -; mapped $A000 window, the kernel can copy between them directly. +; Bitmaps (block 1) and the inode table (blocks 2-3) are cached in WRAMX; file +; and directory data stream through fs_datbuf / fs_dirbuf. Metadata bitmap +; writes are write-through; inode writes are flushed on close. ; ============================================================================= INCLUDE "include/gbos.inc" SECTION "fs", ROM0 ; ----------------------------------------------------------------------------- -; FsSlotBase - in: A = slot (0..7) out: HL = slot base. (A clobbered) +; small helpers ; ----------------------------------------------------------------------------- -FsSlotBase:: - add a ; slot*2 - add HIGH(FS_BASE) ; + $D0 +zero256: ; HL = buffer; zero 256 bytes + ld b, 0 + xor a +.z + ld [hl+], a + dec b + jr nz, .z + ret + +; inode_ptr - A = inode -> HL = &inode in fs_inobuf (= fs_inobuf + inode*16) +inode_ptr:: + ld c, a + and $0F + swap a + ld l, a ; (inode & 15) << 4 + ld a, c + swap a + and $0F ; inode >> 4 + add HIGH(fs_inobuf) ld h, a - ld l, 0 + ret + +; write_inode - A = inode ; flush the inode's block (2 or 3) to disk +write_inode:: + cp 16 + jr nc, .hi + ld hl, fs_inobuf + ld a, BLK_INODE0 + jp write_block +.hi + ld hl, fs_inobuf + 256 + ld a, BLK_INODE0 + 1 + jp write_block + +; bit_addr - A = index, HL = bitmap base -> HL = &byte, E = mask(1<<bit) +bit_addr: + ld c, a + srl a + srl a + srl a ; index/8 + add l + ld l, a + ld a, h + adc 0 + ld h, a + ld a, c + and 7 + ld e, 1 +.sh + or a + jr z, .done + sla e + dec a + jr .sh +.done ret ; ----------------------------------------------------------------------------- -; FsNameEq - compare the <=8-byte NUL-terminated names at DE and HL. -; out: Z set if equal. preserves DE, HL. +; block / inode allocators (bitmaps live in fs_bmbuf, write-through to block 1) ; ----------------------------------------------------------------------------- -FsNameEq:: - push de +write_bitmap: + ld hl, fs_bmbuf + ld a, BLK_BITMAP + jp write_block + +; alloc_block -> A = block# (>=4) or 0 if the disk is full +alloc_block:: + ld c, BLK_DATA0 +.l + ld a, c + ld hl, fs_bmbuf + BM_BLOCKS + call bit_addr ; HL=&byte, E=mask + ld a, [hl] + and e + jr z, .found + inc c + ld a, c + cp FS_NBLOCKS + jr c, .l + xor a + ret +.found + ld a, [hl] + or e + ld [hl], a + ld a, c ; save block# (write_bitmap clobbers C) + push af + call write_bitmap + pop af + ret + +; free_block - A = block# +free_block:: + ld hl, fs_bmbuf + BM_BLOCKS + call bit_addr + ld a, e + cpl + ld e, a + ld a, [hl] + and e + ld [hl], a + jp write_bitmap + +; alloc_inode -> A = inode# (>=2) or 0 +alloc_inode:: + ld c, 2 +.l + ld a, c + ld hl, fs_bmbuf + BM_INODES + call bit_addr + ld a, [hl] + and e + jr z, .found + inc c + ld a, c + cp NINODES + jr c, .l + xor a + ret +.found + ld a, [hl] + or e + ld [hl], a + ld a, c ; save inode# (write_bitmap clobbers C) + push af + call write_bitmap + pop af + ret + +; free_inode - A = inode# +free_inode:: + ld hl, fs_bmbuf + BM_INODES + call bit_addr + ld a, e + cpl + ld e, a + ld a, [hl] + and e + ld [hl], a + jp write_bitmap + +; ----------------------------------------------------------------------------- +; data-block cache (one block in fs_datbuf; wFsCurBlk / wFsDirty) +; ----------------------------------------------------------------------------- +db_flush:: + ld a, [wFsDirty] + or a + ret z + xor a + ld [wFsDirty], a + ld a, [wFsCurBlk] + cp $FF + ret z + ld hl, fs_datbuf + jp write_block + +; db_use - A = block ; ensure that block is loaded in fs_datbuf +db_use:: + ld c, a + ld a, [wFsCurBlk] + cp c + ret z + push bc ; db_flush clobbers C (write_block does ld c,a) + call db_flush + pop bc + ld a, c + ld [wFsCurBlk], a + ld hl, fs_datbuf + jp read_block + +; ----------------------------------------------------------------------------- +; name compare: [HL] vs wFsNameBuf, <=15 bytes NUL-terminated -> Z if equal. +; preserves HL. +; ----------------------------------------------------------------------------- +name_eq: push hl - ld b, 8 -.cmp + ld de, wFsNameBuf + ld b, 15 +.c ld a, [de] cp [hl] jr nz, .ne - or a ; equal byte; if NUL, strings ended equal + or a jr z, .eq - inc de inc hl + inc de dec b - jr nz, .cmp + jr nz, .c .eq pop hl - pop de - xor a ; Z set + xor a ret .ne pop hl - pop de ld a, 1 - and a ; Z clear + and a ret +; entry_ptr - C = entry index -> HL = &fs_dirbuf[C*16] +entry_ptr: + ld a, c + swap a ; C*16 (C < 16) + ld hl, fs_dirbuf + add l + ld l, a + ret ; (fs_dirbuf is page-aligned, no carry) + +; load_rootdir - read the root directory's data block into fs_dirbuf +load_rootdir: + ld a, [fs_inobuf + 16 + I_BLOCKS] ; root inode (1) blocks[0] + ld hl, fs_dirbuf + jp read_block + +; write_rootdir - write fs_dirbuf back to the root directory's data block +write_rootdir: + ld a, [fs_inobuf + 16 + I_BLOCKS] + ld hl, fs_dirbuf + jp write_block + ; ----------------------------------------------------------------------------- -; FsFind - in: DE = name out: A = slot (0..7) or $FF. +; dir_find - name in wFsNameBuf -> A = inode (0 if not found) ; ----------------------------------------------------------------------------- -FsFind:: +dir_find:: + call load_rootdir ld c, 0 .l - ld a, c - call FsSlotBase ; HL = base - ld a, [hl] ; name[0] + call entry_ptr ; HL = &entry + ld a, [hl] ; entry.inode or a - jr z, .next ; free slot - call FsNameEq ; DE vs HL + jr z, .next + inc hl ; &name + call name_eq jr z, .found .next inc c ld a, c - cp FS_MAX_FILES + cp DIRENTS jr c, .l - ld a, $FF + xor a ret .found - ld a, c + dec hl ; back to entry base + ld a, [hl] ret ; ----------------------------------------------------------------------------- -; FsAllocSlot - out: A = free slot or $FF. +; dir_add - A = inode to link (name in wFsNameBuf) -> A = 1 ok / 0 dir full ; ----------------------------------------------------------------------------- -FsAllocSlot:: +dir_add:: + ld [wFsInode], a + call load_rootdir ld c, 0 .l + call entry_ptr + ld a, [hl] + or a + jr z, .free + inc c ld a, c - call FsSlotBase + cp DIRENTS + jr c, .l + xor a + ret +.free + ld a, [wFsInode] + ld [hl+], a ; entry.inode + ld de, wFsNameBuf ; copy the name + ld b, 15 +.cp + ld a, [de] + ld [hl+], a + inc de + dec b + jr nz, .cp + call write_rootdir + ld a, 1 + ret + +; ----------------------------------------------------------------------------- +; dir_remove - name in wFsNameBuf -> A = inode removed (0 if not found) +; ----------------------------------------------------------------------------- +dir_remove:: + call load_rootdir + ld c, 0 +.l + call entry_ptr ld a, [hl] or a + jr z, .next + inc hl + call name_eq jr z, .found +.next inc c ld a, c - cp FS_MAX_FILES + cp DIRENTS jr c, .l - ld a, $FF + xor a ret .found - ld a, c + dec hl ; entry base + ld a, [hl] + ld [wFsInode], a + xor a + ld [hl], a ; clear entry.inode + call write_rootdir + ld a, [wFsInode] ret ; ----------------------------------------------------------------------------- -; FsSetName - copy the name at DE into slot wFsSlot (<=8 bytes, incl. NUL). +; file_truncate - A = inode ; free all data blocks, size = 0 (cached inode) ; ----------------------------------------------------------------------------- -FsSetName:: - ld a, [wFsSlot] - call FsSlotBase ; HL = base (= name) - push de - ld b, 8 -.cp - ld a, [de] - ld [hl+], a +file_truncate:: + ld [wFsInode], a + call inode_ptr + ld a, l + add I_BLOCKS + ld l, a ; HL = &blocks[0] (fs_inobuf, no page cross) + ld b, NDIRECT +.fb + ld a, [hl] or a - jr z, .done - inc de + jr z, .skip + push bc + push hl + call free_block + pop hl + pop bc + xor a + ld [hl], a +.skip + inc hl dec b - jr nz, .cp -.done - pop de + jr nz, .fb + ; size = 0 + ld a, [wFsInode] + call inode_ptr + ld a, l + add I_SIZE + ld l, a + xor a + ld [hl+], a + ld [hl], a + ld a, [wFsInode] + jp write_inode + +; ----------------------------------------------------------------------------- +; format + mount +; ----------------------------------------------------------------------------- +fs_format:: + ; superblock (block 0) + ld hl, fs_datbuf + call zero256 + ld hl, fs_datbuf + ld a, SUPER_MAG0 + ld [hl+], a + ld a, SUPER_MAG1 + ld [hl+], a + ld a, SUPER_MAG2 + ld [hl+], a + ld a, SUPER_MAG3 + ld [hl+], a + ld a, FS_VERSION + ld [hl], a + ld a, BLK_SUPER + ld hl, fs_datbuf + call write_block + ; bitmaps (block 1): blocks 0-4 used, inodes 0-1 used + ld hl, fs_bmbuf + call zero256 + ld a, $1F + ld [fs_bmbuf + BM_BLOCKS], a + ld a, $03 + ld [fs_bmbuf + BM_INODES], a + call write_bitmap + ; inode table (blocks 2-3): zero, then inode 1 = root dir + ld hl, fs_inobuf + call zero256 + ld hl, fs_inobuf + 256 + call zero256 + ld hl, fs_inobuf + 16 ; inode 1 + ld a, IT_DIR + ld [hl], a ; I_TYPE + ld a, 1 + ld [fs_inobuf + 16 + I_NLINK], a + xor a + ld [fs_inobuf + 16 + I_SIZE], a ; size lo + ld a, 1 + ld [fs_inobuf + 16 + I_SIZE + 1], a ; size hi = 256 (one dir block) + ld a, BLK_DATA0 + ld [fs_inobuf + 16 + I_BLOCKS], a ; blocks[0] = block 4 + ld a, BLK_INODE0 + ld hl, fs_inobuf + call write_block + ld a, BLK_INODE0 + 1 + ld hl, fs_inobuf + 256 + call write_block + ; root dir data block (block 4): empty + ld hl, fs_dirbuf + call zero256 + ld a, BLK_DATA0 + ld hl, fs_dirbuf + jp write_block + +; fs_init - mount: format on first boot (magic/version check), load caches. +fs_init:: + ld a, $FF + ld [wFsCurBlk], a + xor a + ld [wFsDirty], a + ; check superblock + ld a, BLK_SUPER + ld hl, fs_datbuf + call read_block + ld hl, fs_datbuf + ld a, [hl+] + cp SUPER_MAG0 + jr nz, .fmt + ld a, [hl+] + cp SUPER_MAG1 + jr nz, .fmt + ld a, [hl+] + cp SUPER_MAG2 + jr nz, .fmt + ld a, [hl+] + cp SUPER_MAG3 + jr nz, .fmt + ld a, [hl] + cp FS_VERSION + jr z, .load +.fmt + call fs_format +.load + ld a, BLK_BITMAP + ld hl, fs_bmbuf + call read_block + ld a, BLK_INODE0 + ld hl, fs_inobuf + call read_block + ld a, BLK_INODE0 + 1 + ld hl, fs_inobuf + 256 + call read_block + ld a, $FF + ld [wFsCurBlk], a ret ; ----------------------------------------------------------------------------- -; OFPtr - in: A = fd out: HL = &open-file entry. preserves DE. +; OFPtr - A = fd -> HL = &open-file entry. preserves DE. ; ----------------------------------------------------------------------------- OFPtr:: push de ld h, 0 ld l, a ld d, h - ld e, l ; DE = fd - add hl, hl ; 2 - add hl, hl ; 4 + ld e, l + add hl, hl + add hl, hl add hl, de ; 5*fd ld de, wOFTable add hl, de pop de ret +; copy the NUL-terminated name at DE (process memory) into wFsNameBuf. +copy_name: + ld hl, wFsNameBuf + ld b, 15 +.c + ld a, [de] + ld [hl+], a + or a + ret z + inc de + dec b + jr nz, .c + xor a + ld [hl], a + ret + ; ============================================================================= ; sys_open(DE = name, B = mode 0=read/1=write) -> A = fd or $FF ; ============================================================================= sys_open:: ld a, b ld [wFsMode], a - call FsFind ; A = slot or $FF (DE = name) - ld [wFsSlot], a + call copy_name ; name -> wFsNameBuf (before any block I/O) + call dir_find ; A = inode or 0 + ld [wFsInode], a ld a, [wFsMode] or a jr nz, .write - ; --- read mode: must exist --- - ld a, [wFsSlot] - cp $FF + ; --- read --- + ld a, [wFsInode] + or a jr z, .fail - jr .alloc + jr .allocof .write - ; --- write mode: create or truncate --- - ld a, [wFsSlot] - cp $FF + ld a, [wFsInode] + or a jr nz, .trunc - call FsAllocSlot - cp $FF + ; --- create --- + call alloc_inode + or a jr z, .fail - ld [wFsSlot], a - call FsSetName ; DE still = name -.trunc - ld a, [wFsSlot] - call FsSlotBase - ld a, l - add FS_LEN - ld l, a ; HL = &len + ld [wFsInode], a + call inode_ptr ; HL = &inode + push hl + ld b, 16 xor a +.zi ld [hl+], a - ld [hl], a ; len = 0 -.alloc - ; --- allocate an open-file entry --- + dec b + jr nz, .zi + pop hl + ld a, IT_FILE + ld [hl], a + inc hl + ld a, 1 + ld [hl], a ; nlink + ld a, [wFsInode] + call write_inode + ld a, [wFsInode] + call dir_add + or a + jr z, .fail + jr .allocof +.trunc + ld a, [wFsInode] + call file_truncate +.allocof ld c, 0 -.of +.ofl ld a, c - call OFPtr ; HL = &OF[c] + call OFPtr ld a, [hl] or a jr z, .gotof inc c ld a, c cp OF_MAX - jr c, .of + jr c, .ofl .fail ld a, $FF ret .gotof ld a, 1 ld [hl+], a ; inuse - ld a, [wFsSlot] - ld [hl+], a ; slot + ld a, [wFsInode] + ld [hl+], a ; inode ld a, [wFsMode] ld [hl+], a ; mode xor a @@ -197,12 +572,24 @@ sys_open:: ret ; ============================================================================= -; sys_close(B = fd) +; sys_close(B = fd) - flush data + inode, free the descriptor ; ============================================================================= sys_close:: ld a, b cp OF_MAX jr nc, .done + ld [wFsSlot], a ; save fd + call OFPtr + ld a, [hl] + or a + jr z, .done + inc hl + ld a, [hl] + ld [wFsInode], a + call db_flush + ld a, [wFsInode] + call write_inode + ld a, [wFsSlot] call OFPtr xor a ld [hl], a ; inuse = 0 @@ -217,7 +604,7 @@ sys_getb:: ld a, b cp OF_MAX jr nc, .eof - call OFPtr ; HL = OF entry + call OFPtr ld a, [hl] or a jr z, .eof @@ -225,44 +612,54 @@ sys_getb:: ld [wFsOFPtr], a ld a, h ld [wFsOFPtr+1], a - inc hl ; OF_SLOT + inc hl ld a, [hl] - ld [wFsSlot], a - inc hl ; OF_MODE + ld [wFsInode], a + inc hl inc hl ; OF_POS lo ld a, [hl+] ld e, a ld a, [hl] ld d, a ; DE = pos - ; file length -> BC - ld a, [wFsSlot] - call FsSlotBase ; HL = base + ; pos < size ? + ld a, [wFsInode] + call inode_ptr ld a, l - add FS_LEN + add I_SIZE ld l, a ld a, [hl+] ld c, a ld a, [hl] - ld b, a ; BC = len - ; pos >= len ? EOF + ld b, a ; BC = size ld a, e sub c ld a, d sbc b - jr nc, .eof - ; addr = base + FS_DATA + pos - ld a, [wFsSlot] - call FsSlotBase ; HL = base (low = 0) - ld a, FS_DATA - add e + jr nc, .eof ; pos >= size + ; data block = inode.blocks[pos/256 = D] + ld a, [wFsInode] + call inode_ptr + ld a, l + add I_BLOCKS + ld l, a + ld a, d + add l + ld l, a ; &blocks[blkidx] + ld a, [hl] + push de + call db_use + pop de + ; byte = fs_datbuf[E] + ld hl, fs_datbuf + ld a, e + add l ld l, a ld a, h - adc d - ld h, a ; HL = &data[pos] + adc 0 + ld h, a ld a, [hl] ld [wFsByte], a inc de ; pos++ - ; store pos back ld a, [wFsOFPtr] add OF_POS ld l, a @@ -274,15 +671,14 @@ sys_getb:: ld a, d ld [hl], a ld a, [wFsByte] - and a ; CF = 0 (success) + and a ; CF = 0 ret .eof scf ret ; ============================================================================= -; sys_putb(B = fd, E = byte) -- byte is in E, not A: the syscall dispatch -; clobbers A (it indexes the jump table with it). +; sys_putb(B = fd, E = byte) ; ============================================================================= sys_putb:: ld a, e @@ -300,42 +696,50 @@ sys_putb:: ld [wFsOFPtr+1], a inc hl ld a, [hl] - ld [wFsSlot], a + ld [wFsInode], a + inc hl inc hl - inc hl ; OF_POS lo ld a, [hl+] ld e, a ld a, [hl] ld d, a ; DE = pos - ; pos >= FS_MAX_DATA ? full - ld a, e - sub LOW(FS_MAX_DATA) + ; ensure inode.blocks[pos/256] is allocated + ld a, [wFsInode] + call inode_ptr + ld a, l + add I_BLOCKS + ld l, a ld a, d - sbc HIGH(FS_MAX_DATA) - jr nc, .done - ; addr = base + FS_DATA + pos - ld a, [wFsSlot] - call FsSlotBase - ld a, FS_DATA - add e + add l + ld l, a ; HL = &blocks[blkidx] + ld a, [hl] + or a + jr nz, .haveblk + push hl + push de + call alloc_block + pop de + pop hl + or a + jr z, .done ; disk full + ld [hl], a +.haveblk + ld a, [hl] ; data block# + push de + call db_use + pop de + ld hl, fs_datbuf + ld a, e + add l ld l, a ld a, h - adc d + adc 0 ld h, a ld a, [wFsByte] - ld [hl], a ; write byte - inc de ; pos++ - ; len = pos (sequential append) - ld a, [wFsSlot] - call FsSlotBase - ld a, l - add FS_LEN - ld l, a - ld a, e - ld [hl+], a - ld a, d ld [hl], a - ; store pos back + ld a, 1 + ld [wFsDirty], a + inc de ; pos++ ld a, [wFsOFPtr] add OF_POS ld l, a @@ -346,22 +750,67 @@ sys_putb:: ld [hl+], a ld a, d ld [hl], a + ; size = max(size, pos) (cached inode; flushed on close) + ld a, [wFsInode] + call inode_ptr + ld a, l + add I_SIZE + ld l, a + ld a, [hl+] + ld c, a + ld a, [hl] + ld b, a ; BC = size, HL at size+1 + ld a, c + sub e + ld a, b + sbc d + jr nc, .done ; size >= pos + dec hl ; size lo + ld a, e + ld [hl+], a + ld a, d + ld [hl], a .done xor a ret ; ============================================================================= -; sys_list(B = slot, DE = namebuf[8]) -> A = 1 if used (name copied), else 0 +; sys_list(B = index, DE = namebuf) -> A = 1 (name copied) / 0 (no more) +; index selects the index-th *used* entry in the root directory. ; ============================================================================= sys_list:: + ld a, e + ld [wFsOFPtr], a + ld a, d + ld [wFsOFPtr+1], a ld a, b - cp FS_MAX_FILES - jr nc, .no - call FsSlotBase ; HL = base (name) + ld [wFsSlot], a ; wanted index + call load_rootdir + ld c, 0 ; entry cursor + ld b, 0 ; used counter +.l + call entry_ptr ; HL = &entry ld a, [hl] or a - jr z, .no - ld b, 8 + jr z, .next + ld a, [wFsSlot] + cp b + jr z, .found + inc b +.next + inc c + ld a, c + cp DIRENTS + jr c, .l + xor a + ret +.found + inc hl ; &name (fs_dirbuf) + ld a, [wFsOFPtr] + ld e, a + ld a, [wFsOFPtr+1] + ld d, a ; DE = namebuf (process memory) + ld b, 15 .cp ld a, [hl+] ld [de], a @@ -370,82 +819,27 @@ sys_list:: jr nz, .cp ld a, 1 ret -.no - xor a - ret ; ============================================================================= ; sys_remove(DE = name) -> A = 0 ok / $FF not found ; ============================================================================= sys_remove:: - call FsFind - cp $FF + call copy_name + call dir_remove ; A = inode or 0 + or a jr z, .no - call FsSlotBase + ld [wFsInode], a + call file_truncate ; A = inode (frees data blocks) + ld a, [wFsInode] + call inode_ptr xor a - ld [hl], a ; name[0] = 0 -> free + ld [hl], a ; I_TYPE = free + ld a, [wFsInode] + call write_inode + ld a, [wFsInode] + call free_inode xor a ret .no ld a, $FF ret - -; ============================================================================= -; fs_init - mark all slots free, clear the OF table, seed a "readme" file. -; ============================================================================= -fs_init:: - ld c, 0 -.clr - ld a, c - call FsSlotBase - xor a - ld [hl], a ; name[0] = 0 - inc c - ld a, c - cp FS_MAX_FILES - jr c, .clr - ; zero the open-file table - ld hl, wOFTable - ld b, OF_MAX * OF_SIZE - xor a -.zof - ld [hl+], a - dec b - jr nz, .zof - ; seed slot 0 = "readme" - xor a - ld [wFsSlot], a - ld de, .rname - call FsSetName - ; copy content -> data - xor a - call FsSlotBase ; HL = base - ld a, FS_DATA - ld l, a ; HL = &data (base low = 0) - ld de, .rtext - ld bc, .rtext_end - .rtext -.ccpy - ld a, [de] - ld [hl+], a - inc de - dec bc - ld a, b - or c - jr nz, .ccpy - ; set len - xor a - call FsSlotBase - ld a, l - add FS_LEN - ld l, a - ld a, LOW(.rtext_end - .rtext) - ld [hl+], a - ld a, HIGH(.rtext_end - .rtext) - ld [hl], a - ret -.rname - db "readme", 0 -.rtext - db "welcome to gbos!", $0D, $0A - db "files live in RAM.", $0D, $0A -.rtext_end |
