| Chase H.Q. | Routines |
| Prev: C3AF | Up: Map | Next: CC50 |
|
Picks one of 5 pre-scripted animation scenes, populates the 9-entry animated-object array at $BB00 from the chosen scene's object table, draws overlay text (title/credits, "PRESS ENTER FOR OPTIONS" always, and "PRESS GEAR TO PLAY" once controls have been selected -- 8001), then falls into the attract-mode wait loop (titlescr_wait_loop) which animates the scene each frame while polling for coin/fire/keyboard input to start a game.
Used by the routines at C000 and run_title_tune.
|
||||
| run_title_screen | C59E | CALL clear_and_fill_border_attrs | Clear the screen bitmap and attribute buffers | |
| C5A1 | LD A,$00 | A = 0 (self-modified below to persist a running value between calls -- acts as a pseudo-random/rotating scene selector) | ||
| C5A3 | RLCA | |||
| C5A4 | AND $1F | |||
| C5A6 | JR NZ,run_title_screen_0 | |||
| C5A8 | INC A | |||
| run_title_screen_0 | C5A9 | LD ($C5A2),A | Self-modify the operand at $C5A2 (the value loaded next call) with the rotated/incremented value | |
| C5AC | LD HL,$CCB7 | Pick one of 5 scene tables by testing successive bits of A via RRA; first bit set selects the table | ||
| C5AF | RRA | |||
| C5B0 | JR C,run_title_screen_1 | |||
| C5B2 | LD HL,$CD4F | |||
| C5B5 | RRA | |||
| C5B6 | JR C,run_title_screen_1 | |||
| C5B8 | LD HL,$CF10 | |||
| C5BB | RRA | |||
| C5BC | JR C,run_title_screen_1 | |||
| C5BE | LD HL,$CFCD | |||
| C5C1 | RRA | |||
| C5C2 | JR C,run_title_screen_1 | |||
| C5C4 | LD HL,$D16C | |||
| run_title_screen_1 | C5C7 | PUSH HL | Save chosen scene table pointer | |
| C5C8 | LD HL,$CC50 | Draw the copyright/credits text block ($CC50) | ||
| C5CB | CALL print_string | |||
| C5CE | LD HL,$BB00 | Zero the whole $BB00-$BB4F object array (9 records x 9 bytes -- see object_script_step for field layout) | ||
| C5D1 | LD DE,$BB01 | |||
| C5D4 | LD BC,$0050 | |||
| C5D7 | LD (HL),$00 | |||
| C5D9 | LDIR | |||
| C5DB | LD IX,$BB00 | Copy the 5-byte-per-object scene table (pointed to by the popped HL) into the 9 object records, one object per iteration, reordering into fields: script pointer low/high (+$07/+$08), then two more bytes into +$06 and +$04/+$05 | ||
| C5DF | LD DE,$0009 | |||
| C5E2 | POP HL | |||
| C5E3 | LD B,$09 | |||
| run_title_screen_2 | C5E5 | LD A,(HL) | ||
| C5E6 | INC HL | |||
| C5E7 | LD (IX+$07),A | |||
| C5EA | LD A,(HL) | |||
| C5EB | INC HL | |||
| C5EC | LD (IX+$08),A | |||
| C5EF | LD A,(HL) | |||
| C5F0 | INC HL | |||
| C5F1 | LD (IX+$06),A | |||
| C5F4 | LD A,(HL) | |||
| C5F5 | INC HL | |||
| C5F6 | LD (IX+$04),A | |||
| C5F9 | LD A,(HL) | |||
| C5FA | INC HL | |||
| C5FB | LD (IX+$05),A | |||
| C5FE | ADD IX,DE | |||
| C600 | DJNZ run_title_screen_2 | |||
| C602 | CALL setup_im2_interrupt_table | Set up interrupts (see setup_im2_interrupt_table) | ||
| C605 | CALL titlescr_animate_frame | Draw the first animation frame before entering the wait loop, so the scene is visible immediately | ||
| C608 | LD HL,$CC9D | Draw the "PRESS ENTER FOR OPTIONS" text block ($CC9D), unconditionally | ||
| C60B | CALL print_character | |||
| C60E | LD A,($8001) | If controls have already been selected (8001, set by the options menu)... | ||
| C611 | AND A | |||
| C612 | LD HL,$CC88 | ...also draw the "PRESS GEAR TO PLAY" text block (CC88) | ||
| C615 | CALL NZ,print_character | |||
| C618 | XOR A | |||
| C619 | CALL titlescr_start_tune | See titlescr_start_tune, called with A=0 | ||
| C61C | EI | |||
| C61D | HALT | Sync to the next interrupt before the wait loop | ||
|
Attract-mode wait loop: animates the current scene once per interrupt and polls for coin-insert / fire / any-key input to start the game or jump to a fresh title screen. Re-entered every frame via titlescr_wait_loop; run_title_screen is re-run (new scene) when a key other than fire is pressed.
|
||||
| titlescr_wait_loop | C61E | CALL titlescr_music | Call titlescr_music (see titlescr_music) | |
| C621 | LD A,($F223) | If a flag is already set, skip straight to the | ||
| C624 | AND A | fire-button check (demo/attract cycle already | ||
| C625 | JR NZ,ts_check_fire | running, don't replay the tune-wait below) | ||
| C627 | LD A,$04 | Otherwise play tune #4 and wait out ~180 frames | ||
| C629 | CALL load_drum_script | (one titlescr_music service call per frame) before | ||
| C62C | LD B,$B4 | falling through to the coin/name-table refresh | ||
| run_title_screen_3 | C62E | PUSH BC | at titlescr_refresh_name_table | |
| C62F | CALL titlescr_music | |||
| C632 | POP BC | |||
| C633 | DJNZ run_title_screen_3 | |||
| C635 | INC B | B wraps 0 -> 1 (DJNZ leaves B = 0) | ||
| C636 | JR titlescr_refresh_name_table | |||
| ts_check_fire | C638 | LD A,$BF | Read keyboard half-row for SPACE (fire) | |
| C63A | IN A,($FE) | |||
| C63C | CPL | |||
| C63D | RRA | |||
| C63E | JP C,omd_redraw_and_poll | Fire pressed -> start the game | ||
| C641 | LD A,($8001) | In coin-op mode, read the coin-slot input | ||
| C644 | AND A | |||
| C645 | JR Z,run_title_screen_4 | |||
| C647 | CALL $800E | |||
| C64A | AND $10 | |||
| C64C | JP NZ,titlescr_credit_inserted | Coin inserted -> refresh coin/credit display | ||
| run_title_screen_4 | C64F | LD A,($8000) | If not in coin-op mode, check the "1"/"2" player | |
| C652 | AND A | select keys instead | ||
| C653 | JR Z,titlescr_wait_loop | |||
| C655 | LD A,$EF | |||
| C657 | IN A,($FE) | |||
| C659 | CPL | |||
| C65A | AND $10 | |||
| C65C | JP Z,run_title_screen_5 | Neither select key held -> check for "any key" | ||
| C65F | DI | A player-select key was pressed: initialise a | ||
| C660 | CALL stop_music_and_silence | fresh 8002 (score_bcd) of $87654321 (a | ||
| C663 | LD HL,$8002 | recognisable placeholder/test score) and stage/ | ||
| C666 | LD (HL),$21 | retry state, check it against the high-score | ||
| C668 | INC HL | table, then restart the title screen | ||
| C669 | LD (HL),$43 | |||
| C66B | INC HL | |||
| C66C | LD (HL),$65 | |||
| C66E | INC HL | |||
| C66F | LD (HL),$87 | |||
| C671 | LD A,$06 | |||
| C673 | LD ($8007),A | |||
| C676 | LD A,$03 | |||
| C678 | LD ($8006),A | |||
| C67B | CALL check_high_score | |||
| C67E | JP run_title_screen | |||
| run_title_screen_5 | C681 | LD A,$F7 | Read keyboard half-row for ENTER | |
| C683 | IN A,($FE) | |||
| C685 | CPL | |||
| C686 | AND $1F | |||
| C688 | JP Z,titlescr_wait_loop | No key pressed -> keep waiting | ||
| C68B | RRCA | A key was pressed: seed the scene selector with | ||
| C68C | LD ($C5A2),A | the key-scan bits, then restart the title screen | ||
| C68F | DI | with a new scene | ||
| C690 | CALL stop_music_and_silence | |||
| C693 | JP run_title_screen | |||
| titlescr_credit_inserted | C696 | LD HL,$8011 | Push $8011 as an extra "credit awarded" flag/value | |
| C699 | PUSH HL | for the shared tail below | ||
| titlescr_refresh_name_table | C69A | PUSH BC | Entry point also reached directly after the ~180- frame attract-tune wait (titlescr_wait_loop), without the $8011 flag push above | |
| C69B | DI | |||
| C69C | CALL stop_music_and_silence | Stop any playing tune and silence the AY chip (see stop_music_and_silence) | ||
| C69F | LD HL,$C403 | Copy the 3 preset high-score name/rank rows from $C403 into the work buffer pointed to by ($800A), 3 times (A = 3), each copy split into 15+7+6 bytes with 2-byte gaps skipped between segments | ||
| C6A2 | LD DE,($800A) | |||
| C6A6 | LD A,$03 | |||
| run_title_screen_6 | C6A8 | LD BC,$000F | ||
| C6AB | LDIR | |||
| C6AD | INC HL | |||
| C6AE | INC HL | |||
| C6AF | LD C,$07 | |||
| C6B1 | LDIR | |||
| C6B3 | INC HL | |||
| C6B4 | LD C,$06 | |||
| C6B6 | LDIR | |||
| C6B8 | INC HL | |||
| C6B9 | INC HL | |||
| C6BA | EX DE,HL | |||
| C6BB | LD C,$07 | |||
| C6BD | ADD HL,BC | |||
| C6BE | EX DE,HL | |||
| C6BF | DEC A | |||
| C6C0 | JR NZ,run_title_screen_6 | |||
| C6C2 | POP AF | Discard the flag/counter pushed by the caller | ||
| C6C3 | RET | |||
|
Per-frame animation driver: waits for the next interrupt, draws the 6 "foreground" objects (records 0-5 of the $BB00 array) via compute_glyph_blit_params, steps the object animation scripts (object_script_step), clears the playfield bitmap (clear_playfield_buffer), then draws the 3 "background" objects (records 6-8) via the alternate blitter compute_glyph_blit_params_b. Loops forever in the ordinary case, but object_script_step (via oss_fetch_opcode_cont's $D2 "end of script" handling, `POP HL : RET` with no matching PUSH) will pop this loop's own return address as data and RET again beneath it, unwinding straight out of this self-loop back to titlescr_animate_frame's *caller* (C605's own continuation) the moment any object's script reaches $D2 -- see oss_fetch_opcode_cont. This is the normal exit: whichever scene object's script ends first stops the whole per-frame animation and hands control back to run_title_screen, which is what starts the tune and enters the (non-animating) attract-mode wait loop. blit_abort_restore_sp / run_title_screen_24-style RET-via-restored-SP inside the blitters is a separate, unrelated mechanism (aborting one partially off-screen glyph draw, not this loop). Uses EXX around each compute_glyph_blit_params/compute_glyph_blit_params_b call: the object record's script pointer (B/C) and screen-position byte (L) are loaded into the shadow registers so the blitter can use HL/DE/BC freely without disturbing the loop's own IX/DE/B state in the main set.
|
||||
| titlescr_animate_frame | C6C4 | EI | ||
| C6C5 | HALT | |||
| C6C6 | DI | |||
| C6C7 | LD B,$06 | 6 foreground objects | ||
| C6C9 | LD DE,$0009 | Object record stride (9 bytes) | ||
| C6CC | LD IX,$BB00 | |||
| ts_draw_fg_objects | C6D0 | EXX | Bank in shadow BC/DE/HL for the blitter call | |
| C6D1 | LD B,(IX+$08) | |||
| C6D4 | LD C,(IX+$07) | |||
| C6D7 | LD L,(IX+$06) | |||
| C6DA | CALL compute_glyph_blit_params | |||
| C6DD | EXX | Restore main BC/DE/HL (IX/DE loop state) | ||
| C6DE | ADD IX,DE | |||
| C6E0 | DJNZ ts_draw_fg_objects | |||
| C6E2 | EXX | (unbalanced EXX vs. the loop above -- swaps back to the blitter's shadow set one more time before the object-script step, effect not fully traced) | ||
| C6E3 | CALL object_script_step | Step every object's animation script by one frame | ||
| C6E6 | CALL clear_playfield_buffer | Clear the playfield bitmap ready for the next frame | ||
| C6E9 | EXX | |||
| C6EA | LD IX,$BB36 | Background objects start at record 6 ($BB00 + 6*9) | ||
| C6EE | LD B,$03 | 3 background objects | ||
| ts_draw_bg_objects | C6F0 | EXX | ||
| C6F1 | LD B,(IX+$08) | |||
| C6F4 | LD C,(IX+$07) | |||
| C6F7 | LD L,(IX+$06) | |||
| C6FA | CALL compute_glyph_blit_params_b | |||
| C6FD | EXX | |||
| C6FE | ADD IX,DE | |||
| C700 | DJNZ ts_draw_bg_objects | |||
| C702 | JP titlescr_animate_frame | |||
|
Object animation script interpreter: advances all 9 objects' scripts by one frame. Each object record (9 bytes, offsets relative to IX): +$00 current opcode / countdown-active flag (0 = idle, fetch next op) +$01 countdown value for the "wait N frames" opcode +$02 X velocity/step, +$03 Y velocity/step +$04/+$05 script pointer (low/high) -- the object's byte-code cursor +$06 screen row/position byte consumed by the blitters +$07/+$08 current X/Y screen position The script byte-code (fetched at oss_fetch_opcode) is a simple state machine: opcode bytes >= $80 (sign bit set) are treated as immediate 2-axis step deltas (oss_op_immediate_step); opcodes $C8-$D0 select a movement/velocity mode (constant velocity, decelerate-to-stop via the D272 lookup table, accelerate, or a literal position jump) and may consume further operand bytes from the script stream. $D1 is not one of these -- it is never tested by either dispatch chain below, so an object whose script emits it (this happens in every one of the 5 title scenes, always right after an initial constant-velocity burst) gets $D1 stored as its active opcode by chain 2 and then permanently frozen by chain 1: chain 1's oss_object_loop dispatch matches none of $C9-$CF for $D1, so it jumps straight to oss_next_object without ever reaching oss_countdown's countdown decrement, and the object can never go idle (opcode -> 0) to fetch a new instruction again. This is a genuine quirk of the original data/interpreter, not a disassembly error -- see $CCF2 for object 0's example. Two separate dispatch chains share this state machine: 1. oss_object_loop (the per-object per-frame entry): dispatches on the *active* opcode already stored at +$00 ($C9-$CF, one of the six movement modes below) and performs one frame's worth of incremental movement. An idle object (+$00 = 0) instead falls through to oss_fetch_opcode to fetch a fresh opcode from the script stream. 2. oss_fetch_opcode_cont (oss_fetch_opcode_cont): dispatches on the *next script byte* fetched from the stream ($C8-$D2, or an immediate step if bit 7 is clear), reads that opcode's operand bytes from the stream, and stores them into +$00-+$03 ready for chain 1 to act on next frame. The six active movement modes (chain 1) are: constant velocity ($C9, oss_op_velocity -- position += velocity every frame, no countdown); decelerate X/Y ($CA/$CB, oss_op_decel_x/oss_op_decel_y -- apply the current step, then look up the next speed from D272 indexed by the +$01/+$03 countdown value, negate it into the other axis's velocity, and count the countdown up toward zero); and three accelerate-X variants ($CC/$CD/$CE, oss_op_accel_x_a/ oss_op_accel_x_c/oss_op_accel_x_b -- apply the current step, look up the next speed from D272 the same way, and count +$02 down/up/down respectively). The "wait N frames" opcode ($CF) has no chain-1 handler of its own: chain 1 falls through to oss_countdown (oss_countdown), which just decrements +$01 and goes idle (opcode -> 0) when it reaches zero. D272 (oss_lookup_speed, oss_lookup_speed) is a 256-byte deceleration/ acceleration curve table indexed by the countdown value passed in C (B is temporarily zeroed for the table-relative add and shuttled through A so the caller's B -- the outer object-loop DJNZ counter -- survives the call); table[C] >> 2 gives that countdown step's velocity magnitude, shared by all five countdown-driven modes.
|
||||
| object_script_step | C705 | LD IX,$BB00 | ||
| C709 | LD DE,$0009 | |||
| C70C | LD B,$09 | |||
| oss_object_loop | C70E | LD A,(IX+$00) | Opcode 0 = idle -> fetch the next script opcode | |
| C711 | AND A | |||
| C712 | JP Z,oss_fetch_opcode | |||
| C715 | SUB $C9 | Dispatch on the active movement-mode opcode | ||
| C717 | JP Z,oss_op_velocity | ($C9 = constant velocity) | ||
| C71A | DEC A | ($CA = decelerate X, via D272) | ||
| C71B | JP Z,oss_op_decel_x | |||
| C71E | DEC A | ($CB = decelerate Y) | ||
| C71F | JP Z,oss_op_decel_y | |||
| C722 | DEC A | ($CC = accelerate X) | ||
| C723 | JP Z,oss_op_accel_x_a | |||
| C726 | DEC A | ($CD = accelerate X, variant c -- positive speed, counting up) | ||
| C727 | JP Z,oss_op_accel_x_c | |||
| C72A | DEC A | ($CE = accelerate X, variant b -- positive speed, counting down) | ||
| C72B | JP Z,oss_op_accel_x_b | |||
| C72E | DEC A | ($CF = "wait N frames": falls through to the | ||
| C72F | JR NZ,oss_next_object | countdown decrement below) | ||
| oss_countdown | C731 | DEC (IX+$01) | Decrement the wait counter; when it reaches 0, | |
| C734 | JP NZ,oss_next_object | go idle so the next frame fetches a new opcode | ||
| C737 | LD (IX+$00),$00 | |||
| oss_next_object | C73B | ADD IX,DE | ||
| C73D | DJNZ oss_object_loop | |||
| C73F | RET | |||
| oss_fetch_opcode | C740 | LD H,(IX+$05) | HL = object's script cursor | |
| C743 | LD L,(IX+$04) | |||
| oss_fetch_opcode_cont | C746 | LD A,(HL) | A = next script byte, advance the cursor | |
| C747 | INC HL | |||
| C748 | AND A | |||
| C749 | JP P,oss_op_immediate_step | Sign bit clear ($00-$7F) -> immediate step opcode | ||
| C74C | LD (IX+$00),A | Sign bit set -> store as the new active opcode and | ||
| C74F | SUB $C8 | dispatch on which one it is | ||
| C751 | JR Z,run_title_screen_9 | ($C8 = set screen-row byte, 1 operand byte) | ||
| C753 | DEC A | ($C9 = set velocity, 2 operand bytes) | ||
| C754 | JR Z,run_title_screen_7 | |||
| C756 | DEC A | ($CA/$CB = decelerate, 3 operand bytes) | ||
| C757 | JP Z,run_title_screen_11 | |||
| C75A | DEC A | |||
| C75B | JR Z,run_title_screen_11 | |||
| C75D | DEC A | ($CC/$CD/$CE = accelerate variants, 3 operand | ||
| C75E | JR Z,run_title_screen_10 | bytes) | ||
| C760 | DEC A | |||
| C761 | JR Z,run_title_screen_10 | |||
| C763 | DEC A | |||
| C764 | JR Z,run_title_screen_10 | |||
| C766 | DEC A | ($CF = "wait N frames", 1 operand byte) | ||
| C767 | JR Z,oss_read_wait_operand | |||
| C769 | DEC A | ($D0 = jump to absolute position, 2 operand bytes) | ||
| C76A | JR Z,run_title_screen_8 | |||
| C76C | SUB $02 | ($D2 = end of script. No PUSH anywhere in this call | ||
| C76E | JR NZ,oss_save_cursor | chain, so the POP HL below pops object_script_step's own | ||
| C770 | POP HL | return address as data, and the RET after it | ||
| C771 | RET | returns to the frame *beneath* that -- unwinding past object_script_step's caller and out through titlescr_animate_frame's self-loop in one go, back to titlescr_animate_frame's own caller. Not "stop animating this object": this ends the whole frame and the whole per-frame animation loop.) | ||
| oss_save_cursor | C772 | LD (IX+$05),H | Save the advanced script cursor back to the object | |
| C775 | LD (IX+$04),L | record, then loop back to re-fetch/execute | ||
| C778 | JP oss_object_loop | |||
| run_title_screen_7 | C77B | LD A,(HL) | Read the 2 velocity operand bytes | |
| C77C | INC HL | |||
| C77D | LD (IX+$02),A | |||
| C780 | LD A,(HL) | |||
| C781 | INC HL | |||
| C782 | LD (IX+$03),A | |||
| oss_read_wait_operand | C785 | LD A,(HL) | Read the 1-byte wait-count operand | |
| C786 | INC HL | |||
| C787 | LD (IX+$01),A | |||
| C78A | JP oss_save_cursor | |||
| oss_op_velocity | C78D | LD A,(IX+$02) | Constant velocity: position += velocity each frame | |
| C790 | ADD A,(IX+$07) | |||
| C793 | LD (IX+$07),A | |||
| C796 | LD A,(IX+$03) | |||
| C799 | ADD A,(IX+$08) | |||
| C79C | LD (IX+$08),A | |||
| C79F | JP oss_countdown | |||
| oss_apply_x_step | C7A2 | LD A,(IX+$02) | Helper: X position += X velocity | |
| C7A5 | ADD A,(IX+$07) | |||
| C7A8 | LD (IX+$07),A | |||
| C7AB | RET | |||
| oss_apply_y_step | C7AC | LD A,(IX+$03) | Helper: Y position += Y velocity | |
| C7AF | ADD A,(IX+$08) | |||
| C7B2 | LD (IX+$08),A | |||
| C7B5 | RET | |||
| run_title_screen_8 | C7B6 | LD A,(HL) | Read the 2-byte absolute-position operand | |
| C7B7 | INC HL | |||
| C7B8 | LD (IX+$07),A | |||
| C7BB | LD A,(HL) | |||
| C7BC | INC HL | |||
| C7BD | LD (IX+$08),A | |||
| C7C0 | JR oss_fetch_opcode_cont | |||
| run_title_screen_9 | C7C2 | LD A,(HL) | Read the 1-byte screen-row operand | |
| C7C3 | INC HL | |||
| C7C4 | LD (IX+$06),A | |||
| C7C7 | JP oss_fetch_opcode_cont | |||
| run_title_screen_10 | C7CA | LD A,(HL) | Read 3 operand bytes: velocity/counter pair for an | |
| C7CB | INC HL | accelerate/decelerate opcode (order differs from | ||
| C7CC | LD (IX+$02),A | the $CA/$CB variant below) | ||
| C7CF | LD A,(HL) | |||
| C7D0 | INC HL | |||
| C7D1 | LD (IX+$01),A | |||
| C7D4 | LD A,(HL) | |||
| C7D5 | INC HL | |||
| C7D6 | LD (IX+$03),A | |||
| C7D9 | JP oss_save_cursor | |||
| run_title_screen_11 | C7DC | LD A,(HL) | Read 3 operand bytes for the $CA/$CB decelerate | |
| C7DD | INC HL | opcodes | ||
| C7DE | LD (IX+$03),A | |||
| C7E1 | LD A,(HL) | |||
| C7E2 | INC HL | |||
| C7E3 | LD (IX+$01),A | |||
| C7E6 | LD A,(HL) | |||
| C7E7 | INC HL | |||
| C7E8 | LD (IX+$02),A | |||
| C7EB | JR oss_save_cursor | |||
| oss_op_decel_x | C7ED | CALL oss_apply_x_step | Decelerate X: apply X step, look up the next speed | |
| C7F0 | LD C,(IX+$03) | from D272 (indexed by the countdown value), | ||
| C7F3 | CALL oss_lookup_speed | negate it and add to Y velocity, then advance the | ||
| C7F6 | NEG | countdown | ||
| C7F8 | ADD A,(IX+$08) | |||
| C7FB | LD (IX+$08),A | |||
| C7FE | INC (IX+$03) | |||
| C801 | JP oss_countdown | |||
| oss_lookup_speed | C804 | LD A,B | Helper: speed = D272[(B<<8 | C)] >> 2 -- decodes | |
| C805 | LD B,$00 | a countdown value C into a velocity magnitude via | ||
| C807 | LD HL,$D272 | the shared deceleration curve table | ||
| C80A | ADD HL,BC | |||
| C80B | LD B,A | |||
| C80C | LD A,(HL) | |||
| C80D | SRL A | |||
| C80F | SRL A | |||
| C811 | RET | |||
| oss_op_decel_y | C812 | CALL oss_apply_x_step | Decelerate Y (mirror of oss_op_decel_x for the Y axis) | |
| C815 | LD C,(IX+$03) | |||
| C818 | CALL oss_lookup_speed | |||
| C81B | ADD A,(IX+$08) | |||
| C81E | LD (IX+$08),A | |||
| C821 | DEC (IX+$03) | |||
| C824 | JP oss_countdown | |||
| oss_op_accel_x_a | C827 | CALL oss_apply_y_step | Accelerate/decelerate X variant (countdown-driven, | |
| C82A | LD C,(IX+$02) | negated speed, counts down) | ||
| C82D | CALL oss_lookup_speed | |||
| C830 | NEG | |||
| C832 | ADD A,(IX+$07) | |||
| C835 | LD (IX+$07),A | |||
| C838 | DEC (IX+$02) | |||
| C83B | JP oss_countdown | |||
| oss_op_accel_x_b | C83E | CALL oss_apply_y_step | Accelerate/decelerate X variant (countdown-driven, | |
| C841 | LD C,(IX+$02) | positive speed, counts down) | ||
| C844 | CALL oss_lookup_speed | |||
| C847 | ADD A,(IX+$07) | |||
| C84A | LD (IX+$07),A | |||
| C84D | DEC (IX+$02) | |||
| C850 | JP oss_countdown | |||
| oss_op_accel_x_c | C853 | CALL oss_apply_y_step | Accelerate/decelerate X variant (countdown-driven, | |
| C856 | LD C,(IX+$02) | positive speed, counts up) | ||
| C859 | CALL oss_lookup_speed | |||
| C85C | ADD A,(IX+$07) | |||
| C85F | LD (IX+$07),A | |||
| C862 | INC (IX+$02) | |||
| C865 | JP oss_countdown | |||
| oss_op_immediate_step | C868 | LD C,A | Immediate 2-axis step opcode ($00-$7F): the low 3 | |
| C869 | AND $03 | bits of each nibble-pair select a step magnitude | ||
| C86B | BIT 2,C | (0-3, doubled via SLA) and a sign bit chooses the | ||
| C86D | JR Z,run_title_screen_12 | direction for X (bits 0-2) and Y (bits 4-6, tested | ||
| C86F | NEG | via BIT 5) independently | ||
| run_title_screen_12 | C871 | SLA A | ||
| C873 | ADD A,(IX+$07) | |||
| C876 | LD (IX+$07),A | |||
| C879 | LD A,C | |||
| C87A | RRA | |||
| C87B | RRA | |||
| C87C | RRA | |||
| C87D | AND $03 | |||
| C87F | BIT 5,C | |||
| C881 | JR Z,run_title_screen_13 | |||
| C883 | NEG | |||
| run_title_screen_13 | C885 | SLA A | ||
| C887 | ADD A,(IX+$08) | |||
| C88A | LD (IX+$08),A | |||
| C88D | JP oss_fetch_opcode_cont | |||
|
Clear the screen bitmap ($4000-$57FF) and attribute area ($5800-$59FF) to zero. This entry point is used by the routine at insert_high_score_entry.
|
||||
| clear_playfield_and_attrs | C890 | LD HL,$5900 | Clear attributes $5900-$5AFF (i.e. from the bottom | |
| C893 | LD DE,$5901 | up), then... (Conv note for later C port: this | ||
| C896 | LD (HL),L | range actually only needs $5800-$59FF -- treat as | ||
| C897 | LD BC,$01FF | a plain memset) | ||
| C89A | LDIR | |||
| C89C | LD HL,$4800 | ...clear the bitmap $4800-$57FF (leaving $4000- | ||
| C89F | LD DE,$4801 | $47FF, the top screen third, untouched here) | ||
| C8A2 | LD BC,$0FFF | |||
| C8A5 | LD (HL),L | |||
| C8A6 | LDIR | |||
| C8A8 | RET | |||
|
Clear the bitmap/attributes (clear_playfield_and_attrs) then set the border attribute rows ($5900-$59FF) to a fixed pattern: black border rows top/bottom (2 bytes each) sandwiching 28 rows of attribute $45 (BRIGHT cyan on black: bit 6 set, ink 5, paper 0) per attribute-cell column, repeated across all 16 columns.
|
||||
| clear_and_fill_border_attrs | C8A9 | CALL clear_playfield_and_attrs | ||
| C8AC | LD HL,$5900 | |||
| C8AF | LD C,$10 | 16 columns | ||
| C8B1 | XOR A | |||
| run_title_screen_14 | C8B2 | LD (HL),A | 2 black rows | |
| C8B3 | INC L | |||
| C8B4 | LD (HL),A | |||
| C8B5 | INC L | |||
| C8B6 | LD B,$1C | 28 rows of attribute $45 | ||
| run_title_screen_15 | C8B8 | LD (HL),$45 | ||
| C8BA | INC L | |||
| C8BB | DJNZ run_title_screen_15 | |||
| C8BD | LD (HL),A | 2 more black rows | ||
| C8BE | INC L | |||
| C8BF | LD (HL),A | |||
| C8C0 | INC HL | |||
| C8C1 | DEC C | |||
| C8C2 | JR NZ,run_title_screen_14 | |||
| C8C4 | RET | |||
|
Compute the screen address and masked-sprite blitter parameters for a single title-screen glyph/object, then dispatch to a width-specific unrolled OR-blit routine (blit_masked_sprite_dispatch onward) which draws it into the playfield bitmap. Called (via EXX-banked BC/L, see ts_draw_fg_objects) once per foreground object per frame. B = object Y screen position (+$08, clamped to a max of $6F -- the overflow past $6F is banked via run_title_screen_16 and used later as a row-skip count), C = object X screen position (+$07), L = the object's screen row/height byte (+$06, set by the script's $C8 opcode). compute_glyph_blit_params- C8CC clamp B; run_title_screen_16-C8EC then build a masked-sprite screen destination address in D/E from B and C, using the same "rotate through carry, XOR, mask $F8, XOR" idiom the ROM uses to interleave a pixel row into the non-linear screen-third layout (not traced bit- exactly here: getting each rotate/XOR wrong silently corrupts only the row within a third, which is easy to get subtly wrong without emulator verification -- flag for later verification against a working build). C8ED-C8FE then use C (object X) and L (screen row/height byte) to index the 4-byte-per-entry glyph table at glyphs (mask width, byte-count, source address), giving B/C/HL = mask width, byte count, and source glyph address. C902 restores the row-clamp flag banked at run_title_screen_16: if set, the source address is used as-is; otherwise cgb_row_offset_loop-C916 (cgb_row_offset_loop) walks the source pointer forward row-by-row (stride = C<<1, i.e. mask-width*2 bytes/row) for the overflow-past-$6F row count, before falling into the blit dispatch at blit_masked_sprite_dispatch.
|
||||
| compute_glyph_blit_params | C8C5 | LD A,B | ||
| C8C6 | CP $70 | |||
| C8C8 | JR C,run_title_screen_16 | |||
| C8CA | LD B,$6F | |||
| C8CC | SUB B | |||
| run_title_screen_16 | C8CD | EX AF,AF' | ||
| C8CE | LD A,$AF | |||
| C8D0 | SUB B | |||
| C8D1 | LD B,A | |||
| C8D2 | AND A | |||
| C8D3 | RRA | |||
| C8D4 | SCF | |||
| C8D5 | RRA | |||
| C8D6 | AND A | |||
| C8D7 | RRA | |||
| C8D8 | XOR B | |||
| C8D9 | AND $F8 | |||
| C8DB | XOR B | |||
| C8DC | LD D,A | |||
| C8DD | LD A,C | |||
| C8DE | RLCA | |||
| C8DF | RLCA | |||
| C8E0 | RLCA | |||
| C8E1 | XOR B | |||
| C8E2 | AND $C7 | |||
| C8E4 | XOR B | |||
| C8E5 | RLCA | |||
| C8E6 | RLCA | |||
| C8E7 | LD E,A | |||
| C8E8 | LD A,C | |||
| C8E9 | RRA | |||
| C8EA | AND $03 | |||
| C8EC | ADD A,L | |||
| C8ED | LD B,$00 | |||
| C8EF | SLA A | |||
| C8F1 | SLA A | |||
| C8F3 | LD C,A | |||
| C8F4 | RL B | |||
| C8F6 | LD HL,$D296 | |||
| C8F9 | ADD HL,BC | |||
| C8FA | LD B,(HL) | B/C/HL = mask width, byte-count, source address | ||
| C8FB | INC HL | from the glyphs glyph table entry | ||
| C8FC | LD C,(HL) | |||
| C8FD | INC HL | |||
| C8FE | LD A,(HL) | |||
| C8FF | INC HL | |||
| C900 | LD H,(HL) | |||
| C901 | LD L,A | |||
| C902 | EX AF,AF' | Restore the flag from the earlier RRA (row clamp) | ||
| C903 | JP C,blit_masked_sprite_dispatch | -- if set, skip straight to the blit dispatch | ||
| cgb_row_offset_loop | C906 | PUSH DE | Otherwise walk the source pointer forward by one | |
| C907 | LD E,C | row at a time (not traced bit-for-bit here) until | ||
| C908 | SLA E | the row-clamp countdown reaches zero | ||
| C90A | SRL A | |||
| C90C | LD D,$00 | |||
| run_title_screen_17 | C90E | ADD HL,DE | ||
| C90F | DEC B | |||
| C910 | JR Z,cgb_row_offset_done | |||
| C912 | DEC A | |||
| C913 | JP NZ,run_title_screen_17 | |||
| C916 | POP DE | |||
|
Masked-sprite blit dispatch: HL/DE hold the destination screen address (from the caller), the popped HL/DE here hold the source glyph address and its mask width in C. Dispatches to one of 6 width-specific unrolled OR-blit routines (blit_width1 .. blit_width7) which draw the glyph into the bitmap by treating the source address as a stack pointer (LD SP,HL) and POPping pixel/mask byte pairs -- see the project's known "LD SP,HL; POP x N sprite copy" translation pitfall. The real SP is saved at $C93D and restored by each blit routine (or by blit_abort_restore_sp on early abort) before returning.
|
||||
| blit_masked_sprite_dispatch | C917 | PUSH BC | ||
| C918 | LD ($C93D),SP | Save the real stack pointer | ||
| C91C | LD SP,HL | SP now points at the glyph source data | ||
| C91D | EX DE,HL | HL = destination screen address | ||
| C91E | DEC C | |||
| C91F | JP Z,blit_width1 | |||
| C922 | DEC C | |||
| C923 | JP Z,blit_width2 | |||
| C926 | DEC C | |||
| C927 | JP Z,blit_width3 | |||
| C92A | DEC C | |||
| C92B | JP Z,blit_width4 | |||
| C92E | DEC C | |||
| C92F | JP Z,blit_width5 | |||
| C932 | JP blit_width6 | |||
| cgb_row_offset_done | C935 | POP DE | ||
| C936 | LD B,$2D | Small fixed delay (not blitting this frame -- | ||
| run_title_screen_18 | C938 | DJNZ run_title_screen_18 | object scrolled fully off, nothing to draw) | |
| C93A | JR cgb_delay_tail | |||
|
Shared "abort the blit early" tail: restores the real SP (saved at $C93D by blit_masked_sprite_dispatch/blit_masked_sprite_dispatch_b) and returns to the object-draw loop.
|
||||
| blit_abort_restore_sp | C93C | LD SP,$0000 | (operand self-modified by C918/C9B4) | |
| C93F | POP BC | |||
| cgb_delay_tail | C940 | LD A,B | ||
| C941 | CPL | |||
| C942 | ADD A,$0F | |||
| C944 | RET NC | |||
| C945 | RET Z | |||
| C946 | LD C,$14 | |||
| run_title_screen_19 | C948 | LD B,C | ||
| run_title_screen_20 | C949 | DJNZ run_title_screen_20 | ||
| C94B | DEC A | |||
| C94C | JR NZ,run_title_screen_19 | |||
| C94E | RET | |||
|
Second glyph blit-parameter computation, structurally identical to compute_glyph_blit_params above but feeding the alternate dispatch table at blit_masked_sprite_dispatch_b. Used for the 3 "background" objects (see ts_draw_bg_objects).
|
||||
| compute_glyph_blit_params_b | C94F | LD A,B | ||
| C950 | CP $70 | |||
| C952 | JR C,run_title_screen_21 | |||
| C954 | LD B,$6F | |||
| C956 | SUB B | |||
| run_title_screen_21 | C957 | EX AF,AF' | ||
| C958 | LD A,$AF | |||
| C95A | SUB B | |||
| C95B | LD B,A | |||
| C95C | AND A | |||
| C95D | RRA | |||
| C95E | SCF | |||
| C95F | RRA | |||
| C960 | AND A | |||
| C961 | RRA | |||
| C962 | XOR B | |||
| C963 | AND $F8 | |||
| C965 | XOR B | |||
| C966 | LD D,A | |||
| C967 | LD A,C | |||
| C968 | RLCA | |||
| C969 | RLCA | |||
| C96A | RLCA | |||
| C96B | XOR B | |||
| C96C | AND $C7 | |||
| C96E | XOR B | |||
| C96F | RLCA | |||
| C970 | RLCA | |||
| C971 | LD E,A | |||
| C972 | LD A,C | |||
| C973 | RRA | |||
| C974 | AND $03 | |||
| C976 | ADD A,L | |||
| C977 | LD B,$00 | |||
| C979 | SLA A | |||
| C97B | SLA A | |||
| C97D | LD C,A | |||
| C97E | RL B | |||
| C980 | LD HL,$D296 | |||
| C983 | ADD HL,BC | |||
| C984 | LD B,(HL) | |||
| C985 | INC HL | |||
| C986 | LD C,(HL) | |||
| C987 | INC HL | |||
| C988 | LD A,(HL) | |||
| C989 | INC HL | |||
| C98A | LD H,(HL) | |||
| C98B | LD L,A | |||
| C98C | EX AF,AF' | |||
| C98D | JP C,blit_masked_sprite_dispatch_b | |||
| cgbb_row_offset_loop | C990 | PUSH DE | ||
| C991 | EX AF,AF' | |||
| C992 | LD E,C | |||
| C993 | LD A,E | |||
| C994 | SUB $06 | |||
| C996 | JR C,run_title_screen_22 | |||
| C998 | CPL | |||
| C999 | ADD A,$03 | |||
| C99B | LD E,A | |||
| run_title_screen_22 | C99C | EX AF,AF' | ||
| C99D | LD D,$00 | |||
| C99F | SLA E | |||
| C9A1 | SRL A | |||
| C9A3 | JR NZ,run_title_screen_23 | |||
| C9A5 | INC A | |||
| run_title_screen_23 | C9A6 | ADD HL,DE | ||
| C9A7 | DEC B | |||
| C9A8 | JR Z,run_title_screen_24 | |||
| C9AA | DEC A | |||
| C9AB | JP NZ,run_title_screen_23 | |||
| C9AE | POP DE | |||
|
Alternate masked-sprite blit dispatch used by the background-object draw path (ts_draw_bg_objects via compute_glyph_blit_params_b). Identical width-selection logic to blit_masked_sprite_dispatch, but preserves B (via an extra push/pop) as a small fixed delay count, and its early-exit tail (run_title_screen_24) simply restores DE rather than aborting via blit_abort_restore_sp.
|
||||
| blit_masked_sprite_dispatch_b | C9AF | LD A,B | ||
| C9B0 | LD B,$14 | |||
| C9B2 | PUSH BC | |||
| C9B3 | LD B,A | |||
| C9B4 | LD ($C93D),SP | |||
| C9B8 | LD SP,HL | |||
| C9B9 | EX DE,HL | |||
| C9BA | DEC C | |||
| C9BB | JR Z,blit_width1 | |||
| C9BD | DEC C | |||
| C9BE | JR Z,blit_width2 | |||
| C9C0 | DEC C | |||
| C9C1 | JP Z,blit_width3 | |||
| C9C4 | DEC C | |||
| C9C5 | JP Z,blit_width4 | |||
| C9C8 | DEC C | |||
| C9C9 | JP Z,blit_width5 | |||
| C9CC | DEC C | |||
| C9CD | JP Z,blit_width6 | |||
| C9D0 | JP blit_width7 | |||
| run_title_screen_24 | C9D3 | POP DE | ||
| C9D4 | RET | |||
|
Width-1 (mask-only, no fill byte) unrolled OR-blit. blit_masked_sprite_dispatch/blit_masked_sprite_dispatch_b dispatch here when the width selector (C, decremented to 0) picks this variant. Draws 2 scanlines per POP DE: E blits into the current HL byte (LD A,(HL) / OR E / LD (HL),A -- a masked, non-overwriting sprite draw), then INC H steps to the next screen row; if that crosses a third boundary (H AND $07 = 0), the SUB $08 / ADD A,$20 / carry-adjust pattern at advance_glyph_scanline fixes up H/L, otherwise the row falls straight through. D then blits the same way into the following row, with its own boundary fix-up at run_title_screen_28. A short fixed delay (run_title_screen_26, a 30-iteration DEC-A loop) pads out the timing before DJNZ repeats for the next row-pair (B counts row-pairs); once B reaches 0, execution falls into blit_abort_restore_sp, which restores the real SP and returns.
|
||||
| blit_width1 | C9D5 | POP DE | ||
| C9D6 | LD A,(HL) | |||
| C9D7 | OR E | |||
| C9D8 | LD (HL),A | |||
| C9D9 | INC H | |||
| C9DA | LD A,H | |||
| C9DB | AND $07 | |||
| C9DD | JR Z,advance_glyph_scanline | |||
| run_title_screen_25 | C9DF | LD A,(HL) | ||
| C9E0 | OR D | |||
| C9E1 | LD (HL),A | |||
| C9E2 | INC H | |||
| C9E3 | LD A,H | |||
| C9E4 | AND $07 | |||
| C9E6 | JR Z,run_title_screen_28 | |||
| run_title_screen_26 | C9E8 | LD A,$1E | ||
| run_title_screen_27 | C9EA | DEC A | ||
| C9EB | JP NZ,run_title_screen_27 | |||
| C9EE | DJNZ blit_width1 | |||
| C9F0 | JP blit_abort_restore_sp | |||
| advance_glyph_scanline | C9F3 | LD A,H | ||
| C9F4 | SUB $08 | |||
| C9F6 | LD H,A | |||
| C9F7 | LD A,L | |||
| C9F8 | ADD A,$20 | |||
| C9FA | LD L,A | |||
| C9FB | JP NC,run_title_screen_25 | |||
| C9FE | LD A,H | |||
| C9FF | ADD A,$08 | |||
| CA01 | LD H,A | |||
| CA02 | JP run_title_screen_25 | |||
| run_title_screen_28 | CA05 | LD A,H | ||
| CA06 | SUB $08 | |||
| CA08 | LD H,A | |||
| CA09 | LD A,L | |||
| CA0A | ADD A,$20 | |||
| CA0C | LD L,A | |||
| CA0D | JP NC,run_title_screen_26 | |||
| CA10 | LD A,H | |||
| CA11 | ADD A,$08 | |||
| CA13 | LD H,A | |||
| CA14 | JP run_title_screen_26 | |||
|
Width-2 unrolled OR-blit variant (see blit_width1 for the general pattern).
|
||||
| blit_width2 | CA17 | POP DE | ||
| CA18 | LD A,(HL) | |||
| CA19 | OR E | |||
| CA1A | LD (HL),A | |||
| CA1B | INC L | |||
| CA1C | LD A,(HL) | |||
| CA1D | OR D | |||
| CA1E | LD (HL),A | |||
| CA1F | DEC L | |||
| CA20 | INC H | |||
| CA21 | LD A,H | |||
| CA22 | AND $07 | |||
| CA24 | JR Z,run_title_screen_32 | |||
| run_title_screen_29 | CA26 | POP DE | ||
| CA27 | LD A,(HL) | |||
| CA28 | OR E | |||
| CA29 | LD (HL),A | |||
| CA2A | INC L | |||
| CA2B | LD A,(HL) | |||
| CA2C | OR D | |||
| CA2D | LD (HL),A | |||
| CA2E | DEC L | |||
| CA2F | INC H | |||
| CA30 | LD A,H | |||
| CA31 | AND $07 | |||
| CA33 | JR Z,run_title_screen_33 | |||
| run_title_screen_30 | CA35 | LD A,$14 | ||
| run_title_screen_31 | CA37 | DEC A | ||
| CA38 | JP NZ,run_title_screen_31 | |||
| CA3B | DJNZ blit_width2 | |||
| CA3D | JP blit_abort_restore_sp | |||
| run_title_screen_32 | CA40 | LD A,H | ||
| CA41 | SUB $08 | |||
| CA43 | LD H,A | |||
| CA44 | LD A,L | |||
| CA45 | ADD A,$20 | |||
| CA47 | LD L,A | |||
| CA48 | JP NC,run_title_screen_29 | |||
| CA4B | LD A,H | |||
| CA4C | ADD A,$08 | |||
| CA4E | LD H,A | |||
| CA4F | JP run_title_screen_29 | |||
| run_title_screen_33 | CA52 | LD A,H | ||
| CA53 | SUB $08 | |||
| CA55 | LD H,A | |||
| CA56 | LD A,L | |||
| CA57 | ADD A,$20 | |||
| CA59 | LD L,A | |||
| CA5A | JP NC,run_title_screen_30 | |||
| CA5D | LD A,H | |||
| CA5E | ADD A,$08 | |||
| CA60 | LD H,A | |||
| CA61 | JP run_title_screen_30 | |||
|
Width-3 unrolled OR-blit variant (see blit_width1 for the general pattern).
|
||||
| blit_width3 | CA64 | LD C,L | ||
| CA65 | POP DE | |||
| CA66 | LD A,(HL) | |||
| CA67 | OR E | |||
| CA68 | LD (HL),A | |||
| CA69 | INC L | |||
| CA6A | LD A,(HL) | |||
| CA6B | OR D | |||
| CA6C | LD (HL),A | |||
| CA6D | INC L | |||
| CA6E | POP DE | |||
| CA6F | LD A,(HL) | |||
| CA70 | OR E | |||
| CA71 | LD (HL),A | |||
| CA72 | LD L,C | |||
| CA73 | INC H | |||
| CA74 | LD A,H | |||
| CA75 | AND $07 | |||
| CA77 | JR Z,run_title_screen_37 | |||
| run_title_screen_34 | CA79 | LD C,L | ||
| CA7A | LD A,(HL) | |||
| CA7B | OR D | |||
| CA7C | LD (HL),A | |||
| CA7D | INC L | |||
| CA7E | POP DE | |||
| CA7F | LD A,(HL) | |||
| CA80 | OR E | |||
| CA81 | LD (HL),A | |||
| CA82 | INC L | |||
| CA83 | LD A,(HL) | |||
| CA84 | OR D | |||
| CA85 | LD (HL),A | |||
| CA86 | LD L,C | |||
| CA87 | INC H | |||
| CA88 | LD A,H | |||
| CA89 | AND $07 | |||
| CA8B | JR Z,run_title_screen_38 | |||
| run_title_screen_35 | CA8D | LD A,$0A | ||
| run_title_screen_36 | CA8F | DEC A | ||
| CA90 | JP NZ,run_title_screen_36 | |||
| CA93 | DJNZ blit_width3 | |||
| CA95 | JP blit_abort_restore_sp | |||
| run_title_screen_37 | CA98 | LD A,H | ||
| CA99 | SUB $08 | |||
| CA9B | LD H,A | |||
| CA9C | LD A,L | |||
| CA9D | ADD A,$20 | |||
| CA9F | LD L,A | |||
| CAA0 | JP NC,run_title_screen_34 | |||
| CAA3 | LD A,H | |||
| CAA4 | ADD A,$08 | |||
| CAA6 | LD H,A | |||
| CAA7 | JP run_title_screen_34 | |||
| run_title_screen_38 | CAAA | LD A,H | ||
| CAAB | SUB $08 | |||
| CAAD | LD H,A | |||
| CAAE | LD A,L | |||
| CAAF | ADD A,$20 | |||
| CAB1 | LD L,A | |||
| CAB2 | JP NC,run_title_screen_35 | |||
| CAB5 | LD A,H | |||
| CAB6 | ADD A,$08 | |||
| CAB8 | LD H,A | |||
| CAB9 | JP run_title_screen_35 | |||
|
Width-4 unrolled OR-blit variant (see blit_width1 for the general pattern).
|
||||
| blit_width4 | CABC | LD C,L | ||
| CABD | POP DE | |||
| CABE | LD A,(HL) | |||
| CABF | OR E | |||
| CAC0 | LD (HL),A | |||
| CAC1 | INC L | |||
| CAC2 | LD A,(HL) | |||
| CAC3 | OR D | |||
| CAC4 | LD (HL),A | |||
| CAC5 | INC L | |||
| CAC6 | POP DE | |||
| CAC7 | LD A,(HL) | |||
| CAC8 | OR E | |||
| CAC9 | LD (HL),A | |||
| CACA | INC L | |||
| CACB | LD A,(HL) | |||
| CACC | OR D | |||
| CACD | LD (HL),A | |||
| CACE | LD L,C | |||
| CACF | INC H | |||
| CAD0 | LD A,H | |||
| CAD1 | AND $07 | |||
| CAD3 | JR Z,run_title_screen_41 | |||
| run_title_screen_39 | CAD5 | LD C,L | ||
| CAD6 | POP DE | |||
| CAD7 | LD A,(HL) | |||
| CAD8 | OR E | |||
| CAD9 | LD (HL),A | |||
| CADA | INC L | |||
| CADB | LD A,(HL) | |||
| CADC | OR D | |||
| CADD | LD (HL),A | |||
| CADE | INC L | |||
| CADF | POP DE | |||
| CAE0 | LD A,(HL) | |||
| CAE1 | OR E | |||
| CAE2 | LD (HL),A | |||
| CAE3 | INC L | |||
| CAE4 | LD A,(HL) | |||
| CAE5 | OR D | |||
| CAE6 | LD (HL),A | |||
| CAE7 | LD L,C | |||
| CAE8 | INC H | |||
| CAE9 | LD A,H | |||
| CAEA | AND $07 | |||
| CAEC | JR Z,run_title_screen_42 | |||
| run_title_screen_40 | CAEE | DJNZ blit_width4 | ||
| CAF0 | JP blit_abort_restore_sp | |||
| run_title_screen_41 | CAF3 | LD A,H | ||
| CAF4 | SUB $08 | |||
| CAF6 | LD H,A | |||
| CAF7 | LD A,L | |||
| CAF8 | ADD A,$20 | |||
| CAFA | LD L,A | |||
| CAFB | JP NC,run_title_screen_39 | |||
| CAFE | LD A,H | |||
| CAFF | ADD A,$08 | |||
| CB01 | LD H,A | |||
| CB02 | JP run_title_screen_39 | |||
| run_title_screen_42 | CB05 | LD A,H | ||
| CB06 | SUB $08 | |||
| CB08 | LD H,A | |||
| CB09 | LD A,L | |||
| CB0A | ADD A,$20 | |||
| CB0C | LD L,A | |||
| CB0D | JP NC,run_title_screen_40 | |||
| CB10 | LD A,H | |||
| CB11 | ADD A,$08 | |||
| CB13 | LD H,A | |||
| CB14 | JP run_title_screen_40 | |||
|
Width-5 unrolled OR-blit variant (see blit_width1 for the general pattern).
|
||||
| blit_width5 | CB17 | LD C,L | ||
| CB18 | POP DE | |||
| CB19 | LD A,(HL) | |||
| CB1A | OR E | |||
| CB1B | LD (HL),A | |||
| CB1C | INC L | |||
| CB1D | LD A,(HL) | |||
| CB1E | OR D | |||
| CB1F | LD (HL),A | |||
| CB20 | INC L | |||
| CB21 | POP DE | |||
| CB22 | LD A,(HL) | |||
| CB23 | OR E | |||
| CB24 | LD (HL),A | |||
| CB25 | INC L | |||
| CB26 | LD A,(HL) | |||
| CB27 | OR D | |||
| CB28 | LD (HL),A | |||
| CB29 | INC L | |||
| CB2A | POP DE | |||
| CB2B | LD A,(HL) | |||
| CB2C | OR E | |||
| CB2D | LD (HL),A | |||
| CB2E | LD L,C | |||
| CB2F | INC H | |||
| CB30 | LD A,H | |||
| CB31 | AND $07 | |||
| CB33 | JR Z,run_title_screen_45 | |||
| run_title_screen_43 | CB35 | LD C,L | ||
| CB36 | LD A,(HL) | |||
| CB37 | OR D | |||
| CB38 | LD (HL),A | |||
| CB39 | INC L | |||
| CB3A | POP DE | |||
| CB3B | LD A,(HL) | |||
| CB3C | OR E | |||
| CB3D | LD (HL),A | |||
| CB3E | INC L | |||
| CB3F | LD A,(HL) | |||
| CB40 | OR D | |||
| CB41 | LD (HL),A | |||
| CB42 | INC L | |||
| CB43 | POP DE | |||
| CB44 | LD A,(HL) | |||
| CB45 | OR E | |||
| CB46 | LD (HL),A | |||
| CB47 | INC L | |||
| CB48 | LD A,(HL) | |||
| CB49 | OR D | |||
| CB4A | LD (HL),A | |||
| CB4B | LD L,C | |||
| CB4C | INC H | |||
| CB4D | LD A,H | |||
| CB4E | AND $07 | |||
| CB50 | JR Z,run_title_screen_46 | |||
| run_title_screen_44 | CB52 | DJNZ blit_width5 | ||
| CB54 | JP blit_abort_restore_sp | |||
| run_title_screen_45 | CB57 | LD A,H | ||
| CB58 | SUB $08 | |||
| CB5A | LD H,A | |||
| CB5B | LD A,L | |||
| CB5C | ADD A,$20 | |||
| CB5E | LD L,A | |||
| CB5F | JP NC,run_title_screen_43 | |||
| CB62 | LD A,H | |||
| CB63 | ADD A,$08 | |||
| CB65 | LD H,A | |||
| CB66 | JP run_title_screen_43 | |||
| run_title_screen_46 | CB69 | LD A,H | ||
| CB6A | SUB $08 | |||
| CB6C | LD H,A | |||
| CB6D | LD A,L | |||
| CB6E | ADD A,$20 | |||
| CB70 | LD L,A | |||
| CB71 | JP NC,run_title_screen_44 | |||
| CB74 | LD A,H | |||
| CB75 | ADD A,$08 | |||
| CB77 | LD H,A | |||
| CB78 | JP run_title_screen_44 | |||
|
Width-6 unrolled OR-blit variant (see blit_width1 for the general pattern).
|
||||
| blit_width6 | CB7B | POP DE | ||
| CB7C | LD A,(HL) | |||
| CB7D | OR E | |||
| CB7E | LD (HL),A | |||
| CB7F | INC L | |||
| CB80 | LD A,(HL) | |||
| CB81 | OR D | |||
| CB82 | LD (HL),A | |||
| CB83 | DEC L | |||
| CB84 | INC H | |||
| CB85 | LD A,H | |||
| CB86 | AND $07 | |||
| CB88 | JR Z,run_title_screen_49 | |||
| run_title_screen_47 | CB8A | POP DE | ||
| CB8B | LD A,(HL) | |||
| CB8C | OR E | |||
| CB8D | LD (HL),A | |||
| CB8E | INC L | |||
| CB8F | LD A,(HL) | |||
| CB90 | OR D | |||
| CB91 | LD (HL),A | |||
| CB92 | DEC L | |||
| CB93 | INC H | |||
| CB94 | LD A,H | |||
| CB95 | AND $07 | |||
| CB97 | JR Z,run_title_screen_50 | |||
| run_title_screen_48 | CB99 | DJNZ blit_width6 | ||
| CB9B | LD HL,($C93D) | |||
| CB9E | LD SP,HL | |||
| CB9F | POP BC | |||
| CBA0 | RET | |||
| run_title_screen_49 | CBA1 | LD A,H | ||
| CBA2 | SUB $08 | |||
| CBA4 | LD H,A | |||
| CBA5 | LD A,L | |||
| CBA6 | ADD A,$20 | |||
| CBA8 | LD L,A | |||
| CBA9 | JP NC,run_title_screen_47 | |||
| CBAC | LD A,H | |||
| CBAD | ADD A,$08 | |||
| CBAF | LD H,A | |||
| CBB0 | JP run_title_screen_47 | |||
| run_title_screen_50 | CBB3 | LD A,H | ||
| CBB4 | SUB $08 | |||
| CBB6 | LD H,A | |||
| CBB7 | LD A,L | |||
| CBB8 | ADD A,$20 | |||
| CBBA | LD L,A | |||
| CBBB | JP NC,run_title_screen_48 | |||
| CBBE | LD A,H | |||
| CBBF | ADD A,$08 | |||
| CBC1 | LD H,A | |||
| CBC2 | JP run_title_screen_48 | |||
|
Width-7 unrolled OR-blit variant (see blit_width1 for the general pattern); the widest/final entry in the dispatch chain, reached when C reaches 0 without matching any of the DEC C; JP Z tests above.
|
||||
| blit_width7 | CBC5 | POP DE | ||
| CBC6 | LD A,(HL) | |||
| CBC7 | OR E | |||
| CBC8 | LD (HL),A | |||
| CBC9 | INC H | |||
| CBCA | LD A,H | |||
| CBCB | AND $07 | |||
| CBCD | JR Z,run_title_screen_53 | |||
| run_title_screen_51 | CBCF | LD A,(HL) | ||
| CBD0 | OR D | |||
| CBD1 | LD (HL),A | |||
| CBD2 | INC H | |||
| CBD3 | LD A,H | |||
| CBD4 | AND $07 | |||
| CBD6 | JR Z,run_title_screen_54 | |||
| run_title_screen_52 | CBD8 | DJNZ blit_width7 | ||
| CBDA | LD HL,($C93D) | Restore the real SP (saved by blit_masked_sprite_dispatch/blit_masked_sprite_dispatch_b) | ||
| CBDD | LD SP,HL | |||
| CBDE | POP BC | |||
| CBDF | RET | |||
| run_title_screen_53 | CBE0 | LD A,H | ||
| CBE1 | SUB $08 | |||
| CBE3 | LD H,A | |||
| CBE4 | LD A,L | |||
| CBE5 | ADD A,$20 | |||
| CBE7 | LD L,A | |||
| CBE8 | JP NC,run_title_screen_51 | |||
| CBEB | LD A,H | |||
| CBEC | ADD A,$08 | |||
| CBEE | LD H,A | |||
| CBEF | JP run_title_screen_51 | |||
| run_title_screen_54 | CBF2 | LD A,H | ||
| CBF3 | SUB $08 | |||
| CBF5 | LD H,A | |||
| CBF6 | LD A,L | |||
| CBF7 | ADD A,$20 | |||
| CBF9 | LD L,A | |||
| CBFA | JP NC,run_title_screen_52 | |||
| CBFD | LD A,H | |||
| CBFE | ADD A,$08 | |||
| CC00 | LD H,A | |||
| CC01 | JP run_title_screen_52 | |||
|
Clear the playfield bitmap ($4800-$57FF, i.e. the lower two screen thirds, excluding the top third at $4000-$47FF which holds the fixed title/credits text) to zero, ready for the next frame's objects. Classic "LD SP,HL; PUSH x N" fast-fill trick (see the project's known translation pitfall of the same name): SP is repointed at the bitmap, then 14 PUSH DE instructions fill 28 bytes per pass, DJNZ-looped 8 times per screen-third row (C = 8, giving 8 x 28 = 224 bytes per call through the inner loop, i.e. one attribute-row's worth), stepping through third-boundary wraps via the usual ADD A,$20 / carry pattern. The real SP is saved at $CC4D and restored before returning.
|
||||
| clear_playfield_buffer | CC04 | LD ($CC4D),SP | Save the real stack pointer | |
| CC08 | LD HL,$481E | |||
| CC0B | LD DE,$0000 | |||
| CC0E | LD C,$08 | |||
| cpb_third1_row_loop | CC10 | LD B,C | ||
| cpb_third1_fill | CC11 | LD SP,HL | ||
| CC12 | PUSH DE | |||
| CC13 | PUSH DE | |||
| CC14 | PUSH DE | |||
| CC15 | PUSH DE | |||
| CC16 | PUSH DE | |||
| CC17 | PUSH DE | |||
| CC18 | PUSH DE | |||
| CC19 | PUSH DE | |||
| CC1A | PUSH DE | |||
| CC1B | PUSH DE | |||
| CC1C | PUSH DE | |||
| CC1D | PUSH DE | |||
| CC1E | PUSH DE | |||
| CC1F | PUSH DE | |||
| CC20 | INC H | |||
| CC21 | DJNZ cpb_third1_fill | |||
| CC23 | LD H,$48 | |||
| CC25 | LD A,L | |||
| CC26 | ADD A,$20 | |||
| CC28 | LD L,A | |||
| CC29 | JP NC,cpb_third1_row_loop | |||
| CC2C | LD H,$50 | Move on to the second screen third ($5000-$57FF) | ||
| cpb_third2_row_loop | CC2E | LD B,C | ||
| cpb_third2_fill | CC2F | LD SP,HL | ||
| CC30 | PUSH DE | |||
| CC31 | PUSH DE | |||
| CC32 | PUSH DE | |||
| CC33 | PUSH DE | |||
| CC34 | PUSH DE | |||
| CC35 | PUSH DE | |||
| CC36 | PUSH DE | |||
| CC37 | PUSH DE | |||
| CC38 | PUSH DE | |||
| CC39 | PUSH DE | |||
| CC3A | PUSH DE | |||
| CC3B | PUSH DE | |||
| CC3C | PUSH DE | |||
| CC3D | PUSH DE | |||
| CC3E | INC H | |||
| CC3F | DJNZ cpb_third2_fill | |||
| CC41 | LD H,$50 | |||
| CC43 | LD A,L | |||
| CC44 | ADD A,$20 | |||
| CC46 | LD L,A | |||
| CC47 | CP $A0 | |||
| CC49 | JP C,cpb_third2_row_loop | |||
| CC4C | LD SP,$0000 | Restore the real stack pointer (operand self- | ||
| CC4F | RET | modified by $CC04) and return | ||
| Prev: C3AF | Up: Map | Next: CC50 |