A door opens, and one map cell changes. This routine redraws its picture without rebuilding the whole screen. The same call can paint a room or the strip of scenery revealed by a camera: choose a source rectangle and a destination, then let the machine’s renderer do the copying.

The capture uses an original diagnostic font ROM, supplied by the test fixture for repeatable glyph checks. It is not the stock font and does not show software-redefinable characters on this machine. Set your game’s descriptors to codes in its installed ROM.
A picture has two screen bytes
Aquarius stores character codes at $3000–$33FF and matching colour bytes at $3400–$37FF. The active 40×25 display uses 1,000 entries from each; the remaining 24 bytes in each allocation stay unchanged.
glyph_codes maps each logical ID to a code in the fixed character ROM. The example uses the deliberately non-identity mapping 0,3,1,2. tile_colours supplies $F0,$F0,$10,$80: the high nibble selects foreground and the low nibble selects background.
The surround repeats cell zero and its colour attribute. Changing (0,0) can change the border as well. BASIC normally uses rows 1–24; direct hardware drawing can use all 25. A game sharing the editor needs an explicit rule for that first row, clearing and scrolling.
Reserve your workspace
Define NR, MAP, MAP_W, MAP_H, TILE_COUNT, SCREEN, COLOUR, SCREEN_COLS=40, SCREEN_ROWS=25, plus the glyph and colour descriptor tables. Include character-regions/z80.inc once. The context needs 32 writable bytes; no scratch initialisation call is needed.
The example source map is twelve bytes wide and eight high. Context, results, source map, guards and stack all fit in the unexpanded $3800–$3FFF RAM. Map dimensions and tile count are nonzero bytes; every allocation must fit mapped memory without wrapping or overlapping the overwritten screen.
AF/BC/DE/HL and flags are clobbered. Six stack bytes cover the direct CALL, paint helper and saved pointer, beyond your own caller/interrupt use. A 5×3 patch writes fifteen character bytes and fifteen colour bytes, plus preflight/address work.
Choose glyphs which exist in the installed ROM. The routine cannot redefine this fixed font in software. Combining available characters into larger scenery or objects gives you more options; a custom bitmap is not a hidden feature of the screen-code copy.
Draw the rectangle
The constants belong to the original caller’s working memory plan. Choose allocations which fit your own project, keeping setup and drawing separate.
Caller-owned memory and display constants
NR EQU 15360
RESULT EQU 15424
MAP EQU 15600
MAP_W EQU 12
MAP_H EQU 8
TILE_COUNT EQU 4
SCREEN_COLS EQU 40
SCREEN_ROWS EQU 25
SCREEN EQU $3000
COLOUR EQU $3400Translate logical IDs into native screen codes and colours
glyph_codes:
DB 0,3,1,2
tile_colours:
DB $f0,$f0,$10,$80Supply six unsigned bytes at NR+0..5: source column, source row, destination column, destination row, width and height. Call region_draw; NR+6 is one for completion or zero for rejection. The six request bytes survive.
Draw a 5×3 patch from map cell (2,1) at display cell (4,3)
case_0:
ld a,2
ld (NR+0),a
ld a,1
ld (NR+1),a
ld a,4
ld (NR+2),a
ld a,3
ld (NR+3),a
ld a,5
ld (NR+4),a
ld a,3
ld (NR+5),a
call region_draw
ld a,(NR+6)
or 128
ld (RESULT+1),aThe result store after the call belongs to the diagnostic. In a game, read the completion flag and carry on with your own logic. The routine rejects zero sizes, invalid starts, source/destination overruns and IDs outside the configured table. Every selected ID is checked before painting begins, so a bad tile cannot leave half a patch behind. This variant rejects rather than clips.
Keep the routine
Checked character and colour region drawing
; Checked character/colour region. See README for symbols, state and ownership.
region_draw:
xor a
ld (NR+6),a
ld a,(NR+4)
or a
ret z
ld a,(NR+0)
cp MAP_W
ret nc
ld b,a
ld a,MAP_W
sub b
ld b,a
ld a,(NR+4)
cp b
jr c,bounds_fit_0
ret nz
bounds_fit_0:
ld a,(NR+5)
or a
ret z
ld a,(NR+1)
cp MAP_H
ret nc
ld b,a
ld a,MAP_H
sub b
ld b,a
ld a,(NR+5)
cp b
jr c,bounds_fit_1
ret nz
bounds_fit_1:
ld a,(NR+4)
or a
ret z
ld a,(NR+2)
cp SCREEN_COLS
ret nc
ld b,a
ld a,SCREEN_COLS
sub b
ld b,a
ld a,(NR+4)
cp b
jr c,bounds_fit_2
ret nz
bounds_fit_2:
ld a,(NR+5)
or a
ret z
ld a,(NR+3)
cp SCREEN_ROWS
ret nc
ld b,a
ld a,SCREEN_ROWS
sub b
ld b,a
ld a,(NR+5)
cp b
jr c,bounds_fit_3
ret nz
bounds_fit_3:
xor a
ld (NR+29),a
region_pass:
xor a
ld (NR+16),a
region_row:
xor a
ld (NR+17),a
region_cell:
ld hl,MAP
ld a,(NR+1)
ld b,a
ld a,(NR+16)
add a,b
or a
jr z,source_column
ld b,a
ld de,MAP_W
source_row:
add hl,de
djnz source_row
source_column:
ld a,(NR)
ld b,a
ld a,(NR+17)
add a,b
ld e,a
ld d,0
add hl,de
ld a,(hl)
ld (NR+19),a
cp TILE_COUNT
ret nc
ld a,(NR+29)
or a
call nz,region_paint
ld hl,NR+17
inc (hl)
ld a,(NR+4)
cp (hl)
jp nz,region_cell
ld hl,NR+16
inc (hl)
ld a,(NR+5)
cp (hl)
jp nz,region_row
ld a,(NR+29)
or a
jr nz,region_success
inc a
ld (NR+29),a
jp region_pass
region_success:
ld a,1
ld (NR+6),a
ret
region_paint:
ld hl,SCREEN
ld a,(NR+3)
ld b,a
ld a,(NR+16)
add a,b
or a
jr z,char_column
ld b,a
ld de,SCREEN_COLS
char_row:
add hl,de
djnz char_row
char_column:
ld a,(NR+2)
ld b,a
ld a,(NR+17)
add a,b
ld e,a
ld d,0
add hl,de
ld a,(NR+19)
ld e,a
push hl
ld hl,glyph_codes
add hl,de
ld a,(hl)
pop hl
ld (hl),a
ld bc,COLOUR-SCREEN
add hl,bc
push hl
ld hl,tile_colours
add hl,de
ld a,(hl)
pop hl
ld (hl),a
retThe context is private and non-re-entrant. Keep the request, map, descriptors or picture data, and display configuration stable throughout the call. Your caller owns video setup, allocations and interrupt policy; the routine does not disable interrupts or negotiate with an OS. Interrupt handlers must preserve the used registers and must not change those resources halfway through drawing.
What was checked
All 18 calls completed: three accepted draws and fifteen map/bounds/ID rejections. Each rejected request also ran in isolation after the same three accepted draws, preserving complete destination allocations and both mapped guards. The source selection crosses a CPU page boundary.
The observer compares every destination byte, unused allocation tails and stored colour bits where present, with an independent model. It compares every native capture pixel with a separate composition, including borders and scaling. Completed wrong-layout and unsafe-destination controls fail the same memory checks; wrong-layout pictures also fail the pixel check.
These results qualify the selected Emu198x 0.39.0 configuration with Asm198x 0.0.71 and the original reset fixture. They do not establish stock-OS loading, original-hardware timing, interrupt coexistence, tear-free updates or throughput.