1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
; =============================================================================
; 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
|