aboutsummaryrefslogtreecommitdiffstats
path: root/README.md
diff options
context:
space:
mode:
authoruser <user@clank>2026-07-16 00:49:58 +0200
committeruser <user@clank>2026-07-16 00:49:58 +0200
commitef88f0e530b898ebcb14f9e3dff1d58e83089ada (patch)
tree4b4e70fb12a92e5e254a8c937fbda34316141d54 /README.md
parentshell working: fix syscall ABI (trap clobbers HL) + document (diff)
downloadgbos-ef88f0e530b898ebcb14f9e3dff1d58e83089ada.tar.gz
gbos-ef88f0e530b898ebcb14f9e3dff1d58e83089ada.tar.xz
gbos-ef88f0e530b898ebcb14f9e3dff1d58e83089ada.zip
C toolchain: run SDCC-compiled C programs as gbos processes
- c/{gbos.h,crt0.s,libc.s,build.sh}: SDCC sm83 -> ROM-bank blob toolchain. libc syscall wrappers save/restore BC/DE/HL around rst $30 (trap clobbers them; SDCC expects them preserved). - build via SDCC native asxxxx path (sdasgb/sdldgb), crt0 linked first so _start is the $4000 entry; blob INCBIN'd into a ROM bank. - chello.c: prints a message + getpid() -> runs as 'chello' shell command. - Makefile: auto-build c/*.bin, track as a dep of programs.o; gitignore blobs. - README: document the C toolchain + the SDCC --asm=rgbds codegen bug that forced the native-toolchain approach. - verified: '$ chello' -> 'hello from C on gbos!' / 'my pid is 2'.
Diffstat (limited to '')
-rw-r--r--README.md41
1 files changed, 40 insertions, 1 deletions
diff --git a/README.md b/README.md
index a0b8338..49909f9 100644
--- a/README.md
+++ b/README.md
@@ -169,13 +169,52 @@ A real gbos would render to VRAM; serial is the zero-VRAM debug channel.
jump table, clobbering the `write()` buffer pointer passed in `DE`. Dispatch
now indexes via `A`/`HL` only, preserving `DE`/`B` for the handler.
+## Writing programs in C
+
+gbos programs can be written in **C**, compiled with **SDCC** (the `sm83` port).
+This makes porting tiny Unix CLI tools realistic. The toolchain (`c/`):
+
+- `c/gbos.h` — the userland API (`writes`, `readc`, `nl`, `getpid`, `sexit`).
+- `c/libc.s` — syscall wrappers (asxxxx asm). Each saves
+ `BC/DE/HL` around `rst $30`, since the trap clobbers them but SDCC expects
+ them preserved.
+- `c/crt0.s` — entry: `call main`; then `exit(0)`. Linked first so `_start` is
+ the `$4000` entry.
+- `c/build.sh` — compiles a `.c` with SDCC's **native** toolchain
+ (`sdasgb` + `sdldgb`), links code at `$4000`, and extracts the ROM-bank blob.
+ The Makefile INCBINs it and registers it as a program.
+
+```c
+#include "gbos.h"
+void main(void) {
+ writes("hello from C on gbos!", 21); nl();
+ writes("my pid is ", 10);
+ { char d = getpid() + '0'; writes(&d, 1); } nl();
+}
+```
+
+```
+$ chello
+hello from C on gbos!
+my pid is 2
+```
+
+**Toolchain gotchas found the hard way:** SDCC's `--asm=rgbds` mode mis-orders
+instructions (emits `ld [hl],a` before the `ld hl,sp+0` that sets the pointer) —
+so we use SDCC's native asxxxx path and INCBIN the blob instead. String literals
+with embedded control chars are also mangled in rgbds mode; C programs pass
+explicit lengths and emit newlines via `nl()`.
+
## Roadmap
- [x] `fork`: copy parent's 8 KiB RAM bank → free bank, child returns 0
- [x] `exec`: point `PROC_ROMB` at a program in a ROM bank, reset stack, enter
- [x] `exit` / `wait` / zombie reaping + cart-RAM bank recycling (free list)
- [ ] `exec` refinement: copy `.data` from ROM + zero `.bss` for RW globals
-- [ ] a real shell program: `fork`+`exec`+`wait` driven from the serial console
+- [x] a real shell program: `fork`+`exec`+`wait` driven from the serial console
+- [x] C toolchain: SDCC (sm83) + libc shim, C programs run as gbos processes
+- [ ] grow libc (strings, a `main(argc,argv)`, more syscalls) + port real tools
+- [ ] Makefile-drive multiple C programs (a `CPROGS` list)
- [ ] Preemptive scheduling: real context save in `TimerISR` → `hSwitchTo`
- [ ] Use the `$D000-$DFFF` u-area (SVBK) for per-process kernel state / kstack
- [ ] `brk`/heap allocator inside the task bank (heap up, stack down, collision = ENOMEM)