aboutsummaryrefslogtreecommitdiffstats
path: root/src/term.asm (follow)
Commit message (Collapse)AuthorAgeFilesLines
* term: SCY ring-scroll - scroll writes ONE map row; OSK toggle is 212 cyclesuser3 days1-75/+110
| | | | | | | | | | | | | | | | | | | | | 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.
* term: 3 more renderer wins - 10.9x scroll, 2.7x putc vs pre-cacheuser3 days1-101/+141
| | | | | | | | | | | | | | | | | | | | | | | 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: cache tile attrs in COL_BUF's spare stride bytes (3.5x scroll)user3 days1-28/+38
| | | | | | | | | | | | | | 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.
* term: 7-color terminal (per-glyph fg+bg) + ANSI escapes; colorize ircuser3 days1-28/+495
| | | | | | | | | | | | | 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.
* term: dark mode - black background, white text (OSK highlight inverts to match)user4 days1-7/+11
|
* term: compute the OSK view offset from the cursor row (keep input visible)user5 days1-9/+29
| | | | | | | | | | | | | | | | | 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.
* term/osk: view-offset scroll region (lossless backlog on OSK toggle)user5 days1-57/+30
| | | | | | | | | | | | | | 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).
* term/osk: scroll region so the OSK never hides the input lineuser5 days1-12/+57
| | | | | | | | | | | | | | | | | | | 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.
* osk: toggle-able on-screen keyboard on the window layeruser5 days1-2/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* syscall: mirror console output to the LCD terminaluser5 days1-0/+14
| | | | | | | | | | | | | | | | | | 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.
* term: cursor + O(1) line scrollinguser5 days1-208/+454
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* font: full mixed-case + punctuation glyph set (not uppercase-only)user5 days1-6/+6
| | | | | | | | | | | | | | 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.
* term: 40-column text terminal on the CGB LCD (4x8 dynamic tiles)user5 days1-0/+381
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.