This program implements a single-player Squash game in which a ball bounces around an enclosed court and the player controls a bat at the bottom using the P and Q keys. The court walls are drawn using inverse-video characters for the sides and block graphics (▄) for the top, while the bat is rendered with a block graphic character. Ball movement is tracked with direction variables L and M, and the collision logic at line 130 uses a chained comparison idiom to detect wall bounces. Scores are tracked separately for the Sinclair (computer) and the player, with the first to reach 10 winning the match.
Program Analysis
This program is a machine code game or application stored entirely within the REM statement at line 1, with execution triggered by RAND USR 17298 (hex 0x4392), which jumps into the machine code block. The REM data spans several hundred bytes of Z80 object code, containing what appears to be a complete self-contained program including display routines, sprite handling, and game logic. Line 4030 saves the program with an auto-run marker. The BASIC lines 4010–4040 serve purely as a loader/utility shell; the real program is the Z80 code embedded in the REM statement.
Program Structure
The BASIC listing is minimal by design. The program consists of five lines:
1 REM ...— contains several hundred bytes of Z80 machine code as raw data embedded in the REM token’s string body.4000 RAND USR 17298— transfers execution to address 17298 decimal (0x4392 hex), which is inside the REM statement’s data area (the BASIC program starts at 0x4000 on this system, and the REM body begins a few bytes in at line 1).4010 STOP— a safety net if USR returns.4020 CLEAR— present but never reached in normal flow; likely a utility/development remnant.4030 SAVE "1024%8"— saves the program.4040 RUN— restarts execution from the first line.
Machine Code Entry Point
The entry point at 0x4392 (17298 decimal) is calculated as follows: the BASIC program area starts at 0x4000; line 1’s REM token occupies bytes at a fixed offset (line number 2 bytes, length 2 bytes, REM keyword 1 byte = 5 bytes), so the REM data body begins at 0x4005. The entry point 0x4392 is therefore 0x38D (909) bytes into the REM data, pointing to a specific subroutine or initialisation block within the machine code rather than the very start of the data.
Machine Code Content Analysis
Disassembling key portions of the REM data reveals the following functional blocks:
- 0x4005 (start of REM body): Begins with
2A 39 40—LD HL,(0x4039), immediately reading a pointer from within the REM area itself, indicating self-referential data structures. - ROM calls: Numerous
CD xx xx(CALL) instructions target ROM addresses (e.g.CD 2B 0F,CD 1F 0A,CD 75 43), making use of system ROM routines for display output (D7= RST 0x10, the character output restart) and other OS services. - Display output: The opcode
D7(RST 16) appears repeatedly throughout the code, used to print characters to the display via the ROM character output routine. - IY register use: Several
FD CBprefixed instructions operate on(IY+offset), accessing the system flags area (IY normally points to FLAGS in the system variables area). - 16-bit arithmetic: Extensive use of
ED 62(SBC HL,HL),ED 52(SBC HL,DE),ED 4B/ED 5B(LD BC/DE,(nn)) and22 xx xx(LD (nn),HL) for multi-byte variable management. - Data tables: The latter portion of the REM (roughly from offset 0x300 onward) contains interleaved code and data including what appear to be text strings stored as offset-encoded bytes (values like
38 36 3A 26...which, when decoded with a consistent offset, form readable ASCII text), and a block of initialisation data ending in zeros at the very end of the REM.
Memory Map of Key Addresses
| Address (hex) | Address (dec) | Role |
|---|---|---|
| 0x4000 | 16384 | BASIC program start (line 1 header) |
| 0x4005 | 16389 | REM data body / machine code start |
| 0x4392 | 17298 | USR entry point (RAND USR target) |
| 0x47xx | ~18xxx | Self-modifying/variable storage within REM (LD (0x47xx),HL patterns) |
Notable Techniques
- REM-as-code: The entire application is stored inside a REM statement, a classic technique that places machine code in a safe location within the BASIC program area where the BASIC interpreter will not attempt to execute it as tokens.
- Self-contained variable storage: Addresses in the 0x47xx range (still within the REM body) are used as RAM storage locations, written to with
LD (nn),HLand read back withLD HL,(nn), making the REM area serve as both code and data space simultaneously. - RST 16 output: Direct use of
D7(RST 0x10) for character-by-character display output bypasses higher-level BASIC print routines for speed. - Encoded text strings: Printable text in the data section appears to be stored with a byte offset applied to each character value, a simple obfuscation/packing technique that also avoids null bytes and BASIC keyword token conflicts within the REM body.
- Stack manipulation: Frequent
E3(EX (SP),HL) instructions are used for efficient stack-based parameter passing and return address manipulation, a Z80 idiom for coroutine-style control flow. - Initialisation block: The final bytes of the REM —
00 00 01 00 01 00 0A 00 00 00 ...— are a zeroed/initialised data block, consistent with game state variables reset at startup by the initialisation routine near 0x4392.
BASIC Shell
The four BASIC lines above 4000 form a minimal loader. RAND USR 17298 is used rather than USR 17298 alone because RAND USR discards the return value without requiring it to be assigned or printed, and on this system it also avoids a potential error condition if the machine code returns a non-numeric result. The STOP at line 4010 ensures the interpreter halts cleanly if control ever returns to BASIC.
Potential Anomalies
- Lines
4020 CLEARand4040 RUNare unreachable in normal operation and appear to be development/utility lines left in the listing. - The SAVE line at 4030 saves only the BASIC wrapper, not explicitly invoking a full binary save — the machine code is preserved as part of the BASIC program file since it resides in the REM statement.
Content
Source Code
1 REM 2A3940E5CD2B FCD1F A3E12D73A2140CB4720262A E40E5CD7543E1FE7728E7FDCB2146 0203AFE762821FE1628 8FE1C38E4FE2630E0D718DD 7 72FE6 2C6 2321E4021 0 03E12D718CB3E13D7CD104138B3E1D5E5CD1F AC1CD18 9E1A7C9FE762826FE1C38AEFE2C30AAD7D61C5F16 019EB211E403528D9EB292929291895FDCB214EC0CB7CC8E1E137C911 0 04B7EFE1620 423 C18F7E5D61C6F26 019EBE1237EFE132815FE7E2811E5D5E1 6 9192BCD 4412310F8EBE118D397B9C8A7ED62ED52EBA7C9223240CBBCD1C9 03A3B40F5CD2B FCD7543A720 2CFFFFE2820F4F1CB77C0C323 F444DC335 F434DC3F5 87D 1 0 0C375 BC5 6107C4D21 0 029CB111730 11910F7C1C9 0 118 6 E 218 2 E 07CAAE68047D5CDED41E3CDED41EBE179A7283678B1E5ED62ED52E5C1D121 0 0373FF57A531E 82930 58FED4A18 987ED4A38 3ED423D3C1D20EC5FF130E2CB4F20 1EBCB7FC818 BCD7F41CB10D018 37C 7D0EBA7ED62ED52C97C 738 6B5C821 1 0C921FFFFC9A7ED52C9A7ED527CB521 0 0C02CC9A7ED52C818E3EB 1 08018 4EB 1 1807CA8677AA857ED5226 0796FD8EE 16FC97CB521 0 0C87AB3C82CC97CB5B2ED6218F53E 118 1AFE35E235623E32B2919A728 8EBE1E3EB732372C95E2356EBC9EBCD6B42EBC9D5114B 0ED4B3240 36268CD 913E56269CD 913C17C8130 1 4677D9030 1256F2BC34C41 0 03A2140CB47201ACB4F20 ACB7C28 63E16D7CDF041 1F0D81EFFC5CDE1 7CDAD AE5C1215D40571E1C70CB7A28 17197ED6F83D797ED6F83D7CB7ACBFA28EFC9E17E23FE70282FFE7620 3D718F3CD794118EE9718 23E904B452130405677D5E5CDB2 BE1D172C9CD C427CB5E35E235623E3C0E1EBE97DE61F4FFDCB 14E28 AFD9638CBFFC63CD471 8FD8639FE213A3A40DE 1CDFA 8FDCB 1C6C9E15E235623E5D521 7 019 6 4562B5E2BD510F9E1C1D17A19EBE1E3732372C5E1 730 1EBCD1B42E1D8C1E9EB73C9C1E5C1C96E26 0C911DA7FD5E5C9C5E1C9EBCD7F43EBC9CD7F4338FBCD7F4330FBD5CDBB 2E5C12C6C28 4CDBD 76E26 07DD1C921 0 022B84721 0 022BA4721 0 022BC4721 1 022BE4721 1 022C04721 A 022C24721 0 022C447CDE04521 6 022C64721 E 022C84721 1 022CA4721D74322CC472AC647E521 8 0D1CD7341CDD24280703E76D72AC647E52113 0D1CD7341CDD24280703E76D7CD2F43C64721 8 022CE472113 022D04721 1 022D247211A4422D44721 5 0E52ACE47D1CD7341CDD24283703E76D7CD2F43CE4721 3 0E521 0 0D1CD7341CDD242382E332831262E37 0382834372A1B1B1C703E76D721 1 0E521 0 0D1CD7341CDD2423E343A37 0382834372A 02E381B1B1B1C703E76D721 F 0E52AC247D1CD7341CDD242 0 3 0703E76D71135 0CD7F43CD 942E51111 02AC247CD2142EBE1CD3542EB2AC24719E51136 0CD7F43CD 942E511 8 02AC247CD2042EBE1CD3542EBE1CD 54222C247CD7F43CD C42CDFD42D944CD5E43ED5BBC4721 6 019E5ED5BBA4721 9 019D1CD7341CDD242 0703E76D7ED5BBA472AC0471911 9 0CD2042E5ED5BBA472AC0471911 0 0CD2142EBE1CD4042CDFD4226452AC047CDF04122C047ED5BBC472ABE471911 8 0CD2042E5ED5BBC472ABE471911 0 0CD2142EBE1CD4042CDFD4256452ABE47CDF04122BE47ED5BC0472ABA471922BA47ED5BBE472ABC471922BC47ED5BBC4721 6 019E5ED5BBA4721 9 019D1CD7341CDD24234703E76D711 8 02ABC47CD 942E5ED5BBA472AC247CD 542CDED4111 9 0CD1B42EBE1CD3542CDFD42B345CD8E4611 8 02ABC47CD 942E5ED5BBA472AC247CD 542CDED4111 8 0CD 942EBE1CD3542CDFD42DD45CD2347C37844CDD2421717171717171717171717 038363A26382D 01717171717171717171717703E76D7CDD242171717 02B2E373839 03934 0382834372A 01D1C 03C2E3338 0171717703E76D73E76D7CDD242173A382A 035 0263329 036 0302A3E38 03934 032343B2A 027263917703E76D73E76D7CDD24217171735372A3838 0 01B351B 0 0302A3E 03934 03531263E1B171717703E76D71135 0CD7F43CD1442CDFA427A46CD2A ACD5E4311 1 02AB8471922B84721 3 0E52110 0D1CD73412AB847CD92423E76D711 A 02AB847CD2142CDFD42BD46CD5E43CD2A A21 A 0E521 1 0D1CD7341CDD2421717171717 02834322A 03433 039373E 0262C262E33 01717171717703E76D721 F 0E521 1 0D1CD7341CDD24235372A3838 0C035C0 03934 03531263E703E76D71135 0CD7F43CD1442CDFA421247C3B54711 1 02AC4471922C44721 1 0E52110 0D1CD73412AC447CD92423E76D711 A 02AC447CD2142CDFD425247CD5E43CD2A A21 A 0E521 1 0D1CD7341CDD24217 02E 03C2E3131 0272A2639 03E343A 0332A3D39 0392E322A 017703E76D721 F 0E521 1 0D1CD7341CDD24235372A3838 0C035C0 03934 03531263E703E76D71135 0CD7F43CD1442CDFA42A747CD2A A 0 0 0 0 0 0 1 0 1 0 A 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
4000 RAND USR 17298
4010 STOP
4020 CLEAR
4030 SAVE "1024%8"
4040 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
