--- title: "Bat Cage" id: 51862 type: "computer_media" slug: "batcage" url: "http://localhost/computer_media/batcage/" markdown_url: "http://localhost/computer_media/batcage.md" published_at: "2023-08-16T01:42:19+00:00" modified_at: "2026-04-04T08:29:27+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2023/08/SCR-20260404-dwby.png" excerpt: "A machine code action game where you catch a falling egg and then maneuver a bat into a cage — nearly all logic lives inside a single REM statement." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "Timex Computer Corporation" slug: "timex-computer-corporation" taxonomy: "post_tag" url: "http://localhost/tag/timex-computer-corporation/" - name: "TS 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" genre: - name: "Arcade" slug: "arcade" taxonomy: "genre" url: "http://localhost/type/arcade/" - name: "Game" slug: "game" taxonomy: "genre" url: "http://localhost/type/game/" media_type: "Cassette" download_url: "https://archive.org/download/timex-sinclair-software-archive/BatCage (1983)(Timex)(US)(TS1000)(Cassette).zip" mediadate: "1983" producer_company: - id: 11401 title: "Timex Computer Corporation" type: "company" url: "http://localhost/company/timex-computer-corporation/" images: - url: "http://localhost/wp-content/uploads/2023/08/SCR-20260404-dwby.png" related_products: - id: 11886 title: "Bat Cage" type: "product" url: "http://localhost/product/bat-cage/" media_type_tags: "Arcade, Game" --- Bat Cage is an action game in which the player catches a falling egg and then traps a bat inside a cage. The program is driven almost entirely by machine code embedded in the REM statement at line 1, with BASIC serving only as a loader that calls the routine via USR 17387 at line 10. The machine code handles all gameplay logic, graphics rendering, collision detection, and input processing directly. A SAVE command at line 20 preserves the program, and RUN 10 at line 30 restarts the game loop. *** ## Program Analysis ### Program Structure The BASIC listing is minimal by design, consisting of just three lines: 1. `1 REM` — contains the entire machine code payload (several hundred bytes) embedded as the body of the remark. 2. `10 LET K=USR 17387` — transfers control to the machine code. The address 17387 (decimal) corresponds to the start of the machine code bytes stored in the REM line’s data area. 3. `20 SAVE "CAGE"` — saves the program to tape. 4. `30 RUN 10` — restarts the program by jumping to line 10. All game logic — movement, collision detection, graphics, timing, and scoring — is implemented entirely in the machine code within the REM statement. BASIC is used solely as a vehicle to load and launch that code. ### Machine Code Embedding via REM Storing machine code in a `REM` statement is a well-established technique. The BASIC interpreter skips REM line content entirely, so arbitrary binary data can be placed there without interference. The `USR` function at line 10 computes the Z80 entry point address (17387) and performs a `CALL` to it, handing control to the machine code. The return value is stored in `K`, though the game does not use it in BASIC. ### Machine Code Analysis The REM data is a dense Z80 routine. Notable structural features visible in the hex stream include: - **CB-prefixed instructions** — extensive use of `CB` opcodes indicates heavy reliance on bit manipulation instructions (`BIT`, `SET`, `RES`, `RLC`, etc.), consistent with sprite/character-level graphics and flag-based state machines. - **ED-prefixed instructions** — `ED` opcodes appear frequently, covering 16-bit loads (`LD BC,(nn)`, `LD DE,(nn)`), block moves (`LDIR`), and `LD A,R` / `LD A,I` used for pseudo-random number generation or timing. - **Block memory operations** — sequences ending in `\ED\B0` (`LDIR`) suggest bulk copying of sprite or screen data. - **Internal subroutine calls** — numerous `CD xx xx` (`CALL`) instructions with targets within the REM block point to a well-structured internal subroutine architecture covering rendering, input reading, collision, and movement. - **Address constants** — repeated references to addresses in the `43xx` and `44xx` hex range (roughly 17000–17600 decimal) indicate game-state variables stored within or just after the REM block itself. ### Key Address Map (inferred) | Hex Address | Decimal | Inferred Role | | --- | --- | --- | | `43CB` | 17355 | Sprite/object X or position low byte | | `43CC` | 17356 | Sprite/object Y or position high byte | | `43CD` | 17357 | Secondary object coordinate | | `43D0` | 17360 | Game state / direction flag | | `43D1` | 17361 | Velocity or delta counter | | `43D2` | 17362 | Additional state variable | | `44B6` | 17590 | Screen buffer or sprite data table | | `44D8` | 17624 | Graphics/shape data | ### Notable Techniques - **LD A,R (`ED 5F`)** — used as a source of pseudo-randomness by reading the Z80 refresh register, a common technique for seeding movement or timing variation without a dedicated RNG. - **Bit-field state machine** — the heavy use of `BIT`, `SET`, and `RES` on single bytes (visible in the `CB 4x`, `CB 5x`, `CB 6x`, `CB 7x` ranges) suggests individual bits of state bytes encode direction, phase, and collision flags compactly. - **Self-contained variable storage** — game variables are stored at fixed offsets within the REM block’s memory region rather than in BASIC variables, avoiding BASIC overhead entirely. - **Loop unrolling with `DJNZ`** — several `10 Fx` byte pairs (`DJNZ` with negative offset) implement tight delay or drawing loops without BASIC’s overhead. - **Exx / DI shadow registers** — `D9` (`EXX`) appears in the code, indicating use of the Z80 alternate register set for temporary storage during interrupt-sensitive sections. ### BASIC Idioms The use of `LET K=USR 17387` rather than a bare `RAND USR` is a minor stylistic choice; both transfer control identically. The `RUN 10` at line 30 provides a simple restart mechanism: if the machine code ever returns to BASIC (e.g., after a game over), the program loops back to re-invoke the machine code rather than halting. ### Bugs and Anomalies No significant BASIC-level bugs are present. The program is straightforward as a loader. Any bugs would reside entirely within the machine code and cannot be fully assessed from a static hex listing alone. ## Source Code ``` 1 REM \CB\38\30\0A\CB\39\30\03\3E\87\C9\3E\04\C9\CB\39\30\03\3E\02\C9\3E\01\C9\0E\80\06\02\E5\79\AE\77\23\10\FA\E1\C9\ED\43\CB\43\22\CD\43\C9\CB\6C\28\32\21\D0\43\AF\BE\C8\2B\3E\E8\BE\C8\77\EB\2A\CB\43\22\E7\43\21\D3\43\3A\D1\43\C6\15\86\D8\77\13\AF\12\C9\12\C9\79\FE\37\C8\D5\E1\0C\CB\47\28\0E\23\18\0B\0D\C8\79\D5\E1\CB\47\28\02\2B\1B\CD\A7\40\4F\EB\CD\82\40\4F\18\61\CD\BB\02\ED\4B\CB\43\ED\5B\CD\43\CB\5D\28\A5\CB\65\20\58\CB\5C\28\C5\7C\EB\11\21\00\CB\67\28\1F\CB\4F\CA\91\43\78\FE\26\C8\04\E5\0F\30\1B\19\D1\CD\A7\40\C5\0E\03\CD\9C\40\EB\CD\9C\40\18\13\05\C8\E5\78\0F\30\03\A7\ED\52\D1\CD\A7\40\EB\07\38\E2\C5\CD\9A\40\C1\CB\41\C8\0E\04\CD\5C\41\EB\0E\01\06\02\79\AE\77\23\23\10\F9\C9\11\D1\43\CB\6D\20\06\1A\A7\C8\3D\18\08\CB\45\C0\1A\FE\23\C8\3C\47\3A\D0\43\A7\C8\3E\1C\80\32\B7\44\78\12\C9\3A\D0\43\A7\C0\E5\2A\D5\43\7E\FE\03\28\0D\3C\FE\26\30\03\77\E1\C9\36\1C\2B\18\EE\36\1D\21\D5\43\35\2B\34\34\2B\AF\77\2B\CB\3E\E1\C9\CD\FB\40\C1\CB\09\30\02\AF\47\C5\21\3C\40\01\50\40\D9\21\D7\43\4E\23\46\04\0C\11\00\28\78\BA\CC\82\44\3A\D4\43\BD\38\0A\1E\80\3A\D0\43\AA\B8\CC\81\44\3E\21\B8\28\56\30\20\2F\B8\28\54\38\1A\3E\17\B9\28\51\30\24\2F\B9\28\4F\38\14\3E\24\B9\28\50\30\50\2F\B9\28\46\38\4A\79\FE\3C\28\08\30\0A\ED\5F\2F\B8\20\04\79\ED\44\4F\3A\CC\43\B8\28\04\2F\B8\20\65\3A\CB\43\3D\B9\30\5E\C6\04\B9\30\0B\C6\01\2F\B9\30\53\C6\04\B9\38\4E\18\6E\CB\C3\18\AE\CB\C2\18\AA\CB\CB\18\0A\CB\CA\18\06\CB\D3\18\02\CB\D2\CB\7B\20\71\CB\43\20\67\CB\4B\20\20\CB\53\20\1C\CD\15\43\F1\F5\B3\A2\AA\CB\47\28\09\F5\78\ED\44\47\CD\8A\41\F1\CB\4F\28\09\CD\8A\41\79\ED\44\4F\18\04\CB\57\20\F3\CD\3B\43\3E\E8\BD\DA\B6\41\3A\D1\43\A7\CA\CB\41\0E\0F\CB\7B\28\02\0E\0A\47\79\3D\20\FD\10\FA\C3\CB\41\CB\7B\28\26\CB\78\20\D6\ED\5F\FE\C0\30\3D\FE\95\30\30\3E\20\32\D0\43\78\ED\44\47\18\C1\7B\B2\D1\B2\57\3A\D2\43\5F\D5\5A\18\B4\3E\E6\32\CF\43\C6\02\95\28\AA\C5\4F\AF\47\E5\D1\1B\23\ED\B0\C1\2B\18\9C\C5\FE\80\D4\7A\44\C1\18\CC\C5\4F\3A\D1\43\CB\3F\81\30\02\06\FF\2F\A0\28\06\47\CD\8A\41\10\FB\C1\18\B3\1E\80\3A\CC\43\FE\21\D8\20\02\CB\C3\3A\CB\43\FE\14\30\03\CB\83\C9\FE\25\30\F9\FE\18\30\02\CB\CB\FE\21\D8\CB\D3\C9\E5\70\2B\71\3E\80\A3\5F\16\FF\3A\CF\43\BD\30\01\14\CB\78\28\03\78\2F\47\CB\79\28\03\79\2F\4F\CD\82\40\AB\A2\F5\CD\7C\43\E5\D9\5E\23\56\EB\0A\AE\77\E1\F1\02\AE\77\EB\72\2B\73\23\23\03\D9\E1\23\C9\58\79\80\01\00\05\51\CB\23\CB\12\10\FA\21\D8\44\19\51\5F\19\C9\CD\3A\44\01\20\00\11\B6\44\21\5A\44\ED\B0\0E\1E\11\CB\43\21\AD\43\ED\B0\CD\3A\44\C9\1C\24\38\47\E8\20\12\80\00\D8\D4\44\1D\03\13\13\13\EA\EA\13\EA\EA\27\13\27\EA\D6\13\D6\EA\1C\24\38\47\E8\20\12\80\00\D8\D4\44\CB\F9\CD\F7\25\10\E2\E9\10\1E\06\E8\0A\DB\C5\F6\CD\0F\83\81\CD\2B\0F\CD\2A\0A\11\CB\43\06\16\C5\D5\01\20\00\CD\6B\0B\D1\C1\10\F4\11\85\05\3E\80\21\B6\44\06\15\C5\06\1E\72\23\77\23\10\FC\73\23\23\C1\10\F1\11\01\00\D5\21\17\21\E5\23\01\00\0C\CD\47\44\11\00\01\CD\45\44\E1\CD\45\44\CD\94\43\C3\B9\41\2A\CB\43\11\01\00\01\00\04\18\02\06\07\E5\D9\C1\CD\82\40\F5\CD\7C\43\F1\AE\77\D9\19\10\EF\C9\03\07\2E\03\03\03\03\03\03\03\03\04\39\00\2E\00\32\00\2A\00\3D\87\03\03\03\03\03\03\03\1C\1C\1C\84\01\1E\26\ED\43\E7\43\78\ED\44\47\C9 10 LET K=USR 17387 20 SAVE "CAG%E" 30 RUN 10 ```