10 REM"_(C2SLFF4
10 REM"_(C2SLFF4
Beej's Bit Bucket ⚡ Tech and Programming Fun | 2026-07-21
Let's take a deep dive into the source code of The Wizard's Castle!
The line 10 REM _(C2SLFF4 serves as the opening statement of this 1980s microcomputer BASIC game, which was originally developed for the Exidy Sorcerer platform.
In this specific language, a REM statement is simply a remark—a comment ignored by the interpreter. For those unfamiliar with vintage coding styles, the 10 is the line number. This exact string appears in the original source as printed in the July 1980 edition of Recreational Computing.
📝 Technical Notes
- Notation: I will be toggling between decimal (which BASIC uses) and hexadecimal (which programmers prefer).
- Hex Format: I'll denote hex values using the
0xprefix, thehsuffix, or by using charactersA-F. - Acknowledgements: A huge shout-out to my fellow hackers, Josh and Chris, for their extensive research and emulator work.
🔍 The Suspicion
Consider this snippet of the source code (cleaned up for clarity):
10 REM _(C2SLFF440 POKE 260,218: POKE 261,1: T = USR(0): T = PEEK(-2049)80 Q = RND(-(2*T+1))
In Sorcerer BASIC, the colon (:) acts as a command separator. The system utilized signed 16-bit integers, meaning the address -2049 is calculated as:
The RND() function (the pseudo-random number generator, or PRNG) is seeded when passed a negative value. Because older PRNGs typically required odd numbers for seeding, the expression was used to guarantee an odd result. Since line 80 is the first time T is used after being set by PEEK(), it's highly probable these lines are all part of the PRNG seeding process.
Since Sorcerer BASIC lacked a RANDOMIZE command, developers had limited options for seeding:
- Prompt the user for a manual seed.
- Use a timing loop that ends when a key is pressed.
- Extract a "random-ish" value from the system hardware or existing software.
The Crazy Theory: Could the REM statement actually contain machine code that just happens to look like ASCII text? It seems absurd that meaningful Z80 machine code could be formed from standard characters, but it was a hypothesis worth testing.
⚙️ The USR() Function
The USR() call triggers a machine code function, though the implementation varies by system. After digging through old technical manuals, we discovered the following:
- Address
259contains aJP(unconditional jump) instruction. - This jump points to a 16-bit absolute address stored in little-endian format.
- By using
POKEon addresses260and261, the programmer specifies the destination of that jump.
Looking at line 40:
40 POKE 260,218: POKE 261,1: T = USR(0): T = PEEK(-2049)
The destination address is calculated as:
When USR(0) is executed, the CPU jumps to the code at address 474. While the argument 0 is stored as a 4-byte float in RAM, and the return value is assigned to T, the return value is actually irrelevant because T is immediately overwritten by the PEEK command.
💾 BASIC RAM Layout
Image Credit: Marcin Wichary, CC BY 2.0
When a line of code is entered into Sorcerer BASIC, the interpreter tokenizes it. For example:
PRINT0x97REM0xC3
These lines are stored in memory as a linked list starting at address 469. Each node follows this structure:
| Offset | Size | Description |
|---|---|---|
| 0 | 2 Bytes | Pointer to the next node |
| 2 | 2 Bytes | Line number |
| 4 | Variable | Tokenized code bytes |
| End | 1 Byte | Null terminator (0x00) |
The Revelation
Let's map the mystery line 10 REM _(C2SLFF4 to RAM:
The USR(0) function is literally executing the text of the comment as Z80 machine code!
The ASCII characters in _(C2SLFF4 translate to the following hex values:
5F 28 43 32 53 4C 46 46 34
Disassembling these bytes yields:
22 5F 28 LD (285Fh), HL ; _ (
43 LD B, E ; C
32 53 4C LD (4C53h), A ; 2 S L
46 LD B, (HL) ; F
46 LD B, (HL) ; F
34 INC (HL) ; 4
This code is a masterpiece of logic. In reality, it makes no sense. The addresses are arbitrary, the B register is never used, the LD B is redundant, and there is no RET instruction to return control to BASIC. Running this in an emulator causes "weird things" like soft resets. We suspect this was a printing error in the magazine where the printer substituted glyphs for bytes it couldn't render.
📺 The PEEK(-2049)
Finally, let's look at the PEEK again:
T = PEEK(-2049)
Address -2049 (0xF7FF) corresponds to the very last byte of the memory-mapped screen text—specifically, the character in the bottom-right corner of the display.
This value is then used to seed the PRNG:
80 Q = RND(-(2*T+1))
If the character were simply a space (ASCII 32), every game would start with the same seed, ruining the replayability of the random dungeon. Therefore, the USR() function must be doing more than just crashing; it likely writes a specific value to address 0xF7FF before the PEEK reads it. Since the screen is cleared shortly after, the player never notices the character appearing there.