| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
KPutc's console path now renders each byte on the LCD terminal via
term_putc in addition to the serial write. Serial is kept so scripted
tests still capture output (and for link-cable/debug), while the shell,
command output, and echoed input now appear on-screen in the 40-col font
with a live cursor and scrolling. Dropped the boot-time term_demo; the
terminal starts blank and fills from real console traffic.
term_putc now saves/forces/restores SVBK=1 so it always reads and writes
the terminal buffer/state in WRAM bank 1, regardless of which process
context KPutc is invoked from (defensive; all procs currently use bank 1).
The stack lives in non-banked WRAM, so saving SVBK across the switch is safe.
Verified: a headless run of `uname; ls; echo hello world` renders each
prompt, the echoed command, and its output on the LCD (captured via the
new `--headless --shot` path), and serial capture is unchanged.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Rework the terminal from a static one-tile-per-screen-position model to
LINE-BOUND tiles with an assign[] indirection, so scrolling is cheap:
- Each line-slot L owns the 20 VRAM tiles at positions [L*20..L*20+19].
- assign[screen_row] -> line-slot; the tilemap points each screen row at
its slot's tiles.
- Scroll = rotate assign[], blank+rebuild only the new bottom line (20
tiles), and rewrite the tilemap. O(1 line) instead of rebuilding all
360 tiles.
- term_putc: printable + \n \r \b, line wrap at col 40, cursor advance
with scroll-on-overflow.
- Cursor: an underline OR'd into the current cell's tile via wCurMask
(no sprites/OAM); moving it just re-renders the old and new tiles.
- term_demo drives 24 lines through term_putc to exercise scroll+cursor.
Also fixes a vicious bug this shook out: build_tile advanced its 16-bit
glyph pointers with `ld hl, wGlyphL+1 / inc [hl]`, which CLOBBERS HL --
and HL is the live VRAM destination pointer. Whenever a glyph's 8 bytes
straddled a page boundary (common with long/varied lines) the next tile
bytes were written into WRAM at $D580+, corrupting wGlyphL/wVram/wCurRow/
wCurCol and freezing the display. Now the pointers are bumped via A so HL
is preserved. (Note: the emulator build had also been silently failing on
an unrelated debug edit, masking this for a while.)
Verified by screenshot: 24 lines scroll to show the last 18 + a visible
cursor at the "ready$" prompt; serial shell and filesystem still work.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
Replace the small-caps placeholder font with a real baseline-aligned
4x8 set covering all 96 printable ASCII: distinct lowercase with true
ascenders (b d f h k l t) and descenders (g j p q y), digits, and
punctuation. Metrics: caps/ascenders rows 1-5, x-height rows 2-5,
baseline row 5, descenders into rows 6-7. Glyphs are ~3px wide in the
4px cell -- cramped but legible; the tile mechanism itself imposes no
character-set limit.
genfont.py now takes per-glyph (top, rows) so glyphs sit on the baseline.
Demo strings in term_test updated to show mixed case + punctuation.
Verified by screenshot: descenders visibly drop below the baseline.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Add a background-tile text terminal that packs TWO 4px-wide characters
into each 8x8 tile, giving a 40x18 grid instead of the 20x18 you'd get
from an 8x8 font. The tilemap is static (one dedicated VRAM tile per
screen position); we rebuild a tile's 16 bytes from two glyphs whenever
a character changes. 360 tiles exceed the 256 a single tilemap can
address, so positions 256-359 live in VRAM bank 1 via the CGB tilemap
attribute bank-bit -- hence CGB-only.
- Switch the ROM to CGB (rgbfix -C). Safe for the FS: every process has
PROC_WRAMB=1, so SVBK stays on bank 1 and the WRAMX FS caches don't move.
- CGB BG palette 0 = white bg / black text via BCPS/BCPD.
- src/term.asm: term_init (palette + static tilemap + clear buffer),
build_tile (combine two 4px glyphs -> one 8x8 tile, correct VRAM bank),
term_redraw (rebuild all tiles), term_puts, term_show, term_test.
- src/font.asm: 96-glyph 3x5-in-4x8 font, generated by tools/genfont.py.
- 40x18 text buffer at $D600 (WRAMX, above the FS caches).
- tools/ppmview.py: render a --shot PPM as ASCII so the LCD is inspectable
from the shell during development.
Verified via emulator screenshot: "GBOS TERMINAL", the alphabet, and a
bank-1 row all render legibly at 40 columns. Serial shell + filesystem
still work unchanged.
Note: a full term_redraw builds 360 tiles and takes ~8 frames; fine for
incremental single-char updates, but scrolling needs a smarter path
(next milestone). Input (no keyboard) is also still TODO.
|
| |
|
|
|
|
|
|
| |
open() now checks the target's inode type: opening a directory as a file
returns $FE (EISDIR) instead of a valid fd, so 'cat docs' no longer streams the
raw directory block as bytes. cat reports 'is a directory'; wc/head/save treat
any invalid fd (>3) as an open failure. (ls is unaffected - it uses the
structural opendir/list path, not open/getb.)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- directories generalized: dir_find/dir_add/dir_remove take any dir inode;
every dir carries '.'/'..'. Path resolution (resolve / resolve_parent) walks
absolute or cwd-relative paths; open/mkdir/chdir/remove/opendir take paths.
- per-process cwd: PROC_CWD in the PCB (root by default, inherited on fork);
sys_chdir sets it, sys_opendir points ls at any directory.
- shell: 'cd' builtin + cwd-aware prompt; 'mkdir'/'ls <dir>' tools; 'exit'/'quit'
and EOF call poweroff() (clean shutdown via the $ED opcode -> reliable save).
- three HL/buffer-clobber bugs fixed along the way: resolve didn't preserve the
path cursor across dir_find; cur_cwd clobbered HL; resolve_parent set the final
name before resolve() overwrote wFsNameBuf (now copied after).
- verified: nested mkdir/cd/save, multi-level paths (cat docs/sub/b), and the
whole tree persists across a reboot.
- README: document directories + the poweroff opcode.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- fs.asm: a real block filesystem on the persistent block device - superblock,
block/inode bitmaps, a 32-entry inode table (type, size, 8 direct block
pointers -> files up to 2 KiB), and a root directory of 16-byte entries.
Metadata cached in WRAMX; one-block data cache streams file/dir blocks.
- same syscall interface (open/getb/putb/list/remove) -> tools unchanged;
ls now enumerates until flist() runs out (16 files, was hardcoded 8).
- old 8-slot WRAM FS removed; cart RAM partitioned: process banks 0-7, disk 8-11.
- two register-clobber bugs fixed: alloc_block/alloc_inode returned the
bitmap-block number (write_bitmap clobbers C); db_use loaded the wrong block
on a transition (db_flush->write_block clobbers C) -> multi-block files broke.
- verified: 10+ files, multi-block (300-byte) files, delete, and persistence
across reboots. Debug 'blk' disk tool retained (fill/peek).
- README: document the block filesystem.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
- blk.asm: read_block/write_block move 256-byte blocks between battery-backed
cart-RAM banks (8-11, the 'disk') and a WRAM bounce buffer. Banking is hidden
in those two routines; they inline the 'restore my bank' step so they never
touch the stack while the disk bank is mapped over the process's $A000 window
(the stack lives there too -- a call/ret would rug-pull it).
- format-on-first-boot: superblock magic in block 0; otherwise the disk persists.
- cart RAM bumped to 128 KiB (-r 4); process banks 0-7, disk banks 8-11.
- debug tool 'blk fill/peek' + syscalls to validate round-trip and persistence.
- verified: round-trip incl. cross-bank (block 100 -> bank 11); block survives a
reboot via .sav; magic intact (no reformat on 2nd boot).
- old WRAM 8-slot FS still backs the tools until stages 2-3.
|
| |
|
|
|
|
|
|
|
|
|
| |
- sys_reap: nohang reap of a finished zombie child (-> pid or 0).
- shell: 'cmd &' launches in the background (prints [pid], no wait); reaps
finished jobs at the prompt ([pid done]). Foreground now waits for its own
child specifically (loops wait(), reporting bg completions meanwhile) so kill
reports the right pid.
- spin: a process that yields forever - a target for ps/kill.
- verified: spin &; ps shows it; kill <pid> removes just that one; immortal
init; self-finishing bg worker reaped with [pid done].
|
| |
|
|
|
|
|
|
|
|
|
| |
- PCB gains PROC_PROG (running program id), set by exec, inherited on fork.
- sys_kill(pid): reject pid 1 (immortal) and unknown/dead pids; mark the target
zombie, reparent its children to init, wake its parent if blocked in wait;
schedule away if a process kills itself. Reuses FindPcbByPid/ReparentToInit.
- sys_ps(slot,buf)->{pid,state,prog}; sys_progname(id) via NameTable reverse
lookup. NameTable gains sh/ps/kill.
- libc: kill/psget/progname; tools ps (pid state cmd) and kill <pid>.
- verified: ps lists sh(B)+ps(R); kill 1 refused; kill 42 fails.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
- kernel I/O routing: PCB gains PROC_STDIN/PROC_STDOUT (default console $FF),
inherited across fork. KGetc/KPutc route read/write/putc to the console or a
file fd. New syscalls: putc(16), setin(17), setout(18), lookup(19).
read/write now go through the routing; putc/puts/nl use SYS_PUTC.
- sys_lookup + NameTable move command-name resolution into the kernel.
- shell rewritten in C (c/sh.c): tokenizes a line, parses > / < / |, and drives
fork+setin/setout+exec+wait. Pipes run as 'a > __pipe ; b < __pipe' (temp
file). asm shell + cmdtab removed; StrEqual/SkipName kept for sys_lookup.
- libc: fork/exec/wait/setin/setout/lookup wrappers.
- verified: echo>file, cat file, wc<file, cat readme|wc -l, echo ...|wc.
|
| |
|
|
|
|
|
|
|
|
|
| |
- fs.asm: 8-slot RAM filesystem in WRAMX ($D000-$DFFF), name[8]+len[2]+data[502];
syscalls open/close/getb/putb/list/remove, seeded with a 'readme' at boot.
- libc: open/close/fgetc/fputc/flist/fremove wrappers + O_READ/O_WRITE/NOFD.
- tools: ls, save (stdin->file, one line), rm; cat/wc/head now take a file arg.
- fix: syscall dispatch clobbers A, so putb takes its byte in E (was reading the
handler's low address byte, 0xDC); ls NUL-terminates 8-char names.
- verified: save/cat/ls/rm cycle; wc readme -> '2 7 38'; head -n 1 readme.
- README: document the filesystem + the A-clobber ABI note.
|
| |
|
|
|
|
|
|
|
|
| |
- c/libc.c: shared C helpers linked into every program - putu (print decimal),
atou (parse decimal), argv_parse (tokenize getargs() into argc/argv).
- wc: count lines/words/chars of stdin. head [n]: first n lines (drains rest to
EOF). args: argc/argv demo.
- pid now uses libc putu; build.sh links libc.c; Makefile CBLOBS + libc dep.
- README: document the new tools + argv_parse.
- verified: 'args one two three' -> argc=3/argv[..]; wc '2 3 16'; head 2.
|
| |
|
|
|
|
|
|
|
|
|
| |
- libc: add putc, puts, strlen, getargs (args string), EOF (=4) for readc.
- args: shell splits the command line at the first space ("cmd\0args\0" at
$A000, inherited by the child via fork); getargs() returns the arg string.
- shell: exit on Ctrl-D/EOF; $ prompt over a clean read loop.
- tools (c/): echo (argv), cat (stdin->stdout to EOF), uname, pid (decimal
print), true, false. Each built to a ROM-bank blob and registered.
- Makefile: CBLOBS list builds all C programs.
- README: document libc + the tool set.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
- 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'.
|
| |
|
|
|
|
|
|
|
|
|
| |
- root cause of the read/echo corruption: SyscallTrap uses HL to index the
dispatch table, so HL is clobbered across a syscall; the shell then wrote its
buffer pointer's garbage into the $0000-$7FFF MBC register region, corrupting
the mapper. fix: userland saves HL around sys_read (push/pop).
- shell now runs commands end to end: $ hello -> hello world!, $ worker ->
worker!, $ foo -> ?
- README: document that syscalls clobber BC/DE/HL (return in A, B for wait);
add read + shell to the syscall table.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
- sys_read (SYS_READ): blocking console input via external-clock serial poll;
yields while waiting. Verified working (direct-echo cat: 'hi' -> 'hi').
- shell (PROG_SH): prompt/read/parse/fork+exec+wait; worker+hello programs;
StrEqual/SkipName helpers; command table.
- init now execs the shell.
- KNOWN BUG: storing the typed char to the line buffer at $A000 (cart RAM of an
exec'd program) corrupts the following sys_read; sys_write reading $A000 also
returns $3E. Kernel syscalls themselves are correct; isolating the cart-RAM /
exec RAM-bank interaction next.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
- exit(): zombie + status, reparent orphans to init, wake blocked parent,
schedule away forever (resources reclaimed by the reaper)
- wait(): scan for a zombie child; reap (free cart-RAM bank + PCB slot) and
return pid/code; block PS_BLOCKED + yield if children still live; $FF if none
- cart-RAM banks are now a free list (wBankUsed bitmap): AllocRamBank/FreeRamBank
- scheduler: FindNextReady returns carry when nothing runnable; yield idles
instead of blindly picking slot 0
- helpers: FindPcbByPid, ReparentToInit
- demo: init forks 3 workers -> exec -> exit(pid) -> wait/reap => wwwR2R3R4!
verified bank recycling with 6 workers over 3 banks (w2w3w4w5w6w7)
- README: document the lifecycle + syscall status
|
| |
|
|
|
|
|
|
|
|
| |
- sys_exec(B=program id): look up ProgramTable, point PROC_ROMB at the program's
ROM text bank, map it into $4000-$7FFF, reset stack, jp to entry (no return)
- programs.asm: two demo programs (ping/pong) ORG'd at the SAME $4000 in banks
2 and 3 - proves execution is driven purely by PROC_ROMB
- demo: init forks; parent execs PROG_PING (bank2, '1'), child execs PROG_PONG
(bank3, '2') -> '1212...', 2000/2000 balanced, zero garbage
- README: document exec + text-in-ROM model
|
| |
|
|
|
|
|
|
|
|
| |
- sys_fork: switch to a kernel stack, bump-allocate a cart-RAM bank, copy the
parent's 8 KiB bank via a WRAM bounce buffer, plant a switch-in frame so the
child returns 0 to the post-fork PC, fill the child PCB (shared ROM text)
- add AllocRamBank (bump allocator) + FindFreeSlot helpers
- demo: init forks; parent prints P, child prints C (PCPC...); nested fork
gives three distinct pids (123...)
- README: document the fork mechanism, mark syscall status
|
|
|
- fix ClearKernelRAM clobbering the kernel stack (only clear $C000-$CBFF)
- fix SyscallTrap clobbering DE (buffer arg) during table dispatch
- README: run via ~/dev/gbc --headless; note bring-up bugs
|