From c2b512e803285223959e0a97601c017730d1b0bb Mon Sep 17 00:00:00 2001 From: user Date: Sat, 18 Jul 2026 22:19:59 +0200 Subject: term+libc: batched write rendering - one tile render per write(), 2.3x lines sys_write sets wBatch; render_cursor_tile - the single choke point all of term_putc's visible mutations pass through - then marks a dirty span (per LINE-SLOT, so spans survive scroll rotation for free) instead of rendering. term_write_end renders every dirty tile exactly once, then the cursor. Scrolls stay immediate (blank rebuild is cheap and artifact-free); file-bound writes flush for free. The enabler is in libc: puts() was a SYS_PUTC trap PER CHARACTER, so almost no console output ever went through sys_write. It now issues one SYS_WRITE for the whole string - one trap, one batch, and every line-printer (echo, irc, the shell) gets the batched path. Measured: 37-char write = 128k cycles (3.5k/char) vs ~8k/char down the per-char trap path. Full demo passes; GIF regenerated. --- usr/libc.s | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) (limited to 'usr/libc.s') diff --git a/usr/libc.s b/usr/libc.s index 2366cd8..fbca836 100644 --- a/usr/libc.s +++ b/usr/libc.s @@ -33,18 +33,28 @@ _putc: rst #0x30 ret - ;; void puts(const char *s /*DE*/) - write until NUL (no newline) + ;; void puts(const char *s /*DE*/) - write until NUL (no newline). + ;; ONE SYS_WRITE for the whole string instead of a SYS_PUTC per char: + ;; a single trap, and the kernel defers tile rendering for the whole + ;; run (sys_write batching), so a line paints each tile once. _puts: -1$: ld a, (de) + push de + ld h, d + ld l, e + ld b, #0 +1$: ld a, (hl) + or a + jr z, 2$ + inc hl + inc b + jr 1$ +2$: pop de + ld a, b or a ret z - push de - ld e, a - ld c, #16 ; SYS_PUTC + ld c, #3 ; SYS_WRITE (DE=buf, B=len) rst #0x30 - pop de - inc de - jr 1$ + ret ;; void nl(void) - CRLF via stdout _nl: -- cgit v1.3.1-sl0p