; ============================================================================= ; blk.asm - persistent block device on battery-backed cart RAM. ; ; The "disk" is cart-RAM banks FS_BANK0.. (256-byte blocks). Blocks are read ; and written through a WRAM bounce buffer, so only read_block/write_block ever ; touch cart-RAM banking; the rest of the filesystem works on WRAM buffers. ; ; block B lives in cart-RAM bank FS_BANK0 + B/32, at $A000 + (B & 31)*256. ; ; After each transfer we remap the current process's own RAM bank, so a syscall ; that does disk I/O leaves the caller's $A000 window exactly as it found it. ; ============================================================================= INCLUDE "include/gbos.inc" SECTION "blk", ROM0 ; A process's stack lives in the $A000 window too, so while the disk bank is ; mapped there NOTHING may touch the stack (no call/ret/push/pop). The block ; routines therefore inline the "restore my bank" step instead of calling it. ; (MACRO because it must not be a `call`.) MACRO restore_bank ld a, [wCurProc] add PROC_RAMB ld l, a ld a, [wCurProc+1] adc 0 ld h, a ld a, [hl] ld [MBC5_RAMB], a ENDM ; ----------------------------------------------------------------------------- ; read_block - in: A = block, HL = dest (WRAM buffer, 256 bytes) ; ----------------------------------------------------------------------------- read_block:: ld c, a srl a srl a srl a srl a srl a ; A = block / 32 add FS_BANK0 ld [MBC5_RAMB], a ; map the disk bank (stack now hidden!) ld a, c and 31 add $A0 ld d, a ld e, 0 ; DE = $A000 + (block&31)*256 ld b, 0 ; 256 bytes .cp ld a, [de] ld [hl+], a inc de dec b jr nz, .cp restore_bank ; inline - no stack while the disk bank is mapped ret ; ----------------------------------------------------------------------------- ; write_block - in: A = block, HL = src (WRAM buffer, 256 bytes) ; ----------------------------------------------------------------------------- write_block:: ld c, a srl a srl a srl a srl a srl a add FS_BANK0 ld [MBC5_RAMB], a ld a, c and 31 add $A0 ld d, a ld e, 0 ; DE = dest in the disk bank ld b, 0 .cp ld a, [hl+] ld [de], a inc de dec b jr nz, .cp restore_bank ret ; ============================================================================= ; [debug] block poke/peek syscalls, to validate the layer + persistence. ; ============================================================================= ; sys_bfill(B = block, E = byte) - fill the whole block with a byte sys_bfill:: ld a, e ld hl, wCopyBuf ld c, 0 .f ld [hl+], a dec c jr nz, .f ld a, b ld hl, wCopyBuf call write_block xor a ret ; sys_bpeek(B = block, E = offset) -> A = block[offset] sys_bpeek:: ld a, e ld [wFsByte], a ; stash offset ld a, b ld hl, wCopyBuf call read_block ld hl, wCopyBuf ld a, [wFsByte] add l ld l, a ld a, h adc 0 ld h, a ld a, [hl] ret