ZX Forth is a Forth programming language interpreter stored in EPROM and loaded into memory via a two-line BASIC loader. The loader saves the program with line 10, then line 20 executes the Forth interpreter entry point directly using RAND USR 17245, jumping into machine code at that address. The bulk of the program is encoded in a single REM statement at line 65310, which holds the complete Forth interpreter as raw machine code bytes — a standard technique for embedding binary data in BASIC programs. The REM line contains 65310’s position near the top of the line-number space, suggesting the data is meant to sit at a fixed memory location. The BASIC tokens, graphics characters, and control bytes visible in the REM are artifacts of the Z80 machine code being interpreted as BASIC text.
Program Analysis
Program Structure
The program consists of exactly three lines:
10 SAVE "ZXFORTH"— saves the program to tape with the given name.20 RAND USR 17245— transfers execution to the Forth interpreter entry point in machine code.65310 REM ...— a very long REM statement containing the entire Forth interpreter as raw Z80 machine code bytes.
The line number 65310 is chosen to place the REM line at a high line number, keeping it out of the way of any normal BASIC code while still being addressable. The REM statement itself is not executed by BASIC; its sole purpose is to act as a container for binary data in the program area.
Machine Code Storage Technique
Embedding machine code in a REM statement is a well-established technique. The Z80 machine code bytes follow immediately after the REM keyword token in memory. When BASIC encounters a REM, it skips to the next line, so the binary content is never interpreted as BASIC tokens at runtime. The entry point address 17245 (decimal) corresponds to a location within or near this REM line’s data area, and RAND USR 17245 performs a direct call to that address, bootstrapping the Forth system.
The address 17245 (0x4340 hex) falls in the upper portion of the ZX81/TS1000 system RAM area, consistent with where a program’s REM data would reside given a short two-line BASIC preamble.
REM Line Content
The content of the REM at line 65310 is Z80 machine code rendered as a mix of BASIC keyword tokens, block graphics characters, and raw bytes. The visible BASIC keywords (RETURN, PRINT, LET, INKEY$, RND, USR, etc.) are not actual BASIC instructions — they appear because the Z80 opcode bytes happen to coincide with the token values used by the BASIC interpreter to represent those keywords. This is purely coincidental and is a common visual artifact when disassembling or listing machine code stored in REM lines.
Loader Design
The two-line BASIC loader follows a minimal pattern:
SAVEon line 10 writes the entire program (including the REM-encoded machine code) to tape as a standard BASIC file, so it can be reloaded withLOAD "".RAND USR 17245on line 20 invokes the machine code.RAND USRis the standard idiom for calling machine code subroutines; it discards the return value and does not require the machine code to return cleanly to BASIC.
Notable Techniques
- REM as binary container: The entire Forth interpreter (~hundreds of bytes) is packed into a single REM statement, making the BASIC file self-contained and loadable with standard tape routines.
- High line number for data: Using line 65310 pushes the data REM to the very end of accessible line-number space, preventing accidental collision with user BASIC code if the loader were ever extended.
- Direct USR entry: Rather than a POKE-based relocation or a copy loop, the interpreter is accessed in-place at its fixed load address, implying the Forth system is position-dependent and expects to reside at a specific address.
- Minimal BASIC footprint: Only two executable BASIC lines are needed; all complexity is hidden in machine code, keeping the BASIC portion trivial to understand and modify.
Potential Anomalies
The SAVE on line 10 executes before RAND USR on line 20 when the program is RUN. This means running the program will first attempt a tape SAVE operation, pausing execution until the save completes or is interrupted, before launching the Forth interpreter. Users wishing to go directly to Forth would need to either GO TO 20 or manually execute RAND USR 17245, or simply load the already-saved program and let it autostart into line 20 on a subsequent load.
Content
Source Code
10 SAVE "ZXFORT[H]"
20 RAND USR 17245
65310 REM ............................................................................................. FASTSTR$ VAL [R]ASN #INKEY$ RETURN█KM RETURN▒CZ RETURN?CV RETURN#S▝CHR$ 4 RETURNKS= RETURNUK▖CHR$ =/= RETURNINKEY$ S# RETURN#K#CHR$ ./▒5[-]INKEY$ #- ;# RETURN#CWACS [R] PRINT UTRND RETURN▘ATN #INKEY$ LET NOT AT SGN LPRINT TAN E:RNDFUTRNDWMTRND#6:RND RETURN#4(F6:RNDY▝MTRNDUURNDWMURNDQ ##INKEY$ FASTSTR$ VAL PRINT UURND RETURN▀C▌Y#NOT /▀LN :£ LET AT SGN LPRINT TAN CHR$ ~~/[3]CHR$ 8/[.]
0
0 ▘▝▀▖▌▞▛▒,,~~ [£]"[?]£$ [(]()*+,-./:;<=>?["][$] [:][>][)]VAL STR$ FAST▘ █UQ RETURN▜4,,LN M? CLEARQP COPY/▀LN P? GOSUB #9RNDLN [X]▛K LPRINT 5 UNPLOT INKEY$ ;###INKEY$ #########LMNOPKTSRQ#####$####4I##PIUVZJB#[-][*]#RND57[/][;][,][.][0][1][+]▒[2][=][>][<]6DC8[3][4]XFH[5] GYWESTR$ #Y#<= RETURN3S$Y RETURN<= RETURN3S▞Y▘[R]#SGN TAN [J]/ IF PRINT INKEY$ 7/ PLOT LET TAN FASTSTR$ VAL PRINT LN 4#)>#Y#<= RETURN *S PRINT .#[N]4 NEXT LET AT SGN LPRINT TAN FASTSTR$ VAL :▘▞ Y#<= RETURNPEEK COPY*S▖( PRINT / LET 2[=]▞,1<= RETURN*ACS ##S PRINT ( PRINT 4▖ RETURN#K>=ZACS )KNOT #/ACS FASTSTR$ VAL PRINT LN 4#)ACS ▒( RETURN.#[N]4 RAND /[R] FASTSTR$ VAL PRINT #RACS <C1[3] NEW▌LEN ▖#PEEK COPY▞7( RETURNLN CLSPI ▞2( RETURN$4 INPUT [R]( CLEAR/ TO #[▒]PIY#<= RETURN3 CLEARACS V▚Y COPYMBRNDTAN PRINT FASTSTR$ VAL UQ RETURN▜ PRINT ATN C? LET CODE F?AT SGN LPRINT LET TAN PRINT FASTSTR$ VAL UQ RETURN▜ PRINT ATN 4? LET CODE 7?AT SGN LPRINT LET TAN FAST PRINT 5##LN #PILN ABS INKEY$ RETURN$C▖ LET LPRINT RTAN LET LPRINT [R]TAN ##INKEY$ ##4#INKEY$ ######$ NEXT 5##7Q▘Y▘[Y]4▌[J]P[Y]C NEXT F6▄##*# #▝#▘▘▘:[O]#▒ 4# STOP#4#█#3 ######; LET [>]4#2#STR$ FAST CLEARO5TAB [F]#LN #PIC▀▘##~~▀#~~▀##7# FOR DIM ▄##USR [Y]#~~▀#~~▀#/CHR$ ▗######VAL [Q]#ABS # LPRINT />=▚PI#INKEY$ ##COS LEN # STEP ####7#F;##/[M]▗KPI#INKEY$ ##COS STR$ # RUN # LPRINT #[P]C SLOW▀▀/[1]▚C####[D] FOR #"#)▘ E[;]#[~~]#7=+# IF B##[-]#7[2]/▌ STEP #76[;]#▀▀#[1]#▗CF####[D] ###SGN /SIN ▜C##[D]S###E[;]#FFFF6[;]#SGN #7#SGN 7#7##[1]#▟TAN ####E[;]##7#STR$ / INPUT ▐####USR #### LPRINT SGN #CHR$ K IF [2]# RETURN~~ IF [<]#CHR$ ▛ RETURN~~ IF [2]#[X] PAUSE [2]##5▘ #[.]###[0]#▚C####[D]##[H]#SGN LPRINT FAST,[I] NEWZ437<,[I]▗4-K RUN 5▌ ; STOP.,[R] PAUSE CODE ##- 5▘ #[.]#S▞<,[R] PAUSE STR$ #< FOR #7##[N]4ASN LPRINT 5 #[0]#▗######VAL [6]# RUN #SGN LPRINT FAST#) COPY COPYF7<[Y]C CLSSTR$ PRINT STR$ .STR$ #[1]# LET PRINT 7<[Y]C~~STR$ #[1]# LET STR$ <STR$ #[1]#▜###USR FOR #Z#ASN #CODE #[6]#[9]#▄#▄## OR E####AT #[,,]Z######INKEY$ ATN X###5 # LPRINT #▙#ABS #####CHR$ #▐####VAL ######AT SGN STOP/▌[L]4 RUN AT /[8]▙#[E]##[~~]#SGN LPRINT VAL ##LN [A]# FAST###LN [A]#SGN #,,EXP ###AT STR$ #[0]#5 :▒D*K▀;EXP $4 PLOT TAN ▙#[J]▄#[X]#5▖ T##7##AT LPRINT #[)]#[/]S▛5 COPY COPY##/3Y(D* FOR DK▝<[R] FOR 3 PRINT K▌[R] GOSUB PI/▞ GOSUB PIK▝,,.< LET X4 STOPAT FASTSTR$ #[1]#▄INKEY$ #CODE [Q]#▝#SGN LPRINT #[9]##[8]##[0]#▙#ABS IF #=#SGN LPRINT #[P]##
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

