Prev: EDD3 Up: Map Next: EF9A
EED3: Plot game window
This transfers the game's linear screen buffer into the game window region of the Spectrum's screen memory. The input buffer is 24x17x8 bytes. The output region is smaller: 23x16x8 bytes. The destination addresses are stored precalculated in the table at game_window_start_addresses.
Scrolling to 4-bit accuracy is permitted by implementing two cases here: aligned and unaligned. Aligned transfers just have to move the bytes across and so are fast. Unaligned transfers have to roll bytes right to effect the left shift, so are much slower.
The aligned case copies 23 bytes per scanline starting at $F291 (one byte into buffer). The unaligned case rolls the bytes right starting at $F290.
This uses the Z80 optimisation where values are popped from the stack.
Used by the routines at main_loop and screen_reset.
plot_game_window EED3 LD ($EDD1),SP Preserve the stack pointer
EED7 LD A,($A7C8) Read upper byte of game_window_offset
EEDA AND A Is it nonzero?
EEDB JP NZ,pgw_unaligned Jump if so
pgw_aligned EEDE LD HL,$F291 Point HL at the screen buffer's start address + 1
EEE1 LD A,($A7C7) Read lower byte of game_window_offset
EEE4 ADD A,L Combine
EEE5 JR NC,plot_game_window_0
EEE7 INC H
plot_game_window_0 EEE8 LD L,A
EEE9 LD SP,$EDD3 Point SP at game_window_start_addresses
EEEC LD A,$80 There are 128 rows
Start loop
plot_game_window_1 EEEE POP DE Pop a target address off the stack
EEEF LDI Copy 23 bytes
EEF1 LDI
EEF3 LDI
EEF5 LDI
EEF7 LDI
EEF9 LDI
EEFB LDI
EEFD LDI
EEFF LDI
EF01 LDI
EF03 LDI
EF05 LDI
EF07 LDI
EF09 LDI
EF0B LDI
EF0D LDI
EF0F LDI
EF11 LDI
EF13 LDI
EF15 LDI
EF17 LDI
EF19 LDI
EF1B LDI
EF1D INC HL Skip the 24th input byte
EF1E DEC A ...loop
EF1F JP NZ,plot_game_window_1
EF22 LD SP,($EDD1) Restore the stack pointer
EF26 RET Return
pgw_unaligned EF27 LD HL,$F290 Point HL at the screen buffer's start address
EF2A LD A,($A7C7) Read lower byte of game_window_offset
EF2D ADD A,L Combine
EF2E JR NC,plot_game_window_2
EF30 INC H
plot_game_window_2 EF31 LD L,A
EF32 LD A,(HL) Fetch a first source byte
EF33 INC L
EF34 LD SP,$EDD3 Point SP at game_window_start_addresses
EF37 EXX Bank
EF38 LD B,$80 There are 128 rows
Start loop
plot_game_window_3 EF3A EXX Unbank
EF3B POP DE Pop a target address off the stack
EF3C LD B,$04 4 iterations of 5, plus 3 at the end = 23
Start loop
plot_game_window_4 EF3E LD C,(HL) Fetch a second source byte (so we can restore it later)
RRD does a 12-bit rotate: nibble_out = (HL) & $0F; (HL) = ((HL) >> 4) | (A << 4); A = (A & $F0) | nibble_out;
EF3F RRD Shift (HL) down and rotate A's bottom nibble into the top of (HL)
EF41 EX AF,AF' Bank
EF42 LD A,(HL) Load the rotated and merged value
EF43 LD (DE),A Store it to the screen
EF44 LD (HL),C Restore the corrupted byte
EF45 EX AF,AF' Unbank
EF46 INC HL Advance
EF47 INC E Advance
EF48 LD C,(HL) Repeat
EF49 RRD
EF4B EX AF,AF'
EF4C LD A,(HL)
EF4D LD (DE),A
EF4E LD (HL),C
EF4F EX AF,AF'
EF50 INC HL
EF51 INC E
EF52 LD C,(HL) Repeat
EF53 RRD
EF55 EX AF,AF'
EF56 LD A,(HL)
EF57 LD (DE),A
EF58 LD (HL),C
EF59 EX AF,AF'
EF5A INC HL
EF5B INC E
EF5C LD C,(HL) Repeat
EF5D RRD
EF5F EX AF,AF'
EF60 LD A,(HL)
EF61 LD (DE),A
EF62 LD (HL),C
EF63 EX AF,AF'
EF64 INC HL
EF65 INC E
EF66 LD C,(HL) Repeat
EF67 RRD
EF69 EX AF,AF'
EF6A LD A,(HL)
EF6B LD (DE),A
EF6C LD (HL),C
EF6D EX AF,AF'
EF6E INC HL
EF6F INC E
EF70 DJNZ plot_game_window_4 ...loop
EF72 LD C,(HL) Repeat
EF73 RRD
EF75 EX AF,AF'
EF76 LD A,(HL)
EF77 LD (DE),A
EF78 LD (HL),C
EF79 EX AF,AF'
EF7A INC HL
EF7B INC E
EF7C LD C,(HL) Repeat
EF7D RRD
EF7F EX AF,AF'
EF80 LD A,(HL)
EF81 LD (DE),A
EF82 LD (HL),C
EF83 EX AF,AF'
EF84 INC HL
EF85 INC E
EF86 LD C,(HL) Repeat
EF87 RRD
EF89 EX AF,AF'
EF8A LD A,(HL)
EF8B LD (DE),A
EF8C LD (HL),C
EF8D EX AF,AF'
EF8E INC HL
EF8F INC E
EF90 LD A,(HL) Preload the next scanline's first input byte
EF91 INC HL
EF92 EXX Unbank
EF93 DJNZ plot_game_window_3 ...loop
EF95 LD SP,($EDD1) Restore the stack pointer
EF99 RET Return
Prev: EDD3 Up: Map Next: EF9A