; ============================================================================= ; programs.asm - userland program images (text-in-ROM model). ; ; Each program is linked to execute from the ROMX window ($4000-$7FFF) and ; lives in its own ROM bank. exec() maps the bank and jumps to the entry. ; ; To prove ROM banking really drives execution, both demo programs are ORG'd at ; the SAME address ($4000) in DIFFERENT banks - the only thing selecting which ; code runs is PROC_ROMB. They also read their message string out of the mapped ; bank, so the correct bank must be live when sys_write runs. ; ; Programs only ever talk to the kernel via `rst $30` (the trap + all kernel ; code live in ROM0, which is always mapped), so they never call kernel labels. ; ============================================================================= INCLUDE "include/gbos.inc" SECTION "prog_ping", ROMX[$4000], BANK[2] ProgPing: .loop ld de, .msg ld b, 1 ld c, SYS_WRITE rst $30 ld c, SYS_YIELD rst $30 jr .loop .msg db "1" SECTION "prog_pong", ROMX[$4000], BANK[3] ProgPong: .loop ld de, .msg ld b, 1 ld c, SYS_WRITE rst $30 ld c, SYS_YIELD rst $30 jr .loop .msg db "2" ; ----------------------------------------------------------------------------- ; Program table (in ROM0, always mapped). Indexed by exec()'s program id. ; Entry layout: bank (2 bytes, MBC5 16-bit) then entry address (2 bytes). ; ----------------------------------------------------------------------------- SECTION "progtab", ROM0 ProgramTable:: db LOW(BANK(ProgPing)), HIGH(BANK(ProgPing)) dw ProgPing db LOW(BANK(ProgPong)), HIGH(BANK(ProgPong)) dw ProgPong