aboutsummaryrefslogtreecommitdiffstats
path: root/src/blk.asm
blob: 2be961ef982c6589809b011e22347dd6a30e78d9 (plain) (blame)
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