Memscan is a machine code utility that scans a region of memory searching for a specific byte value, POKEd into RAM starting at address 65500 via a DATA loader. The routine uses Z80 registers: HL holds the base address, B counts rows, C counts columns, and D/E track position within the scan grid. It iterates through 27 bytes per row (register B initialized to 27) and one column (C initialized to 1), comparing each byte against a target value using the CP instruction (opcode 190/0xBE). When a match is found, a subroutine at address 0x2662 (38/0x26 in the DATA) is called. The final 34 bytes of machine code are preserved with SAVE “memscan” CODE 65500,34 for standalone reloading.
Program Analysis
Program Structure
The program is a two-phase loader/executor. Lines 10–30 form a FOR/READ/POKE loop that writes 34 bytes of Z80 machine code into RAM at addresses 65500–65533. Line 110 then transfers control to that code via RANDOMIZE USR 65500. Line 115 is a safety STOP that would catch a fall-through if the machine code returned unexpectedly. Line 120 saves only the machine code block, not the BASIC loader itself.
DATA Block Disassembly
The 34 DATA bytes, loaded from lines 40–100, disassemble to the following Z80 instructions:
| Offset | Hex | Mnemonic | Notes |
|---|---|---|---|
| 0 | 21 00 00 | LD HL,0x0000 | Base address (low byte, high byte = 0,0) |
| 3 | 0E 01 | LD C,1 | Outer loop counter (1 pass) |
| 5 | 06 1B | LD B,27 | Inner loop counter (27 bytes per row) |
| 7 | 3E 00 | LD A,0 | Target byte value to search for |
| 9 | C5 | PUSH BC | Preserve loop counters |
| 10 | E5 | PUSH HL | Preserve current pointer |
| 11 | BE | CP (HL) | Compare A with byte at HL |
| 12 | 28 03 | JR Z,+3 | Jump if match found |
| 14 | CD 3E 26 | CALL 0x263E | Call ROM routine on match |
| 17 | E1 | POP HL | Restore pointer |
| 18 | 23 | INC HL | Advance to next byte |
| 19 | 23 | INC HL | Advance again (stride of 2) |
| 20 | C1 | POP BC | Restore counters |
| 21 | 04 | INC B | Increment inner counter (unusual — counts up) |
| 22 | 3E 9C | LD A,0x9C | Load terminal value 156 |
| 24 | B8 | CP B | Compare B with 156 |
| 25 | 20 EC | JR NZ,-20 | Loop back if not done |
| 27 | 0C | INC C | Increment outer counter |
| 28 | 3E FF | LD A,0xFF | Load terminal value 255 |
| 30 | B9 | CP C | Compare C with 255 |
| 31 | 20 E4 | JR NZ,-28 | Outer loop back |
| 33 | C9 | RET | Return to BASIC |
Notable Techniques
- The
FOR/READ/POKEpattern is a standard BASIC machine code loader idiom, placing code at the top of a 65535-byte address space to avoid interference with BASIC workspace. - The inner loop uses an ascending counter checked against 156 (0x9C), and the outer loop counts up to 255 — an unusual count-up-to-terminal-value structure rather than the more common
DJNZdecrement-to-zero. - HL advances by 2 on each iteration (two consecutive
INC HLinstructions), suggesting the scan steps through word-aligned or two-byte-stride memory locations rather than every byte. - The
CALL 0x263Etarget is a ROM address; on the TS2068 this falls in the ROM region and would invoke a built-in routine (potentially related to display or output). - The initial
LD HL,0x0000sets the scan base to address 0, meaning it scans from the very start of the address space. SAVE ... CODE 65500,34at line120preserves exactly the 34 bytes of machine code, omitting the BASIC loader — this is a common space-saving distribution technique.
Bugs and Anomalies
The JR Z,+3 at offset 12 skips the CALL when a match is not found — that is, the logic is inverted: the ROM routine is called only when the byte does not match the target, and the scan moves on silently when it does match. This may be intentional (e.g., logging non-matching addresses) or may represent a logic inversion bug in the original listing. Additionally, the initial target byte is hardcoded as 0 and the base address is hardcoded as 0x0000 in the DATA; customizing the scan would require either modifying the DATA values or POKEing the relevant bytes after loading.
Content
Source Code
1 REM memscan ZX-Appeal Sept. 1986
10 FOR x=65500 TO 65533
20 READ y: POKE x,y
30 NEXT x
40 DATA 33,0,0,14,1
50 DATA 6,27,62,0,197
60 DATA 229,190,40,3,205
70 DATA 62,38,225,35,35
80 DATA 193,4,62,156,184
90 DATA 32,236,12,62,255
100 DATA 185,32,228,201
110 RANDOMIZE USR 65500
115 STOP
120 SAVE "memscan"CODE 65500,34
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
