| Commit message (Collapse) | Author | Age | Files | 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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
The ring-scroll wrote SCY mid-frame; SCY is sampled per scanline (on
hardware and in sl0pboy's PPU), so a scroll landing mid-frame rendered
the top of the frame at the old offset and the bottom at the new one -
a one-frame shear, invisible in frame-sampled GIF captures but ugly on
a live sixel view.
term_view_update now writes hSCY (HRAM) and a transparent VBlank ISR
(push af / apply / pop af / reti, same profile as TimerISR) copies it
to rSCY, so the view only ever moves at frame boundaries. The scroll's
tile+map writes stay immediate: the new map row is invisible at the
old SCY by construction (it's the ring row one past the visible 18).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The BG map's 32 rows become a ring: logical row L always lives at map
row (wMapTop + L) & 31, and SCY = (wMapTop + wViewTop)*8 places the
view. Scrolling bumps wMapTop, rebuilds the one new bottom line and
writes its single map row (map_row_one); the other 17 rows move for
free. The whole OSK view dance - shift the cursor above the keys,
restore the backlog on hide - is now term_view_update: one SCY write,
no map rewrite at all.
OSK safety: the keyboard lives on the WINDOW layer, which SCY never
moves. Stale ring rows can only appear under it: wViewTop = max(0,
wCurRow-14) <= 3 is nonzero only while the OSK is visible, and the
window covers exactly those bottom 3 rows (WX=7, WY=120). Verified:
scroll + view shift + scroll-while-OSK-up + backlog restore all
pixel-correct via VRAM screenshots; full README demo passes.
term_scroll: 78.5k -> 35.6k T-cycles (857k pre-optimization: 24x).
OSK toggle: 45k tilemap rewrite -> 212 cycles.
Regenerated demo/gbos-demo.gif on the new renderer.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
1. color_setup memoization: a call with the same (colL,colR) pair as
last time returns immediately (masks/attr still valid in WRAM).
Runs of same-colored cells - i.e. almost all text - hit this.
2. build_tile blank fast path: two spaces = bg-only planes, 8 constant
rows; term_scroll's cleared line and every blank region skip the
glyph pipeline entirely.
3. build_tile two-phase rewrite: combine both glyphs into wRowBuf with
pointers in registers (the old per-row 16-bit WRAM pointer walk was
most of the blit), then compose planes unrolled with plane-0 masks
in B/C.
4. term_write_tilemap attr pass: split each row at the pos-256 VRAM
bank boundary into two tight cache->tilemap copy runs - no per-tile
addressing or bank test.
Measured (emulator cycle counter, ANSI test screen):
term_scroll 857k -> 248k (attr cache) -> 78.5k T-cycles
term_write_tilemap 723k -> 114k -> 45.4k
term_putc 18.2k -> 6.7k
A scroll is now ~1.1 frames of guest CPU (was 12); a full 40-char line
prints in ~63ms of guest time (was ~173ms).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
term_write_tilemap's attribute pass ran color_setup - the full Fano
palette walk - for all 360 tiles on every scroll. render_tile already
computes the attr when a tile changes, so store it (COL_BUF + slot*64
+ ACACHE + tcol; the stride's 24 spare bytes were free) and the attr
pass becomes a table read. update_cursor_attr reads the cache too.
term_init now redraws before writing the tilemap so the cache is warm.
Measured entry-to-return with the emulator cycle counter, ANSI test
screen content: term_write_tilemap 723k -> 114k T-cycles (6.3x),
term_scroll 857k -> 248k (3.5x) - a scroll drops from ~12 frames of
guest CPU to ~3.5.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Fano-plane palette scheme: the 7 colors map onto 7 CGB BG palettes so
any color pair shares one palette; a tile's palette is picked from the
set of colors its two cells need (tables generated by tools/gencolor.py).
Per cell a packed (bg<<4)|fg byte lives alongside the char shadow, and
the glyph blitter steers glyph/empty pixels to each cell's fg/bg color
slots via plane masks.
An ANSI-ish CSI parser (ESC [ .. m) drives it; usr/ansi.c demos it and
the irc client now renders hashed nick colors, status dimming and a
channel-activity bar.
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A fixed offset of OSK_ROWS pushed the cursor off the top of the screen when
there was little backlog (e.g. a fresh terminal: cursor at logical row 0 ->
screen row -3, hidden). Now the offset is max(0, wCurRow - 14): 0 when the
cursor is within the visible area, growing only enough to keep the cursor
line at the bottom visible row (14) once the terminal has filled past it.
compute_offset (from wOskVisible + wCurRow) runs at the top of
term_write_tilemap; cursor_down re-runs the tilemap when the cursor changes
rows while the OSK is up; osk_toggle just re-runs it. Shared OSK_DOCK
constant in gbos.inc keeps term.asm and osk.asm in sync.
Verified: fresh terminal + OSK shows the input at row 0; filling past row 14
shifts the view to hold the input at row 14; full screen + OSK puts it at
row 14; toggle on+off is still lossless.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
Replace the shrink-and-scroll region with a view offset. The terminal is
always 18 logical rows; term_write_tilemap maps screen row -> logical row +
wViewTop (rows the OSK covers clamp to the cursor line). Showing the OSK
sets the offset to OSK_ROWS so the cursor line lands at row 14 (above the
keyboard) and hiding it sets the offset back to 0 - now purely a remap, so
nothing is scrolled off or destroyed. term_set_view replaces term_set_rows;
term_scroll/cursor_down are back to plain 18-row scrolling.
Result: full 18-row backlog when the OSK is hidden, a shifted 15-row window
when shown, and toggling is lossless (verified: OSK-shown view == baseline
rows 3..17, and toggle on+off == baseline exactly).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The terminal now has a variable usable height (wTermRows). term_scroll and
cursor_down operate within [0 .. wTermRows-1], and term_set_rows(n) shrinks
or grows that region, scrolling the cursor up into view when it would fall
outside. osk_toggle shrinks the terminal to the rows above the keyboard on
show (18 - OSK_ROWS = 15) and restores full height on hide, so the active
line is always visible just above the docked keyboard, and hiding the OSK
reclaims all 18 rows.
Also add c/count.c ("count [n]", default 25): prints n numbered lines to
observe/debug scrolling and the scroll-region behavior. Registered as
program id 21 / bank 23. Fixed the arg to read argv[0] (getargs returns the
string after the command name).
Verified: filling the screen then opening the OSK scrolls the latest line
to row 14 (visible) with the keyboard at 15-17; closing it restores rows
15-17; count N prints exactly N lines.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A joypad-driven keyboard that costs zero permanent screen space: it lives
on the GB window layer, so SELECT just flips LCDC bit 5 (window enable) and
the terminal's background layer underneath is never disturbed.
- src/joypad.asm: read $FF00 with edge detection (wPadCur/Prev/New).
- src/osk.asm: 3x20 key grid (letters, digits, space, punctuation, plus
Enter/Backspace) built once into spare bank-1 VRAM tiles (104+) and laid
out on the $9C00 window map, docked to the bottom 3 rows. The highlighted
key is a palette swap on its window attribute byte (CGB BG palette 1 =
inverted), so moving the cursor is 1-2 attribute writes with no tile
rebuilding. SELECT toggles, d-pad moves, A types.
- KGetc's console poll loop now polls the joypad and osk_handle each
iteration; a key press returns its byte to the reader exactly like a
serial byte, so the shell is oblivious to the input source.
Verified in the emulator (via --keys): SELECT shows the keyboard, the
highlight tracks the d-pad, and typing "ls"+Enter runs the command and
lists the files; a second SELECT hides it and reclaims the full 18 rows.
Known limitation: the OSK overlays the bottom 3 terminal rows, so if the
prompt has scrolled to the very bottom the current input line can be
hidden. A follow-up can add a scroll region (terminal uses rows 0-14 while
the OSK is up). Input over serial still works unchanged.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|