Routines |
Prev: EDD3 | Up: Map | Next: EF9A |
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 |