aboutsummaryrefslogtreecommitdiffstats
path: root/src/boot.asm
blob: f6490084d736c07ef2a1f3027f1d5792d026b1d0 (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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
; =============================================================================
; boot.asm - cartridge header, reset vectors, kernel entry & init
; =============================================================================
INCLUDE "include/gbos.inc"

; -----------------------------------------------------------------------------
; RST vectors. We reserve rst $30 as the syscall trap.
; -----------------------------------------------------------------------------
SECTION "rst00", ROM0[$00]
    ret
SECTION "rst30_syscall", ROM0[$30]
    jp SyscallTrap          ; user code does: ld c, SYS_x ; rst $30

; -----------------------------------------------------------------------------
; Interrupt vectors
; -----------------------------------------------------------------------------
SECTION "vblank", ROM0[$40]
    jp VBlankISR            ; applies the latched SCY (see hram.asm hSCY)
SECTION "stat", ROM0[$48]
    reti
SECTION "timer", ROM0[$50]
    jp TimerISR             ; drives preemptive scheduling
SECTION "serial", ROM0[$58]
    reti
SECTION "joypad", ROM0[$60]
    reti

; -----------------------------------------------------------------------------
; Entry point. rgbfix writes the Nintendo logo + header over $104-$14F.
; -----------------------------------------------------------------------------
SECTION "entry", ROM0[$100]
    nop
    jp KernelInit
    ds $150 - @         ; reserve $104-$14F for logo + header (rgbfix fills)

; -----------------------------------------------------------------------------
; Kernel init
; -----------------------------------------------------------------------------
SECTION "kinit", ROM0

KernelInit:
    di
    ld sp, KSTACK_TOP
    push af                     ; boot ROM hands the console model in A/B -
    push bc                     ; park it on the (uncleared) stack for dmesg

    ; CGB double-speed mode: 8.4 MHz for the whole kernel + userland. The
    ; PPU/LCD keep their normal rate; the timer and DIV double with the CPU,
    ; which TimerISR (128 Hz -> 64 Hz toggle) and sys_sleep (DIV halving)
    ; compensate for. P1 select lines off first, per the hardware procedure.
    ldh a, [$FF4D]              ; KEY1
    bit 7, a                    ; already fast? (warm reboot)
    jr nz, .fast
    ld a, $30
    ldh [$FF00], a              ; P1: no select lines (STOP quirk guard)
    ld a, 1
    ldh [$FF4D], a              ; KEY1.0 = prepare speed switch
    stop                        ; switch: continues in double speed
.fast

    ; enable cart RAM (MBC5)
    ld a, $0A
    ld [MBC5_RAM_ENABLE], a

    call ClearKernelRAM
    pop bc
    pop af
    ld [wBootA], a
    ld a, b
    ld [wBootB], a
    call CopyHramCode           ; move context-switch trampoline into HRAM
    call ProcInit               ; wipe process table
    ; point wCurProc at the (zeroed) kernel PCB so disk I/O during boot restores
    ; RAM bank 0 after each block transfer (wKernelPCB.PROC_RAMB = 0).
    ld a, LOW(wKernelPCB)
    ld [wCurProc], a
    ld a, HIGH(wKernelPCB)
    ld [wCurProc+1], a
    call pipe_init              ; mark all pipes free
    call term_init              ; LCD console first, so the boot spew is visible
    call boot_banner            ; dmesg: kernel/console/cart/mem/proc lines
    call net_init               ; clear the socket table, set our IP (10.0.0.2)
    call boot_net
    call fs_init                ; mount the disk (format on first boot; persists)
    call boot_fs
    call osk_init               ; build the on-screen keyboard (window layer)
    call boot_tty
    call boot_init              ; "init: spawning pid 1"

    ; --- spawn the init task (pid 1); it fork()s the rest ---
    ld hl, TaskInit
    ld b, 0                     ; cart-RAM bank 0
    ld c, 1                     ; WRAM u-area bank
    call ProcCreate

    call SchedInit              ; pick first task, set wCurProc

    ; system tick: hardware timer at 16384 Hz input, TMA=0 -> TIMA overflow
    ; IRQ at 64 Hz. TimerISR just counts (wTicks); scheduling stays
    ; cooperative. VBlank is enabled too, but its ISR is equally
    ; transparent: it only applies the latched SCY (terminal ring-scroll).
    xor a
    ld [rTIMA], a
    ld [rTMA], a
    ld a, %00000111             ; enable | 16384 Hz
    ld [rTAC], a
    xor a
    ld [rIF], a
    ld a, IEF_TIMER | IEF_VBLANK
    ld [rIE], a
    ei

    ; hand control to the first task via a context switch-in
    jp SchedRunFirst

; -----------------------------------------------------------------------------
ClearKernelRAM:
    ; zero the kernel globals region only ($C000-$CBFF). We must NOT touch
    ; $CC00-$CFFF: the kernel stack (SP=$D000) grows down into it, and our
    ; own return address lives there while this routine runs.
    ld hl, $C000
    ld bc, $0C00
.loop
    xor a
    ld [hl+], a
    dec bc
    ld a, b
    or c
    jr nz, .loop
    ret

; -----------------------------------------------------------------------------
; VBlankISR - transparent, like TimerISR: applies the latched SCY so terminal
; ring-scrolls land at frame boundaries. SCY is sampled per scanline, so a
; mid-frame write shears the picture (top at the old offset, bottom at the
; new) - exactly the sixel-view glitch this ISR exists to prevent.
; -----------------------------------------------------------------------------
SECTION "vblank_isr", ROM0
VBlankISR:
    push af
    ldh a, [hSCY]
    ldh [$FF42], a              ; rSCY
    pop af
    reti