aboutsummaryrefslogtreecommitdiffstats
path: root/src/term.asm
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/term.asm129
1 files changed, 128 insertions, 1 deletions
diff --git a/src/term.asm b/src/term.asm
index 46cd23e..a3bfe19 100644
--- a/src/term.asm
+++ b/src/term.asm
@@ -36,6 +36,10 @@ DEF ACACHE EQU 40 ; attr cache in COL_BUF's spare stride bytes: the tile
; terminal state (WRAMX gap $D580-$D5FF)
DEF wVram EQU $D584 ; 2
DEF wMapTop EQU $D5BB ; BG-map ring: tilemap row where logical row 0 lives
+; batched-write dirty spans, indexed by LINE-SLOT (slots survive scroll
+; rotation, so a span stays valid however much the batch scrolls):
+DEF wDMin EQU $D5BC ; 18 bytes: first dirty tile col per slot ($FF = clean)
+DEF wDMax EQU $D5CE ; 18 bytes: last dirty tile col per slot
DEF wCurRow EQU $D586 ; cursor screen row 0..17
DEF wCurCol EQU $D587 ; cursor screen col 0..39
DEF wCursorOn EQU $D588 ; draw the cursor?
@@ -96,6 +100,23 @@ term_init::
ld a, $FF
ld [wCSPL], a ; invalidate the color_setup memo (no packed
; color is $FF: bg/fg nibbles are 0..7)
+ ; dirty spans: all clean ($FF min / 0 max); no batch active
+ ld hl, wDMin
+ ld b, 18
+.dspan
+ ld a, $FF
+ ld [hl+], a
+ dec b
+ jr nz, .dspan
+ ld hl, wDMax
+ ld b, 18
+.dspan2
+ xor a
+ ld [hl+], a
+ dec b
+ jr nz, .dspan2
+ ld [wBatch], a
+ ld [wBatchDirty], a
ld a, 1
ld [wCursorOn], a
ld a, 7
@@ -689,8 +710,50 @@ render_tile:
ld [rVBK], a
ret
-; render_cursor_tile - rebuild the tile at the cursor position.
+; render_cursor_tile - rebuild the tile at the cursor position. Inside a
+; batched write (sys_write sets wBatch) it renders NOTHING: it marks the
+; cursor's tile in the per-slot dirty span instead, and term_write_end
+; renders every dirty tile exactly once. This is the single choke point all
+; of term_putc's visible mutations (char, \n, \r, \b, cursor moves) pass
+; through, so batching here covers them all.
render_cursor_tile:
+ ld a, [wBatch]
+ or a
+ jr z, .render
+ ; mark: span[assign[wCurRow]] grows to include wCurCol/2
+ ld a, [wCurRow]
+ add LOW(wAssign)
+ ld l, a
+ ld a, HIGH(wAssign)
+ adc 0
+ ld h, a
+ ld a, [hl] ; slot
+ add LOW(wDMin)
+ ld l, a
+ ld a, HIGH(wDMin)
+ adc 0
+ ld h, a ; HL = &wDMin[slot]
+ ld a, [wCurCol]
+ srl a
+ ld b, a ; B = tile col
+ ld a, [hl]
+ cp b
+ jr c, .minok ; min < tcol: keep
+ ld a, b
+ ld [hl], a
+.minok
+ ld de, wDMax - wDMin
+ add hl, de ; HL = &wDMax[slot]
+ ld a, [hl]
+ cp b
+ jr nc, .maxok ; max >= tcol: keep
+ ld a, b
+ ld [hl], a
+.maxok
+ ld a, 1
+ ld [wBatchDirty], a
+ ret
+.render
ld a, [wCurRow]
ld b, a
ld a, [wCurCol]
@@ -931,6 +994,70 @@ compute_offset::
ret
; -----------------------------------------------------------------------------
+; term_write_end - flush a batched write: render every dirty span tile once,
+; then the cursor tile (which also refreshes its map attr). Costs nothing
+; when the batch produced no console output (file-bound writes).
+; -----------------------------------------------------------------------------
+term_write_end::
+ xor a
+ ld [wBatch], a
+ ld a, [wBatchDirty]
+ or a
+ ret z ; no console output in this batch
+ xor a
+ ld [wBatchDirty], a
+ ld a, [rSVBK] ; same banking guard as term_putc
+ push af
+ ld a, 1
+ ld [rSVBK], a
+ ld b, 0 ; screen row
+.row
+ ; slot = assign[row]; skip if its span is clean
+ ld a, b
+ add LOW(wAssign)
+ ld l, a
+ ld a, HIGH(wAssign)
+ adc 0
+ ld h, a
+ ld a, [hl]
+ add LOW(wDMin)
+ ld l, a
+ ld a, HIGH(wDMin)
+ adc 0
+ ld h, a
+ ld a, [hl]
+ cp $FF
+ jr z, .next
+ ld c, a ; C = first dirty tile col
+ ld a, $FF
+ ld [hl], a ; reset min
+ ld de, wDMax - wDMin
+ add hl, de
+ ld a, [hl]
+ ld d, a ; D = last dirty tile col
+ xor a
+ ld [hl], a ; reset max
+.tile
+ push bc
+ push de
+ call render_tile ; B = row, C = tile col
+ pop de
+ pop bc
+ inc c
+ ld a, d
+ cp c
+ jr nc, .tile ; while last >= col
+.next
+ inc b
+ ld a, b
+ cp TROWS
+ jr c, .row
+ call render_cursor_tile ; wBatch is 0 again: real render + map attr
+ pop af
+ ld [rSVBK], a
+ ret
+
+; -----------------------------------------------------------------------------
; term_putc - A = character. Print at the cursor, advance, handle \n \r \b.
; -----------------------------------------------------------------------------
; term_putc guarantees SVBK=1 so the buffer/state at $D5xx/$D6xx are the ones