Put a score beside a moving object, label a map or draw a message inside a panel. This routine draws an 8×8 character or a counted string at a pixel position you choose. It uses the existing span backend, so your text and shapes agree about where pixels live.

Include it, then draw a string
Reserve 96 bytes at T plus 48 at BP, separate from code, stack, font, string and bitmap. This complete caller uses 256×192 pixels, T at $7200 and BP at $7000. The bitmap is $4000–$57FF; attributes remain separate. Include the existing pixel_addr helper too. The reset caller owns ULA/attribute setup and maps stored one to the chosen ink colour.
Define TEXT_WIDTH, TEXT_HEIGHT, TEXT_PEN_MAX and TEXT_PACKED as shown in the caller. Include the text CPU component and its existing span backend once. Mono targets use pen maximum 1 and packed 0; CPC uses 3 and 1. BP must be zero page on 6502; T need not be. Scratch needs no initialisation; public inputs do.
After the display setup, this is an ordinary game call. The mailbox which follows is just how the verifier submits more requests.
Draw PIXEL TEXT at (21,37)
; A normal game call: eight-pixel advance, off-grid origin, opaque label.
ld hl,21
ld (T+0),hl
ld hl,37
ld (T+2),hl
ld hl,font_data
ld (T+4),hl
ld hl,label_data
ld (T+6),hl
ld hl,64
ld (T+11),hl
ld hl,0
ld (T+18),hl
ld hl,0
ld (T+20),hl
ld hl,256
ld (T+22),hl
ld hl,192
ld (T+24),hl
ld a,10
ld (T+8),a
ld a,65
ld (T+9),a
ld a,32
ld (T+10),a
ld a,63
ld (T+13),a
ld a,1
ld (T+14),a
ld a,1
ld (T+15),a
ld a,0
ld (T+16),a
call text_string
ld a,0
ld (COMMAND),a
ld a,239
ld (COMMAND+1),aCall text_string, then read T+17. Change X/Y and the string address/length to draw another label. For one character, set T+9 and call text_char; string address and length are then ignored. There is no retained scene, cursor or game loop inside the routine.
The calling contract
Words and the 32-bit count use little-endian order. The origin is the cell’s top-left corner, with Y downwards. Pens are 0–1, selecting stored bitmap bits; the display palette/attributes determine their colours. Both pen inputs must be valid, even when transparent mode does not draw the background.
| T offset | Supply or read |
|---|---|
| 0,2 | Signed 16-bit X,Y origin, each −512..511 |
| 4 | Font address word |
| 6,8 | String address word and byte length 0..255 |
| 9 | Single code byte for text_char |
| 10,11 | First code byte and glyph-count word, 1..256 |
| 13 | Fallback code, which must exist in the font |
| 14 | 0 transparent, 1 opaque |
| 15,16 | Foreground and background pen bytes |
| 17 | Output: 1 accepted, 0 rejected |
| 18,20,22,24 | Scissor left,top,right,bottom words; right/bottom exclusive |
| 26 | Output signed word: next X |
| 28,29 | Output bytes: codes consumed, substitutions |
| 30 | Output word: backend span calls |
| 32 | Output 32-bit destination-byte writes |
| 36–95 | Private scratch |
A string is counted, not zero-terminated. A zero byte is a code; there is no newline, wrapping or implicit case conversion. An empty string is accepted without source reads or drawing, after declaration checks. A glyph always advances by eight: nextX = inputX + 8*consumed, including blank, substituted and fully clipped glyphs. That output is signed 16-bit, not a byte that wraps at 255.
The scissor must be nonempty and inside this physical bitmap. The routine intersects glyph runs with it before calling the backend. A completely clipped valid string still succeeds. Bad coordinates, mode, pens, font range, fallback, scissor or a source/font end beyond $10000 reject before destination writes, with the original X returned and zero counters. An allocation ending exactly at $10000 is allowed by the arithmetic check.
Inputs 0–16 and 18–25 survive. Source ranges must actually be readable in your machine’s current mapping: arithmetic checks cannot establish memory ownership or negotiate a bank switch. Keep the font/string stable and disjoint from code, contexts, stack and destination for the whole call.
Supply a font you own
Each glyph is eight bytes, top row first, bit 7 leftmost. The address of a row is font + (code-first)*8 + row. The optional original Code198x font supplies 64 glyphs for ASCII 32..95, occupying 512 bytes under the sample repository’s MIT licence. It was drawn for these examples, not copied from a machine ROM. Its visible design is five columns by seven rows inside each 8×8 cell.
You can supply a ten-digit font in just 80 bytes, or a contiguous 256-code font in 2,048. First code plus glyph count must not exceed 256; fallback must belong to that range. Unsupported codes use the fallback and increase the substitution count, even when clipped. Lowercase needs its own glyphs or explicit conversion in your caller.
Open the sample font data
Original 64-glyph 8×8 font
; SPDX-License-Identifier: MIT
; Original Code198x diagnostic glyphs, ASCII 32..95. Eight MSB-left rows each.
db $00,$00,$00,$00,$00,$00,$00,$00 ; code 32
db $10,$10,$10,$10,$10,$00,$10,$00 ; code 33
db $28,$28,$28,$00,$00,$00,$00,$00 ; code 34
db $28,$7c,$28,$28,$7c,$28,$00,$00 ; code 35
db $10,$3c,$50,$38,$14,$78,$10,$00 ; code 36
db $64,$68,$08,$10,$20,$2c,$4c,$00 ; code 37
db $30,$48,$50,$20,$54,$48,$34,$00 ; code 38
db $10,$10,$20,$00,$00,$00,$00,$00 ; code 39
db $08,$10,$20,$20,$20,$10,$08,$00 ; code 40
db $20,$10,$08,$08,$08,$10,$20,$00 ; code 41
db $00,$54,$38,$7c,$38,$54,$00,$00 ; code 42
db $00,$10,$10,$7c,$10,$10,$00,$00 ; code 43
db $00,$00,$00,$00,$00,$10,$20,$00 ; code 44
db $00,$00,$00,$7c,$00,$00,$00,$00 ; code 45
db $00,$00,$00,$00,$00,$00,$10,$00 ; code 46
db $04,$08,$08,$10,$20,$20,$40,$00 ; code 47
db $38,$44,$4c,$54,$64,$44,$38,$00 ; code 48
db $10,$30,$10,$10,$10,$10,$38,$00 ; code 49
db $38,$44,$04,$08,$10,$20,$7c,$00 ; code 50
db $78,$04,$04,$38,$04,$04,$78,$00 ; code 51
db $08,$18,$28,$48,$7c,$08,$08,$00 ; code 52
db $7c,$40,$40,$78,$04,$04,$78,$00 ; code 53
db $38,$40,$40,$78,$44,$44,$38,$00 ; code 54
db $7c,$04,$08,$10,$20,$20,$20,$00 ; code 55
db $38,$44,$44,$38,$44,$44,$38,$00 ; code 56
db $38,$44,$44,$3c,$04,$04,$38,$00 ; code 57
db $00,$10,$00,$00,$10,$00,$00,$00 ; code 58
db $00,$10,$00,$00,$10,$10,$20,$00 ; code 59
db $04,$08,$10,$20,$10,$08,$04,$00 ; code 60
db $00,$00,$7c,$00,$7c,$00,$00,$00 ; code 61
db $40,$20,$10,$08,$10,$20,$40,$00 ; code 62
db $38,$44,$04,$08,$10,$00,$10,$00 ; code 63
db $38,$44,$5c,$54,$5c,$40,$38,$00 ; code 64
db $38,$44,$44,$7c,$44,$44,$44,$00 ; code 65
db $78,$44,$44,$78,$44,$44,$78,$00 ; code 66
db $38,$44,$40,$40,$40,$44,$38,$00 ; code 67
db $78,$44,$44,$44,$44,$44,$78,$00 ; code 68
db $7c,$40,$40,$78,$40,$40,$7c,$00 ; code 69
db $7c,$40,$40,$78,$40,$40,$40,$00 ; code 70
db $38,$44,$40,$5c,$44,$44,$3c,$00 ; code 71
db $44,$44,$44,$7c,$44,$44,$44,$00 ; code 72
db $38,$10,$10,$10,$10,$10,$38,$00 ; code 73
db $1c,$08,$08,$08,$48,$48,$30,$00 ; code 74
db $44,$48,$50,$60,$50,$48,$44,$00 ; code 75
db $40,$40,$40,$40,$40,$40,$7c,$00 ; code 76
db $44,$6c,$54,$54,$44,$44,$44,$00 ; code 77
db $44,$64,$64,$54,$4c,$4c,$44,$00 ; code 78
db $38,$44,$44,$44,$44,$44,$38,$00 ; code 79
db $78,$44,$44,$78,$40,$40,$40,$00 ; code 80
db $38,$44,$44,$44,$54,$48,$34,$00 ; code 81
db $78,$44,$44,$78,$50,$48,$44,$00 ; code 82
db $3c,$40,$40,$38,$04,$04,$78,$00 ; code 83
db $7c,$10,$10,$10,$10,$10,$10,$00 ; code 84
db $44,$44,$44,$44,$44,$44,$38,$00 ; code 85
db $44,$44,$44,$44,$44,$28,$10,$00 ; code 86
db $44,$44,$44,$54,$54,$6c,$44,$00 ; code 87
db $44,$44,$28,$10,$28,$44,$44,$00 ; code 88
db $44,$44,$28,$10,$10,$10,$10,$00 ; code 89
db $7c,$04,$08,$10,$20,$40,$7c,$00 ; code 90
db $38,$20,$20,$20,$20,$20,$38,$00 ; code 91
db $40,$20,$20,$10,$08,$08,$04,$00 ; code 92
db $38,$08,$08,$08,$08,$08,$38,$00 ; code 93
db $10,$28,$44,$00,$00,$00,$00,$00 ; code 94
db $00,$00,$00,$00,$00,$00,$7c,$00 ; code 95Translation and byte boundaries
Glyph-local (3,5) at origin (21,37) lands at (24,42). The next cell starts at X=29. A blank space moves the next cell too: ink, cell bounds and advance are different things. Move a glyph, keep its shape works through that translation, clipping and division/remainder without requiring an algebra course.
Eight pixels at an arbitrary X can touch two mono bytes, or three four-pixel CPC bytes. The component finds foreground runs in each glyph row and sends them to bp_hspan. Transparent mode leaves zero font bits alone. Opaque mode paints the cell’s background row first, then its foreground runs; it replaces the visible clipped cell, including the blank rows/columns.
For the ten-code PIXEL TEXT, transparent drawing at X=24 and X=31 makes 77 / 77 destination-byte writes; opaque makes 157 / 237. Foreground uses 77 spans; opaque adds 80 background spans. Gaps and edge masks affect those counts, so an unaligned cell is not automatically more expensive in every workload.
This baseline favours understandable composition. Opaque drawing touches foreground bytes again after clearing their background. A masked KEEP/image blitter could combine those operations; pre-shifted glyph phases trade more font storage for less shifting/address work. Compare masked sprites and pre-shifted sprites. Those are design choices to measure, not invisible upgrades to this routine.
The text component assembles to 2,288 bytes, plus 533 for the backend, the chosen font/string and the contexts. Spectrum also needs the existing pixel_addr helper. Reset setup, display and stack are additional. These are storage and byte-write measurements, not cycle counts or a frame-budget promise.
Own the display and scratch
Clobbers: AF/BC/DE/HL and flags. Reserve a conservative 64-byte stack budget beyond your other calls/interrupts. T and BP are non-re-entrant. No call changes interrupt state, waits for a frame or synchronises video. On 6502, text temporarily uses BP+46/47 for indirect source reads, with no live source pointer carried over a span call. The caller owns banks, display access and interruption/coexistence policy.
Open the reusable Z80 text component
Include the text component once alongside its backend
; SPDX-License-Identifier: MIT
; Original 8x8 fixed-width text using bp_hspan; no display/font/OS setup.
; T: 96 private bytes; BP: separate 48 bytes (zero page on 6502).
; All registers/flags used by the backend may change. Non-re-entrant.
; See README.md for trusted source allocations, pens, bounds and outputs.
t_x equ T+0
t_y equ T+2
t_font equ T+4
t_source equ T+6
t_length equ T+8
t_code equ T+9
t_first equ T+10
t_count equ T+11
t_fallback equ T+13
t_mode equ T+14
t_fg equ T+15
t_bg equ T+16
t_status equ T+17
t_clip_l equ T+18
t_clip_t equ T+20
t_clip_r equ T+22
t_clip_b equ T+24
t_next_x equ T+26
t_consumed equ T+28
t_missing equ T+29
t_calls equ T+30
t_writes equ T+32
t_entry equ T+36
t_limit equ T+37
t_i equ T+38
t_index equ T+40
t_end equ T+42
t_pointer equ T+44
t_row equ T+46
t_column equ T+47
t_bits equ T+48
t_run equ T+49
t_start equ T+50
t_left equ T+52
t_right equ T+54
t_py equ T+56
t_pen equ T+58
t_temp equ T+60
t_work equ T+64
t_cmp equ T+95
bp_x0 equ BP+0
bp_y0 equ BP+2
bp_x1 equ BP+4
bp_op equ BP+8
bp_pen equ BP+11
bp_writes equ BP+40
g_cmp equ T+95
text_char:
ld a,$00
ld (t_entry),a
jp text_enter
text_string:
ld a,$01
ld (t_entry),a
jp text_enter
text_enter:
ld a,$00
ld (t_status),a
ld a,$00
ld (t_writes),a
ld a,$00
ld (t_writes+1),a
ld a,$00
ld (t_writes+2),a
ld a,$00
ld (t_writes+3),a
ld hl,$0000
ld (t_calls),hl
ld a,$00
ld (t_consumed),a
ld a,$00
ld (t_missing),a
ld hl,(t_x)
ld (t_next_x),hl
; Validate the complete declaration before drawing; no source read yet.
ld a,$fe
xor $80
ld (g_cmp),a
ld a,(t_x+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
jp nz,text_branch_1
ld a,$00
ld (g_cmp),a
ld a,(t_x)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
text_branch_1:
ld a,$01
xor $80
ld (g_cmp),a
ld a,(t_x+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_2
jp nz,text_done
ld a,$ff
ld (g_cmp),a
ld a,(t_x)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_2
jp nz,text_done
text_branch_2:
ld a,$fe
xor $80
ld (g_cmp),a
ld a,(t_y+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
jp nz,text_branch_3
ld a,$00
ld (g_cmp),a
ld a,(t_y)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
text_branch_3:
ld a,$01
xor $80
ld (g_cmp),a
ld a,(t_y+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_4
jp nz,text_done
ld a,$ff
ld (g_cmp),a
ld a,(t_y)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_4
jp nz,text_done
text_branch_4:
ld a,$01
ld (g_cmp),a
ld a,(t_mode)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_5
jp nz,text_done
text_branch_5:
ld hl,$0000
ld (t_temp),hl
ld a,(t_fg)
ld (t_temp),a
ld hl,TEXT_PEN_MAX
ld (t_end),hl
ld a,(t_end+1)
ld (g_cmp),a
ld a,(t_temp+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_6
jp nz,text_done
ld a,(t_end)
ld (g_cmp),a
ld a,(t_temp)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_6
jp nz,text_done
text_branch_6:
ld hl,$0000
ld (t_temp),hl
ld a,(t_bg)
ld (t_temp),a
ld hl,TEXT_PEN_MAX
ld (t_end),hl
ld a,(t_end+1)
ld (g_cmp),a
ld a,(t_temp+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_7
jp nz,text_done
ld a,(t_end)
ld (g_cmp),a
ld a,(t_temp)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_7
jp nz,text_done
text_branch_7:
ld a,$00
xor $80
ld (g_cmp),a
ld a,(t_clip_l+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
jp nz,text_branch_8
ld a,$00
ld (g_cmp),a
ld a,(t_clip_l)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
text_branch_8:
ld a,$00
xor $80
ld (g_cmp),a
ld a,(t_clip_t+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
jp nz,text_branch_9
ld a,$00
ld (g_cmp),a
ld a,(t_clip_t)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
text_branch_9:
ld a,(t_clip_r+1)
xor $80
ld (g_cmp),a
ld a,(t_clip_l+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_10
jp nz,text_done
ld a,(t_clip_r)
ld (g_cmp),a
ld a,(t_clip_l)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_10
jp text_done
text_branch_10:
ld a,(t_clip_b+1)
xor $80
ld (g_cmp),a
ld a,(t_clip_t+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_11
jp nz,text_done
ld a,(t_clip_b)
ld (g_cmp),a
ld a,(t_clip_t)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_11
jp text_done
text_branch_11:
ld hl,TEXT_WIDTH
ld (t_end),hl
ld a,(t_end+1)
ld (g_cmp),a
ld a,(t_clip_r+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_12
jp nz,text_done
ld a,(t_end)
ld (g_cmp),a
ld a,(t_clip_r)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_12
jp nz,text_done
text_branch_12:
ld hl,TEXT_HEIGHT
ld (t_end),hl
ld a,(t_end+1)
ld (g_cmp),a
ld a,(t_clip_b+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_13
jp nz,text_done
ld a,(t_end)
ld (g_cmp),a
ld a,(t_clip_b)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_13
jp nz,text_done
text_branch_13:
ld a,$00
ld (g_cmp),a
ld a,(t_count+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_14
ld a,$00
ld (g_cmp),a
ld a,(t_count)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_14
jp text_done
text_branch_14:
ld a,$01
ld (g_cmp),a
ld a,(t_count+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_15
jp nz,text_done
ld a,$00
ld (g_cmp),a
ld a,(t_count)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_15
jp nz,text_done
text_branch_15:
ld hl,$0000
ld (t_end),hl
ld a,(t_first)
ld (t_end),a
ld hl,(t_end)
ld de,(t_count)
add hl,de
ld (t_end),hl
ld a,$01
ld (g_cmp),a
ld a,(t_end+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_16
jp nz,text_done
ld a,$00
ld (g_cmp),a
ld a,(t_end)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_16
jp nz,text_done
text_branch_16:
ld hl,$0000
ld (t_index),hl
ld a,(t_fallback)
ld (t_index),a
ld hl,$0000
ld (t_temp),hl
ld a,(t_first)
ld (t_temp),a
ld a,(t_temp+1)
ld (g_cmp),a
ld a,(t_index+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
jp nz,text_branch_17
ld a,(t_temp)
ld (g_cmp),a
ld a,(t_index)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
text_branch_17:
ld a,(t_end+1)
ld (g_cmp),a
ld a,(t_index+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_18
jp nz,text_done
ld a,(t_end)
ld (g_cmp),a
ld a,(t_index)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_18
jp text_done
text_branch_18:
ld hl,(t_count)
ld (t_temp),hl
ld hl,t_temp
sla (hl)
inc hl
rl (hl)
ld hl,t_temp
sla (hl)
inc hl
rl (hl)
ld hl,t_temp
sla (hl)
inc hl
rl (hl)
ld hl,(t_temp)
ld de,(t_font)
add hl,de
ld (t_temp),hl
ld a,$00
ld (g_cmp),a
ld a,(t_temp+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_20
ld a,$00
ld (g_cmp),a
ld a,(t_temp)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_20
jp text_branch_19
text_branch_20:
ld a,(t_font+1)
ld (g_cmp),a
ld a,(t_temp+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
jp nz,text_branch_21
ld a,(t_font)
ld (g_cmp),a
ld a,(t_temp)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
text_branch_21:
text_branch_19:
ld a,$01
ld (t_limit),a
ld a,$00
ld (g_cmp),a
ld a,(t_entry)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_23
jp text_branch_22
text_branch_23:
ld a,(t_length)
ld (t_limit),a
ld hl,$0000
ld (t_temp),hl
ld a,(t_length)
ld (t_temp),a
ld hl,(t_temp)
ld de,(t_source)
add hl,de
ld (t_temp),hl
ld a,$00
ld (g_cmp),a
ld a,(t_temp+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_25
ld a,$00
ld (g_cmp),a
ld a,(t_temp)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_25
jp text_branch_24
text_branch_25:
ld a,(t_source+1)
ld (g_cmp),a
ld a,(t_temp+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
jp nz,text_branch_26
ld a,(t_source)
ld (g_cmp),a
ld a,(t_temp)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
text_branch_26:
text_branch_24:
text_branch_22:
ld a,$01
ld (t_status),a
ld a,$00
ld (t_i),a
text_glyph:
ld a,(t_limit)
ld (g_cmp),a
ld a,(t_i)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_27
jp text_done
text_branch_27:
ld a,$00
ld (g_cmp),a
ld a,(t_entry)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_30
jp text_branch_28
text_branch_30:
ld hl,$0000
ld (t_pointer),hl
ld a,(t_i)
ld (t_pointer),a
ld hl,(t_pointer)
ld de,(t_source)
add hl,de
ld (t_pointer),hl
ld hl,(t_pointer)
ld a,(hl)
ld (t_index),a
ld hl,$0000
ld (t_temp),hl
ld a,$00
ld (t_index+1),a
jp text_branch_29
text_branch_28:
ld hl,$0000
ld (t_index),hl
ld a,(t_code)
ld (t_index),a
text_branch_29:
ld hl,$0000
ld (t_temp),hl
ld a,(t_first)
ld (t_temp),a
ld a,(t_temp+1)
ld (g_cmp),a
ld a,(t_index+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_31
jp nz,text_branch_33
ld a,(t_temp)
ld (g_cmp),a
ld a,(t_index)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_31
text_branch_33:
ld hl,(t_index)
ld de,(t_temp)
or a
sbc hl,de
ld (t_index),hl
ld a,(t_count+1)
ld (g_cmp),a
ld a,(t_index+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_32
jp nz,text_branch_34
ld a,(t_count)
ld (g_cmp),a
ld a,(t_index)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_32
text_branch_34:
text_branch_31:
ld hl,$0000
ld (t_index),hl
ld a,(t_fallback)
ld (t_index),a
ld hl,$0000
ld (t_temp),hl
ld a,(t_first)
ld (t_temp),a
ld hl,(t_index)
ld de,(t_temp)
or a
sbc hl,de
ld (t_index),hl
or a
ld a,$01
ld b,a
ld a,(t_missing)
adc a,b
ld (t_missing),a
text_branch_32:
ld hl,t_index
sla (hl)
inc hl
rl (hl)
ld hl,t_index
sla (hl)
inc hl
rl (hl)
ld hl,t_index
sla (hl)
inc hl
rl (hl)
ld hl,(t_font)
ld (t_pointer),hl
ld hl,(t_pointer)
ld de,(t_index)
add hl,de
ld (t_pointer),hl
ld a,$00
ld (t_row),a
text_row:
ld a,$08
ld (g_cmp),a
ld a,(t_row)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_35
jp text_next_glyph
text_branch_35:
ld hl,(t_y)
ld (t_py),hl
ld hl,$0000
ld (t_temp),hl
ld a,(t_row)
ld (t_temp),a
ld hl,(t_py)
ld de,(t_temp)
add hl,de
ld (t_py),hl
ld a,$00
ld (g_cmp),a
ld a,(t_mode)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_37
jp text_branch_36
text_branch_37:
ld hl,(t_next_x)
ld (t_left),hl
ld hl,(t_next_x)
ld (t_right),hl
ld hl,(t_right)
ld de,$0008
add hl,de
ld (t_right),hl
ld a,(t_bg)
ld (t_pen),a
call text_span
text_branch_36:
ld hl,(t_pointer)
ld a,(hl)
ld (t_bits),a
ld hl,(t_pointer)
ld de,$0001
add hl,de
ld (t_pointer),hl
ld a,$00
ld (t_column),a
ld a,$00
ld (t_run),a
text_bit:
ld a,$08
ld (g_cmp),a
ld a,(t_column)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_38
jp text_row_end
text_branch_38:
ld a,(t_bits)
and $80
jp z,text_branch_39
ld a,$00
ld (g_cmp),a
ld a,(t_run)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_40
text_branch_41:
ld a,(t_column)
ld (t_start),a
ld a,$01
ld (t_run),a
jp text_branch_40
text_branch_39:
ld a,$00
ld (g_cmp),a
ld a,(t_run)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_42
jp text_branch_40
text_branch_42:
call text_run
ld a,$00
ld (t_run),a
text_branch_40:
ld hl,t_bits
sla (hl)
or a
ld a,$01
ld b,a
ld a,(t_column)
adc a,b
ld (t_column),a
jp text_bit
text_row_end:
ld a,$00
ld (g_cmp),a
ld a,(t_run)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_44
jp text_branch_43
text_branch_44:
call text_run
text_branch_43:
or a
ld a,$01
ld b,a
ld a,(t_row)
adc a,b
ld (t_row),a
jp text_row
text_next_glyph:
ld hl,(t_next_x)
ld de,$0008
add hl,de
ld (t_next_x),hl
or a
ld a,$01
ld b,a
ld a,(t_i)
adc a,b
ld (t_i),a
ld a,(t_i)
ld (t_consumed),a
jp text_glyph
text_done:
ret
text_run:
ld hl,$0000
ld (t_left),hl
ld a,(t_start)
ld (t_left),a
ld hl,(t_left)
ld de,(t_next_x)
add hl,de
ld (t_left),hl
ld hl,$0000
ld (t_right),hl
ld a,(t_column)
ld (t_right),a
ld hl,(t_right)
ld de,(t_next_x)
add hl,de
ld (t_right),hl
ld a,(t_fg)
ld (t_pen),a
jp text_span
text_span:
; Intersect a half-open run with the validated physical-screen scissor.
ld a,(t_clip_t+1)
xor $80
ld (g_cmp),a
ld a,(t_py+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_span_done
jp nz,text_branch_45
ld a,(t_clip_t)
ld (g_cmp),a
ld a,(t_py)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_span_done
text_branch_45:
ld a,(t_clip_b+1)
xor $80
ld (g_cmp),a
ld a,(t_py+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_46
jp nz,text_span_done
ld a,(t_clip_b)
ld (g_cmp),a
ld a,(t_py)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_46
jp text_span_done
text_branch_46:
ld a,(t_clip_l+1)
xor $80
ld (g_cmp),a
ld a,(t_right+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_span_done
jp nz,text_branch_47
ld a,(t_clip_l)
ld (g_cmp),a
ld a,(t_right)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_span_done
jp z,text_span_done
text_branch_47:
ld a,(t_clip_r+1)
xor $80
ld (g_cmp),a
ld a,(t_left+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_48
jp nz,text_span_done
ld a,(t_clip_r)
ld (g_cmp),a
ld a,(t_left)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_48
jp text_span_done
text_branch_48:
ld a,(t_clip_l+1)
xor $80
ld (g_cmp),a
ld a,(t_left+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_50
jp nz,text_branch_49
ld a,(t_clip_l)
ld (g_cmp),a
ld a,(t_left)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_50
jp text_branch_49
text_branch_50:
ld hl,(t_clip_l)
ld (t_left),hl
text_branch_49:
ld a,(t_clip_r+1)
xor $80
ld (g_cmp),a
ld a,(t_right+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_51
jp nz,text_branch_52
ld a,(t_clip_r)
ld (g_cmp),a
ld a,(t_right)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_51
jp z,text_branch_51
text_branch_52:
ld hl,(t_clip_r)
ld (t_right),hl
text_branch_51:
ld hl,(t_left)
ld (bp_x0),hl
ld hl,(t_right)
ld (bp_x1),hl
ld hl,(t_py)
ld (bp_y0),hl
if TEXT_PACKED
ld a,$00
ld (bp_op),a
ld a,(t_pen)
ld (bp_pen),a
else
ld a,$01
ld (bp_op),a
ld a,$00
ld (g_cmp),a
ld a,(t_pen)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_54
jp text_branch_53
text_branch_54:
ld a,$00
ld (bp_op),a
text_branch_53:
endif
call bp_hspan
ld a,$00
ld (t_work),a
ld a,$00
ld (t_work+1),a
ld a,$00
ld (t_work+2),a
ld a,$00
ld (t_work+3),a
ld a,(bp_writes)
ld (t_work),a
ld a,(bp_writes+1)
ld (t_work+1),a
or a
ld a,(t_work)
ld b,a
ld a,(t_writes)
adc a,b
ld (t_writes),a
ld a,(t_work+1)
ld b,a
ld a,(t_writes+1)
adc a,b
ld (t_writes+1),a
ld a,(t_work+2)
ld b,a
ld a,(t_writes+2)
adc a,b
ld (t_writes+2),a
ld a,(t_work+3)
ld b,a
ld a,(t_writes+3)
adc a,b
ld (t_writes+3),a
ld hl,(t_calls)
ld de,$0001
add hl,de
ld (t_calls),hl
text_span_done:
ret
text_end:What was verified
76 calls completed using Asm198x 0.0.71 and native Emu198x 0.39.0 in this original reset configuration. Every call compares the full bitmap, guards, font/string preservation, inputs, acceptance, advance, consumption/substitutions and work counters with an independent pixel model. Cases include phases, negative origins, scissor edges, all pen pairs, empty/long strings, fallback, 256-code fonts and rejected declarations. Selected whole native frames also match independently composed pixels.
Wrong glyph-bit and string-advance builds each completed accepted calls and failed both memory and picture checks. Retained records are bound to source and exact tools, with failure tests for missing/corrupted evidence. This establishes the stated reset fixture; stock-OS loading, real-hardware timing and tear-free live drawing need their own checks.
- Complete caller and execution evidence
- Full contract, costs and MIT attribution
- Compare text paths
- Underlying pixels and spans
Make the letters bigger
A title need not use the same tiny cells as a score. Repeat each source pixel twice in both directions and an 8×8 cell becomes 16×16. Use different factors for deliberately wide or tall lettering: 3×2 gives a 24×16 cell. The font still stores just eight bytes per glyph.

Choose scaled-text/z80.inc instead of the fixed bitmap-text CPU include. It exports the same text_char and text_string labels, so include only one. Keep this machine’s existing backend and required helper/tables. The allocations remain 96 bytes at T plus 48 at BP. Add two explicit inputs: T+68 is scale X and T+69 is scale Y, each an integer from 1 to 4. Set both, even for 1×1; an old fixed-width caller leaves those bytes uninitialised.
Initialise font, pens, scissor and both scales before text_string
; SPDX-License-Identifier: MIT
; A normal game call: enlarged glyph cells, off-grid origin, opaque label.
ld hl,21
ld (T+0),hl
ld hl,37
ld (T+2),hl
ld hl,font_data
ld (T+4),hl
ld hl,label_data
ld (T+6),hl
ld hl,64
ld (T+11),hl
ld hl,0
ld (T+18),hl
ld hl,0
ld (T+20),hl
ld hl,256
ld (T+22),hl
ld hl,192
ld (T+24),hl
ld a,MESSAGE_LENGTH
ld (T+8),a
ld a,65
ld (T+9),a
ld a,32
ld (T+10),a
ld a,63
ld (T+13),a
ld a,1
ld (T+14),a
ld a,1
ld (T+15),a
ld a,0
ld (T+16),a
ld a,SCALE_X
ld (T+68),a
ld a,SCALE_Y
ld (T+69),a
call text_stringThe existing font/range, fallback, source/count, mode, pens and scissor contract still applies. Inputs T+0..16, +18..25 and +68..69 survive. T+17 reports acceptance; T+26 returns X + length×8×scaleX as a word. Clipped, blank and fallback codes still advance. At scale X=4, 255 codes advance 8,160 pixels; a byte would lose most of that result. A rejected declaration preserves the original X and returns zero consumed, fallback, span and write counts before any destination writes.
Each font pixel becomes a rectangle, rather than a smoothed edge. For a destination-local pixel, the source position is (x div scaleX, y div scaleY). Equivalently, source column 3 at scale X=2 occupies local columns 6 and 7. Add the cell origin, then clip. A cut-off letter keeps that sampling phase: it does not start again at font column zero at the clipping edge. Integer division and remainders and glyph-local coordinates explain those two steps.
The native code scales the endpoints of each foreground run and repeats source rows. The independent checker instead samples destination pixels using integer division. Transparent zero bits preserve the picture underneath; opaque mode paints the enlarged background cell first, then its ink. Opaque spaces therefore clear their whole enlarged cells. Neither mode clears unused panel space.
Make it your own: wide lettering
The maintained custom caller changes 2×2 to 3×2 and replaces the ten-byte PIXEL TEXT message with four-byte BIG!. Its cells become 24×16, and the four-code label advances 96 pixels. The font and workspace sizes stay the same. Change the counted length with the message.
Choose independent X/Y enlargement and a counted label
; SPDX-License-Identifier: MIT
CUSTOM_TEXT equ 1
SCALE_X equ 3
SCALE_Y equ 2
MESSAGE_LENGTH equ 4
include "caller.inc"
Use 1×4 or 4×1 for other shapes; all sixteen pairs are executed. These factors describe logical pixels. Equal X/Y factors preserve the native raster’s pixel proportions, which are not necessarily square on a physical display. The captures do not calibrate a television’s aspect ratio.
Bigger glyphs, but an old drawing step
The following fragment is deliberately wrong. The glyph is now 16 pixels wide, but the next origin still moves eight. WAVE overlaps its neighbours. In opaque mode, a later background cell can erase part of the preceding letter.
Deliberately wrong: keep an eight-pixel advance
; BEGIN WRONG
ld hl,(t_next_x)
ld de,8
add hl,de
ld (t_next_x),hl
Restore the cached 8×scaleX advance, then check both the final X and the full picture:
Correct: move by the enlarged cell width
; BEGIN FIX
ld hl,(t_next_x)
ld de,(t_advance)
add hl,de
ld (t_next_x),hl
Size has a drawing cost
The scaled component uses 2,898 code bytes with the qualified assembler; the backend remains 533. The original sample font is still 512 bytes, and T/BP remain 96+48. BBC scanline tables, display memory, caller, string and stack remain separate. Keep a conservative 64-byte stack budget plus your caller/interrupt depth, and the renderer’s CPU/register obligations above.
For the same original W! label at (21,37), opaque mode and the same pens, native counters report. Cell dimensions are logical pixels:
| Scale | Cell (px) | Spans | Byte writes |
|---|---|---|---|
| 1×1 | 8×8 | 38 | 54 |
| 2×2 | 16×16 | 76 | 168 |
| 3×3 | 24×24 | 114 | 282 |
| 4×4 | 32×32 | 152 | 416 |
Doubling both factors quadruples a cell’s background area. Horizontal enlargement widens runs and changes byte crossings; vertical enlargement repeats rows and spans. CPC packs four pen indices per byte while the mono backends pack eight pixels, so their write counts differ. Counters include repeated writes to a byte. They measure drawing work, not cycles or a frame budget.
A separate pre-rendered size costs more assets but can avoid runtime expansion. Pre-shifted/masked blitters or precomposed hardware characters offer other trade-offs. Fully clipped cells skip raster work after resolving fallback, retaining logical advance and consumed/missing counts. This avoids expanding invisible rows in long offscreen strings.
The component owns T/BP, is non-re-entrant and supplies no OS negotiation, banking, interrupt protection or safe display interval. Keep source, font, code, contexts, stack and bitmap distinct and stable. This is a direct character/string renderer: the current fixed/proportional text-layout wrappers assume eight-pixel cells and row heights and cannot simply be placed over this include. A scaled layout must agree on both dimensions. Scaled wrapping, baselines and kerning remain separate work. The bounded shrinking routine below resamples ink inside an eight-byte cell. The glyph transform below supplies flips and quarter-turns before drawing.
The complete source and retained records contain 155 positive native calls, the customisation and completed wrong/fixed observations. Full bitmap allocations, neighbours, public outputs, counted source/font immutability and selected entire native frames match independent expectations. Coverage includes all scale pairs, every horizontal bit phase, pens, partial/full clipping, empty/255-code input, a 256-glyph declaration and invalid declarations. Qualified tools are Asm198x 0.0.71 and Emu198x 0.41.0 for this named reset/display path; original hardware, stock-OS coexistence, live tearing and other modes need separate checks.
Turn or reflect a glyph
An arrow can point in four directions without four hand-drawn assets. This separate z80 glyph_transform routine takes eight row bytes and writes eight transformed bytes. It can turn by 0°, 90°, 180° or 270° clockwise, then optionally reflect horizontally. It does not draw or rotate the arrangement of a string.

Define F as 32 writable bytes, include cross-platform/patterns/rendering/glyph-transform/z80.inc once, and set the source address, destination address and flags before calling glyph_transform. No extra zero-page or direct-page allocation is required. The complete caller owns the same display setup and text backend as the enlarged example above.
Transform eight bytes, then draw the result
; SPDX-License-Identifier: MIT
ld hl,font_data+304
ld (F),hl
ld hl,32896
ld (F+2),hl
ld a,GLYPH_FLAGS
ld (F+4),a
call glyph_transform
; SPDX-License-Identifier: MIT
; A normal game call: enlarged glyph cells, off-grid origin, opaque label.
ld hl,21
ld (T+0),hl
ld hl,37
ld (T+2),hl
ld hl,32896
ld (T+4),hl
ld hl,label_data
ld (T+6),hl
ld hl,1
ld (T+11),hl
ld hl,0
ld (T+18),hl
ld hl,0
ld (T+20),hl
ld hl,256
ld (T+22),hl
ld hl,192
ld (T+24),hl
ld a,MESSAGE_LENGTH
ld (T+8),a
ld a,65
ld (T+9),a
ld a,65
ld (T+10),a
ld a,65
ld (T+13),a
ld a,1
ld (T+14),a
ld a,1
ld (T+15),a
ld a,0
ld (T+16),a
ld a,SCALE_X
ld (T+68),a
ld a,SCALE_Y
ld (T+69),a
call text_stringThe first call produces a one-glyph font in RAM. The rest declares that font to the existing renderer and draws it. The source is our original F glyph; the one-glyph output is deliberately assigned code 65. Change the source address to reuse the component for your own icon. No other part of the font is required by the transform.
| F offset | Supply or read |
|---|---|
| 0 | Source address word, eight readable bytes |
| 2 | Destination address word, eight writable bytes |
| 4 | Flags 0..7: quarter-turns in bits 0..1, horizontal reflection in bit 2 |
| 5 | Output: 1 completed, 0 rejected |
| 6..31 | Private scratch, including an eight-byte snapshot |
Use little-endian words. Inputs 0..4 survive. Flags above 7, or either address above $FFF8, reject before source/destination access. An allocation ending exactly at $10000 passes the arithmetic check; you still own its mapping and access permissions. Keep F, code and stack disjoint from both glyph buffers. Source and destination may overlap, including exact in-place operation: the routine snapshots all eight rows before clearing output.
Clobbers: AF/BC/DE/HL and flags. Scratch is non-re-entrant. Reserve a conservative 16 stack bytes beyond the caller and interrupt requirements. The routine changes no interrupt policy or display state. An interrupt handler must preserve live registers and leave its buffers and scratch alone. The later drawing call retains the renderer’s separate stack and hardware obligations.
The top-left dot must move to the top-right
Coordinates inside the glyph run from 0 to 7, with Y down. A clockwise quarter-turn maps (x,y) to (7−y,x): local (0,0) becomes (7,0). Twice gives (7−x,7−y); three turns gives (y,7−x); four returns the original. Reflection then maps final X to 7−X. Doing the reflection first generally gives a different result.
The transformed glyph still occupies an 8×8 cell. Scale 4 makes it a 32×32 drawn cell; translation places it at the chosen screen origin. Layout advance and the order of characters do not rotate. Proportional widths and bearings need their own matching metrics; they are not updated by turning the ink. The Maths for Games overview places this alongside planned transform coverage without requiring that future lesson to use the routine.
Make it your own: a reflected icon
Change GLYPH_FLAGS from 1 to 4: no turn, then horizontal reflection. The stem of F moves to the right and its top bar stays horizontal. The input/output sizes and reusable component stay the same.
Reflect the same source glyph
; SPDX-License-Identifier: MIT
CUSTOM_TEXT equ 1
SCALE_X equ 4
SCALE_Y equ 4
MESSAGE_LENGTH equ 1
GLYPH_FLAGS equ 4
include "caller.inc"
To retain a whole transformed font, call once per glyph and move both pointers by eight. Check the whole bank in your caller. Per-glyph overlap safety does not make an overlapping bank traversal safe: one result could overwrite the next source glyph. Use separate banks or arrange traversal/snapshots deliberately.
Common mistake: a diagonal reflection instead of a turn
Swapping X and Y alone produces (y,x). That is a transpose: on this F, the long top bar points down from the left instead of becoming the right-hand vertical bar. The wrong routine returns success and stays inside its output buffer. Neither property proves that its picture is right.
Deliberately wrong mapping:
Swap coordinates without reversing an axis
; BEGIN WRONG
ld a,(f_dy)
ld (f_dx),a
Restore the missing 7−y:
Turn the glyph clockwise
; BEGIN FIX
ld a,$07
ld (f_dx),a
or a
ld a,(f_dy)
ld b,a
ld a,(f_dx)
sbc a,b
ld (f_dx),a
Pay once, cache, or store the variants
The transform component occupies 507 bytes, including its eight masks; it needs 32 bytes at F, eight bytes for each retained result. Font, renderer, backend, bitmap, caller and stack are additional.
A valid call reads eight source bytes into its snapshot, clears eight output bytes and scans all 64 source pixels. Each set pixel then reads and writes its destination byte. These are glyph-buffer operations, not all CPU accesses or cycle timings. More quarter-turns add coordinate arithmetic per set pixel. The original F contains 14 set pixels, so it makes that many destination read/modify/write operations after the eight clears.
Cache the result while it is useful, or prepare the variants at build time. Eight orientations cost 64 bytes per glyph rather than eight; eight whole 64-glyph banks cost 4,096 rather than 512. Stored variants avoid this transform call but still need drawing or transfer work. A hardware flip can be a better choice where the native display supports one; these bitmap backends do not gain that facility from this routine. No cycle or frame-budget claim follows from a correct still image.
All eight transforms preserve every source bit exactly. Arbitrary-angle rotation, larger pictures and pixel-aspect correction remain separate extensions. The bounded shrinking routine below supplies one explicit sampling policy.
What the transform checks establish
596 native observations completed on this machine with Asm198x 0.0.71 and Emu198x 0.41.0: all eight orientations, every single source pixel, asymmetric/full/empty glyphs, partial/exact overlap, invalid flags and wrapping addresses, plus normal, customised, faulty and repaired paths. Complete glyph/source/guard memory and selected full bitmap/native frames match an independent matrix-based oracle. The wrong rotation completed and failed the correct-image comparison; the repaired build matches the positive binary.
This is the same original reset configuration as the enlargement example, with exclusive ownership of the display and buffers. Stock OS integration, original hardware, interrupt coexistence and cycle timing need separate qualification. Retained replay binds source and tools and rejects incomplete, missing, corrupted and rehashed-but-wrong evidence.
Open the glyph transform routine
Transform a glyph independently of the display
; SPDX-License-Identifier: MIT
; Transform one MSB-left 8x8 glyph. F = 32 caller-owned RAM bytes.
; 6502 additionally needs GP = two zero-page bytes, disjoint from F and data.
; Flags 0..3 clockwise quarter-turns, bit 2 horizontal reflection AFTER rotation.
; Snapshot input before any output; overlapping source/destination is supported.
f_source equ F+0
f_dest equ F+2
f_flags equ F+4
f_status equ F+5
f_ptr equ F+6
f_x equ F+8
f_y equ F+9
f_dx equ F+10
f_dy equ F+11
f_bits equ F+12
f_mask equ F+13
f_turns equ F+14
f_i equ F+15
f_copy equ F+16
f_tmp equ F+24
f_cmp equ F+31
glyph_cmp equ F+31
glyph_transform:
ld a,$00
ld (f_status),a
ld a,$07
ld (glyph_cmp),a
ld a,(f_flags)
ld b,a
ld a,(glyph_cmp)
ld c,a
ld a,b
cp c
jp c,glyph_branch_1
jp nz,glyph_done
glyph_branch_1:
ld a,$ff
ld (glyph_cmp),a
ld a,(f_source+1)
ld b,a
ld a,(glyph_cmp)
ld c,a
ld a,b
cp c
jp c,glyph_branch_2
jp nz,glyph_done
ld a,$f8
ld (glyph_cmp),a
ld a,(f_source)
ld b,a
ld a,(glyph_cmp)
ld c,a
ld a,b
cp c
jp c,glyph_branch_2
jp nz,glyph_done
glyph_branch_2:
ld a,$ff
ld (glyph_cmp),a
ld a,(f_dest+1)
ld b,a
ld a,(glyph_cmp)
ld c,a
ld a,b
cp c
jp c,glyph_branch_3
jp nz,glyph_done
ld a,$f8
ld (glyph_cmp),a
ld a,(f_dest)
ld b,a
ld a,(glyph_cmp)
ld c,a
ld a,b
cp c
jp c,glyph_branch_3
jp nz,glyph_done
glyph_branch_3:
; Copy all eight source rows before clearing the destination.
ld a,$00
ld (f_i),a
ld hl,(f_source)
ld (f_ptr),hl
glyph_snapshot:
ld hl,(f_ptr)
ld a,(hl)
push af
ld a,(f_i)
ld l,a
ld h,0
ld de,f_copy
add hl,de
pop af
ld (hl),a
ld hl,(f_ptr)
ld de,$0001
add hl,de
ld (f_ptr),hl
or a
ld a,$01
ld b,a
ld a,(f_i)
adc a,b
ld (f_i),a
ld a,$08
ld (glyph_cmp),a
ld a,(f_i)
ld b,a
ld a,(glyph_cmp)
ld c,a
ld a,b
cp c
jp c,glyph_snapshot
glyph_branch_4:
ld a,$00
ld (f_i),a
ld hl,(f_dest)
ld (f_ptr),hl
glyph_clear:
ld a,$00
ld hl,(f_ptr)
ld (hl),a
ld hl,(f_ptr)
ld de,$0001
add hl,de
ld (f_ptr),hl
or a
ld a,$01
ld b,a
ld a,(f_i)
adc a,b
ld (f_i),a
ld a,$08
ld (glyph_cmp),a
ld a,(f_i)
ld b,a
ld a,(glyph_cmp)
ld c,a
ld a,b
cp c
jp c,glyph_clear
glyph_branch_5:
ld a,$00
ld (f_y),a
glyph_row:
ld a,(f_y)
ld l,a
ld h,0
ld de,f_copy
add hl,de
ld a,(hl)
ld (f_bits),a
ld a,$00
ld (f_x),a
glyph_pixel:
ld a,(f_bits)
and $80
jp z,glyph_next
ld a,(f_x)
ld (f_dx),a
ld a,(f_y)
ld (f_dy),a
ld a,(f_flags)
and 3
ld (f_turns),a
glyph_turn:
ld a,$00
ld (glyph_cmp),a
ld a,(f_turns)
ld b,a
ld a,(glyph_cmp)
ld c,a
ld a,b
cp c
jp nz,glyph_branch_6
jp glyph_reflect
glyph_branch_6:
ld a,(f_dx)
ld (f_tmp),a
; BEGIN ROTATION FIX: (x,y) becomes (7-y,x), not (y,x).
ld a,$07
ld (f_dx),a
or a
ld a,(f_dy)
ld b,a
ld a,(f_dx)
sbc a,b
ld (f_dx),a
; END ROTATION FIX
ld a,(f_tmp)
ld (f_dy),a
or a
ld a,$ff
ld b,a
ld a,(f_turns)
adc a,b
ld (f_turns),a
jp glyph_turn
glyph_reflect:
ld a,(f_flags)
and 4
jp z,glyph_store
ld a,$07
ld (f_tmp),a
or a
ld a,(f_dx)
ld b,a
ld a,(f_tmp)
sbc a,b
ld (f_tmp),a
ld a,(f_tmp)
ld (f_dx),a
glyph_store:
ld a,(f_dx)
ld l,a
ld h,0
ld de,glyph_masks
add hl,de
ld a,(hl)
ld (f_mask),a
ld hl,$0000
ld (f_ptr),hl
ld a,(f_dy)
ld (f_ptr),a
ld hl,(f_ptr)
ld de,(f_dest)
add hl,de
ld (f_ptr),hl
ld hl,(f_ptr)
ld a,(hl)
ld b,a
ld a,(f_mask)
or b
ld hl,(f_ptr)
ld (hl),a
glyph_next:
ld hl,f_bits
sla (hl)
or a
ld a,$01
ld b,a
ld a,(f_x)
adc a,b
ld (f_x),a
ld a,$08
ld (glyph_cmp),a
ld a,(f_x)
ld b,a
ld a,(glyph_cmp)
ld c,a
ld a,b
cp c
jp c,glyph_pixel
glyph_branch_7:
or a
ld a,$01
ld b,a
ld a,(f_y)
adc a,b
ld (f_y),a
ld a,$08
ld (glyph_cmp),a
ld a,(f_y)
ld b,a
ld a,(glyph_cmp)
ld c,a
ld a,b
cp c
jp c,glyph_row
glyph_branch_8:
ld a,$01
ld (f_status),a
glyph_done:
ret
glyph_masks:
db 128,64,32,16,8,4,2,1
glyph_transform_end:Shrink the ink, keep the cell
Need a smaller icon? glyph_resize resamples an 8×8 source into a width and height you choose, each 1..8. The result still occupies eight bytes: useful pixels sit at the top-left, with zero padding to the right and below. Your existing renderer can draw that cell without learning a new asset format. The whole source cell is sampled, including blank margins: the requested rectangle is not a measured tight ink box.

Define RZ as 32 writable bytes and include cross-platform/patterns/rendering/glyph-resize/z80.inc once. No extra zero-page or direct-page allocation is needed. Set both pointers and both dimensions before calling glyph_resize. Scratch needs no initialisation.
These are the complete caller’s scratch addresses. Choose free RAM in your own game; the address declaration does not allocate or protect it. The include is separate from the renderer and backend already shown above. Adjust repository-relative paths to match your project’s files.
Name the caller-owned scratch storage
RZ equ 29312Include the reusable resize component once
include "../../../../../cross-platform/patterns/rendering/glyph-resize/z80.inc"Resample one glyph, then draw its padded cell
; SPDX-License-Identifier: MIT
ld hl,font_data+304
ld (RZ),hl
ld hl,32896
ld (RZ+2),hl
ld a,GLYPH_WIDTH
ld (RZ+4),a
ld a,GLYPH_HEIGHT
ld (RZ+5),a
call glyph_resize
; SPDX-License-Identifier: MIT
; A normal game call: enlarged glyph cells, off-grid origin, opaque label.
ld hl,21
ld (T+0),hl
ld hl,37
ld (T+2),hl
ld hl,32896
ld (T+4),hl
ld hl,label_data
ld (T+6),hl
ld hl,1
ld (T+11),hl
ld hl,0
ld (T+18),hl
ld hl,0
ld (T+20),hl
ld hl,256
ld (T+22),hl
ld hl,192
ld (T+24),hl
ld a,MESSAGE_LENGTH
ld (T+8),a
ld a,65
ld (T+9),a
ld a,65
ld (T+10),a
ld a,65
ld (T+13),a
ld a,1
ld (T+14),a
ld a,1
ld (T+15),a
ld a,0
ld (T+16),a
ld a,SCALE_X
ld (T+68),a
ld a,SCALE_Y
ld (T+69),a
call text_stringThe source is our original F; the caller assigns its resized output code 65 in a one-glyph font. The second part declares that font and calls the existing enlarged renderer. The resize routine itself draws nothing and changes no text metrics. Transparent drawing leaves zero padding alone. Opaque drawing still paints the background across the whole padded 8×8 cell (32×32 at the demo’s scale four), not just the requested sampling rectangle.
| RZ offset | Supply or read |
|---|---|
| 0 | Source address word, eight readable bytes |
| 2 | Destination address word, eight writable bytes |
| 4,5 | Width and height bytes, each 1..8 |
| 6 | Output: 1 completed, 0 rejected |
| 7..31 | Private scratch, including eight source snapshot bytes |
Words are little-endian; inputs 0..5 survive. Dimensions outside 1..8 or either pointer above $FFF8 reject before source/destination access. An eight-byte range ending at $10000 passes the arithmetic check; you must still own its mapped memory. Source and destination may overlap, even exactly, because all source rows are copied before output is cleared. Keep RZ, code and stack disjoint from both.
Clobbers: AF/BC/DE/HL and flags. The routine is non-re-entrant and changes no interrupt/display policy. Reserve a conservative 16-byte stack allowance beyond caller/interrupt requirements. An interrupt handler must preserve live registers and avoid its scratch and buffers. The later renderer retains its own stack, bank, display-access and interrupt obligations. This reset caller owns the same machine-specific display setup as the examples above; it is not a stock-OS launcher.
Sampling is a choice
Destination (x,y) selects source (x*8 div width, y*8 div height). This is an explicit top-left nearest-neighbour convention: select one source pixel, with no interpolation. Width five samples columns 0,1,3,4,6; width four samples 0,2,4,6. Height follows the same rule independently. An 8×8 request is the identity; 1×1 retains only the top-left source pixel.
The z80 implementation uses bounded error accumulators. Add eight after each output pixel, subtract width and advance the source column while the error is at least width. Reset that state at the next row. The independent oracle uses direct division, so it checks the recurrence against a different calculation. Division and remainders explain the quotient and leftover; local-to-screen coordinates place the resulting cell.
A one-pixel vertical stroke in source column one disappears at width four: that column is never sampled. A specially drawn small icon can be clearer. Averaging, coverage filters and pixel-centre sampling would give different results; they are not hidden options in this routine. Logical bitmap pixels can also have non-square physical proportions, which these numeric dimensions do not correct.
Make it your own: a short, wide icon
Change GLYPH_WIDTH/GLYPH_HEIGHT from 5/7 to 8/4. Horizontal detail returns while alternate source rows are omitted. The result still occupies eight bytes, and the renderer’s cell and advance stay unchanged.
Keep all columns and halve the useful height
; SPDX-License-Identifier: MIT
CUSTOM_TEXT equ 1
SCALE_X equ 4
SCALE_Y equ 4
MESSAGE_LENGTH equ 1
GLYPH_WIDTH equ 8
GLYPH_HEIGHT equ 4
include "caller.inc"
Replace the eight source bytes to resize another icon. A larger input, target above eight, tightly packed variable-size output or proportional metrics needs a different contract. For a bank, validate the complete allocation before calling once per glyph. Per-call overlap safety does not make an overlapping bank traversal safe: an early result may overwrite a later source. Prefer separate banks or plan snapshots/traversal explicitly.
Common mistake: crop instead of resample
The following fragment is deliberately wrong. It advances the source column by one per output pixel. At width five it takes columns 0..4 and drops the right side, rather than selecting across the whole source. Y still resamples correctly in this example. The F’s bars acquire the wrong proportions despite a successful, in-bounds call.
Wrong: take only the left source columns
; BEGIN WRONG
or a
ld a,$01
ld b,a
ld a,(r_sx)
adc a,b
ld (r_sx),a
Restore the accumulator which distributes eight source steps over the requested width:
Resample across the whole source width
; BEGIN FIX
or a
ld a,$08
ld b,a
ld a,(r_xe)
adc a,b
ld (r_xe),a
resize_x_sample:
ld a,(r_width)
ld (resize_cmp),a
ld a,(r_xe)
ld b,a
ld a,(resize_cmp)
ld c,a
ld a,b
cp c
jp c,resize_x_ready
resize_branch_9:
or a
ld a,(r_width)
ld b,a
ld a,(r_xe)
sbc a,b
ld (r_xe),a
or a
ld a,$01
ld b,a
ld a,(r_sx)
adc a,b
ld (r_sx),a
jp resize_x_sample
resize_x_ready:
Work, storage and quality
The component occupies 589 bytes, including its eight masks. It needs 32 bytes at RZ, and eight bytes per retained result. Font, renderer, backend, caller, display memory and stack remain additional.
Each valid call snapshots eight source bytes, clears eight result bytes and samples width×height pixels, from 1 to 64. Each sampled set bit reads and writes its destination byte. These are glyph-buffer operations, not all CPU accesses or measured cycles. Smaller requests also perform repeated accumulator subtraction; cost does not fall simply in proportion to output area.
The output always costs eight bytes, even for 1×1. This implementation preserves a convenient asset format rather than packing smaller glyphs. Cache a useful size or prepare it at build time. All 64 dimension pairs, including the 8×8 identity, cost 512 bytes per source glyph if stored together; one source costs eight. Store only the sizes your game needs. A hand-designed small font may preserve strokes better, and enlargement after shrinking cannot recover discarded details.
This does not change text advance, bearings or wrapping. A proportional font must keep its cropped pixels and metric table in agreement. Arbitrary angles, targets above eight and scale-aware layout remain separate extensions.
What the resize checks establish
543 native observations completed for this machine with Asm198x 0.0.71 and Emu198x 0.41.0: all 64 size pairs on four source shapes, every source pixel at four representative dimensions, partial/exact overlap, rejected dimensions/addresses, normal/customised callers, and completed wrong/repaired sampling. Complete glyph/source/guard data and selected full bitmap/native frames match an independent division-based oracle. Retained controls reject missing, incomplete, corrupted and rehashed-but-wrong evidence.
This qualifies the named original reset fixture, not stock-OS loading, original hardware, interrupt coexistence or cycle timing. Width/height are useful ink bounds inside the padded cell, not a promise of variable-size layout or hardware upload.
Open the glyph shrinking routine
Resample independently of the display
; SPDX-License-Identifier: MIT
; Shrink an MSB-left 8x8 glyph into 1..8 by 1..8 ink bounds, zero-padded to 8x8.
; RZ = 32 RAM bytes; 6502 RP = separate two zero-page bytes.
; Source sampling: floor(destination*8/size), top-left convention. Snapshot permits overlap.
r_source equ RZ+0
r_dest equ RZ+2
r_width equ RZ+4
r_height equ RZ+5
r_status equ RZ+6
r_ptr equ RZ+8
r_x equ RZ+10
r_y equ RZ+11
r_sx equ RZ+12
r_sy equ RZ+13
r_xe equ RZ+14
r_ye equ RZ+15
r_bits equ RZ+16
r_mask equ RZ+17
r_cmp equ RZ+23
r_copy equ RZ+24
resize_cmp equ RZ+23
glyph_resize:
ld a,$00
ld (r_status),a
ld a,$01
ld (resize_cmp),a
ld a,(r_width)
ld b,a
ld a,(resize_cmp)
ld c,a
ld a,b
cp c
jp c,resize_done
resize_branch_1:
ld a,$08
ld (resize_cmp),a
ld a,(r_width)
ld b,a
ld a,(resize_cmp)
ld c,a
ld a,b
cp c
jp c,resize_branch_2
jp nz,resize_done
resize_branch_2:
ld a,$01
ld (resize_cmp),a
ld a,(r_height)
ld b,a
ld a,(resize_cmp)
ld c,a
ld a,b
cp c
jp c,resize_done
resize_branch_3:
ld a,$08
ld (resize_cmp),a
ld a,(r_height)
ld b,a
ld a,(resize_cmp)
ld c,a
ld a,b
cp c
jp c,resize_branch_4
jp nz,resize_done
resize_branch_4:
ld a,$ff
ld (resize_cmp),a
ld a,(r_source+1)
ld b,a
ld a,(resize_cmp)
ld c,a
ld a,b
cp c
jp c,resize_branch_5
jp nz,resize_done
ld a,$f8
ld (resize_cmp),a
ld a,(r_source)
ld b,a
ld a,(resize_cmp)
ld c,a
ld a,b
cp c
jp c,resize_branch_5
jp nz,resize_done
resize_branch_5:
ld a,$ff
ld (resize_cmp),a
ld a,(r_dest+1)
ld b,a
ld a,(resize_cmp)
ld c,a
ld a,b
cp c
jp c,resize_branch_6
jp nz,resize_done
ld a,$f8
ld (resize_cmp),a
ld a,(r_dest)
ld b,a
ld a,(resize_cmp)
ld c,a
ld a,b
cp c
jp c,resize_branch_6
jp nz,resize_done
resize_branch_6:
ld a,$00
ld (r_x),a
ld hl,(r_source)
ld (r_ptr),hl
resize_snapshot:
ld hl,(r_ptr)
ld a,(hl)
push af
ld a,(r_x)
ld l,a
ld h,0
ld de,r_copy
add hl,de
pop af
ld (hl),a
ld hl,(r_ptr)
ld de,$0001
add hl,de
ld (r_ptr),hl
or a
ld a,$01
ld b,a
ld a,(r_x)
adc a,b
ld (r_x),a
ld a,$08
ld (resize_cmp),a
ld a,(r_x)
ld b,a
ld a,(resize_cmp)
ld c,a
ld a,b
cp c
jp c,resize_snapshot
resize_branch_7:
ld a,$00
ld (r_x),a
ld hl,(r_dest)
ld (r_ptr),hl
resize_clear:
ld a,$00
ld hl,(r_ptr)
ld (hl),a
ld hl,(r_ptr)
ld de,$0001
add hl,de
ld (r_ptr),hl
or a
ld a,$01
ld b,a
ld a,(r_x)
adc a,b
ld (r_x),a
ld a,$08
ld (resize_cmp),a
ld a,(r_x)
ld b,a
ld a,(resize_cmp)
ld c,a
ld a,b
cp c
jp c,resize_clear
resize_branch_8:
ld a,$00
ld (r_y),a
ld a,$00
ld (r_sy),a
ld a,$00
ld (r_ye),a
resize_row:
ld a,(r_sy)
ld l,a
ld h,0
ld de,r_copy
add hl,de
ld a,(hl)
ld (r_bits),a
ld a,$00
ld (r_x),a
ld a,$00
ld (r_sx),a
ld a,$00
ld (r_xe),a
resize_pixel:
ld a,(r_sx)
ld l,a
ld h,0
ld de,resize_masks
add hl,de
ld a,(hl)
ld b,a
ld a,(r_bits)
and b
jp z,resize_next
ld a,(r_x)
ld l,a
ld h,0
ld de,resize_masks
add hl,de
ld a,(hl)
ld (r_mask),a
ld hl,$0000
ld (r_ptr),hl
ld a,(r_y)
ld (r_ptr),a
ld hl,(r_ptr)
ld de,(r_dest)
add hl,de
ld (r_ptr),hl
ld hl,(r_ptr)
ld a,(hl)
ld b,a
ld a,(r_mask)
or b
ld hl,(r_ptr)
ld (hl),a
resize_next:
; BEGIN SAMPLING FIX: accumulate eight source steps per destination width.
or a
ld a,$08
ld b,a
ld a,(r_xe)
adc a,b
ld (r_xe),a
resize_x_sample:
ld a,(r_width)
ld (resize_cmp),a
ld a,(r_xe)
ld b,a
ld a,(resize_cmp)
ld c,a
ld a,b
cp c
jp c,resize_x_ready
resize_branch_9:
or a
ld a,(r_width)
ld b,a
ld a,(r_xe)
sbc a,b
ld (r_xe),a
or a
ld a,$01
ld b,a
ld a,(r_sx)
adc a,b
ld (r_sx),a
jp resize_x_sample
resize_x_ready:
; END SAMPLING FIX
or a
ld a,$01
ld b,a
ld a,(r_x)
adc a,b
ld (r_x),a
ld a,(r_width)
ld (resize_cmp),a
ld a,(r_x)
ld b,a
ld a,(resize_cmp)
ld c,a
ld a,b
cp c
jp c,resize_pixel
resize_branch_10:
or a
ld a,$08
ld b,a
ld a,(r_ye)
adc a,b
ld (r_ye),a
resize_y_sample:
ld a,(r_height)
ld (resize_cmp),a
ld a,(r_ye)
ld b,a
ld a,(resize_cmp)
ld c,a
ld a,b
cp c
jp c,resize_y_ready
resize_branch_11:
or a
ld a,(r_height)
ld b,a
ld a,(r_ye)
sbc a,b
ld (r_ye),a
or a
ld a,$01
ld b,a
ld a,(r_sy)
adc a,b
ld (r_sy),a
jp resize_y_sample
resize_y_ready:
or a
ld a,$01
ld b,a
ld a,(r_y)
adc a,b
ld (r_y),a
ld a,(r_height)
ld (resize_cmp),a
ld a,(r_y)
ld b,a
ld a,(resize_cmp)
ld c,a
ld a,b
cp c
jp c,resize_row
resize_branch_12:
ld a,$01
ld (r_status),a
resize_done:
ret
resize_masks:
db 128,64,32,16,8,4,2,1
glyph_resize_end:Read the reusable integer-enlarged renderer
Scaled foreground runs over the existing native span backend
; SPDX-License-Identifier: MIT
; Integer-enlarged 8x8 glyphs using the existing bp_hspan backend.
; T: 96 bytes, with scale inputs T+68/69 (1..4). BP: separate 48 bytes.
; All registers/flags used by the backend may change. Non-re-entrant.
; See README.md for trusted source allocations, pens, bounds and outputs.
t_x equ T+0
t_y equ T+2
t_font equ T+4
t_source equ T+6
t_length equ T+8
t_code equ T+9
t_first equ T+10
t_count equ T+11
t_fallback equ T+13
t_mode equ T+14
t_fg equ T+15
t_bg equ T+16
t_status equ T+17
t_clip_l equ T+18
t_clip_t equ T+20
t_clip_r equ T+22
t_clip_b equ T+24
t_next_x equ T+26
t_consumed equ T+28
t_missing equ T+29
t_calls equ T+30
t_writes equ T+32
t_entry equ T+36
t_limit equ T+37
t_i equ T+38
t_index equ T+40
t_end equ T+42
t_pointer equ T+44
t_row equ T+46
t_column equ T+47
t_bits equ T+48
t_run equ T+49
t_start equ T+50
t_left equ T+52
t_right equ T+54
t_py equ T+56
t_pen equ T+58
t_temp equ T+60
t_work equ T+64
t_sx equ T+68
t_sy equ T+69
t_advance equ T+70
t_repeat equ T+74
t_product equ T+76
t_factor equ T+78
t_raw equ T+80
t_cmp equ T+95
bp_x0 equ BP+0
bp_y0 equ BP+2
bp_x1 equ BP+4
bp_op equ BP+8
bp_pen equ BP+11
bp_writes equ BP+40
g_cmp equ T+95
text_char:
ld a,$00
ld (t_entry),a
jp text_enter
text_string:
ld a,$01
ld (t_entry),a
jp text_enter
text_enter:
ld a,$00
ld (t_status),a
ld a,$00
ld (t_writes),a
ld a,$00
ld (t_writes+1),a
ld a,$00
ld (t_writes+2),a
ld a,$00
ld (t_writes+3),a
ld hl,$0000
ld (t_calls),hl
ld a,$00
ld (t_consumed),a
ld a,$00
ld (t_missing),a
ld hl,(t_x)
ld (t_next_x),hl
; Validate the complete declaration before drawing; no source read yet.
ld a,$fe
xor $80
ld (g_cmp),a
ld a,(t_x+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
jp nz,text_branch_1
ld a,$00
ld (g_cmp),a
ld a,(t_x)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
text_branch_1:
ld a,$01
xor $80
ld (g_cmp),a
ld a,(t_x+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_2
jp nz,text_done
ld a,$ff
ld (g_cmp),a
ld a,(t_x)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_2
jp nz,text_done
text_branch_2:
ld a,$fe
xor $80
ld (g_cmp),a
ld a,(t_y+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
jp nz,text_branch_3
ld a,$00
ld (g_cmp),a
ld a,(t_y)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
text_branch_3:
ld a,$01
xor $80
ld (g_cmp),a
ld a,(t_y+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_4
jp nz,text_done
ld a,$ff
ld (g_cmp),a
ld a,(t_y)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_4
jp nz,text_done
text_branch_4:
ld a,$01
ld (g_cmp),a
ld a,(t_sx)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
text_branch_5:
ld a,$04
ld (g_cmp),a
ld a,(t_sx)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_6
jp nz,text_done
text_branch_6:
ld a,$01
ld (g_cmp),a
ld a,(t_sy)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
text_branch_7:
ld a,$04
ld (g_cmp),a
ld a,(t_sy)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_8
jp nz,text_done
text_branch_8:
ld a,$01
ld (g_cmp),a
ld a,(t_mode)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_9
jp nz,text_done
text_branch_9:
ld hl,$0000
ld (t_temp),hl
ld a,(t_fg)
ld (t_temp),a
ld hl,TEXT_PEN_MAX
ld (t_end),hl
ld a,(t_end+1)
ld (g_cmp),a
ld a,(t_temp+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_10
jp nz,text_done
ld a,(t_end)
ld (g_cmp),a
ld a,(t_temp)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_10
jp nz,text_done
text_branch_10:
ld hl,$0000
ld (t_temp),hl
ld a,(t_bg)
ld (t_temp),a
ld hl,TEXT_PEN_MAX
ld (t_end),hl
ld a,(t_end+1)
ld (g_cmp),a
ld a,(t_temp+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_11
jp nz,text_done
ld a,(t_end)
ld (g_cmp),a
ld a,(t_temp)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_11
jp nz,text_done
text_branch_11:
ld a,$00
xor $80
ld (g_cmp),a
ld a,(t_clip_l+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
jp nz,text_branch_12
ld a,$00
ld (g_cmp),a
ld a,(t_clip_l)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
text_branch_12:
ld a,$00
xor $80
ld (g_cmp),a
ld a,(t_clip_t+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
jp nz,text_branch_13
ld a,$00
ld (g_cmp),a
ld a,(t_clip_t)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
text_branch_13:
ld a,(t_clip_r+1)
xor $80
ld (g_cmp),a
ld a,(t_clip_l+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_14
jp nz,text_done
ld a,(t_clip_r)
ld (g_cmp),a
ld a,(t_clip_l)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_14
jp text_done
text_branch_14:
ld a,(t_clip_b+1)
xor $80
ld (g_cmp),a
ld a,(t_clip_t+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_15
jp nz,text_done
ld a,(t_clip_b)
ld (g_cmp),a
ld a,(t_clip_t)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_15
jp text_done
text_branch_15:
ld hl,TEXT_WIDTH
ld (t_end),hl
ld a,(t_end+1)
ld (g_cmp),a
ld a,(t_clip_r+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_16
jp nz,text_done
ld a,(t_end)
ld (g_cmp),a
ld a,(t_clip_r)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_16
jp nz,text_done
text_branch_16:
ld hl,TEXT_HEIGHT
ld (t_end),hl
ld a,(t_end+1)
ld (g_cmp),a
ld a,(t_clip_b+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_17
jp nz,text_done
ld a,(t_end)
ld (g_cmp),a
ld a,(t_clip_b)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_17
jp nz,text_done
text_branch_17:
ld a,$00
ld (g_cmp),a
ld a,(t_count+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_18
ld a,$00
ld (g_cmp),a
ld a,(t_count)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_18
jp text_done
text_branch_18:
ld a,$01
ld (g_cmp),a
ld a,(t_count+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_19
jp nz,text_done
ld a,$00
ld (g_cmp),a
ld a,(t_count)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_19
jp nz,text_done
text_branch_19:
ld hl,$0000
ld (t_end),hl
ld a,(t_first)
ld (t_end),a
ld hl,(t_end)
ld de,(t_count)
add hl,de
ld (t_end),hl
ld a,$01
ld (g_cmp),a
ld a,(t_end+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_20
jp nz,text_done
ld a,$00
ld (g_cmp),a
ld a,(t_end)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_20
jp nz,text_done
text_branch_20:
ld hl,$0000
ld (t_index),hl
ld a,(t_fallback)
ld (t_index),a
ld hl,$0000
ld (t_temp),hl
ld a,(t_first)
ld (t_temp),a
ld a,(t_temp+1)
ld (g_cmp),a
ld a,(t_index+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
jp nz,text_branch_21
ld a,(t_temp)
ld (g_cmp),a
ld a,(t_index)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
text_branch_21:
ld a,(t_end+1)
ld (g_cmp),a
ld a,(t_index+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_22
jp nz,text_done
ld a,(t_end)
ld (g_cmp),a
ld a,(t_index)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_22
jp text_done
text_branch_22:
ld hl,(t_count)
ld (t_temp),hl
ld hl,t_temp
sla (hl)
inc hl
rl (hl)
ld hl,t_temp
sla (hl)
inc hl
rl (hl)
ld hl,t_temp
sla (hl)
inc hl
rl (hl)
ld hl,(t_temp)
ld de,(t_font)
add hl,de
ld (t_temp),hl
ld a,$00
ld (g_cmp),a
ld a,(t_temp+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_24
ld a,$00
ld (g_cmp),a
ld a,(t_temp)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_24
jp text_branch_23
text_branch_24:
ld a,(t_font+1)
ld (g_cmp),a
ld a,(t_temp+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
jp nz,text_branch_25
ld a,(t_font)
ld (g_cmp),a
ld a,(t_temp)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
text_branch_25:
text_branch_23:
ld a,$01
ld (t_limit),a
ld a,$00
ld (g_cmp),a
ld a,(t_entry)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_27
jp text_branch_26
text_branch_27:
ld a,(t_length)
ld (t_limit),a
ld hl,$0000
ld (t_temp),hl
ld a,(t_length)
ld (t_temp),a
ld hl,(t_temp)
ld de,(t_source)
add hl,de
ld (t_temp),hl
ld a,$00
ld (g_cmp),a
ld a,(t_temp+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_29
ld a,$00
ld (g_cmp),a
ld a,(t_temp)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_29
jp text_branch_28
text_branch_29:
ld a,(t_source+1)
ld (g_cmp),a
ld a,(t_temp+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
jp nz,text_branch_30
ld a,(t_source)
ld (g_cmp),a
ld a,(t_temp)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_done
text_branch_30:
text_branch_28:
text_branch_26:
ld hl,$0000
ld (t_advance),hl
ld a,(t_sx)
ld (t_advance),a
ld hl,t_advance
sla (hl)
inc hl
rl (hl)
ld hl,t_advance
sla (hl)
inc hl
rl (hl)
ld hl,t_advance
sla (hl)
inc hl
rl (hl)
ld a,$01
ld (t_status),a
ld a,$00
ld (t_i),a
text_glyph:
ld a,(t_limit)
ld (g_cmp),a
ld a,(t_i)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_31
jp text_done
text_branch_31:
ld a,$00
ld (g_cmp),a
ld a,(t_entry)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_34
jp text_branch_32
text_branch_34:
ld hl,$0000
ld (t_pointer),hl
ld a,(t_i)
ld (t_pointer),a
ld hl,(t_pointer)
ld de,(t_source)
add hl,de
ld (t_pointer),hl
ld hl,(t_pointer)
ld a,(hl)
ld (t_index),a
ld hl,$0000
ld (t_temp),hl
ld a,$00
ld (t_index+1),a
jp text_branch_33
text_branch_32:
ld hl,$0000
ld (t_index),hl
ld a,(t_code)
ld (t_index),a
text_branch_33:
ld hl,$0000
ld (t_temp),hl
ld a,(t_first)
ld (t_temp),a
ld a,(t_temp+1)
ld (g_cmp),a
ld a,(t_index+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_35
jp nz,text_branch_37
ld a,(t_temp)
ld (g_cmp),a
ld a,(t_index)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_35
text_branch_37:
ld hl,(t_index)
ld de,(t_temp)
or a
sbc hl,de
ld (t_index),hl
ld a,(t_count+1)
ld (g_cmp),a
ld a,(t_index+1)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_36
jp nz,text_branch_38
ld a,(t_count)
ld (g_cmp),a
ld a,(t_index)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_36
text_branch_38:
text_branch_35:
ld hl,$0000
ld (t_index),hl
ld a,(t_fallback)
ld (t_index),a
ld hl,$0000
ld (t_temp),hl
ld a,(t_first)
ld (t_temp),a
ld hl,(t_index)
ld de,(t_temp)
or a
sbc hl,de
ld (t_index),hl
or a
ld a,$01
ld b,a
ld a,(t_missing)
adc a,b
ld (t_missing),a
text_branch_36:
; Reject fully clipped glyph cells after resolving fallback, before reading font rows.
ld a,(t_clip_r+1)
xor $80
ld (g_cmp),a
ld a,(t_next_x+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_39
jp nz,text_next_glyph
ld a,(t_clip_r)
ld (g_cmp),a
ld a,(t_next_x)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_39
jp text_next_glyph
text_branch_39:
ld hl,(t_next_x)
ld (t_temp),hl
ld hl,(t_temp)
ld de,(t_advance)
add hl,de
ld (t_temp),hl
ld a,(t_clip_l+1)
xor $80
ld (g_cmp),a
ld a,(t_temp+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_next_glyph
jp nz,text_branch_40
ld a,(t_clip_l)
ld (g_cmp),a
ld a,(t_temp)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_next_glyph
jp z,text_next_glyph
text_branch_40:
ld a,(t_clip_b+1)
xor $80
ld (g_cmp),a
ld a,(t_y+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_41
jp nz,text_next_glyph
ld a,(t_clip_b)
ld (g_cmp),a
ld a,(t_y)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_41
jp text_next_glyph
text_branch_41:
ld hl,$0000
ld (t_temp),hl
ld a,(t_sy)
ld (t_temp),a
ld hl,t_temp
sla (hl)
inc hl
rl (hl)
ld hl,t_temp
sla (hl)
inc hl
rl (hl)
ld hl,t_temp
sla (hl)
inc hl
rl (hl)
ld hl,(t_temp)
ld de,(t_y)
add hl,de
ld (t_temp),hl
ld a,(t_clip_t+1)
xor $80
ld (g_cmp),a
ld a,(t_temp+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_next_glyph
jp nz,text_branch_42
ld a,(t_clip_t)
ld (g_cmp),a
ld a,(t_temp)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_next_glyph
jp z,text_next_glyph
text_branch_42:
ld hl,t_index
sla (hl)
inc hl
rl (hl)
ld hl,t_index
sla (hl)
inc hl
rl (hl)
ld hl,t_index
sla (hl)
inc hl
rl (hl)
ld hl,(t_font)
ld (t_pointer),hl
ld hl,(t_pointer)
ld de,(t_index)
add hl,de
ld (t_pointer),hl
ld a,$00
ld (t_row),a
text_row:
ld a,$08
ld (g_cmp),a
ld a,(t_row)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_43
jp text_next_glyph
text_branch_43:
ld hl,(t_pointer)
ld a,(hl)
ld (t_raw),a
ld a,$00
ld (t_repeat),a
text_scaled_row:
ld hl,(t_y)
ld (t_py),hl
ld hl,$0000
ld (t_temp),hl
ld a,(t_row)
ld (t_temp),a
ld hl,(t_temp)
ld (t_product),hl
ld hl,$0000
ld (t_temp),hl
ld a,(t_sy)
ld (t_factor),a
text_branch_44:
ld hl,(t_temp)
ld de,(t_product)
add hl,de
ld (t_temp),hl
or a
ld a,$ff
ld b,a
ld a,(t_factor)
adc a,b
ld (t_factor),a
ld a,$00
ld (g_cmp),a
ld a,(t_factor)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_44
text_branch_45:
ld hl,(t_py)
ld de,(t_temp)
add hl,de
ld (t_py),hl
ld hl,$0000
ld (t_temp),hl
ld a,(t_repeat)
ld (t_temp),a
ld hl,(t_py)
ld de,(t_temp)
add hl,de
ld (t_py),hl
ld a,$00
ld (g_cmp),a
ld a,(t_mode)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_47
jp text_branch_46
text_branch_47:
ld hl,(t_next_x)
ld (t_left),hl
ld hl,(t_next_x)
ld (t_right),hl
ld hl,(t_right)
ld de,(t_advance)
add hl,de
ld (t_right),hl
ld a,(t_bg)
ld (t_pen),a
call text_span
text_branch_46:
ld a,(t_raw)
ld (t_bits),a
ld a,$00
ld (t_column),a
ld a,$00
ld (t_run),a
text_bit:
ld a,$08
ld (g_cmp),a
ld a,(t_column)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_48
jp text_row_end
text_branch_48:
ld a,(t_bits)
and $80
jp z,text_branch_49
ld a,$00
ld (g_cmp),a
ld a,(t_run)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_50
text_branch_51:
ld a,(t_column)
ld (t_start),a
ld a,$01
ld (t_run),a
jp text_branch_50
text_branch_49:
ld a,$00
ld (g_cmp),a
ld a,(t_run)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_52
jp text_branch_50
text_branch_52:
call text_run
ld a,$00
ld (t_run),a
text_branch_50:
ld hl,t_bits
sla (hl)
or a
ld a,$01
ld b,a
ld a,(t_column)
adc a,b
ld (t_column),a
jp text_bit
text_row_end:
ld a,$00
ld (g_cmp),a
ld a,(t_run)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_54
jp text_branch_53
text_branch_54:
call text_run
text_branch_53:
or a
ld a,$01
ld b,a
ld a,(t_repeat)
adc a,b
ld (t_repeat),a
ld a,(t_sy)
ld (g_cmp),a
ld a,(t_repeat)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_scaled_row
text_branch_55:
ld hl,(t_pointer)
ld de,$0001
add hl,de
ld (t_pointer),hl
or a
ld a,$01
ld b,a
ld a,(t_row)
adc a,b
ld (t_row),a
jp text_row
text_next_glyph:
; BEGIN ADVANCE FIX: move by the enlarged glyph cell width.
ld hl,(t_next_x)
ld de,(t_advance)
add hl,de
ld (t_next_x),hl
; END ADVANCE FIX
or a
ld a,$01
ld b,a
ld a,(t_i)
adc a,b
ld (t_i),a
ld a,(t_i)
ld (t_consumed),a
jp text_glyph
text_done:
ret
text_run:
ld hl,$0000
ld (t_left),hl
ld a,(t_start)
ld (t_left),a
ld hl,(t_left)
ld (t_product),hl
ld hl,$0000
ld (t_left),hl
ld a,(t_sx)
ld (t_factor),a
text_branch_56:
ld hl,(t_left)
ld de,(t_product)
add hl,de
ld (t_left),hl
or a
ld a,$ff
ld b,a
ld a,(t_factor)
adc a,b
ld (t_factor),a
ld a,$00
ld (g_cmp),a
ld a,(t_factor)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_56
text_branch_57:
ld hl,(t_left)
ld de,(t_next_x)
add hl,de
ld (t_left),hl
ld hl,$0000
ld (t_right),hl
ld a,(t_column)
ld (t_right),a
ld hl,(t_right)
ld (t_product),hl
ld hl,$0000
ld (t_right),hl
ld a,(t_sx)
ld (t_factor),a
text_branch_58:
ld hl,(t_right)
ld de,(t_product)
add hl,de
ld (t_right),hl
or a
ld a,$ff
ld b,a
ld a,(t_factor)
adc a,b
ld (t_factor),a
ld a,$00
ld (g_cmp),a
ld a,(t_factor)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_58
text_branch_59:
ld hl,(t_right)
ld de,(t_next_x)
add hl,de
ld (t_right),hl
ld a,(t_fg)
ld (t_pen),a
jp text_span
text_span:
; Intersect a half-open run with the validated physical-screen scissor.
ld a,(t_clip_t+1)
xor $80
ld (g_cmp),a
ld a,(t_py+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_span_done
jp nz,text_branch_60
ld a,(t_clip_t)
ld (g_cmp),a
ld a,(t_py)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_span_done
text_branch_60:
ld a,(t_clip_b+1)
xor $80
ld (g_cmp),a
ld a,(t_py+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_61
jp nz,text_span_done
ld a,(t_clip_b)
ld (g_cmp),a
ld a,(t_py)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_61
jp text_span_done
text_branch_61:
ld a,(t_clip_l+1)
xor $80
ld (g_cmp),a
ld a,(t_right+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_span_done
jp nz,text_branch_62
ld a,(t_clip_l)
ld (g_cmp),a
ld a,(t_right)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_span_done
jp z,text_span_done
text_branch_62:
ld a,(t_clip_r+1)
xor $80
ld (g_cmp),a
ld a,(t_left+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_63
jp nz,text_span_done
ld a,(t_clip_r)
ld (g_cmp),a
ld a,(t_left)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_63
jp text_span_done
text_branch_63:
ld a,(t_clip_l+1)
xor $80
ld (g_cmp),a
ld a,(t_left+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_65
jp nz,text_branch_64
ld a,(t_clip_l)
ld (g_cmp),a
ld a,(t_left)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_65
jp text_branch_64
text_branch_65:
ld hl,(t_clip_l)
ld (t_left),hl
text_branch_64:
ld a,(t_clip_r+1)
xor $80
ld (g_cmp),a
ld a,(t_right+1)
xor $80
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_66
jp nz,text_branch_67
ld a,(t_clip_r)
ld (g_cmp),a
ld a,(t_right)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp c,text_branch_66
jp z,text_branch_66
text_branch_67:
ld hl,(t_clip_r)
ld (t_right),hl
text_branch_66:
ld hl,(t_left)
ld (bp_x0),hl
ld hl,(t_right)
ld (bp_x1),hl
ld hl,(t_py)
ld (bp_y0),hl
if TEXT_PACKED
ld a,$00
ld (bp_op),a
ld a,(t_pen)
ld (bp_pen),a
else
ld a,$01
ld (bp_op),a
ld a,$00
ld (g_cmp),a
ld a,(t_pen)
ld b,a
ld a,(g_cmp)
ld c,a
ld a,b
cp c
jp nz,text_branch_69
jp text_branch_68
text_branch_69:
ld a,$00
ld (bp_op),a
text_branch_68:
endif
call bp_hspan
ld a,$00
ld (t_work),a
ld a,$00
ld (t_work+1),a
ld a,$00
ld (t_work+2),a
ld a,$00
ld (t_work+3),a
ld a,(bp_writes)
ld (t_work),a
ld a,(bp_writes+1)
ld (t_work+1),a
or a
ld a,(t_work)
ld b,a
ld a,(t_writes)
adc a,b
ld (t_writes),a
ld a,(t_work+1)
ld b,a
ld a,(t_writes+1)
adc a,b
ld (t_writes+1),a
ld a,(t_work+2)
ld b,a
ld a,(t_writes+2)
adc a,b
ld (t_writes+2),a
ld a,(t_work+3)
ld b,a
ld a,(t_writes+3)
adc a,b
ld (t_writes+3),a
ld hl,(t_calls)
ld de,$0001
add hl,de
ld (t_calls),hl
text_span_done:
ret
text_end: