; ============================================================================= ; programs.asm - userland program images (text-in-ROM model) + the shell. ; ; Programs are linked to run from the ROMX window ($4000-$7FFF) and live in ; their own ROM banks. exec() maps the bank and jumps in. Programs talk to the ; kernel only via `rst $30`. ; ============================================================================= INCLUDE "include/gbos.inc" ; the shell keeps its line buffer + scratch at the bottom of its RAM bank DEF SH_LINEBUF EQU $A000 ; up to 32 bytes DEF SH_PROGID EQU $A040 ; chosen program id (survives fork via bank copy) DEF SH_MAXLINE EQU 32 ; ----------------------------------------------------------------------------- ; PROG_WORKER (bank 2) - print a line, exit(0). ; ----------------------------------------------------------------------------- SECTION "prog_worker", ROMX[$4000], BANK[2] ProgWorker: ld de, .msg ld b, .msgend - .msg ld c, SYS_WRITE rst $30 ld b, 0 ld c, SYS_EXIT rst $30 .msg db "worker!", $0D, $0A .msgend ; ----------------------------------------------------------------------------- ; PROG_HELLO (bank 4) - print a line, exit(0). ; ----------------------------------------------------------------------------- SECTION "prog_hello", ROMX[$4000], BANK[4] ProgHello: ld de, .msg ld b, .msgend - .msg ld c, SYS_WRITE rst $30 ld b, 0 ld c, SYS_EXIT rst $30 .msg db "hello world!", $0D, $0A .msgend ; ----------------------------------------------------------------------------- ; PROG_CHELLO (bank 5) - a program written in C, compiled with SDCC to a ; self-contained ROM-bank image (crt0 + libc + code) and included verbatim. ; Rebuild with: sh c/build.sh c/chello.c c/chello.bin ; ----------------------------------------------------------------------------- SECTION "prog_chello", ROMX[$4000], BANK[5] ProgChello: INCBIN "c/chello.bin" SECTION "prog_echo", ROMX[$4000], BANK[6] ProgEcho: INCBIN "c/echo.bin" SECTION "prog_true", ROMX[$4000], BANK[7] ProgTrue: INCBIN "c/true.bin" SECTION "prog_false", ROMX[$4000], BANK[8] ProgFalse: INCBIN "c/false.bin" SECTION "prog_uname", ROMX[$4000], BANK[9] ProgUname: INCBIN "c/uname.bin" SECTION "prog_pid", ROMX[$4000], BANK[10] ProgPid: INCBIN "c/pid.bin" SECTION "prog_cat", ROMX[$4000], BANK[11] ProgCat: INCBIN "c/cat.bin" SECTION "prog_wc", ROMX[$4000], BANK[12] ProgWc: INCBIN "c/wc.bin" SECTION "prog_head", ROMX[$4000], BANK[13] ProgHead: INCBIN "c/head.bin" SECTION "prog_args", ROMX[$4000], BANK[14] ProgArgs: INCBIN "c/args.bin" SECTION "prog_ls", ROMX[$4000], BANK[15] ProgLs: INCBIN "c/ls.bin" SECTION "prog_save", ROMX[$4000], BANK[16] ProgSave: INCBIN "c/save.bin" SECTION "prog_rm", ROMX[$4000], BANK[17] ProgRm: INCBIN "c/rm.bin" SECTION "prog_ps", ROMX[$4000], BANK[18] ProgPs: INCBIN "c/ps.bin" SECTION "prog_kill", ROMX[$4000], BANK[19] ProgKill: INCBIN "c/kill.bin" ; ----------------------------------------------------------------------------- ; PROG_SH (bank 3) - the shell, now written in C (c/sh.c): parses >/ equal inc hl inc de jr .l ; SkipName(DE) - advance DE to its NUL terminator. SkipName:: .l ld a, [de] or a ret z inc de jr .l ; ----------------------------------------------------------------------------- ; Program table (ROM0). Index = program id. Entry: bank (2) + entry addr (2). ; ----------------------------------------------------------------------------- SECTION "progtab", ROM0 ProgramTable:: db LOW(BANK(ProgWorker)), HIGH(BANK(ProgWorker)) dw ProgWorker db LOW(BANK(ProgSh)), HIGH(BANK(ProgSh)) dw ProgSh db LOW(BANK(ProgHello)), HIGH(BANK(ProgHello)) dw ProgHello db LOW(BANK(ProgChello)), HIGH(BANK(ProgChello)) dw ProgChello db LOW(BANK(ProgEcho)), HIGH(BANK(ProgEcho)) dw ProgEcho db LOW(BANK(ProgTrue)), HIGH(BANK(ProgTrue)) dw ProgTrue db LOW(BANK(ProgFalse)), HIGH(BANK(ProgFalse)) dw ProgFalse db LOW(BANK(ProgUname)), HIGH(BANK(ProgUname)) dw ProgUname db LOW(BANK(ProgPid)), HIGH(BANK(ProgPid)) dw ProgPid db LOW(BANK(ProgCat)), HIGH(BANK(ProgCat)) dw ProgCat db LOW(BANK(ProgWc)), HIGH(BANK(ProgWc)) dw ProgWc db LOW(BANK(ProgHead)), HIGH(BANK(ProgHead)) dw ProgHead db LOW(BANK(ProgArgs)), HIGH(BANK(ProgArgs)) dw ProgArgs db LOW(BANK(ProgLs)), HIGH(BANK(ProgLs)) dw ProgLs db LOW(BANK(ProgSave)), HIGH(BANK(ProgSave)) dw ProgSave db LOW(BANK(ProgRm)), HIGH(BANK(ProgRm)) dw ProgRm db LOW(BANK(ProgPs)), HIGH(BANK(ProgPs)) dw ProgPs db LOW(BANK(ProgKill)), HIGH(BANK(ProgKill)) dw ProgKill ; ----------------------------------------------------------------------------- ; NameTable (ROM0) - command name -> program id, searched by sys_lookup. ; ----------------------------------------------------------------------------- SECTION "nametab", ROM0 NameTable:: db "worker", 0 db PROG_WORKER db "hello", 0 db PROG_HELLO db "chello", 0 db PROG_CHELLO db "echo", 0 db PROG_ECHO db "true", 0 db PROG_TRUE db "false", 0 db PROG_FALSE db "uname", 0 db PROG_UNAME db "pid", 0 db PROG_PID db "cat", 0 db PROG_CAT db "wc", 0 db PROG_WC db "head", 0 db PROG_HEAD db "args", 0 db PROG_ARGS db "ls", 0 db PROG_LS db "save", 0 db PROG_SAVE db "rm", 0 db PROG_RM db "sh", 0 db PROG_SH db "ps", 0 db PROG_PS db "kill", 0 db PROG_KILL db 0