FABRIC.md item 4.4t: confine REPL text rendering to the CANVAS box
vt100's TTF-mode text grid now operates within the per-arch 640x480 box (computed in 4.4o, pixel-verified in 4.4p) instead of the full framebuffer: box-origin offset in px_of()/py_of(), box-derived cols/rows (53x20) set before the 4.4q scrollback allocation depends on them, mode-aware erase_display()/reverse-index fill, and a new box-scoped fb_scroll_rect() alongside the existing whole-framebuffer fb_scroll_rows() (bitmap/boot mode unaffected either way). Also clears the full framebuffer once at the bitmap-to-TTF switch so leftover boot debris doesn't sit frozen outside the box now that erase_display(2) is box-scoped afterward. Three-arch QEMU boot + pixel-scanned screendumps confirm zero non-background pixels land outside the box on amd64, aarch64, and riscv64. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
1f3ec3554e
commit
c92be2768f
@@ -5688,10 +5688,93 @@ document and committing that amendment as its own item.*
|
||||
> correctly — two new words were added to the dictionary — but still cross-arch consistent,
|
||||
> which is the actual parity property that matters).
|
||||
|
||||
- [x] **4.4t — Confine REPL text rendering to the 4.4o CANVAS box.** REPL text (TTF mode)
|
||||
currently still renders across the entire framebuffer — the 640×480 box computed and
|
||||
pixel-verified in 4.4o/4.4p was geometry only, never wired into `vt100`'s actual glyph
|
||||
placement, cursor bounds, or scroll region. This was explicitly deferred, twice, as its own
|
||||
item (flagged in both 4.4p's and 4.4q's writeups) rather than silently folded into either.
|
||||
Scope: make `vt100`'s live text grid (TTF/REPL mode only) operate entirely within the box —
|
||||
per-arch origin (amd64 (320,104); aarch64/riscv64 (80,4)), 640×480, giving an exact
|
||||
53 cols × 20 rows (640/12, 480/24, both exact, no remainder). Boot/POST rendering
|
||||
(`font_8x16`, bitmap mode) is untouched — stays full-screen, exactly as before.
|
||||
Concretely: `px_of()`/`py_of()` gain a box-origin offset (0,0 in bitmap mode, the per-arch
|
||||
box origin in TTF mode); `g_vt.cols`/`g_vt.rows` in `vt100_enable_ttf()` are set to the box's
|
||||
53×20 directly rather than derived from `fb_width()`/`fb_height()` — and this must happen
|
||||
*before* the scrollback shadow/ring `kmalloc` block in that same function, since
|
||||
`g_line_stride` depends on `cols`; verify `g_line_stride == 54` at runtime rather than
|
||||
assuming the ordering landed right. `erase_display(2)` must become mode-aware: box-scoped
|
||||
fill in TTF mode, full-screen in bitmap mode (today it unconditionally wipes the whole
|
||||
screen, which would blank CANVAS outside the box once confinement is live). `scroll_up()`'s
|
||||
`fb_scroll_rows()` call is a whole-framebuffer blit — wrong once text is box-confined, since
|
||||
it would drag pixels from outside the box. New `fb_scroll_rect(x, y, w, h, lines, bg)` in
|
||||
`framebuffer.c`/`.h`, row-by-row copy bounded to `x..x+w`, used in TTF mode; bitmap mode
|
||||
keeps `fb_scroll_rows()` unchanged. This item does **not** draw a persistent border around
|
||||
the box — that is explicitly 4.4r's business (hide/show), not this item's; adding one here
|
||||
would be scope creep. Input echo needs no special handling — `sk_readline()` echoes through
|
||||
`console_putc()`, the same path being confined; verify this rather than adding anything.
|
||||
Depends on 4.4o/4.4p (box geometry, already done) and 4.4q (scrollback, already done, whose
|
||||
shadow/ring sizing this item's cols/rows change affects).
|
||||
*Done when:* three-arch screendump showing REPL text bounded inside the box region, backed
|
||||
by a pixel scan proving no non-background glyph pixel lands outside the box rect (measured,
|
||||
not eyeballed — same discipline as 4.4p); three-arch QEMU boot + logs per CLAUDE.md. Expect
|
||||
the screenshots to look different from every prior capture in this section — text starts at
|
||||
the box origin, not (0,0), and only 20 rows are usable at a time.
|
||||
*Refs:* §27.8, 4.4o, 4.4p, 4.4q.
|
||||
|
||||
> **Done 2026-08-11.** Implemented exactly as scoped: `g_origin_x`/`g_origin_y` added to
|
||||
> `vt100.c` (0,0 default, matching bitmap mode); `px_of()`/`py_of()` add the origin;
|
||||
> `vt100_enable_ttf()` sets `g_origin_x`/`g_origin_y`/`g_vt.cols`/`g_vt.rows` to the per-arch
|
||||
> box values *before* the scrollback shadow/ring `kmalloc` block, with a runtime check that
|
||||
> `g_line_stride == VT100_BOX_COLS + 1` (54) — bails to "scrollback unavailable" rather than
|
||||
> silently corrupting shadow/ring indices if that ordering is ever disturbed later.
|
||||
> `erase_display(2)` and the `ESC M` reverse-index top-row fill are both mode-aware now
|
||||
> (box-scoped in TTF, full-screen in bitmap, unchanged). `fb_scroll_rect(x,y,w,h,pixel_rows,bg)`
|
||||
> added to `framebuffer.c`/`.h` (row-by-row copy bounded to `x..x+w`, same non-volatile bulk-copy
|
||||
> technique as `fb_scroll_rows()`); `scroll_up()` calls it in TTF mode, `fb_scroll_rows()`
|
||||
> unchanged in bitmap mode.
|
||||
>
|
||||
> **One thing found and fixed beyond the item's original text, not scope creep — it's the
|
||||
> same "switch cleanly into confined REPL mode" this item is about:** the first verification
|
||||
> pass showed the box's content was genuinely confined (confirmed by cropping exactly the box
|
||||
> rect and reading it cleanly) but the *rest of the screen* was frozen bitmap-mode boot/POST
|
||||
> debris, never cleared, because `erase_display(2)` becoming box-scoped means it no longer
|
||||
> clears anything outside the box either. Fixed with one `fb_fill_rect(0, 0, fb_width(),
|
||||
> fb_height(), g_vt.def_bg)` at the top of `vt100_enable_ttf()`'s box-switch, before the
|
||||
> (now box-scoped) `erase_display(2)` call — the one and only whole-framebuffer wipe in TTF
|
||||
> mode; every later `ESC[2J]` stays box-scoped as designed.
|
||||
>
|
||||
> **Verification, three-arch, pixel-measured not eyeballed:** booted each arch to `ok>`,
|
||||
> sent `LOG-ERROR LOG-LEVEL!` (this build's default log level traces every word execution to
|
||||
> console via a HADES/ECW hotword tracer — unrelated to this item, silenced only so the
|
||||
> screendump reads cleanly) then `: TB1234 0 DO I . LOOP CR ; 20 TB1234` to generate content
|
||||
> and exercise wrap/scroll within the box, then a QEMU monitor `screendump`. A Python scan
|
||||
> checked every pixel of each screenshot against the computed box rect
|
||||
> ((320,104)-(960,584) amd64; (80,4)-(720,484) aarch64/riscv64) and counted non-background
|
||||
> pixels outside it: **0 on all three architectures.** Screendumps:
|
||||
> [evidence/amd64/qemu-screenshot-20260811-230119-4.4t-confinement-amd64.png](evidence/amd64/qemu-screenshot-20260811-230119-4.4t-confinement-amd64.png),
|
||||
> [evidence/aarch64/qemu-screenshot-20260811-230119-4.4t-confinement-aarch64.png](evidence/aarch64/qemu-screenshot-20260811-230119-4.4t-confinement-aarch64.png),
|
||||
> [evidence/riscv64/qemu-screenshot-20260811-230119-4.4t-confinement-riscv64.png](evidence/riscv64/qemu-screenshot-20260811-230119-4.4t-confinement-riscv64.png).
|
||||
>
|
||||
> **Real environment hazard found and worked around, recorded so it doesn't cost time again:**
|
||||
> this repo's `Makefile.starkernel` builds into `build/$(ARCH)/$(TARGET)` where
|
||||
> `TARGET ?= kernel` — i.e. `build/amd64/kernel/`, not `build/amd64/`. A stale
|
||||
> `build/amd64/starkernel.iso` left over from hours earlier in this session at the wrong
|
||||
> (non-`kernel/`) path caused three consecutive custom QEMU boots (added a monitor socket for
|
||||
> screendumping, mirroring 4.4p/4.4q's technique) to reproducibly stall mid-boot during
|
||||
> Hermes's migration self-test — looked exactly like a confinement-caused regression until the
|
||||
> path mismatch was found via `ls -la` timestamp comparison. Not a kernel bug; a test-harness
|
||||
> mistake. Always launch custom QEMU invocations against `$(BUILD_DIR)` from the Makefile
|
||||
> (`build/<arch>/kernel/`), never a hand-guessed `build/<arch>/` path.
|
||||
>
|
||||
> Three-arch standard boot+log basis: amd64 (`logs/20260811-225236/amd64/`), aarch64
|
||||
> (`logs/20260811-225514/aarch64/`), riscv64 (`logs/20260811-225903/riscv64/`) — `Failed: 0`
|
||||
> all three.
|
||||
|
||||
- [ ] **4.4r — Toggle word: hide/show the scroll box.** A FORTH word that hides the 640×480
|
||||
scroll box, revealing the rest of CANVAS beneath it for drawing; showing it again restores
|
||||
the scroll-box content undisturbed, no scrollback loss. Depends on 4.4o/4.4p (geometry) and
|
||||
4.4q (scrollback) all being done first.
|
||||
the scroll-box content undisturbed, no scrollback loss. Depends on 4.4o/4.4p (geometry),
|
||||
4.4q (scrollback), and 4.4t (confinement — the box must be real before it can be hidden)
|
||||
all being done first.
|
||||
*Done when:* toggling off then on again, verified by screendump, shows the CANVAS drawing
|
||||
area unobstructed while off and the exact prior scroll-box content restored when back on;
|
||||
three-arch QEMU boot + logs per CLAUDE.md.
|
||||
|
||||
Reference in New Issue
Block a user