; ============================================================================= ; 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