This program implements a hex editor for ZX81/TS1000 memory, allowing the user to list, write, insert, and delete bytes at arbitrary addresses using hexadecimal notation. The machine code routine embedded in the REM statement at line 1 (stored from address 16393 onward) provides the core editing engine; BASIC acts purely as a menu and input layer. Address entry uses a clever two-byte POKE calculation at lines 640–650, converting ASCII hex digit pairs into raw byte values via the formula `16*CODE + CODE – 476`. RAND USR calls at lines 30, 140, 240, 340, 410, 500 dispatch into the machine code at specific offsets to perform list, write, insert, delete, save, and load operations. The CLEAR statement at line 660 is used to free string space after each input rather than to reset variables, a common ZX81 memory-management idiom.
Program Analysis
Program Structure
The program is organized as a set of numbered entry points, each implementing one editing operation, plus a shared address-input subroutine:
| Line(s) | Function |
|---|---|
| 1 | REM — stores the machine code routine |
| 10–30 | LIST mode: display memory from address |
| 100–150 | WRITE mode: accept hex byte string, poke into memory |
| 200–250 | INSERT mode: insert byte(s) into memory |
| 300–340 | DELETE mode: delete byte(s) from memory |
| 400–420 | Save routine: dimension output buffer, save to tape |
| 500–520 | Load/quit: calls USR 16669, then CLEAR and STOP |
| 600–670 | Shared address-input subroutine |
The user selects a mode by running the program from a specific line number (e.g., RUN 10 for LIST, RUN 100 for WRITE). There is no top-level menu; the entry point is the mode selector.
Machine Code in the REM Statement
The REM at line 1 contains approximately 170 bytes of Z80 machine code beginning at address 16393 (0x4009, the byte immediately after the REM token). Several distinct routines are embedded at fixed offsets, each called by a separate RAND USR invocation:
| USR Address | Decimal Offset in REM | Purpose |
|---|---|---|
| 16539 | 146 | LIST — dump memory bytes in hex |
| 16589 | 196 | WRITE — write input hex string to memory |
| 16635 | 242 | Return buffer size for DIM at line 400 |
| 16651 | 258 | Save helper |
| 16669 | 276 | Load helper |
| 16687 | 294 | INSERT — insert bytes into memory block |
| 16732 | 339 | DELETE — remove bytes from memory block |
The machine code manipulates system variables and string pointers directly. The two-byte address of the current edit target is stored at fixed locations within the ZX81 memory map (around 0x4093–0x4099, i.e. addresses 16531–16537), shared between BASIC and machine code via POKEs at lines 640–650.
Hex Address Input Subroutine (Lines 600–670)
The subroutine beginning at line 600 reads a four-character hex string and converts it into a 16-bit address stored via two POKEs. The formula used is:
POKE A+1, 16*CODE A$ + CODE A$(2) - 476— high byte from first two hex digitsPOKE A, 16*CODE A$(3) + CODE A$(4) - 476— low byte from last two hex digits
The constant 476 is derived from the ASCII/ZX81 character codes: for the digit ‘0’ (code 28 on ZX81), the value 16*28 + 28 = 476 represents the baseline for “00”, so subtracting 476 normalises the result to zero. Letters A–F would follow the same arithmetic using their respective character codes. The address is stored in little-endian order (low byte first), consistent with Z80 convention.
The variable A is pre-loaded before the GOSUB 610 call: line 320 sets A=16535 for DELETE mode, while line 600 sets A=16533 for all other modes, pointing POKEs at different target locations within the shared data area.
Key BASIC Idioms
RAND USRinstead ofPRINT USR: avoids printing the return value on screen and discards it safely.RUN USR 16732at line 340: usesRUN(notRAND), which on the ZX81 is a synonym forRANDOMIZE— the distinction here is purely cosmetic but unusual.CLEARat line 660: called after each INPUT to reclaim string storage without resetting numeric variables or the GOSUB return stack; a standard ZX81 memory-pressure technique.- Loop via
GOTO: lines 150 and 250 create write/insert loops by jumping back to the INPUT line, relying onCLEARto prevent string space exhaustion during repeated entry. DIM O$(USR 16635)at line 400: uses the return value of a machine code routine to dynamically size a string array, a neat way to let the MC determine the required buffer length.
Notable Techniques
The machine code makes use of Z80 block-move instructions (LDIR, opcode ED B0) for INSERT and DELETE operations, visible in the REM bytes as the sequence \ED\B0 appearing multiple times. This allows efficient shifting of memory blocks without byte-by-byte loops.
The RST 8 instruction (CF) appears several times in the machine code — this is the ZX81 character-output routine, used by the LIST function to display hex digits directly to the screen without returning to BASIC.
Bugs and Anomalies
- The hex conversion formula assumes ZX81 character codes for digits 0–9 and, implicitly, letters A–F. If a non-hex character is entered, the POKE value will be incorrect but no error is raised — there is no input validation.
- The
GOTO 120andGOTO 220loops have no exit condition in BASIC; the user must break with BREAK or the machine code must halt execution itself. - Line 420
SAVE "HEXLD%3"saves the program to tape. The%3is a zmakebas escape for an inverse character; in context this forms part of the filename.
Content
Source Code
1 REM \F5\E6\F0 itemtype='https://schema.org/Blog' itemscope='itemscope' class="wp-singular computer_media-template-default single single-computer_media postid-56687 wp-custom-logo wp-embed-responsive wp-theme-astra wp-child-theme-astra-child ast-desktop ast-separate-container ast-left-sidebar astra-4.12.7 group-blog ast-blog-single-style-1 ast-custom-post-type ast-single-post ast-inherit-site-logo-transparent ast-hfb-header ast-full-width-primary-header ast-box-layout ast-normal-title-enabled astra-addon-4.12.5"F itemtype='https://schema.org/Blog' itemscope='itemscope' class="wp-singular computer_media-template-default single single-computer_media postid-56687 wp-custom-logo wp-embed-responsive wp-theme-astra wp-child-theme-astra-child ast-desktop ast-separate-container ast-left-sidebar astra-4.12.7 group-blog ast-blog-single-style-1 ast-custom-post-type ast-single-post ast-inherit-site-logo-transparent ast-hfb-header ast-full-width-primary-header ast-box-layout ast-normal-title-enabled astra-addon-4.12.5"F itemtype='https://schema.org/Blog' itemscope='itemscope' class="wp-singular computer_media-template-default single single-computer_media postid-56687 wp-custom-logo wp-embed-responsive wp-theme-astra wp-child-theme-astra-child ast-desktop ast-separate-container ast-left-sidebar astra-4.12.7 group-blog ast-blog-single-style-1 ast-custom-post-type ast-single-post ast-inherit-site-logo-transparent ast-hfb-header ast-full-width-primary-header ast-box-layout ast-normal-title-enabled astra-addon-4.12.5"F itemtype='https://schema.org/Blog' itemscope='itemscope' class="wp-singular computer_media-template-default single single-computer_media postid-56687 wp-custom-logo wp-embed-responsive wp-theme-astra wp-child-theme-astra-child ast-desktop ast-separate-container ast-left-sidebar astra-4.12.7 group-blog ast-blog-single-style-1 ast-custom-post-type ast-single-post ast-inherit-site-logo-transparent ast-hfb-header ast-full-width-primary-header ast-box-layout ast-normal-title-enabled astra-addon-4.12.5"F\C6 itemtype='https://schema.org/Blog' itemscope='itemscope' class="wp-singular computer_media-template-default single single-computer_media postid-56687 wp-custom-logo wp-embed-responsive wp-theme-astra wp-child-theme-astra-child ast-desktop ast-separate-container ast-left-sidebar astra-4.12.7 group-blog ast-blog-single-style-1 ast-custom-post-type ast-single-post ast-inherit-site-logo-transparent ast-hfb-header ast-full-width-primary-header ast-box-layout ast-normal-title-enabled astra-addon-4.12.5"C\D7\F1\E6
Skip to content
Hexload III
This program implements a hex editor for ZX81/TS1000 memory, allowing the user to list, write, insert, and delete bytes at arbitrary addresses using hexadecimal notation. The machine code routine embedded in the REM statement at line 1 (stored from address 16393 onward) provides the core editing engine; BASIC acts purely as a menu and input layer. Address entry uses a clever two-byte POKE calculation at lines 640–650, converting ASCII hex digit pairs into raw byte values via the formula `16*CODE + CODE – 476`. RAND USR calls at lines 30, 140, 240, 340, 410, 500 dispatch into the machine code at specific offsets to perform list, write, insert, delete, save, and load operations. The CLEAR statement at line 660 is used to free string space after each input rather than to reset variables, a common ZX81 memory-management idiom.
Program Analysis
Program Structure
The program is organized as a set of numbered entry points, each implementing one editing operation, plus a shared address-input subroutine:
Line(s) Function 1 REM — stores the machine code routine 10–30 LIST mode: display memory from address 100–150 WRITE mode: accept hex byte string, poke into memory 200–250 INSERT mode: insert byte(s) into memory 300–340 DELETE mode: delete byte(s) from memory 400–420 Save routine: dimension output buffer, save to tape 500–520 Load/quit: calls USR 16669, then CLEAR and STOP 600–670 Shared address-input subroutine
The user selects a mode by running the program from a specific line number (e.g., RUN 10 for LIST, RUN 100 for WRITE). There is no top-level menu; the entry point is the mode selector.
Machine Code in the REM Statement
The REM at line 1 contains approximately 170 bytes of Z80 machine code beginning at address 16393 (0x4009, the byte immediately after the REM token). Several distinct routines are embedded at fixed offsets, each called by a separate RAND USR invocation:
USR Address Decimal Offset in REM Purpose 16539 146 LIST — dump memory bytes in hex 16589 196 WRITE — write input hex string to memory 16635 242 Return buffer size for DIM at line 400 16651 258 Save helper 16669 276 Load helper 16687 294 INSERT — insert bytes into memory block 16732 339 DELETE — remove bytes from memory block
The machine code manipulates system variables and string pointers directly. The two-byte address of the current edit target is stored at fixed locations within the ZX81 memory map (around 0x4093–0x4099, i.e. addresses 16531–16537), shared between BASIC and machine code via POKEs at lines 640–650.
Hex Address Input Subroutine (Lines 600–670)
The subroutine beginning at line 600 reads a four-character hex string and converts it into a 16-bit address stored via two POKEs. The formula used is:
POKE A+1, 16*CODE A$ + CODE A$(2) - 476 — high byte from first two hex digits
POKE A, 16*CODE A$(3) + CODE A$(4) - 476 — low byte from last two hex digits
The constant 476 is derived from the ASCII/ZX81 character codes: for the digit ‘0’ (code 28 on ZX81), the value 16*28 + 28 = 476 represents the baseline for “00”, so subtracting 476 normalises the result to zero. Letters A–F would follow the same arithmetic using their respective character codes. The address is stored in little-endian order (low byte first), consistent with Z80 convention.
The variable A is pre-loaded before the GOSUB 610 call: line 320 sets A=16535 for DELETE mode, while line 600 sets A=16533 for all other modes, pointing POKEs at different target locations within the shared data area.
Key BASIC Idioms
RAND USR instead of PRINT USR: avoids printing the return value on screen and discards it safely.
RUN USR 16732 at line 340: uses RUN (not RAND), which on the ZX81 is a synonym for RANDOMIZE — the distinction here is purely cosmetic but unusual.
CLEAR at line 660: called after each INPUT to reclaim string storage without resetting numeric variables or the GOSUB return stack; a standard ZX81 memory-pressure technique.
- Loop via
GOTO: lines 150 and 250 create write/insert loops by jumping back to the INPUT line, relying on CLEAR to prevent string space exhaustion during repeated entry.
DIM O$(USR 16635) at line 400: uses the return value of a machine code routine to dynamically size a string array, a neat way to let the MC determine the required buffer length.
Notable Techniques
The machine code makes use of Z80 block-move instructions (LDIR, opcode ED B0) for INSERT and DELETE operations, visible in the REM bytes as the sequence \ED\B0 appearing multiple times. This allows efficient shifting of memory blocks without byte-by-byte loops.
The RST 8 instruction (CF) appears several times in the machine code — this is the ZX81 character-output routine, used by the LIST function to display hex digits directly to the screen without returning to BASIC.
Bugs and Anomalies
- The hex conversion formula assumes ZX81 character codes for digits 0–9 and, implicitly, letters A–F. If a non-hex character is entered, the POKE value will be incorrect but no error is raised — there is no input validation.
- The
GOTO 120 and GOTO 220 loops have no exit condition in BASIC; the user must break with BREAK or the machine code must halt execution itself.
- Line 420
SAVE "HEXLD%3" saves the program to tape. The %3 is a zmakebas escape for an inverse character; in context this forms part of the filename.
Content
Source Code
1 REM \F5\E6\F0\1F\1F\1F\1F\C6\1C\D7\F1\E6\0F\C6\1C\D7\C9\82\40\E4\2C\37\75\37\75\2A\99\40\22\97\40\54\5D\2A\95\40\A7\ED\52\19\30\1F\7C\CD\82\40\7D\CD\82\40\AF\D7\7E\CD\82\40\CB\76\20\04\AF\D7\7E\D7\3E\76\D7\23\22\95\40\18\DB\CF\14\2A\10\40\23\46\23\CB\28\28\F4\ED\5B\95\40\23\7E\87\87\87\87\23\86\C6\24\12\13\ED\53\95\40\E5\2A\99\40\ED\52\E1\30\04\ED\53\99\40\10\E1\C9\2A\99\40\ED\5B\93\40\A7\ED\52\22\97\40\44\4D\C9\2A\10\40\11\06\00\19\EB\2A\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\11\06\00\19\ED\5B\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\23\4E\23\46\CB\28\CB\19\20\02\CF\15\C5\2A\99\40\ED\5B\95\40\A7\ED\52\23\44\4D\E1\ED\5B\99\40\19\22\99\40\EB\ED\B8\CD\CD\40\C9\2A\99\40\ED\5B\97\40\D5\A7\ED\52\44\4D\E1\23\ED\5B\95\40\ED\B0\1B\ED\53\99\40\CF\12\3B\3C\3D\3E\26\27\28\29\2A
10 PRINT " LIST "
20 GOSUB 600
30 RAND USR 16539
100 PRINT "WRITE"
110 GOSUB 600
120 INPUT A$
130 PRINT A$;" ";
140 RAND USR 16589
150 GOTO 120
200 PRINT "INSERT"
210 GOSUB 600
220 INPUT A$
230 PRINT A$;" ";
240 RAND USR 16687
250 GOTO 220
300 PRINT "DELETE"
310 GOSUB 600
320 LET A=16535
330 GOSUB 610
340 RUN USR 16732
400 DIM O$(USR 16635)
410 RAND USR 16651
420 SAVE "HEXLD%3"
500 RAND USR 16669
510 CLEAR
520 STOP
600 LET A=16533
610 PRINT "ADDRESS ";
620 INPUT A$
630 PRINT A$
640 POKE A+1,16*CODE A$+CODE A$(2)-476
650 POKE A,16*CODE A$(3)+CODE A$(4)-476
660 CLEAR
670 RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
F\C6 itemtype='https://schema.org/Blog' itemscope='itemscope' class="wp-singular computer_media-template-default single single-computer_media postid-56687 wp-custom-logo wp-embed-responsive wp-theme-astra wp-child-theme-astra-child ast-desktop ast-separate-container ast-left-sidebar astra-4.12.7 group-blog ast-blog-single-style-1 ast-custom-post-type ast-single-post ast-inherit-site-logo-transparent ast-hfb-header ast-full-width-primary-header ast-box-layout ast-normal-title-enabled astra-addon-4.12.5"C\D7\C9\E4
Skip to content
Hexload III
This program implements a hex editor for ZX81/TS1000 memory, allowing the user to list, write, insert, and delete bytes at arbitrary addresses using hexadecimal notation. The machine code routine embedded in the REM statement at line 1 (stored from address 16393 onward) provides the core editing engine; BASIC acts purely as a menu and input layer. Address entry uses a clever two-byte POKE calculation at lines 640–650, converting ASCII hex digit pairs into raw byte values via the formula `16*CODE + CODE – 476`. RAND USR calls at lines 30, 140, 240, 340, 410, 500 dispatch into the machine code at specific offsets to perform list, write, insert, delete, save, and load operations. The CLEAR statement at line 660 is used to free string space after each input rather than to reset variables, a common ZX81 memory-management idiom.
Program Analysis
Program Structure
The program is organized as a set of numbered entry points, each implementing one editing operation, plus a shared address-input subroutine:
Line(s) Function 1 REM — stores the machine code routine 10–30 LIST mode: display memory from address 100–150 WRITE mode: accept hex byte string, poke into memory 200–250 INSERT mode: insert byte(s) into memory 300–340 DELETE mode: delete byte(s) from memory 400–420 Save routine: dimension output buffer, save to tape 500–520 Load/quit: calls USR 16669, then CLEAR and STOP 600–670 Shared address-input subroutine
The user selects a mode by running the program from a specific line number (e.g., RUN 10 for LIST, RUN 100 for WRITE). There is no top-level menu; the entry point is the mode selector.
Machine Code in the REM Statement
The REM at line 1 contains approximately 170 bytes of Z80 machine code beginning at address 16393 (0x4009, the byte immediately after the REM token). Several distinct routines are embedded at fixed offsets, each called by a separate RAND USR invocation:
USR Address Decimal Offset in REM Purpose 16539 146 LIST — dump memory bytes in hex 16589 196 WRITE — write input hex string to memory 16635 242 Return buffer size for DIM at line 400 16651 258 Save helper 16669 276 Load helper 16687 294 INSERT — insert bytes into memory block 16732 339 DELETE — remove bytes from memory block
The machine code manipulates system variables and string pointers directly. The two-byte address of the current edit target is stored at fixed locations within the ZX81 memory map (around 0x4093–0x4099, i.e. addresses 16531–16537), shared between BASIC and machine code via POKEs at lines 640–650.
Hex Address Input Subroutine (Lines 600–670)
The subroutine beginning at line 600 reads a four-character hex string and converts it into a 16-bit address stored via two POKEs. The formula used is:
POKE A+1, 16*CODE A$ + CODE A$(2) - 476 — high byte from first two hex digits
POKE A, 16*CODE A$(3) + CODE A$(4) - 476 — low byte from last two hex digits
The constant 476 is derived from the ASCII/ZX81 character codes: for the digit ‘0’ (code 28 on ZX81), the value 16*28 + 28 = 476 represents the baseline for “00”, so subtracting 476 normalises the result to zero. Letters A–F would follow the same arithmetic using their respective character codes. The address is stored in little-endian order (low byte first), consistent with Z80 convention.
The variable A is pre-loaded before the GOSUB 610 call: line 320 sets A=16535 for DELETE mode, while line 600 sets A=16533 for all other modes, pointing POKEs at different target locations within the shared data area.
Key BASIC Idioms
RAND USR instead of PRINT USR: avoids printing the return value on screen and discards it safely.
RUN USR 16732 at line 340: uses RUN (not RAND), which on the ZX81 is a synonym for RANDOMIZE — the distinction here is purely cosmetic but unusual.
CLEAR at line 660: called after each INPUT to reclaim string storage without resetting numeric variables or the GOSUB return stack; a standard ZX81 memory-pressure technique.
- Loop via
GOTO: lines 150 and 250 create write/insert loops by jumping back to the INPUT line, relying on CLEAR to prevent string space exhaustion during repeated entry.
DIM O$(USR 16635) at line 400: uses the return value of a machine code routine to dynamically size a string array, a neat way to let the MC determine the required buffer length.
Notable Techniques
The machine code makes use of Z80 block-move instructions (LDIR, opcode ED B0) for INSERT and DELETE operations, visible in the REM bytes as the sequence \ED\B0 appearing multiple times. This allows efficient shifting of memory blocks without byte-by-byte loops.
The RST 8 instruction (CF) appears several times in the machine code — this is the ZX81 character-output routine, used by the LIST function to display hex digits directly to the screen without returning to BASIC.
Bugs and Anomalies
- The hex conversion formula assumes ZX81 character codes for digits 0–9 and, implicitly, letters A–F. If a non-hex character is entered, the POKE value will be incorrect but no error is raised — there is no input validation.
- The
GOTO 120 and GOTO 220 loops have no exit condition in BASIC; the user must break with BREAK or the machine code must halt execution itself.
- Line 420
SAVE "HEXLD%3" saves the program to tape. The %3 is a zmakebas escape for an inverse character; in context this forms part of the filename.
Content
Source Code
1 REM \F5\E6\F0\1F\1F\1F\1F\C6\1C\D7\F1\E6\0F\C6\1C\D7\C9\82\40\E4\2C\37\75\37\75\2A\99\40\22\97\40\54\5D\2A\95\40\A7\ED\52\19\30\1F\7C\CD\82\40\7D\CD\82\40\AF\D7\7E\CD\82\40\CB\76\20\04\AF\D7\7E\D7\3E\76\D7\23\22\95\40\18\DB\CF\14\2A\10\40\23\46\23\CB\28\28\F4\ED\5B\95\40\23\7E\87\87\87\87\23\86\C6\24\12\13\ED\53\95\40\E5\2A\99\40\ED\52\E1\30\04\ED\53\99\40\10\E1\C9\2A\99\40\ED\5B\93\40\A7\ED\52\22\97\40\44\4D\C9\2A\10\40\11\06\00\19\EB\2A\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\11\06\00\19\ED\5B\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\23\4E\23\46\CB\28\CB\19\20\02\CF\15\C5\2A\99\40\ED\5B\95\40\A7\ED\52\23\44\4D\E1\ED\5B\99\40\19\22\99\40\EB\ED\B8\CD\CD\40\C9\2A\99\40\ED\5B\97\40\D5\A7\ED\52\44\4D\E1\23\ED\5B\95\40\ED\B0\1B\ED\53\99\40\CF\12\3B\3C\3D\3E\26\27\28\29\2A
10 PRINT " LIST "
20 GOSUB 600
30 RAND USR 16539
100 PRINT "WRITE"
110 GOSUB 600
120 INPUT A$
130 PRINT A$;" ";
140 RAND USR 16589
150 GOTO 120
200 PRINT "INSERT"
210 GOSUB 600
220 INPUT A$
230 PRINT A$;" ";
240 RAND USR 16687
250 GOTO 220
300 PRINT "DELETE"
310 GOSUB 600
320 LET A=16535
330 GOSUB 610
340 RUN USR 16732
400 DIM O$(USR 16635)
410 RAND USR 16651
420 SAVE "HEXLD%3"
500 RAND USR 16669
510 CLEAR
520 STOP
600 LET A=16533
610 PRINT "ADDRESS ";
620 INPUT A$
630 PRINT A$
640 POKE A+1,16*CODE A$+CODE A$(2)-476
650 POKE A,16*CODE A$(3)+CODE A$(4)-476
660 CLEAR
670 RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
C
Skip to content
Hexload III
This program implements a hex editor for ZX81/TS1000 memory, allowing the user to list, write, insert, and delete bytes at arbitrary addresses using hexadecimal notation. The machine code routine embedded in the REM statement at line 1 (stored from address 16393 onward) provides the core editing engine; BASIC acts purely as a menu and input layer. Address entry uses a clever two-byte POKE calculation at lines 640–650, converting ASCII hex digit pairs into raw byte values via the formula `16*CODE + CODE – 476`. RAND USR calls at lines 30, 140, 240, 340, 410, 500 dispatch into the machine code at specific offsets to perform list, write, insert, delete, save, and load operations. The CLEAR statement at line 660 is used to free string space after each input rather than to reset variables, a common ZX81 memory-management idiom.
Program Analysis
Program Structure
The program is organized as a set of numbered entry points, each implementing one editing operation, plus a shared address-input subroutine:
Line(s) Function 1 REM — stores the machine code routine 10–30 LIST mode: display memory from address 100–150 WRITE mode: accept hex byte string, poke into memory 200–250 INSERT mode: insert byte(s) into memory 300–340 DELETE mode: delete byte(s) from memory 400–420 Save routine: dimension output buffer, save to tape 500–520 Load/quit: calls USR 16669, then CLEAR and STOP 600–670 Shared address-input subroutine
The user selects a mode by running the program from a specific line number (e.g., RUN 10 for LIST, RUN 100 for WRITE). There is no top-level menu; the entry point is the mode selector.
Machine Code in the REM Statement
The REM at line 1 contains approximately 170 bytes of Z80 machine code beginning at address 16393 (0x4009, the byte immediately after the REM token). Several distinct routines are embedded at fixed offsets, each called by a separate RAND USR invocation:
USR Address Decimal Offset in REM Purpose 16539 146 LIST — dump memory bytes in hex 16589 196 WRITE — write input hex string to memory 16635 242 Return buffer size for DIM at line 400 16651 258 Save helper 16669 276 Load helper 16687 294 INSERT — insert bytes into memory block 16732 339 DELETE — remove bytes from memory block
The machine code manipulates system variables and string pointers directly. The two-byte address of the current edit target is stored at fixed locations within the ZX81 memory map (around 0x4093–0x4099, i.e. addresses 16531–16537), shared between BASIC and machine code via POKEs at lines 640–650.
Hex Address Input Subroutine (Lines 600–670)
The subroutine beginning at line 600 reads a four-character hex string and converts it into a 16-bit address stored via two POKEs. The formula used is:
POKE A+1, 16*CODE A$ + CODE A$(2) - 476 — high byte from first two hex digits
POKE A, 16*CODE A$(3) + CODE A$(4) - 476 — low byte from last two hex digits
The constant 476 is derived from the ASCII/ZX81 character codes: for the digit ‘0’ (code 28 on ZX81), the value 16*28 + 28 = 476 represents the baseline for “00”, so subtracting 476 normalises the result to zero. Letters A–F would follow the same arithmetic using their respective character codes. The address is stored in little-endian order (low byte first), consistent with Z80 convention.
The variable A is pre-loaded before the GOSUB 610 call: line 320 sets A=16535 for DELETE mode, while line 600 sets A=16533 for all other modes, pointing POKEs at different target locations within the shared data area.
Key BASIC Idioms
RAND USR instead of PRINT USR: avoids printing the return value on screen and discards it safely.
RUN USR 16732 at line 340: uses RUN (not RAND), which on the ZX81 is a synonym for RANDOMIZE — the distinction here is purely cosmetic but unusual.
CLEAR at line 660: called after each INPUT to reclaim string storage without resetting numeric variables or the GOSUB return stack; a standard ZX81 memory-pressure technique.
- Loop via
GOTO: lines 150 and 250 create write/insert loops by jumping back to the INPUT line, relying on CLEAR to prevent string space exhaustion during repeated entry.
DIM O$(USR 16635) at line 400: uses the return value of a machine code routine to dynamically size a string array, a neat way to let the MC determine the required buffer length.
Notable Techniques
The machine code makes use of Z80 block-move instructions (LDIR, opcode ED B0) for INSERT and DELETE operations, visible in the REM bytes as the sequence \ED\B0 appearing multiple times. This allows efficient shifting of memory blocks without byte-by-byte loops.
The RST 8 instruction (CF) appears several times in the machine code — this is the ZX81 character-output routine, used by the LIST function to display hex digits directly to the screen without returning to BASIC.
Bugs and Anomalies
- The hex conversion formula assumes ZX81 character codes for digits 0–9 and, implicitly, letters A–F. If a non-hex character is entered, the POKE value will be incorrect but no error is raised — there is no input validation.
- The
GOTO 120 and GOTO 220 loops have no exit condition in BASIC; the user must break with BREAK or the machine code must halt execution itself.
- Line 420
SAVE "HEXLD%3" saves the program to tape. The %3 is a zmakebas escape for an inverse character; in context this forms part of the filename.
Content
Source Code
1 REM \F5\E6\F0\1F\1F\1F\1F\C6\1C\D7\F1\E6\0F\C6\1C\D7\C9\82\40\E4\2C\37\75\37\75\2A\99\40\22\97\40\54\5D\2A\95\40\A7\ED\52\19\30\1F\7C\CD\82\40\7D\CD\82\40\AF\D7\7E\CD\82\40\CB\76\20\04\AF\D7\7E\D7\3E\76\D7\23\22\95\40\18\DB\CF\14\2A\10\40\23\46\23\CB\28\28\F4\ED\5B\95\40\23\7E\87\87\87\87\23\86\C6\24\12\13\ED\53\95\40\E5\2A\99\40\ED\52\E1\30\04\ED\53\99\40\10\E1\C9\2A\99\40\ED\5B\93\40\A7\ED\52\22\97\40\44\4D\C9\2A\10\40\11\06\00\19\EB\2A\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\11\06\00\19\ED\5B\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\23\4E\23\46\CB\28\CB\19\20\02\CF\15\C5\2A\99\40\ED\5B\95\40\A7\ED\52\23\44\4D\E1\ED\5B\99\40\19\22\99\40\EB\ED\B8\CD\CD\40\C9\2A\99\40\ED\5B\97\40\D5\A7\ED\52\44\4D\E1\23\ED\5B\95\40\ED\B0\1B\ED\53\99\40\CF\12\3B\3C\3D\3E\26\27\28\29\2A
10 PRINT " LIST "
20 GOSUB 600
30 RAND USR 16539
100 PRINT "WRITE"
110 GOSUB 600
120 INPUT A$
130 PRINT A$;" ";
140 RAND USR 16589
150 GOTO 120
200 PRINT "INSERT"
210 GOSUB 600
220 INPUT A$
230 PRINT A$;" ";
240 RAND USR 16687
250 GOTO 220
300 PRINT "DELETE"
310 GOSUB 600
320 LET A=16535
330 GOSUB 610
340 RUN USR 16732
400 DIM O$(USR 16635)
410 RAND USR 16651
420 SAVE "HEXLD%3"
500 RAND USR 16669
510 CLEAR
520 STOP
600 LET A=16533
610 PRINT "ADDRESS ";
620 INPUT A$
630 PRINT A$
640 POKE A+1,16*CODE A$+CODE A$(2)-476
650 POKE A,16*CODE A$(3)+CODE A$(4)-476
660 CLEAR
670 RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
AD
Skip to content
Hexload III
This program implements a hex editor for ZX81/TS1000 memory, allowing the user to list, write, insert, and delete bytes at arbitrary addresses using hexadecimal notation. The machine code routine embedded in the REM statement at line 1 (stored from address 16393 onward) provides the core editing engine; BASIC acts purely as a menu and input layer. Address entry uses a clever two-byte POKE calculation at lines 640–650, converting ASCII hex digit pairs into raw byte values via the formula `16*CODE + CODE – 476`. RAND USR calls at lines 30, 140, 240, 340, 410, 500 dispatch into the machine code at specific offsets to perform list, write, insert, delete, save, and load operations. The CLEAR statement at line 660 is used to free string space after each input rather than to reset variables, a common ZX81 memory-management idiom.
Program Analysis
Program Structure
The program is organized as a set of numbered entry points, each implementing one editing operation, plus a shared address-input subroutine:
Line(s) Function 1 REM — stores the machine code routine 10–30 LIST mode: display memory from address 100–150 WRITE mode: accept hex byte string, poke into memory 200–250 INSERT mode: insert byte(s) into memory 300–340 DELETE mode: delete byte(s) from memory 400–420 Save routine: dimension output buffer, save to tape 500–520 Load/quit: calls USR 16669, then CLEAR and STOP 600–670 Shared address-input subroutine
The user selects a mode by running the program from a specific line number (e.g., RUN 10 for LIST, RUN 100 for WRITE). There is no top-level menu; the entry point is the mode selector.
Machine Code in the REM Statement
The REM at line 1 contains approximately 170 bytes of Z80 machine code beginning at address 16393 (0x4009, the byte immediately after the REM token). Several distinct routines are embedded at fixed offsets, each called by a separate RAND USR invocation:
USR Address Decimal Offset in REM Purpose 16539 146 LIST — dump memory bytes in hex 16589 196 WRITE — write input hex string to memory 16635 242 Return buffer size for DIM at line 400 16651 258 Save helper 16669 276 Load helper 16687 294 INSERT — insert bytes into memory block 16732 339 DELETE — remove bytes from memory block
The machine code manipulates system variables and string pointers directly. The two-byte address of the current edit target is stored at fixed locations within the ZX81 memory map (around 0x4093–0x4099, i.e. addresses 16531–16537), shared between BASIC and machine code via POKEs at lines 640–650.
Hex Address Input Subroutine (Lines 600–670)
The subroutine beginning at line 600 reads a four-character hex string and converts it into a 16-bit address stored via two POKEs. The formula used is:
POKE A+1, 16*CODE A$ + CODE A$(2) - 476 — high byte from first two hex digits
POKE A, 16*CODE A$(3) + CODE A$(4) - 476 — low byte from last two hex digits
The constant 476 is derived from the ASCII/ZX81 character codes: for the digit ‘0’ (code 28 on ZX81), the value 16*28 + 28 = 476 represents the baseline for “00”, so subtracting 476 normalises the result to zero. Letters A–F would follow the same arithmetic using their respective character codes. The address is stored in little-endian order (low byte first), consistent with Z80 convention.
The variable A is pre-loaded before the GOSUB 610 call: line 320 sets A=16535 for DELETE mode, while line 600 sets A=16533 for all other modes, pointing POKEs at different target locations within the shared data area.
Key BASIC Idioms
RAND USR instead of PRINT USR: avoids printing the return value on screen and discards it safely.
RUN USR 16732 at line 340: uses RUN (not RAND), which on the ZX81 is a synonym for RANDOMIZE — the distinction here is purely cosmetic but unusual.
CLEAR at line 660: called after each INPUT to reclaim string storage without resetting numeric variables or the GOSUB return stack; a standard ZX81 memory-pressure technique.
- Loop via
GOTO: lines 150 and 250 create write/insert loops by jumping back to the INPUT line, relying on CLEAR to prevent string space exhaustion during repeated entry.
DIM O$(USR 16635) at line 400: uses the return value of a machine code routine to dynamically size a string array, a neat way to let the MC determine the required buffer length.
Notable Techniques
The machine code makes use of Z80 block-move instructions (LDIR, opcode ED B0) for INSERT and DELETE operations, visible in the REM bytes as the sequence \ED\B0 appearing multiple times. This allows efficient shifting of memory blocks without byte-by-byte loops.
The RST 8 instruction (CF) appears several times in the machine code — this is the ZX81 character-output routine, used by the LIST function to display hex digits directly to the screen without returning to BASIC.
Bugs and Anomalies
- The hex conversion formula assumes ZX81 character codes for digits 0–9 and, implicitly, letters A–F. If a non-hex character is entered, the POKE value will be incorrect but no error is raised — there is no input validation.
- The
GOTO 120 and GOTO 220 loops have no exit condition in BASIC; the user must break with BREAK or the machine code must halt execution itself.
- Line 420
SAVE "HEXLD%3" saves the program to tape. The %3 is a zmakebas escape for an inverse character; in context this forms part of the filename.
Content
Source Code
1 REM \F5\E6\F0\1F\1F\1F\1F\C6\1C\D7\F1\E6\0F\C6\1C\D7\C9\82\40\E4\2C\37\75\37\75\2A\99\40\22\97\40\54\5D\2A\95\40\A7\ED\52\19\30\1F\7C\CD\82\40\7D\CD\82\40\AF\D7\7E\CD\82\40\CB\76\20\04\AF\D7\7E\D7\3E\76\D7\23\22\95\40\18\DB\CF\14\2A\10\40\23\46\23\CB\28\28\F4\ED\5B\95\40\23\7E\87\87\87\87\23\86\C6\24\12\13\ED\53\95\40\E5\2A\99\40\ED\52\E1\30\04\ED\53\99\40\10\E1\C9\2A\99\40\ED\5B\93\40\A7\ED\52\22\97\40\44\4D\C9\2A\10\40\11\06\00\19\EB\2A\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\11\06\00\19\ED\5B\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\23\4E\23\46\CB\28\CB\19\20\02\CF\15\C5\2A\99\40\ED\5B\95\40\A7\ED\52\23\44\4D\E1\ED\5B\99\40\19\22\99\40\EB\ED\B8\CD\CD\40\C9\2A\99\40\ED\5B\97\40\D5\A7\ED\52\44\4D\E1\23\ED\5B\95\40\ED\B0\1B\ED\53\99\40\CF\12\3B\3C\3D\3E\26\27\28\29\2A
10 PRINT " LIST "
20 GOSUB 600
30 RAND USR 16539
100 PRINT "WRITE"
110 GOSUB 600
120 INPUT A$
130 PRINT A$;" ";
140 RAND USR 16589
150 GOTO 120
200 PRINT "INSERT"
210 GOSUB 600
220 INPUT A$
230 PRINT A$;" ";
240 RAND USR 16687
250 GOTO 220
300 PRINT "DELETE"
310 GOSUB 600
320 LET A=16535
330 GOSUB 610
340 RUN USR 16732
400 DIM O$(USR 16635)
410 RAND USR 16651
420 SAVE "HEXLD%3"
500 RAND USR 16669
510 CLEAR
520 STOP
600 LET A=16533
610 PRINT "ADDRESS ";
620 INPUT A$
630 PRINT A$
640 POKE A+1,16*CODE A$+CODE A$(2)-476
650 POKE A,16*CODE A$(3)+CODE A$(4)-476
660 CLEAR
670 RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
A\A7\ED itemtype='https://schema.org/Blog' itemscope='itemscope' class="wp-singular computer_media-template-default single single-computer_media postid-56687 wp-custom-logo wp-embed-responsive wp-theme-astra wp-child-theme-astra-child ast-desktop ast-separate-container ast-left-sidebar astra-4.12.7 group-blog ast-blog-single-style-1 ast-custom-post-type ast-single-post ast-inherit-site-logo-transparent ast-hfb-header ast-full-width-primary-header ast-box-layout ast-normal-title-enabled astra-addon-4.12.5"FC\CDD\CD\AF\D7E\CD\CB\AF\D7E\D7E\D7\DB\CF
Skip to content
Hexload III
This program implements a hex editor for ZX81/TS1000 memory, allowing the user to list, write, insert, and delete bytes at arbitrary addresses using hexadecimal notation. The machine code routine embedded in the REM statement at line 1 (stored from address 16393 onward) provides the core editing engine; BASIC acts purely as a menu and input layer. Address entry uses a clever two-byte POKE calculation at lines 640–650, converting ASCII hex digit pairs into raw byte values via the formula `16*CODE + CODE – 476`. RAND USR calls at lines 30, 140, 240, 340, 410, 500 dispatch into the machine code at specific offsets to perform list, write, insert, delete, save, and load operations. The CLEAR statement at line 660 is used to free string space after each input rather than to reset variables, a common ZX81 memory-management idiom.
Program Analysis
Program Structure
The program is organized as a set of numbered entry points, each implementing one editing operation, plus a shared address-input subroutine:
Line(s) Function 1 REM — stores the machine code routine 10–30 LIST mode: display memory from address 100–150 WRITE mode: accept hex byte string, poke into memory 200–250 INSERT mode: insert byte(s) into memory 300–340 DELETE mode: delete byte(s) from memory 400–420 Save routine: dimension output buffer, save to tape 500–520 Load/quit: calls USR 16669, then CLEAR and STOP 600–670 Shared address-input subroutine
The user selects a mode by running the program from a specific line number (e.g., RUN 10 for LIST, RUN 100 for WRITE). There is no top-level menu; the entry point is the mode selector.
Machine Code in the REM Statement
The REM at line 1 contains approximately 170 bytes of Z80 machine code beginning at address 16393 (0x4009, the byte immediately after the REM token). Several distinct routines are embedded at fixed offsets, each called by a separate RAND USR invocation:
USR Address Decimal Offset in REM Purpose 16539 146 LIST — dump memory bytes in hex 16589 196 WRITE — write input hex string to memory 16635 242 Return buffer size for DIM at line 400 16651 258 Save helper 16669 276 Load helper 16687 294 INSERT — insert bytes into memory block 16732 339 DELETE — remove bytes from memory block
The machine code manipulates system variables and string pointers directly. The two-byte address of the current edit target is stored at fixed locations within the ZX81 memory map (around 0x4093–0x4099, i.e. addresses 16531–16537), shared between BASIC and machine code via POKEs at lines 640–650.
Hex Address Input Subroutine (Lines 600–670)
The subroutine beginning at line 600 reads a four-character hex string and converts it into a 16-bit address stored via two POKEs. The formula used is:
POKE A+1, 16*CODE A$ + CODE A$(2) - 476 — high byte from first two hex digits
POKE A, 16*CODE A$(3) + CODE A$(4) - 476 — low byte from last two hex digits
The constant 476 is derived from the ASCII/ZX81 character codes: for the digit ‘0’ (code 28 on ZX81), the value 16*28 + 28 = 476 represents the baseline for “00”, so subtracting 476 normalises the result to zero. Letters A–F would follow the same arithmetic using their respective character codes. The address is stored in little-endian order (low byte first), consistent with Z80 convention.
The variable A is pre-loaded before the GOSUB 610 call: line 320 sets A=16535 for DELETE mode, while line 600 sets A=16533 for all other modes, pointing POKEs at different target locations within the shared data area.
Key BASIC Idioms
RAND USR instead of PRINT USR: avoids printing the return value on screen and discards it safely.
RUN USR 16732 at line 340: uses RUN (not RAND), which on the ZX81 is a synonym for RANDOMIZE — the distinction here is purely cosmetic but unusual.
CLEAR at line 660: called after each INPUT to reclaim string storage without resetting numeric variables or the GOSUB return stack; a standard ZX81 memory-pressure technique.
- Loop via
GOTO: lines 150 and 250 create write/insert loops by jumping back to the INPUT line, relying on CLEAR to prevent string space exhaustion during repeated entry.
DIM O$(USR 16635) at line 400: uses the return value of a machine code routine to dynamically size a string array, a neat way to let the MC determine the required buffer length.
Notable Techniques
The machine code makes use of Z80 block-move instructions (LDIR, opcode ED B0) for INSERT and DELETE operations, visible in the REM bytes as the sequence \ED\B0 appearing multiple times. This allows efficient shifting of memory blocks without byte-by-byte loops.
The RST 8 instruction (CF) appears several times in the machine code — this is the ZX81 character-output routine, used by the LIST function to display hex digits directly to the screen without returning to BASIC.
Bugs and Anomalies
- The hex conversion formula assumes ZX81 character codes for digits 0–9 and, implicitly, letters A–F. If a non-hex character is entered, the POKE value will be incorrect but no error is raised — there is no input validation.
- The
GOTO 120 and GOTO 220 loops have no exit condition in BASIC; the user must break with BREAK or the machine code must halt execution itself.
- Line 420
SAVE "HEXLD%3" saves the program to tape. The %3 is a zmakebas escape for an inverse character; in context this forms part of the filename.
Content
Source Code
1 REM \F5\E6\F0\1F\1F\1F\1F\C6\1C\D7\F1\E6\0F\C6\1C\D7\C9\82\40\E4\2C\37\75\37\75\2A\99\40\22\97\40\54\5D\2A\95\40\A7\ED\52\19\30\1F\7C\CD\82\40\7D\CD\82\40\AF\D7\7E\CD\82\40\CB\76\20\04\AF\D7\7E\D7\3E\76\D7\23\22\95\40\18\DB\CF\14\2A\10\40\23\46\23\CB\28\28\F4\ED\5B\95\40\23\7E\87\87\87\87\23\86\C6\24\12\13\ED\53\95\40\E5\2A\99\40\ED\52\E1\30\04\ED\53\99\40\10\E1\C9\2A\99\40\ED\5B\93\40\A7\ED\52\22\97\40\44\4D\C9\2A\10\40\11\06\00\19\EB\2A\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\11\06\00\19\ED\5B\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\23\4E\23\46\CB\28\CB\19\20\02\CF\15\C5\2A\99\40\ED\5B\95\40\A7\ED\52\23\44\4D\E1\ED\5B\99\40\19\22\99\40\EB\ED\B8\CD\CD\40\C9\2A\99\40\ED\5B\97\40\D5\A7\ED\52\44\4D\E1\23\ED\5B\95\40\ED\B0\1B\ED\53\99\40\CF\12\3B\3C\3D\3E\26\27\28\29\2A
10 PRINT " LIST "
20 GOSUB 600
30 RAND USR 16539
100 PRINT "WRITE"
110 GOSUB 600
120 INPUT A$
130 PRINT A$;" ";
140 RAND USR 16589
150 GOTO 120
200 PRINT "INSERT"
210 GOSUB 600
220 INPUT A$
230 PRINT A$;" ";
240 RAND USR 16687
250 GOTO 220
300 PRINT "DELETE"
310 GOSUB 600
320 LET A=16535
330 GOSUB 610
340 RUN USR 16732
400 DIM O$(USR 16635)
410 RAND USR 16651
420 SAVE "HEXLD%3"
500 RAND USR 16669
510 CLEAR
520 STOP
600 LET A=16533
610 PRINT "ADDRESS ";
620 INPUT A$
630 PRINT A$
640 POKE A+1,16*CODE A$+CODE A$(2)-476
650 POKE A,16*CODE A$(3)+CODE A$(4)-476
660 CLEAR
670 RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
A\CB\F4\EDBE\C6\ED\E5
Skip to content
Hexload III
This program implements a hex editor for ZX81/TS1000 memory, allowing the user to list, write, insert, and delete bytes at arbitrary addresses using hexadecimal notation. The machine code routine embedded in the REM statement at line 1 (stored from address 16393 onward) provides the core editing engine; BASIC acts purely as a menu and input layer. Address entry uses a clever two-byte POKE calculation at lines 640–650, converting ASCII hex digit pairs into raw byte values via the formula `16*CODE + CODE – 476`. RAND USR calls at lines 30, 140, 240, 340, 410, 500 dispatch into the machine code at specific offsets to perform list, write, insert, delete, save, and load operations. The CLEAR statement at line 660 is used to free string space after each input rather than to reset variables, a common ZX81 memory-management idiom.
Program Analysis
Program Structure
The program is organized as a set of numbered entry points, each implementing one editing operation, plus a shared address-input subroutine:
Line(s) Function 1 REM — stores the machine code routine 10–30 LIST mode: display memory from address 100–150 WRITE mode: accept hex byte string, poke into memory 200–250 INSERT mode: insert byte(s) into memory 300–340 DELETE mode: delete byte(s) from memory 400–420 Save routine: dimension output buffer, save to tape 500–520 Load/quit: calls USR 16669, then CLEAR and STOP 600–670 Shared address-input subroutine
The user selects a mode by running the program from a specific line number (e.g., RUN 10 for LIST, RUN 100 for WRITE). There is no top-level menu; the entry point is the mode selector.
Machine Code in the REM Statement
The REM at line 1 contains approximately 170 bytes of Z80 machine code beginning at address 16393 (0x4009, the byte immediately after the REM token). Several distinct routines are embedded at fixed offsets, each called by a separate RAND USR invocation:
USR Address Decimal Offset in REM Purpose 16539 146 LIST — dump memory bytes in hex 16589 196 WRITE — write input hex string to memory 16635 242 Return buffer size for DIM at line 400 16651 258 Save helper 16669 276 Load helper 16687 294 INSERT — insert bytes into memory block 16732 339 DELETE — remove bytes from memory block
The machine code manipulates system variables and string pointers directly. The two-byte address of the current edit target is stored at fixed locations within the ZX81 memory map (around 0x4093–0x4099, i.e. addresses 16531–16537), shared between BASIC and machine code via POKEs at lines 640–650.
Hex Address Input Subroutine (Lines 600–670)
The subroutine beginning at line 600 reads a four-character hex string and converts it into a 16-bit address stored via two POKEs. The formula used is:
POKE A+1, 16*CODE A$ + CODE A$(2) - 476 — high byte from first two hex digits
POKE A, 16*CODE A$(3) + CODE A$(4) - 476 — low byte from last two hex digits
The constant 476 is derived from the ASCII/ZX81 character codes: for the digit ‘0’ (code 28 on ZX81), the value 16*28 + 28 = 476 represents the baseline for “00”, so subtracting 476 normalises the result to zero. Letters A–F would follow the same arithmetic using their respective character codes. The address is stored in little-endian order (low byte first), consistent with Z80 convention.
The variable A is pre-loaded before the GOSUB 610 call: line 320 sets A=16535 for DELETE mode, while line 600 sets A=16533 for all other modes, pointing POKEs at different target locations within the shared data area.
Key BASIC Idioms
RAND USR instead of PRINT USR: avoids printing the return value on screen and discards it safely.
RUN USR 16732 at line 340: uses RUN (not RAND), which on the ZX81 is a synonym for RANDOMIZE — the distinction here is purely cosmetic but unusual.
CLEAR at line 660: called after each INPUT to reclaim string storage without resetting numeric variables or the GOSUB return stack; a standard ZX81 memory-pressure technique.
- Loop via
GOTO: lines 150 and 250 create write/insert loops by jumping back to the INPUT line, relying on CLEAR to prevent string space exhaustion during repeated entry.
DIM O$(USR 16635) at line 400: uses the return value of a machine code routine to dynamically size a string array, a neat way to let the MC determine the required buffer length.
Notable Techniques
The machine code makes use of Z80 block-move instructions (LDIR, opcode ED B0) for INSERT and DELETE operations, visible in the REM bytes as the sequence \ED\B0 appearing multiple times. This allows efficient shifting of memory blocks without byte-by-byte loops.
The RST 8 instruction (CF) appears several times in the machine code — this is the ZX81 character-output routine, used by the LIST function to display hex digits directly to the screen without returning to BASIC.
Bugs and Anomalies
- The hex conversion formula assumes ZX81 character codes for digits 0–9 and, implicitly, letters A–F. If a non-hex character is entered, the POKE value will be incorrect but no error is raised — there is no input validation.
- The
GOTO 120 and GOTO 220 loops have no exit condition in BASIC; the user must break with BREAK or the machine code must halt execution itself.
- Line 420
SAVE "HEXLD%3" saves the program to tape. The %3 is a zmakebas escape for an inverse character; in context this forms part of the filename.
Content
Source Code
1 REM \F5\E6\F0\1F\1F\1F\1F\C6\1C\D7\F1\E6\0F\C6\1C\D7\C9\82\40\E4\2C\37\75\37\75\2A\99\40\22\97\40\54\5D\2A\95\40\A7\ED\52\19\30\1F\7C\CD\82\40\7D\CD\82\40\AF\D7\7E\CD\82\40\CB\76\20\04\AF\D7\7E\D7\3E\76\D7\23\22\95\40\18\DB\CF\14\2A\10\40\23\46\23\CB\28\28\F4\ED\5B\95\40\23\7E\87\87\87\87\23\86\C6\24\12\13\ED\53\95\40\E5\2A\99\40\ED\52\E1\30\04\ED\53\99\40\10\E1\C9\2A\99\40\ED\5B\93\40\A7\ED\52\22\97\40\44\4D\C9\2A\10\40\11\06\00\19\EB\2A\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\11\06\00\19\ED\5B\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\23\4E\23\46\CB\28\CB\19\20\02\CF\15\C5\2A\99\40\ED\5B\95\40\A7\ED\52\23\44\4D\E1\ED\5B\99\40\19\22\99\40\EB\ED\B8\CD\CD\40\C9\2A\99\40\ED\5B\97\40\D5\A7\ED\52\44\4D\E1\23\ED\5B\95\40\ED\B0\1B\ED\53\99\40\CF\12\3B\3C\3D\3E\26\27\28\29\2A
10 PRINT " LIST "
20 GOSUB 600
30 RAND USR 16539
100 PRINT "WRITE"
110 GOSUB 600
120 INPUT A$
130 PRINT A$;" ";
140 RAND USR 16589
150 GOTO 120
200 PRINT "INSERT"
210 GOSUB 600
220 INPUT A$
230 PRINT A$;" ";
240 RAND USR 16687
250 GOTO 220
300 PRINT "DELETE"
310 GOSUB 600
320 LET A=16535
330 GOSUB 610
340 RUN USR 16732
400 DIM O$(USR 16635)
410 RAND USR 16651
420 SAVE "HEXLD%3"
500 RAND USR 16669
510 CLEAR
520 STOP
600 LET A=16533
610 PRINT "ADDRESS ";
620 INPUT A$
630 PRINT A$
640 POKE A+1,16*CODE A$+CODE A$(2)-476
650 POKE A,16*CODE A$(3)+CODE A$(4)-476
660 CLEAR
670 RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
A\ED\E1\ED\E1\C9
Skip to content
Hexload III
This program implements a hex editor for ZX81/TS1000 memory, allowing the user to list, write, insert, and delete bytes at arbitrary addresses using hexadecimal notation. The machine code routine embedded in the REM statement at line 1 (stored from address 16393 onward) provides the core editing engine; BASIC acts purely as a menu and input layer. Address entry uses a clever two-byte POKE calculation at lines 640–650, converting ASCII hex digit pairs into raw byte values via the formula `16*CODE + CODE – 476`. RAND USR calls at lines 30, 140, 240, 340, 410, 500 dispatch into the machine code at specific offsets to perform list, write, insert, delete, save, and load operations. The CLEAR statement at line 660 is used to free string space after each input rather than to reset variables, a common ZX81 memory-management idiom.
Program Analysis
Program Structure
The program is organized as a set of numbered entry points, each implementing one editing operation, plus a shared address-input subroutine:
Line(s) Function 1 REM — stores the machine code routine 10–30 LIST mode: display memory from address 100–150 WRITE mode: accept hex byte string, poke into memory 200–250 INSERT mode: insert byte(s) into memory 300–340 DELETE mode: delete byte(s) from memory 400–420 Save routine: dimension output buffer, save to tape 500–520 Load/quit: calls USR 16669, then CLEAR and STOP 600–670 Shared address-input subroutine
The user selects a mode by running the program from a specific line number (e.g., RUN 10 for LIST, RUN 100 for WRITE). There is no top-level menu; the entry point is the mode selector.
Machine Code in the REM Statement
The REM at line 1 contains approximately 170 bytes of Z80 machine code beginning at address 16393 (0x4009, the byte immediately after the REM token). Several distinct routines are embedded at fixed offsets, each called by a separate RAND USR invocation:
USR Address Decimal Offset in REM Purpose 16539 146 LIST — dump memory bytes in hex 16589 196 WRITE — write input hex string to memory 16635 242 Return buffer size for DIM at line 400 16651 258 Save helper 16669 276 Load helper 16687 294 INSERT — insert bytes into memory block 16732 339 DELETE — remove bytes from memory block
The machine code manipulates system variables and string pointers directly. The two-byte address of the current edit target is stored at fixed locations within the ZX81 memory map (around 0x4093–0x4099, i.e. addresses 16531–16537), shared between BASIC and machine code via POKEs at lines 640–650.
Hex Address Input Subroutine (Lines 600–670)
The subroutine beginning at line 600 reads a four-character hex string and converts it into a 16-bit address stored via two POKEs. The formula used is:
POKE A+1, 16*CODE A$ + CODE A$(2) - 476 — high byte from first two hex digits
POKE A, 16*CODE A$(3) + CODE A$(4) - 476 — low byte from last two hex digits
The constant 476 is derived from the ASCII/ZX81 character codes: for the digit ‘0’ (code 28 on ZX81), the value 16*28 + 28 = 476 represents the baseline for “00”, so subtracting 476 normalises the result to zero. Letters A–F would follow the same arithmetic using their respective character codes. The address is stored in little-endian order (low byte first), consistent with Z80 convention.
The variable A is pre-loaded before the GOSUB 610 call: line 320 sets A=16535 for DELETE mode, while line 600 sets A=16533 for all other modes, pointing POKEs at different target locations within the shared data area.
Key BASIC Idioms
RAND USR instead of PRINT USR: avoids printing the return value on screen and discards it safely.
RUN USR 16732 at line 340: uses RUN (not RAND), which on the ZX81 is a synonym for RANDOMIZE — the distinction here is purely cosmetic but unusual.
CLEAR at line 660: called after each INPUT to reclaim string storage without resetting numeric variables or the GOSUB return stack; a standard ZX81 memory-pressure technique.
- Loop via
GOTO: lines 150 and 250 create write/insert loops by jumping back to the INPUT line, relying on CLEAR to prevent string space exhaustion during repeated entry.
DIM O$(USR 16635) at line 400: uses the return value of a machine code routine to dynamically size a string array, a neat way to let the MC determine the required buffer length.
Notable Techniques
The machine code makes use of Z80 block-move instructions (LDIR, opcode ED B0) for INSERT and DELETE operations, visible in the REM bytes as the sequence \ED\B0 appearing multiple times. This allows efficient shifting of memory blocks without byte-by-byte loops.
The RST 8 instruction (CF) appears several times in the machine code — this is the ZX81 character-output routine, used by the LIST function to display hex digits directly to the screen without returning to BASIC.
Bugs and Anomalies
- The hex conversion formula assumes ZX81 character codes for digits 0–9 and, implicitly, letters A–F. If a non-hex character is entered, the POKE value will be incorrect but no error is raised — there is no input validation.
- The
GOTO 120 and GOTO 220 loops have no exit condition in BASIC; the user must break with BREAK or the machine code must halt execution itself.
- Line 420
SAVE "HEXLD%3" saves the program to tape. The %3 is a zmakebas escape for an inverse character; in context this forms part of the filename.
Content
Source Code
1 REM \F5\E6\F0\1F\1F\1F\1F\C6\1C\D7\F1\E6\0F\C6\1C\D7\C9\82\40\E4\2C\37\75\37\75\2A\99\40\22\97\40\54\5D\2A\95\40\A7\ED\52\19\30\1F\7C\CD\82\40\7D\CD\82\40\AF\D7\7E\CD\82\40\CB\76\20\04\AF\D7\7E\D7\3E\76\D7\23\22\95\40\18\DB\CF\14\2A\10\40\23\46\23\CB\28\28\F4\ED\5B\95\40\23\7E\87\87\87\87\23\86\C6\24\12\13\ED\53\95\40\E5\2A\99\40\ED\52\E1\30\04\ED\53\99\40\10\E1\C9\2A\99\40\ED\5B\93\40\A7\ED\52\22\97\40\44\4D\C9\2A\10\40\11\06\00\19\EB\2A\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\11\06\00\19\ED\5B\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\23\4E\23\46\CB\28\CB\19\20\02\CF\15\C5\2A\99\40\ED\5B\95\40\A7\ED\52\23\44\4D\E1\ED\5B\99\40\19\22\99\40\EB\ED\B8\CD\CD\40\C9\2A\99\40\ED\5B\97\40\D5\A7\ED\52\44\4D\E1\23\ED\5B\95\40\ED\B0\1B\ED\53\99\40\CF\12\3B\3C\3D\3E\26\27\28\29\2A
10 PRINT " LIST "
20 GOSUB 600
30 RAND USR 16539
100 PRINT "WRITE"
110 GOSUB 600
120 INPUT A$
130 PRINT A$;" ";
140 RAND USR 16589
150 GOTO 120
200 PRINT "INSERT"
210 GOSUB 600
220 INPUT A$
230 PRINT A$;" ";
240 RAND USR 16687
250 GOTO 220
300 PRINT "DELETE"
310 GOSUB 600
320 LET A=16535
330 GOSUB 610
340 RUN USR 16732
400 DIM O$(USR 16635)
410 RAND USR 16651
420 SAVE "HEXLD%3"
500 RAND USR 16669
510 CLEAR
520 STOP
600 LET A=16533
610 PRINT "ADDRESS ";
620 INPUT A$
630 PRINT A$
640 POKE A+1,16*CODE A$+CODE A$(2)-476
650 POKE A,16*CODE A$(3)+CODE A$(4)-476
660 CLEAR
670 RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
A\EDB\A7\EDD\C9
Skip to content
Hexload III
This program implements a hex editor for ZX81/TS1000 memory, allowing the user to list, write, insert, and delete bytes at arbitrary addresses using hexadecimal notation. The machine code routine embedded in the REM statement at line 1 (stored from address 16393 onward) provides the core editing engine; BASIC acts purely as a menu and input layer. Address entry uses a clever two-byte POKE calculation at lines 640–650, converting ASCII hex digit pairs into raw byte values via the formula `16*CODE + CODE – 476`. RAND USR calls at lines 30, 140, 240, 340, 410, 500 dispatch into the machine code at specific offsets to perform list, write, insert, delete, save, and load operations. The CLEAR statement at line 660 is used to free string space after each input rather than to reset variables, a common ZX81 memory-management idiom.
Program Analysis
Program Structure
The program is organized as a set of numbered entry points, each implementing one editing operation, plus a shared address-input subroutine:
Line(s) Function 1 REM — stores the machine code routine 10–30 LIST mode: display memory from address 100–150 WRITE mode: accept hex byte string, poke into memory 200–250 INSERT mode: insert byte(s) into memory 300–340 DELETE mode: delete byte(s) from memory 400–420 Save routine: dimension output buffer, save to tape 500–520 Load/quit: calls USR 16669, then CLEAR and STOP 600–670 Shared address-input subroutine
The user selects a mode by running the program from a specific line number (e.g., RUN 10 for LIST, RUN 100 for WRITE). There is no top-level menu; the entry point is the mode selector.
Machine Code in the REM Statement
The REM at line 1 contains approximately 170 bytes of Z80 machine code beginning at address 16393 (0x4009, the byte immediately after the REM token). Several distinct routines are embedded at fixed offsets, each called by a separate RAND USR invocation:
USR Address Decimal Offset in REM Purpose 16539 146 LIST — dump memory bytes in hex 16589 196 WRITE — write input hex string to memory 16635 242 Return buffer size for DIM at line 400 16651 258 Save helper 16669 276 Load helper 16687 294 INSERT — insert bytes into memory block 16732 339 DELETE — remove bytes from memory block
The machine code manipulates system variables and string pointers directly. The two-byte address of the current edit target is stored at fixed locations within the ZX81 memory map (around 0x4093–0x4099, i.e. addresses 16531–16537), shared between BASIC and machine code via POKEs at lines 640–650.
Hex Address Input Subroutine (Lines 600–670)
The subroutine beginning at line 600 reads a four-character hex string and converts it into a 16-bit address stored via two POKEs. The formula used is:
POKE A+1, 16*CODE A$ + CODE A$(2) - 476 — high byte from first two hex digits
POKE A, 16*CODE A$(3) + CODE A$(4) - 476 — low byte from last two hex digits
The constant 476 is derived from the ASCII/ZX81 character codes: for the digit ‘0’ (code 28 on ZX81), the value 16*28 + 28 = 476 represents the baseline for “00”, so subtracting 476 normalises the result to zero. Letters A–F would follow the same arithmetic using their respective character codes. The address is stored in little-endian order (low byte first), consistent with Z80 convention.
The variable A is pre-loaded before the GOSUB 610 call: line 320 sets A=16535 for DELETE mode, while line 600 sets A=16533 for all other modes, pointing POKEs at different target locations within the shared data area.
Key BASIC Idioms
RAND USR instead of PRINT USR: avoids printing the return value on screen and discards it safely.
RUN USR 16732 at line 340: uses RUN (not RAND), which on the ZX81 is a synonym for RANDOMIZE — the distinction here is purely cosmetic but unusual.
CLEAR at line 660: called after each INPUT to reclaim string storage without resetting numeric variables or the GOSUB return stack; a standard ZX81 memory-pressure technique.
- Loop via
GOTO: lines 150 and 250 create write/insert loops by jumping back to the INPUT line, relying on CLEAR to prevent string space exhaustion during repeated entry.
DIM O$(USR 16635) at line 400: uses the return value of a machine code routine to dynamically size a string array, a neat way to let the MC determine the required buffer length.
Notable Techniques
The machine code makes use of Z80 block-move instructions (LDIR, opcode ED B0) for INSERT and DELETE operations, visible in the REM bytes as the sequence \ED\B0 appearing multiple times. This allows efficient shifting of memory blocks without byte-by-byte loops.
The RST 8 instruction (CF) appears several times in the machine code — this is the ZX81 character-output routine, used by the LIST function to display hex digits directly to the screen without returning to BASIC.
Bugs and Anomalies
- The hex conversion formula assumes ZX81 character codes for digits 0–9 and, implicitly, letters A–F. If a non-hex character is entered, the POKE value will be incorrect but no error is raised — there is no input validation.
- The
GOTO 120 and GOTO 220 loops have no exit condition in BASIC; the user must break with BREAK or the machine code must halt execution itself.
- Line 420
SAVE "HEXLD%3" saves the program to tape. The %3 is a zmakebas escape for an inverse character; in context this forms part of the filename.
Content
Source Code
1 REM \F5\E6\F0\1F\1F\1F\1F\C6\1C\D7\F1\E6\0F\C6\1C\D7\C9\82\40\E4\2C\37\75\37\75\2A\99\40\22\97\40\54\5D\2A\95\40\A7\ED\52\19\30\1F\7C\CD\82\40\7D\CD\82\40\AF\D7\7E\CD\82\40\CB\76\20\04\AF\D7\7E\D7\3E\76\D7\23\22\95\40\18\DB\CF\14\2A\10\40\23\46\23\CB\28\28\F4\ED\5B\95\40\23\7E\87\87\87\87\23\86\C6\24\12\13\ED\53\95\40\E5\2A\99\40\ED\52\E1\30\04\ED\53\99\40\10\E1\C9\2A\99\40\ED\5B\93\40\A7\ED\52\22\97\40\44\4D\C9\2A\10\40\11\06\00\19\EB\2A\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\11\06\00\19\ED\5B\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\23\4E\23\46\CB\28\CB\19\20\02\CF\15\C5\2A\99\40\ED\5B\95\40\A7\ED\52\23\44\4D\E1\ED\5B\99\40\19\22\99\40\EB\ED\B8\CD\CD\40\C9\2A\99\40\ED\5B\97\40\D5\A7\ED\52\44\4D\E1\23\ED\5B\95\40\ED\B0\1B\ED\53\99\40\CF\12\3B\3C\3D\3E\26\27\28\29\2A
10 PRINT " LIST "
20 GOSUB 600
30 RAND USR 16539
100 PRINT "WRITE"
110 GOSUB 600
120 INPUT A$
130 PRINT A$;" ";
140 RAND USR 16589
150 GOTO 120
200 PRINT "INSERT"
210 GOSUB 600
220 INPUT A$
230 PRINT A$;" ";
240 RAND USR 16687
250 GOTO 220
300 PRINT "DELETE"
310 GOSUB 600
320 LET A=16535
330 GOSUB 610
340 RUN USR 16732
400 DIM O$(USR 16635)
410 RAND USR 16651
420 SAVE "HEXLD%3"
500 RAND USR 16669
510 CLEAR
520 STOP
600 LET A=16533
610 PRINT "ADDRESS ";
620 INPUT A$
630 PRINT A$
640 POKE A+1,16*CODE A$+CODE A$(2)-476
650 POKE A,16*CODE A$(3)+CODE A$(4)-476
660 CLEAR
670 RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
A
Skip to content
Hexload III
This program implements a hex editor for ZX81/TS1000 memory, allowing the user to list, write, insert, and delete bytes at arbitrary addresses using hexadecimal notation. The machine code routine embedded in the REM statement at line 1 (stored from address 16393 onward) provides the core editing engine; BASIC acts purely as a menu and input layer. Address entry uses a clever two-byte POKE calculation at lines 640–650, converting ASCII hex digit pairs into raw byte values via the formula `16*CODE + CODE – 476`. RAND USR calls at lines 30, 140, 240, 340, 410, 500 dispatch into the machine code at specific offsets to perform list, write, insert, delete, save, and load operations. The CLEAR statement at line 660 is used to free string space after each input rather than to reset variables, a common ZX81 memory-management idiom.
Program Analysis
Program Structure
The program is organized as a set of numbered entry points, each implementing one editing operation, plus a shared address-input subroutine:
Line(s) Function 1 REM — stores the machine code routine 10–30 LIST mode: display memory from address 100–150 WRITE mode: accept hex byte string, poke into memory 200–250 INSERT mode: insert byte(s) into memory 300–340 DELETE mode: delete byte(s) from memory 400–420 Save routine: dimension output buffer, save to tape 500–520 Load/quit: calls USR 16669, then CLEAR and STOP 600–670 Shared address-input subroutine
The user selects a mode by running the program from a specific line number (e.g., RUN 10 for LIST, RUN 100 for WRITE). There is no top-level menu; the entry point is the mode selector.
Machine Code in the REM Statement
The REM at line 1 contains approximately 170 bytes of Z80 machine code beginning at address 16393 (0x4009, the byte immediately after the REM token). Several distinct routines are embedded at fixed offsets, each called by a separate RAND USR invocation:
USR Address Decimal Offset in REM Purpose 16539 146 LIST — dump memory bytes in hex 16589 196 WRITE — write input hex string to memory 16635 242 Return buffer size for DIM at line 400 16651 258 Save helper 16669 276 Load helper 16687 294 INSERT — insert bytes into memory block 16732 339 DELETE — remove bytes from memory block
The machine code manipulates system variables and string pointers directly. The two-byte address of the current edit target is stored at fixed locations within the ZX81 memory map (around 0x4093–0x4099, i.e. addresses 16531–16537), shared between BASIC and machine code via POKEs at lines 640–650.
Hex Address Input Subroutine (Lines 600–670)
The subroutine beginning at line 600 reads a four-character hex string and converts it into a 16-bit address stored via two POKEs. The formula used is:
POKE A+1, 16*CODE A$ + CODE A$(2) - 476 — high byte from first two hex digits
POKE A, 16*CODE A$(3) + CODE A$(4) - 476 — low byte from last two hex digits
The constant 476 is derived from the ASCII/ZX81 character codes: for the digit ‘0’ (code 28 on ZX81), the value 16*28 + 28 = 476 represents the baseline for “00”, so subtracting 476 normalises the result to zero. Letters A–F would follow the same arithmetic using their respective character codes. The address is stored in little-endian order (low byte first), consistent with Z80 convention.
The variable A is pre-loaded before the GOSUB 610 call: line 320 sets A=16535 for DELETE mode, while line 600 sets A=16533 for all other modes, pointing POKEs at different target locations within the shared data area.
Key BASIC Idioms
RAND USR instead of PRINT USR: avoids printing the return value on screen and discards it safely.
RUN USR 16732 at line 340: uses RUN (not RAND), which on the ZX81 is a synonym for RANDOMIZE — the distinction here is purely cosmetic but unusual.
CLEAR at line 660: called after each INPUT to reclaim string storage without resetting numeric variables or the GOSUB return stack; a standard ZX81 memory-pressure technique.
- Loop via
GOTO: lines 150 and 250 create write/insert loops by jumping back to the INPUT line, relying on CLEAR to prevent string space exhaustion during repeated entry.
DIM O$(USR 16635) at line 400: uses the return value of a machine code routine to dynamically size a string array, a neat way to let the MC determine the required buffer length.
Notable Techniques
The machine code makes use of Z80 block-move instructions (LDIR, opcode ED B0) for INSERT and DELETE operations, visible in the REM bytes as the sequence \ED\B0 appearing multiple times. This allows efficient shifting of memory blocks without byte-by-byte loops.
The RST 8 instruction (CF) appears several times in the machine code — this is the ZX81 character-output routine, used by the LIST function to display hex digits directly to the screen without returning to BASIC.
Bugs and Anomalies
- The hex conversion formula assumes ZX81 character codes for digits 0–9 and, implicitly, letters A–F. If a non-hex character is entered, the POKE value will be incorrect but no error is raised — there is no input validation.
- The
GOTO 120 and GOTO 220 loops have no exit condition in BASIC; the user must break with BREAK or the machine code must halt execution itself.
- Line 420
SAVE "HEXLD%3" saves the program to tape. The %3 is a zmakebas escape for an inverse character; in context this forms part of the filename.
Content
Source Code
1 REM \F5\E6\F0\1F\1F\1F\1F\C6\1C\D7\F1\E6\0F\C6\1C\D7\C9\82\40\E4\2C\37\75\37\75\2A\99\40\22\97\40\54\5D\2A\95\40\A7\ED\52\19\30\1F\7C\CD\82\40\7D\CD\82\40\AF\D7\7E\CD\82\40\CB\76\20\04\AF\D7\7E\D7\3E\76\D7\23\22\95\40\18\DB\CF\14\2A\10\40\23\46\23\CB\28\28\F4\ED\5B\95\40\23\7E\87\87\87\87\23\86\C6\24\12\13\ED\53\95\40\E5\2A\99\40\ED\52\E1\30\04\ED\53\99\40\10\E1\C9\2A\99\40\ED\5B\93\40\A7\ED\52\22\97\40\44\4D\C9\2A\10\40\11\06\00\19\EB\2A\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\11\06\00\19\ED\5B\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\23\4E\23\46\CB\28\CB\19\20\02\CF\15\C5\2A\99\40\ED\5B\95\40\A7\ED\52\23\44\4D\E1\ED\5B\99\40\19\22\99\40\EB\ED\B8\CD\CD\40\C9\2A\99\40\ED\5B\97\40\D5\A7\ED\52\44\4D\E1\23\ED\5B\95\40\ED\B0\1B\ED\53\99\40\CF\12\3B\3C\3D\3E\26\27\28\29\2A
10 PRINT " LIST "
20 GOSUB 600
30 RAND USR 16539
100 PRINT "WRITE"
110 GOSUB 600
120 INPUT A$
130 PRINT A$;" ";
140 RAND USR 16589
150 GOTO 120
200 PRINT "INSERT"
210 GOSUB 600
220 INPUT A$
230 PRINT A$;" ";
240 RAND USR 16687
250 GOTO 220
300 PRINT "DELETE"
310 GOSUB 600
320 LET A=16535
330 GOSUB 610
340 RUN USR 16732
400 DIM O$(USR 16635)
410 RAND USR 16651
420 SAVE "HEXLD%3"
500 RAND USR 16669
510 CLEAR
520 STOP
600 LET A=16533
610 PRINT "ADDRESS ";
620 INPUT A$
630 PRINT A$
640 POKE A+1,16*CODE A$+CODE A$(2)-476
650 POKE A,16*CODE A$(3)+CODE A$(4)-476
660 CLEAR
670 RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
\EB
Skip to content
Hexload III
This program implements a hex editor for ZX81/TS1000 memory, allowing the user to list, write, insert, and delete bytes at arbitrary addresses using hexadecimal notation. The machine code routine embedded in the REM statement at line 1 (stored from address 16393 onward) provides the core editing engine; BASIC acts purely as a menu and input layer. Address entry uses a clever two-byte POKE calculation at lines 640–650, converting ASCII hex digit pairs into raw byte values via the formula `16*CODE + CODE – 476`. RAND USR calls at lines 30, 140, 240, 340, 410, 500 dispatch into the machine code at specific offsets to perform list, write, insert, delete, save, and load operations. The CLEAR statement at line 660 is used to free string space after each input rather than to reset variables, a common ZX81 memory-management idiom.
Program Analysis
Program Structure
The program is organized as a set of numbered entry points, each implementing one editing operation, plus a shared address-input subroutine:
Line(s) Function 1 REM — stores the machine code routine 10–30 LIST mode: display memory from address 100–150 WRITE mode: accept hex byte string, poke into memory 200–250 INSERT mode: insert byte(s) into memory 300–340 DELETE mode: delete byte(s) from memory 400–420 Save routine: dimension output buffer, save to tape 500–520 Load/quit: calls USR 16669, then CLEAR and STOP 600–670 Shared address-input subroutine
The user selects a mode by running the program from a specific line number (e.g., RUN 10 for LIST, RUN 100 for WRITE). There is no top-level menu; the entry point is the mode selector.
Machine Code in the REM Statement
The REM at line 1 contains approximately 170 bytes of Z80 machine code beginning at address 16393 (0x4009, the byte immediately after the REM token). Several distinct routines are embedded at fixed offsets, each called by a separate RAND USR invocation:
USR Address Decimal Offset in REM Purpose 16539 146 LIST — dump memory bytes in hex 16589 196 WRITE — write input hex string to memory 16635 242 Return buffer size for DIM at line 400 16651 258 Save helper 16669 276 Load helper 16687 294 INSERT — insert bytes into memory block 16732 339 DELETE — remove bytes from memory block
The machine code manipulates system variables and string pointers directly. The two-byte address of the current edit target is stored at fixed locations within the ZX81 memory map (around 0x4093–0x4099, i.e. addresses 16531–16537), shared between BASIC and machine code via POKEs at lines 640–650.
Hex Address Input Subroutine (Lines 600–670)
The subroutine beginning at line 600 reads a four-character hex string and converts it into a 16-bit address stored via two POKEs. The formula used is:
POKE A+1, 16*CODE A$ + CODE A$(2) - 476 — high byte from first two hex digits
POKE A, 16*CODE A$(3) + CODE A$(4) - 476 — low byte from last two hex digits
The constant 476 is derived from the ASCII/ZX81 character codes: for the digit ‘0’ (code 28 on ZX81), the value 16*28 + 28 = 476 represents the baseline for “00”, so subtracting 476 normalises the result to zero. Letters A–F would follow the same arithmetic using their respective character codes. The address is stored in little-endian order (low byte first), consistent with Z80 convention.
The variable A is pre-loaded before the GOSUB 610 call: line 320 sets A=16535 for DELETE mode, while line 600 sets A=16533 for all other modes, pointing POKEs at different target locations within the shared data area.
Key BASIC Idioms
RAND USR instead of PRINT USR: avoids printing the return value on screen and discards it safely.
RUN USR 16732 at line 340: uses RUN (not RAND), which on the ZX81 is a synonym for RANDOMIZE — the distinction here is purely cosmetic but unusual.
CLEAR at line 660: called after each INPUT to reclaim string storage without resetting numeric variables or the GOSUB return stack; a standard ZX81 memory-pressure technique.
- Loop via
GOTO: lines 150 and 250 create write/insert loops by jumping back to the INPUT line, relying on CLEAR to prevent string space exhaustion during repeated entry.
DIM O$(USR 16635) at line 400: uses the return value of a machine code routine to dynamically size a string array, a neat way to let the MC determine the required buffer length.
Notable Techniques
The machine code makes use of Z80 block-move instructions (LDIR, opcode ED B0) for INSERT and DELETE operations, visible in the REM bytes as the sequence \ED\B0 appearing multiple times. This allows efficient shifting of memory blocks without byte-by-byte loops.
The RST 8 instruction (CF) appears several times in the machine code — this is the ZX81 character-output routine, used by the LIST function to display hex digits directly to the screen without returning to BASIC.
Bugs and Anomalies
- The hex conversion formula assumes ZX81 character codes for digits 0–9 and, implicitly, letters A–F. If a non-hex character is entered, the POKE value will be incorrect but no error is raised — there is no input validation.
- The
GOTO 120 and GOTO 220 loops have no exit condition in BASIC; the user must break with BREAK or the machine code must halt execution itself.
- Line 420
SAVE "HEXLD%3" saves the program to tape. The %3 is a zmakebas escape for an inverse character; in context this forms part of the filename.
Content
Source Code
1 REM \F5\E6\F0\1F\1F\1F\1F\C6\1C\D7\F1\E6\0F\C6\1C\D7\C9\82\40\E4\2C\37\75\37\75\2A\99\40\22\97\40\54\5D\2A\95\40\A7\ED\52\19\30\1F\7C\CD\82\40\7D\CD\82\40\AF\D7\7E\CD\82\40\CB\76\20\04\AF\D7\7E\D7\3E\76\D7\23\22\95\40\18\DB\CF\14\2A\10\40\23\46\23\CB\28\28\F4\ED\5B\95\40\23\7E\87\87\87\87\23\86\C6\24\12\13\ED\53\95\40\E5\2A\99\40\ED\52\E1\30\04\ED\53\99\40\10\E1\C9\2A\99\40\ED\5B\93\40\A7\ED\52\22\97\40\44\4D\C9\2A\10\40\11\06\00\19\EB\2A\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\11\06\00\19\ED\5B\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\23\4E\23\46\CB\28\CB\19\20\02\CF\15\C5\2A\99\40\ED\5B\95\40\A7\ED\52\23\44\4D\E1\ED\5B\99\40\19\22\99\40\EB\ED\B8\CD\CD\40\C9\2A\99\40\ED\5B\97\40\D5\A7\ED\52\44\4D\E1\23\ED\5B\95\40\ED\B0\1B\ED\53\99\40\CF\12\3B\3C\3D\3E\26\27\28\29\2A
10 PRINT " LIST "
20 GOSUB 600
30 RAND USR 16539
100 PRINT "WRITE"
110 GOSUB 600
120 INPUT A$
130 PRINT A$;" ";
140 RAND USR 16589
150 GOTO 120
200 PRINT "INSERT"
210 GOSUB 600
220 INPUT A$
230 PRINT A$;" ";
240 RAND USR 16687
250 GOTO 220
300 PRINT "DELETE"
310 GOSUB 600
320 LET A=16535
330 GOSUB 610
340 RUN USR 16732
400 DIM O$(USR 16635)
410 RAND USR 16651
420 SAVE "HEXLD%3"
500 RAND USR 16669
510 CLEAR
520 STOP
600 LET A=16533
610 PRINT "ADDRESS ";
620 INPUT A$
630 PRINT A$
640 POKE A+1,16*CODE A$+CODE A$(2)-476
650 POKE A,16*CODE A$(3)+CODE A$(4)-476
660 CLEAR
670 RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
A\EDB\ED\B0\C9
Skip to content
Hexload III
This program implements a hex editor for ZX81/TS1000 memory, allowing the user to list, write, insert, and delete bytes at arbitrary addresses using hexadecimal notation. The machine code routine embedded in the REM statement at line 1 (stored from address 16393 onward) provides the core editing engine; BASIC acts purely as a menu and input layer. Address entry uses a clever two-byte POKE calculation at lines 640–650, converting ASCII hex digit pairs into raw byte values via the formula `16*CODE + CODE – 476`. RAND USR calls at lines 30, 140, 240, 340, 410, 500 dispatch into the machine code at specific offsets to perform list, write, insert, delete, save, and load operations. The CLEAR statement at line 660 is used to free string space after each input rather than to reset variables, a common ZX81 memory-management idiom.
Program Analysis
Program Structure
The program is organized as a set of numbered entry points, each implementing one editing operation, plus a shared address-input subroutine:
Line(s) Function 1 REM — stores the machine code routine 10–30 LIST mode: display memory from address 100–150 WRITE mode: accept hex byte string, poke into memory 200–250 INSERT mode: insert byte(s) into memory 300–340 DELETE mode: delete byte(s) from memory 400–420 Save routine: dimension output buffer, save to tape 500–520 Load/quit: calls USR 16669, then CLEAR and STOP 600–670 Shared address-input subroutine
The user selects a mode by running the program from a specific line number (e.g., RUN 10 for LIST, RUN 100 for WRITE). There is no top-level menu; the entry point is the mode selector.
Machine Code in the REM Statement
The REM at line 1 contains approximately 170 bytes of Z80 machine code beginning at address 16393 (0x4009, the byte immediately after the REM token). Several distinct routines are embedded at fixed offsets, each called by a separate RAND USR invocation:
USR Address Decimal Offset in REM Purpose 16539 146 LIST — dump memory bytes in hex 16589 196 WRITE — write input hex string to memory 16635 242 Return buffer size for DIM at line 400 16651 258 Save helper 16669 276 Load helper 16687 294 INSERT — insert bytes into memory block 16732 339 DELETE — remove bytes from memory block
The machine code manipulates system variables and string pointers directly. The two-byte address of the current edit target is stored at fixed locations within the ZX81 memory map (around 0x4093–0x4099, i.e. addresses 16531–16537), shared between BASIC and machine code via POKEs at lines 640–650.
Hex Address Input Subroutine (Lines 600–670)
The subroutine beginning at line 600 reads a four-character hex string and converts it into a 16-bit address stored via two POKEs. The formula used is:
POKE A+1, 16*CODE A$ + CODE A$(2) - 476 — high byte from first two hex digits
POKE A, 16*CODE A$(3) + CODE A$(4) - 476 — low byte from last two hex digits
The constant 476 is derived from the ASCII/ZX81 character codes: for the digit ‘0’ (code 28 on ZX81), the value 16*28 + 28 = 476 represents the baseline for “00”, so subtracting 476 normalises the result to zero. Letters A–F would follow the same arithmetic using their respective character codes. The address is stored in little-endian order (low byte first), consistent with Z80 convention.
The variable A is pre-loaded before the GOSUB 610 call: line 320 sets A=16535 for DELETE mode, while line 600 sets A=16533 for all other modes, pointing POKEs at different target locations within the shared data area.
Key BASIC Idioms
RAND USR instead of PRINT USR: avoids printing the return value on screen and discards it safely.
RUN USR 16732 at line 340: uses RUN (not RAND), which on the ZX81 is a synonym for RANDOMIZE — the distinction here is purely cosmetic but unusual.
CLEAR at line 660: called after each INPUT to reclaim string storage without resetting numeric variables or the GOSUB return stack; a standard ZX81 memory-pressure technique.
- Loop via
GOTO: lines 150 and 250 create write/insert loops by jumping back to the INPUT line, relying on CLEAR to prevent string space exhaustion during repeated entry.
DIM O$(USR 16635) at line 400: uses the return value of a machine code routine to dynamically size a string array, a neat way to let the MC determine the required buffer length.
Notable Techniques
The machine code makes use of Z80 block-move instructions (LDIR, opcode ED B0) for INSERT and DELETE operations, visible in the REM bytes as the sequence \ED\B0 appearing multiple times. This allows efficient shifting of memory blocks without byte-by-byte loops.
The RST 8 instruction (CF) appears several times in the machine code — this is the ZX81 character-output routine, used by the LIST function to display hex digits directly to the screen without returning to BASIC.
Bugs and Anomalies
- The hex conversion formula assumes ZX81 character codes for digits 0–9 and, implicitly, letters A–F. If a non-hex character is entered, the POKE value will be incorrect but no error is raised — there is no input validation.
- The
GOTO 120 and GOTO 220 loops have no exit condition in BASIC; the user must break with BREAK or the machine code must halt execution itself.
- Line 420
SAVE "HEXLD%3" saves the program to tape. The %3 is a zmakebas escape for an inverse character; in context this forms part of the filename.
Content
Source Code
1 REM \F5\E6\F0\1F\1F\1F\1F\C6\1C\D7\F1\E6\0F\C6\1C\D7\C9\82\40\E4\2C\37\75\37\75\2A\99\40\22\97\40\54\5D\2A\95\40\A7\ED\52\19\30\1F\7C\CD\82\40\7D\CD\82\40\AF\D7\7E\CD\82\40\CB\76\20\04\AF\D7\7E\D7\3E\76\D7\23\22\95\40\18\DB\CF\14\2A\10\40\23\46\23\CB\28\28\F4\ED\5B\95\40\23\7E\87\87\87\87\23\86\C6\24\12\13\ED\53\95\40\E5\2A\99\40\ED\52\E1\30\04\ED\53\99\40\10\E1\C9\2A\99\40\ED\5B\93\40\A7\ED\52\22\97\40\44\4D\C9\2A\10\40\11\06\00\19\EB\2A\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\11\06\00\19\ED\5B\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\23\4E\23\46\CB\28\CB\19\20\02\CF\15\C5\2A\99\40\ED\5B\95\40\A7\ED\52\23\44\4D\E1\ED\5B\99\40\19\22\99\40\EB\ED\B8\CD\CD\40\C9\2A\99\40\ED\5B\97\40\D5\A7\ED\52\44\4D\E1\23\ED\5B\95\40\ED\B0\1B\ED\53\99\40\CF\12\3B\3C\3D\3E\26\27\28\29\2A
10 PRINT " LIST "
20 GOSUB 600
30 RAND USR 16539
100 PRINT "WRITE"
110 GOSUB 600
120 INPUT A$
130 PRINT A$;" ";
140 RAND USR 16589
150 GOTO 120
200 PRINT "INSERT"
210 GOSUB 600
220 INPUT A$
230 PRINT A$;" ";
240 RAND USR 16687
250 GOTO 220
300 PRINT "DELETE"
310 GOSUB 600
320 LET A=16535
330 GOSUB 610
340 RUN USR 16732
400 DIM O$(USR 16635)
410 RAND USR 16651
420 SAVE "HEXLD%3"
500 RAND USR 16669
510 CLEAR
520 STOP
600 LET A=16533
610 PRINT "ADDRESS ";
620 INPUT A$
630 PRINT A$
640 POKE A+1,16*CODE A$+CODE A$(2)-476
650 POKE A,16*CODE A$(3)+CODE A$(4)-476
660 CLEAR
670 RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
A
Skip to content
Hexload III
This program implements a hex editor for ZX81/TS1000 memory, allowing the user to list, write, insert, and delete bytes at arbitrary addresses using hexadecimal notation. The machine code routine embedded in the REM statement at line 1 (stored from address 16393 onward) provides the core editing engine; BASIC acts purely as a menu and input layer. Address entry uses a clever two-byte POKE calculation at lines 640–650, converting ASCII hex digit pairs into raw byte values via the formula `16*CODE + CODE – 476`. RAND USR calls at lines 30, 140, 240, 340, 410, 500 dispatch into the machine code at specific offsets to perform list, write, insert, delete, save, and load operations. The CLEAR statement at line 660 is used to free string space after each input rather than to reset variables, a common ZX81 memory-management idiom.
Program Analysis
Program Structure
The program is organized as a set of numbered entry points, each implementing one editing operation, plus a shared address-input subroutine:
Line(s) Function 1 REM — stores the machine code routine 10–30 LIST mode: display memory from address 100–150 WRITE mode: accept hex byte string, poke into memory 200–250 INSERT mode: insert byte(s) into memory 300–340 DELETE mode: delete byte(s) from memory 400–420 Save routine: dimension output buffer, save to tape 500–520 Load/quit: calls USR 16669, then CLEAR and STOP 600–670 Shared address-input subroutine
The user selects a mode by running the program from a specific line number (e.g., RUN 10 for LIST, RUN 100 for WRITE). There is no top-level menu; the entry point is the mode selector.
Machine Code in the REM Statement
The REM at line 1 contains approximately 170 bytes of Z80 machine code beginning at address 16393 (0x4009, the byte immediately after the REM token). Several distinct routines are embedded at fixed offsets, each called by a separate RAND USR invocation:
USR Address Decimal Offset in REM Purpose 16539 146 LIST — dump memory bytes in hex 16589 196 WRITE — write input hex string to memory 16635 242 Return buffer size for DIM at line 400 16651 258 Save helper 16669 276 Load helper 16687 294 INSERT — insert bytes into memory block 16732 339 DELETE — remove bytes from memory block
The machine code manipulates system variables and string pointers directly. The two-byte address of the current edit target is stored at fixed locations within the ZX81 memory map (around 0x4093–0x4099, i.e. addresses 16531–16537), shared between BASIC and machine code via POKEs at lines 640–650.
Hex Address Input Subroutine (Lines 600–670)
The subroutine beginning at line 600 reads a four-character hex string and converts it into a 16-bit address stored via two POKEs. The formula used is:
POKE A+1, 16*CODE A$ + CODE A$(2) - 476 — high byte from first two hex digits
POKE A, 16*CODE A$(3) + CODE A$(4) - 476 — low byte from last two hex digits
The constant 476 is derived from the ASCII/ZX81 character codes: for the digit ‘0’ (code 28 on ZX81), the value 16*28 + 28 = 476 represents the baseline for “00”, so subtracting 476 normalises the result to zero. Letters A–F would follow the same arithmetic using their respective character codes. The address is stored in little-endian order (low byte first), consistent with Z80 convention.
The variable A is pre-loaded before the GOSUB 610 call: line 320 sets A=16535 for DELETE mode, while line 600 sets A=16533 for all other modes, pointing POKEs at different target locations within the shared data area.
Key BASIC Idioms
RAND USR instead of PRINT USR: avoids printing the return value on screen and discards it safely.
RUN USR 16732 at line 340: uses RUN (not RAND), which on the ZX81 is a synonym for RANDOMIZE — the distinction here is purely cosmetic but unusual.
CLEAR at line 660: called after each INPUT to reclaim string storage without resetting numeric variables or the GOSUB return stack; a standard ZX81 memory-pressure technique.
- Loop via
GOTO: lines 150 and 250 create write/insert loops by jumping back to the INPUT line, relying on CLEAR to prevent string space exhaustion during repeated entry.
DIM O$(USR 16635) at line 400: uses the return value of a machine code routine to dynamically size a string array, a neat way to let the MC determine the required buffer length.
Notable Techniques
The machine code makes use of Z80 block-move instructions (LDIR, opcode ED B0) for INSERT and DELETE operations, visible in the REM bytes as the sequence \ED\B0 appearing multiple times. This allows efficient shifting of memory blocks without byte-by-byte loops.
The RST 8 instruction (CF) appears several times in the machine code — this is the ZX81 character-output routine, used by the LIST function to display hex digits directly to the screen without returning to BASIC.
Bugs and Anomalies
- The hex conversion formula assumes ZX81 character codes for digits 0–9 and, implicitly, letters A–F. If a non-hex character is entered, the POKE value will be incorrect but no error is raised — there is no input validation.
- The
GOTO 120 and GOTO 220 loops have no exit condition in BASIC; the user must break with BREAK or the machine code must halt execution itself.
- Line 420
SAVE "HEXLD%3" saves the program to tape. The %3 is a zmakebas escape for an inverse character; in context this forms part of the filename.
Content
Source Code
1 REM \F5\E6\F0\1F\1F\1F\1F\C6\1C\D7\F1\E6\0F\C6\1C\D7\C9\82\40\E4\2C\37\75\37\75\2A\99\40\22\97\40\54\5D\2A\95\40\A7\ED\52\19\30\1F\7C\CD\82\40\7D\CD\82\40\AF\D7\7E\CD\82\40\CB\76\20\04\AF\D7\7E\D7\3E\76\D7\23\22\95\40\18\DB\CF\14\2A\10\40\23\46\23\CB\28\28\F4\ED\5B\95\40\23\7E\87\87\87\87\23\86\C6\24\12\13\ED\53\95\40\E5\2A\99\40\ED\52\E1\30\04\ED\53\99\40\10\E1\C9\2A\99\40\ED\5B\93\40\A7\ED\52\22\97\40\44\4D\C9\2A\10\40\11\06\00\19\EB\2A\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\11\06\00\19\ED\5B\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\23\4E\23\46\CB\28\CB\19\20\02\CF\15\C5\2A\99\40\ED\5B\95\40\A7\ED\52\23\44\4D\E1\ED\5B\99\40\19\22\99\40\EB\ED\B8\CD\CD\40\C9\2A\99\40\ED\5B\97\40\D5\A7\ED\52\44\4D\E1\23\ED\5B\95\40\ED\B0\1B\ED\53\99\40\CF\12\3B\3C\3D\3E\26\27\28\29\2A
10 PRINT " LIST "
20 GOSUB 600
30 RAND USR 16539
100 PRINT "WRITE"
110 GOSUB 600
120 INPUT A$
130 PRINT A$;" ";
140 RAND USR 16589
150 GOTO 120
200 PRINT "INSERT"
210 GOSUB 600
220 INPUT A$
230 PRINT A$;" ";
240 RAND USR 16687
250 GOTO 220
300 PRINT "DELETE"
310 GOSUB 600
320 LET A=16535
330 GOSUB 610
340 RUN USR 16732
400 DIM O$(USR 16635)
410 RAND USR 16651
420 SAVE "HEXLD%3"
500 RAND USR 16669
510 CLEAR
520 STOP
600 LET A=16533
610 PRINT "ADDRESS ";
620 INPUT A$
630 PRINT A$
640 POKE A+1,16*CODE A$+CODE A$(2)-476
650 POKE A,16*CODE A$(3)+CODE A$(4)-476
660 CLEAR
670 RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
\EDB\EDB\ED\B0\C9
Skip to content
Hexload III
This program implements a hex editor for ZX81/TS1000 memory, allowing the user to list, write, insert, and delete bytes at arbitrary addresses using hexadecimal notation. The machine code routine embedded in the REM statement at line 1 (stored from address 16393 onward) provides the core editing engine; BASIC acts purely as a menu and input layer. Address entry uses a clever two-byte POKE calculation at lines 640–650, converting ASCII hex digit pairs into raw byte values via the formula `16*CODE + CODE – 476`. RAND USR calls at lines 30, 140, 240, 340, 410, 500 dispatch into the machine code at specific offsets to perform list, write, insert, delete, save, and load operations. The CLEAR statement at line 660 is used to free string space after each input rather than to reset variables, a common ZX81 memory-management idiom.
Program Analysis
Program Structure
The program is organized as a set of numbered entry points, each implementing one editing operation, plus a shared address-input subroutine:
Line(s) Function 1 REM — stores the machine code routine 10–30 LIST mode: display memory from address 100–150 WRITE mode: accept hex byte string, poke into memory 200–250 INSERT mode: insert byte(s) into memory 300–340 DELETE mode: delete byte(s) from memory 400–420 Save routine: dimension output buffer, save to tape 500–520 Load/quit: calls USR 16669, then CLEAR and STOP 600–670 Shared address-input subroutine
The user selects a mode by running the program from a specific line number (e.g., RUN 10 for LIST, RUN 100 for WRITE). There is no top-level menu; the entry point is the mode selector.
Machine Code in the REM Statement
The REM at line 1 contains approximately 170 bytes of Z80 machine code beginning at address 16393 (0x4009, the byte immediately after the REM token). Several distinct routines are embedded at fixed offsets, each called by a separate RAND USR invocation:
USR Address Decimal Offset in REM Purpose 16539 146 LIST — dump memory bytes in hex 16589 196 WRITE — write input hex string to memory 16635 242 Return buffer size for DIM at line 400 16651 258 Save helper 16669 276 Load helper 16687 294 INSERT — insert bytes into memory block 16732 339 DELETE — remove bytes from memory block
The machine code manipulates system variables and string pointers directly. The two-byte address of the current edit target is stored at fixed locations within the ZX81 memory map (around 0x4093–0x4099, i.e. addresses 16531–16537), shared between BASIC and machine code via POKEs at lines 640–650.
Hex Address Input Subroutine (Lines 600–670)
The subroutine beginning at line 600 reads a four-character hex string and converts it into a 16-bit address stored via two POKEs. The formula used is:
POKE A+1, 16*CODE A$ + CODE A$(2) - 476 — high byte from first two hex digits
POKE A, 16*CODE A$(3) + CODE A$(4) - 476 — low byte from last two hex digits
The constant 476 is derived from the ASCII/ZX81 character codes: for the digit ‘0’ (code 28 on ZX81), the value 16*28 + 28 = 476 represents the baseline for “00”, so subtracting 476 normalises the result to zero. Letters A–F would follow the same arithmetic using their respective character codes. The address is stored in little-endian order (low byte first), consistent with Z80 convention.
The variable A is pre-loaded before the GOSUB 610 call: line 320 sets A=16535 for DELETE mode, while line 600 sets A=16533 for all other modes, pointing POKEs at different target locations within the shared data area.
Key BASIC Idioms
RAND USR instead of PRINT USR: avoids printing the return value on screen and discards it safely.
RUN USR 16732 at line 340: uses RUN (not RAND), which on the ZX81 is a synonym for RANDOMIZE — the distinction here is purely cosmetic but unusual.
CLEAR at line 660: called after each INPUT to reclaim string storage without resetting numeric variables or the GOSUB return stack; a standard ZX81 memory-pressure technique.
- Loop via
GOTO: lines 150 and 250 create write/insert loops by jumping back to the INPUT line, relying on CLEAR to prevent string space exhaustion during repeated entry.
DIM O$(USR 16635) at line 400: uses the return value of a machine code routine to dynamically size a string array, a neat way to let the MC determine the required buffer length.
Notable Techniques
The machine code makes use of Z80 block-move instructions (LDIR, opcode ED B0) for INSERT and DELETE operations, visible in the REM bytes as the sequence \ED\B0 appearing multiple times. This allows efficient shifting of memory blocks without byte-by-byte loops.
The RST 8 instruction (CF) appears several times in the machine code — this is the ZX81 character-output routine, used by the LIST function to display hex digits directly to the screen without returning to BASIC.
Bugs and Anomalies
- The hex conversion formula assumes ZX81 character codes for digits 0–9 and, implicitly, letters A–F. If a non-hex character is entered, the POKE value will be incorrect but no error is raised — there is no input validation.
- The
GOTO 120 and GOTO 220 loops have no exit condition in BASIC; the user must break with BREAK or the machine code must halt execution itself.
- Line 420
SAVE "HEXLD%3" saves the program to tape. The %3 is a zmakebas escape for an inverse character; in context this forms part of the filename.
Content
Source Code
1 REM \F5\E6\F0\1F\1F\1F\1F\C6\1C\D7\F1\E6\0F\C6\1C\D7\C9\82\40\E4\2C\37\75\37\75\2A\99\40\22\97\40\54\5D\2A\95\40\A7\ED\52\19\30\1F\7C\CD\82\40\7D\CD\82\40\AF\D7\7E\CD\82\40\CB\76\20\04\AF\D7\7E\D7\3E\76\D7\23\22\95\40\18\DB\CF\14\2A\10\40\23\46\23\CB\28\28\F4\ED\5B\95\40\23\7E\87\87\87\87\23\86\C6\24\12\13\ED\53\95\40\E5\2A\99\40\ED\52\E1\30\04\ED\53\99\40\10\E1\C9\2A\99\40\ED\5B\93\40\A7\ED\52\22\97\40\44\4D\C9\2A\10\40\11\06\00\19\EB\2A\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\11\06\00\19\ED\5B\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\23\4E\23\46\CB\28\CB\19\20\02\CF\15\C5\2A\99\40\ED\5B\95\40\A7\ED\52\23\44\4D\E1\ED\5B\99\40\19\22\99\40\EB\ED\B8\CD\CD\40\C9\2A\99\40\ED\5B\97\40\D5\A7\ED\52\44\4D\E1\23\ED\5B\95\40\ED\B0\1B\ED\53\99\40\CF\12\3B\3C\3D\3E\26\27\28\29\2A
10 PRINT " LIST "
20 GOSUB 600
30 RAND USR 16539
100 PRINT "WRITE"
110 GOSUB 600
120 INPUT A$
130 PRINT A$;" ";
140 RAND USR 16589
150 GOTO 120
200 PRINT "INSERT"
210 GOSUB 600
220 INPUT A$
230 PRINT A$;" ";
240 RAND USR 16687
250 GOTO 220
300 PRINT "DELETE"
310 GOSUB 600
320 LET A=16535
330 GOSUB 610
340 RUN USR 16732
400 DIM O$(USR 16635)
410 RAND USR 16651
420 SAVE "HEXLD%3"
500 RAND USR 16669
510 CLEAR
520 STOP
600 LET A=16533
610 PRINT "ADDRESS ";
620 INPUT A$
630 PRINT A$
640 POKE A+1,16*CODE A$+CODE A$(2)-476
650 POKE A,16*CODE A$(3)+CODE A$(4)-476
660 CLEAR
670 RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
AE\CB\CB
Skip to content
Hexload III
This program implements a hex editor for ZX81/TS1000 memory, allowing the user to list, write, insert, and delete bytes at arbitrary addresses using hexadecimal notation. The machine code routine embedded in the REM statement at line 1 (stored from address 16393 onward) provides the core editing engine; BASIC acts purely as a menu and input layer. Address entry uses a clever two-byte POKE calculation at lines 640–650, converting ASCII hex digit pairs into raw byte values via the formula `16*CODE + CODE – 476`. RAND USR calls at lines 30, 140, 240, 340, 410, 500 dispatch into the machine code at specific offsets to perform list, write, insert, delete, save, and load operations. The CLEAR statement at line 660 is used to free string space after each input rather than to reset variables, a common ZX81 memory-management idiom.
Program Analysis
Program Structure
The program is organized as a set of numbered entry points, each implementing one editing operation, plus a shared address-input subroutine:
Line(s) Function 1 REM — stores the machine code routine 10–30 LIST mode: display memory from address 100–150 WRITE mode: accept hex byte string, poke into memory 200–250 INSERT mode: insert byte(s) into memory 300–340 DELETE mode: delete byte(s) from memory 400–420 Save routine: dimension output buffer, save to tape 500–520 Load/quit: calls USR 16669, then CLEAR and STOP 600–670 Shared address-input subroutine
The user selects a mode by running the program from a specific line number (e.g., RUN 10 for LIST, RUN 100 for WRITE). There is no top-level menu; the entry point is the mode selector.
Machine Code in the REM Statement
The REM at line 1 contains approximately 170 bytes of Z80 machine code beginning at address 16393 (0x4009, the byte immediately after the REM token). Several distinct routines are embedded at fixed offsets, each called by a separate RAND USR invocation:
USR Address Decimal Offset in REM Purpose 16539 146 LIST — dump memory bytes in hex 16589 196 WRITE — write input hex string to memory 16635 242 Return buffer size for DIM at line 400 16651 258 Save helper 16669 276 Load helper 16687 294 INSERT — insert bytes into memory block 16732 339 DELETE — remove bytes from memory block
The machine code manipulates system variables and string pointers directly. The two-byte address of the current edit target is stored at fixed locations within the ZX81 memory map (around 0x4093–0x4099, i.e. addresses 16531–16537), shared between BASIC and machine code via POKEs at lines 640–650.
Hex Address Input Subroutine (Lines 600–670)
The subroutine beginning at line 600 reads a four-character hex string and converts it into a 16-bit address stored via two POKEs. The formula used is:
POKE A+1, 16*CODE A$ + CODE A$(2) - 476 — high byte from first two hex digits
POKE A, 16*CODE A$(3) + CODE A$(4) - 476 — low byte from last two hex digits
The constant 476 is derived from the ASCII/ZX81 character codes: for the digit ‘0’ (code 28 on ZX81), the value 16*28 + 28 = 476 represents the baseline for “00”, so subtracting 476 normalises the result to zero. Letters A–F would follow the same arithmetic using their respective character codes. The address is stored in little-endian order (low byte first), consistent with Z80 convention.
The variable A is pre-loaded before the GOSUB 610 call: line 320 sets A=16535 for DELETE mode, while line 600 sets A=16533 for all other modes, pointing POKEs at different target locations within the shared data area.
Key BASIC Idioms
RAND USR instead of PRINT USR: avoids printing the return value on screen and discards it safely.
RUN USR 16732 at line 340: uses RUN (not RAND), which on the ZX81 is a synonym for RANDOMIZE — the distinction here is purely cosmetic but unusual.
CLEAR at line 660: called after each INPUT to reclaim string storage without resetting numeric variables or the GOSUB return stack; a standard ZX81 memory-pressure technique.
- Loop via
GOTO: lines 150 and 250 create write/insert loops by jumping back to the INPUT line, relying on CLEAR to prevent string space exhaustion during repeated entry.
DIM O$(USR 16635) at line 400: uses the return value of a machine code routine to dynamically size a string array, a neat way to let the MC determine the required buffer length.
Notable Techniques
The machine code makes use of Z80 block-move instructions (LDIR, opcode ED B0) for INSERT and DELETE operations, visible in the REM bytes as the sequence \ED\B0 appearing multiple times. This allows efficient shifting of memory blocks without byte-by-byte loops.
The RST 8 instruction (CF) appears several times in the machine code — this is the ZX81 character-output routine, used by the LIST function to display hex digits directly to the screen without returning to BASIC.
Bugs and Anomalies
- The hex conversion formula assumes ZX81 character codes for digits 0–9 and, implicitly, letters A–F. If a non-hex character is entered, the POKE value will be incorrect but no error is raised — there is no input validation.
- The
GOTO 120 and GOTO 220 loops have no exit condition in BASIC; the user must break with BREAK or the machine code must halt execution itself.
- Line 420
SAVE "HEXLD%3" saves the program to tape. The %3 is a zmakebas escape for an inverse character; in context this forms part of the filename.
Content
Source Code
1 REM \F5\E6\F0\1F\1F\1F\1F\C6\1C\D7\F1\E6\0F\C6\1C\D7\C9\82\40\E4\2C\37\75\37\75\2A\99\40\22\97\40\54\5D\2A\95\40\A7\ED\52\19\30\1F\7C\CD\82\40\7D\CD\82\40\AF\D7\7E\CD\82\40\CB\76\20\04\AF\D7\7E\D7\3E\76\D7\23\22\95\40\18\DB\CF\14\2A\10\40\23\46\23\CB\28\28\F4\ED\5B\95\40\23\7E\87\87\87\87\23\86\C6\24\12\13\ED\53\95\40\E5\2A\99\40\ED\52\E1\30\04\ED\53\99\40\10\E1\C9\2A\99\40\ED\5B\93\40\A7\ED\52\22\97\40\44\4D\C9\2A\10\40\11\06\00\19\EB\2A\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\11\06\00\19\ED\5B\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\23\4E\23\46\CB\28\CB\19\20\02\CF\15\C5\2A\99\40\ED\5B\95\40\A7\ED\52\23\44\4D\E1\ED\5B\99\40\19\22\99\40\EB\ED\B8\CD\CD\40\C9\2A\99\40\ED\5B\97\40\D5\A7\ED\52\44\4D\E1\23\ED\5B\95\40\ED\B0\1B\ED\53\99\40\CF\12\3B\3C\3D\3E\26\27\28\29\2A
10 PRINT " LIST "
20 GOSUB 600
30 RAND USR 16539
100 PRINT "WRITE"
110 GOSUB 600
120 INPUT A$
130 PRINT A$;" ";
140 RAND USR 16589
150 GOTO 120
200 PRINT "INSERT"
210 GOSUB 600
220 INPUT A$
230 PRINT A$;" ";
240 RAND USR 16687
250 GOTO 220
300 PRINT "DELETE"
310 GOSUB 600
320 LET A=16535
330 GOSUB 610
340 RUN USR 16732
400 DIM O$(USR 16635)
410 RAND USR 16651
420 SAVE "HEXLD%3"
500 RAND USR 16669
510 CLEAR
520 STOP
600 LET A=16533
610 PRINT "ADDRESS ";
620 INPUT A$
630 PRINT A$
640 POKE A+1,16*CODE A$+CODE A$(2)-476
650 POKE A,16*CODE A$(3)+CODE A$(4)-476
660 CLEAR
670 RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
\CF\C5
Skip to content
Hexload III
This program implements a hex editor for ZX81/TS1000 memory, allowing the user to list, write, insert, and delete bytes at arbitrary addresses using hexadecimal notation. The machine code routine embedded in the REM statement at line 1 (stored from address 16393 onward) provides the core editing engine; BASIC acts purely as a menu and input layer. Address entry uses a clever two-byte POKE calculation at lines 640–650, converting ASCII hex digit pairs into raw byte values via the formula `16*CODE + CODE – 476`. RAND USR calls at lines 30, 140, 240, 340, 410, 500 dispatch into the machine code at specific offsets to perform list, write, insert, delete, save, and load operations. The CLEAR statement at line 660 is used to free string space after each input rather than to reset variables, a common ZX81 memory-management idiom.
Program Analysis
Program Structure
The program is organized as a set of numbered entry points, each implementing one editing operation, plus a shared address-input subroutine:
Line(s) Function 1 REM — stores the machine code routine 10–30 LIST mode: display memory from address 100–150 WRITE mode: accept hex byte string, poke into memory 200–250 INSERT mode: insert byte(s) into memory 300–340 DELETE mode: delete byte(s) from memory 400–420 Save routine: dimension output buffer, save to tape 500–520 Load/quit: calls USR 16669, then CLEAR and STOP 600–670 Shared address-input subroutine
The user selects a mode by running the program from a specific line number (e.g., RUN 10 for LIST, RUN 100 for WRITE). There is no top-level menu; the entry point is the mode selector.
Machine Code in the REM Statement
The REM at line 1 contains approximately 170 bytes of Z80 machine code beginning at address 16393 (0x4009, the byte immediately after the REM token). Several distinct routines are embedded at fixed offsets, each called by a separate RAND USR invocation:
USR Address Decimal Offset in REM Purpose 16539 146 LIST — dump memory bytes in hex 16589 196 WRITE — write input hex string to memory 16635 242 Return buffer size for DIM at line 400 16651 258 Save helper 16669 276 Load helper 16687 294 INSERT — insert bytes into memory block 16732 339 DELETE — remove bytes from memory block
The machine code manipulates system variables and string pointers directly. The two-byte address of the current edit target is stored at fixed locations within the ZX81 memory map (around 0x4093–0x4099, i.e. addresses 16531–16537), shared between BASIC and machine code via POKEs at lines 640–650.
Hex Address Input Subroutine (Lines 600–670)
The subroutine beginning at line 600 reads a four-character hex string and converts it into a 16-bit address stored via two POKEs. The formula used is:
POKE A+1, 16*CODE A$ + CODE A$(2) - 476 — high byte from first two hex digits
POKE A, 16*CODE A$(3) + CODE A$(4) - 476 — low byte from last two hex digits
The constant 476 is derived from the ASCII/ZX81 character codes: for the digit ‘0’ (code 28 on ZX81), the value 16*28 + 28 = 476 represents the baseline for “00”, so subtracting 476 normalises the result to zero. Letters A–F would follow the same arithmetic using their respective character codes. The address is stored in little-endian order (low byte first), consistent with Z80 convention.
The variable A is pre-loaded before the GOSUB 610 call: line 320 sets A=16535 for DELETE mode, while line 600 sets A=16533 for all other modes, pointing POKEs at different target locations within the shared data area.
Key BASIC Idioms
RAND USR instead of PRINT USR: avoids printing the return value on screen and discards it safely.
RUN USR 16732 at line 340: uses RUN (not RAND), which on the ZX81 is a synonym for RANDOMIZE — the distinction here is purely cosmetic but unusual.
CLEAR at line 660: called after each INPUT to reclaim string storage without resetting numeric variables or the GOSUB return stack; a standard ZX81 memory-pressure technique.
- Loop via
GOTO: lines 150 and 250 create write/insert loops by jumping back to the INPUT line, relying on CLEAR to prevent string space exhaustion during repeated entry.
DIM O$(USR 16635) at line 400: uses the return value of a machine code routine to dynamically size a string array, a neat way to let the MC determine the required buffer length.
Notable Techniques
The machine code makes use of Z80 block-move instructions (LDIR, opcode ED B0) for INSERT and DELETE operations, visible in the REM bytes as the sequence \ED\B0 appearing multiple times. This allows efficient shifting of memory blocks without byte-by-byte loops.
The RST 8 instruction (CF) appears several times in the machine code — this is the ZX81 character-output routine, used by the LIST function to display hex digits directly to the screen without returning to BASIC.
Bugs and Anomalies
- The hex conversion formula assumes ZX81 character codes for digits 0–9 and, implicitly, letters A–F. If a non-hex character is entered, the POKE value will be incorrect but no error is raised — there is no input validation.
- The
GOTO 120 and GOTO 220 loops have no exit condition in BASIC; the user must break with BREAK or the machine code must halt execution itself.
- Line 420
SAVE "HEXLD%3" saves the program to tape. The %3 is a zmakebas escape for an inverse character; in context this forms part of the filename.
Content
Source Code
1 REM \F5\E6\F0\1F\1F\1F\1F\C6\1C\D7\F1\E6\0F\C6\1C\D7\C9\82\40\E4\2C\37\75\37\75\2A\99\40\22\97\40\54\5D\2A\95\40\A7\ED\52\19\30\1F\7C\CD\82\40\7D\CD\82\40\AF\D7\7E\CD\82\40\CB\76\20\04\AF\D7\7E\D7\3E\76\D7\23\22\95\40\18\DB\CF\14\2A\10\40\23\46\23\CB\28\28\F4\ED\5B\95\40\23\7E\87\87\87\87\23\86\C6\24\12\13\ED\53\95\40\E5\2A\99\40\ED\52\E1\30\04\ED\53\99\40\10\E1\C9\2A\99\40\ED\5B\93\40\A7\ED\52\22\97\40\44\4D\C9\2A\10\40\11\06\00\19\EB\2A\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\11\06\00\19\ED\5B\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\23\4E\23\46\CB\28\CB\19\20\02\CF\15\C5\2A\99\40\ED\5B\95\40\A7\ED\52\23\44\4D\E1\ED\5B\99\40\19\22\99\40\EB\ED\B8\CD\CD\40\C9\2A\99\40\ED\5B\97\40\D5\A7\ED\52\44\4D\E1\23\ED\5B\95\40\ED\B0\1B\ED\53\99\40\CF\12\3B\3C\3D\3E\26\27\28\29\2A
10 PRINT " LIST "
20 GOSUB 600
30 RAND USR 16539
100 PRINT "WRITE"
110 GOSUB 600
120 INPUT A$
130 PRINT A$;" ";
140 RAND USR 16589
150 GOTO 120
200 PRINT "INSERT"
210 GOSUB 600
220 INPUT A$
230 PRINT A$;" ";
240 RAND USR 16687
250 GOTO 220
300 PRINT "DELETE"
310 GOSUB 600
320 LET A=16535
330 GOSUB 610
340 RUN USR 16732
400 DIM O$(USR 16635)
410 RAND USR 16651
420 SAVE "HEXLD%3"
500 RAND USR 16669
510 CLEAR
520 STOP
600 LET A=16533
610 PRINT "ADDRESS ";
620 INPUT A$
630 PRINT A$
640 POKE A+1,16*CODE A$+CODE A$(2)-476
650 POKE A,16*CODE A$(3)+CODE A$(4)-476
660 CLEAR
670 RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
A\EDB\A7\EDD\E1\EDB\EB\ED\B8\CD\CD\C9
Skip to content
Hexload III
This program implements a hex editor for ZX81/TS1000 memory, allowing the user to list, write, insert, and delete bytes at arbitrary addresses using hexadecimal notation. The machine code routine embedded in the REM statement at line 1 (stored from address 16393 onward) provides the core editing engine; BASIC acts purely as a menu and input layer. Address entry uses a clever two-byte POKE calculation at lines 640–650, converting ASCII hex digit pairs into raw byte values via the formula `16*CODE + CODE – 476`. RAND USR calls at lines 30, 140, 240, 340, 410, 500 dispatch into the machine code at specific offsets to perform list, write, insert, delete, save, and load operations. The CLEAR statement at line 660 is used to free string space after each input rather than to reset variables, a common ZX81 memory-management idiom.
Program Analysis
Program Structure
The program is organized as a set of numbered entry points, each implementing one editing operation, plus a shared address-input subroutine:
Line(s) Function 1 REM — stores the machine code routine 10–30 LIST mode: display memory from address 100–150 WRITE mode: accept hex byte string, poke into memory 200–250 INSERT mode: insert byte(s) into memory 300–340 DELETE mode: delete byte(s) from memory 400–420 Save routine: dimension output buffer, save to tape 500–520 Load/quit: calls USR 16669, then CLEAR and STOP 600–670 Shared address-input subroutine
The user selects a mode by running the program from a specific line number (e.g., RUN 10 for LIST, RUN 100 for WRITE). There is no top-level menu; the entry point is the mode selector.
Machine Code in the REM Statement
The REM at line 1 contains approximately 170 bytes of Z80 machine code beginning at address 16393 (0x4009, the byte immediately after the REM token). Several distinct routines are embedded at fixed offsets, each called by a separate RAND USR invocation:
USR Address Decimal Offset in REM Purpose 16539 146 LIST — dump memory bytes in hex 16589 196 WRITE — write input hex string to memory 16635 242 Return buffer size for DIM at line 400 16651 258 Save helper 16669 276 Load helper 16687 294 INSERT — insert bytes into memory block 16732 339 DELETE — remove bytes from memory block
The machine code manipulates system variables and string pointers directly. The two-byte address of the current edit target is stored at fixed locations within the ZX81 memory map (around 0x4093–0x4099, i.e. addresses 16531–16537), shared between BASIC and machine code via POKEs at lines 640–650.
Hex Address Input Subroutine (Lines 600–670)
The subroutine beginning at line 600 reads a four-character hex string and converts it into a 16-bit address stored via two POKEs. The formula used is:
POKE A+1, 16*CODE A$ + CODE A$(2) - 476 — high byte from first two hex digits
POKE A, 16*CODE A$(3) + CODE A$(4) - 476 — low byte from last two hex digits
The constant 476 is derived from the ASCII/ZX81 character codes: for the digit ‘0’ (code 28 on ZX81), the value 16*28 + 28 = 476 represents the baseline for “00”, so subtracting 476 normalises the result to zero. Letters A–F would follow the same arithmetic using their respective character codes. The address is stored in little-endian order (low byte first), consistent with Z80 convention.
The variable A is pre-loaded before the GOSUB 610 call: line 320 sets A=16535 for DELETE mode, while line 600 sets A=16533 for all other modes, pointing POKEs at different target locations within the shared data area.
Key BASIC Idioms
RAND USR instead of PRINT USR: avoids printing the return value on screen and discards it safely.
RUN USR 16732 at line 340: uses RUN (not RAND), which on the ZX81 is a synonym for RANDOMIZE — the distinction here is purely cosmetic but unusual.
CLEAR at line 660: called after each INPUT to reclaim string storage without resetting numeric variables or the GOSUB return stack; a standard ZX81 memory-pressure technique.
- Loop via
GOTO: lines 150 and 250 create write/insert loops by jumping back to the INPUT line, relying on CLEAR to prevent string space exhaustion during repeated entry.
DIM O$(USR 16635) at line 400: uses the return value of a machine code routine to dynamically size a string array, a neat way to let the MC determine the required buffer length.
Notable Techniques
The machine code makes use of Z80 block-move instructions (LDIR, opcode ED B0) for INSERT and DELETE operations, visible in the REM bytes as the sequence \ED\B0 appearing multiple times. This allows efficient shifting of memory blocks without byte-by-byte loops.
The RST 8 instruction (CF) appears several times in the machine code — this is the ZX81 character-output routine, used by the LIST function to display hex digits directly to the screen without returning to BASIC.
Bugs and Anomalies
- The hex conversion formula assumes ZX81 character codes for digits 0–9 and, implicitly, letters A–F. If a non-hex character is entered, the POKE value will be incorrect but no error is raised — there is no input validation.
- The
GOTO 120 and GOTO 220 loops have no exit condition in BASIC; the user must break with BREAK or the machine code must halt execution itself.
- Line 420
SAVE "HEXLD%3" saves the program to tape. The %3 is a zmakebas escape for an inverse character; in context this forms part of the filename.
Content
Source Code
1 REM \F5\E6\F0\1F\1F\1F\1F\C6\1C\D7\F1\E6\0F\C6\1C\D7\C9\82\40\E4\2C\37\75\37\75\2A\99\40\22\97\40\54\5D\2A\95\40\A7\ED\52\19\30\1F\7C\CD\82\40\7D\CD\82\40\AF\D7\7E\CD\82\40\CB\76\20\04\AF\D7\7E\D7\3E\76\D7\23\22\95\40\18\DB\CF\14\2A\10\40\23\46\23\CB\28\28\F4\ED\5B\95\40\23\7E\87\87\87\87\23\86\C6\24\12\13\ED\53\95\40\E5\2A\99\40\ED\52\E1\30\04\ED\53\99\40\10\E1\C9\2A\99\40\ED\5B\93\40\A7\ED\52\22\97\40\44\4D\C9\2A\10\40\11\06\00\19\EB\2A\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\11\06\00\19\ED\5B\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\23\4E\23\46\CB\28\CB\19\20\02\CF\15\C5\2A\99\40\ED\5B\95\40\A7\ED\52\23\44\4D\E1\ED\5B\99\40\19\22\99\40\EB\ED\B8\CD\CD\40\C9\2A\99\40\ED\5B\97\40\D5\A7\ED\52\44\4D\E1\23\ED\5B\95\40\ED\B0\1B\ED\53\99\40\CF\12\3B\3C\3D\3E\26\27\28\29\2A
10 PRINT " LIST "
20 GOSUB 600
30 RAND USR 16539
100 PRINT "WRITE"
110 GOSUB 600
120 INPUT A$
130 PRINT A$;" ";
140 RAND USR 16589
150 GOTO 120
200 PRINT "INSERT"
210 GOSUB 600
220 INPUT A$
230 PRINT A$;" ";
240 RAND USR 16687
250 GOTO 220
300 PRINT "DELETE"
310 GOSUB 600
320 LET A=16535
330 GOSUB 610
340 RUN USR 16732
400 DIM O$(USR 16635)
410 RAND USR 16651
420 SAVE "HEXLD%3"
500 RAND USR 16669
510 CLEAR
520 STOP
600 LET A=16533
610 PRINT "ADDRESS ";
620 INPUT A$
630 PRINT A$
640 POKE A+1,16*CODE A$+CODE A$(2)-476
650 POKE A,16*CODE A$(3)+CODE A$(4)-476
660 CLEAR
670 RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
A\EDB\D5\A7\EDD\E1\EDB\ED\B0 itemtype='https://schema.org/Blog' itemscope='itemscope' class="wp-singular computer_media-template-default single single-computer_media postid-56687 wp-custom-logo wp-embed-responsive wp-theme-astra wp-child-theme-astra-child ast-desktop ast-separate-container ast-left-sidebar astra-4.12.7 group-blog ast-blog-single-style-1 ast-custom-post-type ast-single-post ast-inherit-site-logo-transparent ast-hfb-header ast-full-width-primary-header ast-box-layout ast-normal-title-enabled astra-addon-4.12.5"B\ED\CFBCDE
Skip to content
Hexload III
This program implements a hex editor for ZX81/TS1000 memory, allowing the user to list, write, insert, and delete bytes at arbitrary addresses using hexadecimal notation. The machine code routine embedded in the REM statement at line 1 (stored from address 16393 onward) provides the core editing engine; BASIC acts purely as a menu and input layer. Address entry uses a clever two-byte POKE calculation at lines 640–650, converting ASCII hex digit pairs into raw byte values via the formula `16*CODE + CODE – 476`. RAND USR calls at lines 30, 140, 240, 340, 410, 500 dispatch into the machine code at specific offsets to perform list, write, insert, delete, save, and load operations. The CLEAR statement at line 660 is used to free string space after each input rather than to reset variables, a common ZX81 memory-management idiom.
Program Analysis
Program Structure
The program is organized as a set of numbered entry points, each implementing one editing operation, plus a shared address-input subroutine:
Line(s) Function 1 REM — stores the machine code routine 10–30 LIST mode: display memory from address 100–150 WRITE mode: accept hex byte string, poke into memory 200–250 INSERT mode: insert byte(s) into memory 300–340 DELETE mode: delete byte(s) from memory 400–420 Save routine: dimension output buffer, save to tape 500–520 Load/quit: calls USR 16669, then CLEAR and STOP 600–670 Shared address-input subroutine
The user selects a mode by running the program from a specific line number (e.g., RUN 10 for LIST, RUN 100 for WRITE). There is no top-level menu; the entry point is the mode selector.
Machine Code in the REM Statement
The REM at line 1 contains approximately 170 bytes of Z80 machine code beginning at address 16393 (0x4009, the byte immediately after the REM token). Several distinct routines are embedded at fixed offsets, each called by a separate RAND USR invocation:
USR Address Decimal Offset in REM Purpose 16539 146 LIST — dump memory bytes in hex 16589 196 WRITE — write input hex string to memory 16635 242 Return buffer size for DIM at line 400 16651 258 Save helper 16669 276 Load helper 16687 294 INSERT — insert bytes into memory block 16732 339 DELETE — remove bytes from memory block
The machine code manipulates system variables and string pointers directly. The two-byte address of the current edit target is stored at fixed locations within the ZX81 memory map (around 0x4093–0x4099, i.e. addresses 16531–16537), shared between BASIC and machine code via POKEs at lines 640–650.
Hex Address Input Subroutine (Lines 600–670)
The subroutine beginning at line 600 reads a four-character hex string and converts it into a 16-bit address stored via two POKEs. The formula used is:
POKE A+1, 16*CODE A$ + CODE A$(2) - 476 — high byte from first two hex digits
POKE A, 16*CODE A$(3) + CODE A$(4) - 476 — low byte from last two hex digits
The constant 476 is derived from the ASCII/ZX81 character codes: for the digit ‘0’ (code 28 on ZX81), the value 16*28 + 28 = 476 represents the baseline for “00”, so subtracting 476 normalises the result to zero. Letters A–F would follow the same arithmetic using their respective character codes. The address is stored in little-endian order (low byte first), consistent with Z80 convention.
The variable A is pre-loaded before the GOSUB 610 call: line 320 sets A=16535 for DELETE mode, while line 600 sets A=16533 for all other modes, pointing POKEs at different target locations within the shared data area.
Key BASIC Idioms
RAND USR instead of PRINT USR: avoids printing the return value on screen and discards it safely.
RUN USR 16732 at line 340: uses RUN (not RAND), which on the ZX81 is a synonym for RANDOMIZE — the distinction here is purely cosmetic but unusual.
CLEAR at line 660: called after each INPUT to reclaim string storage without resetting numeric variables or the GOSUB return stack; a standard ZX81 memory-pressure technique.
- Loop via
GOTO: lines 150 and 250 create write/insert loops by jumping back to the INPUT line, relying on CLEAR to prevent string space exhaustion during repeated entry.
DIM O$(USR 16635) at line 400: uses the return value of a machine code routine to dynamically size a string array, a neat way to let the MC determine the required buffer length.
Notable Techniques
The machine code makes use of Z80 block-move instructions (LDIR, opcode ED B0) for INSERT and DELETE operations, visible in the REM bytes as the sequence \ED\B0 appearing multiple times. This allows efficient shifting of memory blocks without byte-by-byte loops.
The RST 8 instruction (CF) appears several times in the machine code — this is the ZX81 character-output routine, used by the LIST function to display hex digits directly to the screen without returning to BASIC.
Bugs and Anomalies
- The hex conversion formula assumes ZX81 character codes for digits 0–9 and, implicitly, letters A–F. If a non-hex character is entered, the POKE value will be incorrect but no error is raised — there is no input validation.
- The
GOTO 120 and GOTO 220 loops have no exit condition in BASIC; the user must break with BREAK or the machine code must halt execution itself.
- Line 420
SAVE "HEXLD%3" saves the program to tape. The %3 is a zmakebas escape for an inverse character; in context this forms part of the filename.
Content
Source Code
1 REM \F5\E6\F0\1F\1F\1F\1F\C6\1C\D7\F1\E6\0F\C6\1C\D7\C9\82\40\E4\2C\37\75\37\75\2A\99\40\22\97\40\54\5D\2A\95\40\A7\ED\52\19\30\1F\7C\CD\82\40\7D\CD\82\40\AF\D7\7E\CD\82\40\CB\76\20\04\AF\D7\7E\D7\3E\76\D7\23\22\95\40\18\DB\CF\14\2A\10\40\23\46\23\CB\28\28\F4\ED\5B\95\40\23\7E\87\87\87\87\23\86\C6\24\12\13\ED\53\95\40\E5\2A\99\40\ED\52\E1\30\04\ED\53\99\40\10\E1\C9\2A\99\40\ED\5B\93\40\A7\ED\52\22\97\40\44\4D\C9\2A\10\40\11\06\00\19\EB\2A\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\11\06\00\19\ED\5B\93\40\ED\4B\97\40\ED\B0\C9\2A\10\40\23\4E\23\46\CB\28\CB\19\20\02\CF\15\C5\2A\99\40\ED\5B\95\40\A7\ED\52\23\44\4D\E1\ED\5B\99\40\19\22\99\40\EB\ED\B8\CD\CD\40\C9\2A\99\40\ED\5B\97\40\D5\A7\ED\52\44\4D\E1\23\ED\5B\95\40\ED\B0\1B\ED\53\99\40\CF\12\3B\3C\3D\3E\26\27\28\29\2A
10 PRINT " LIST "
20 GOSUB 600
30 RAND USR 16539
100 PRINT "WRITE"
110 GOSUB 600
120 INPUT A$
130 PRINT A$;" ";
140 RAND USR 16589
150 GOTO 120
200 PRINT "INSERT"
210 GOSUB 600
220 INPUT A$
230 PRINT A$;" ";
240 RAND USR 16687
250 GOTO 220
300 PRINT "DELETE"
310 GOSUB 600
320 LET A=16535
330 GOSUB 610
340 RUN USR 16732
400 DIM O$(USR 16635)
410 RAND USR 16651
420 SAVE "HEXLD%3"
500 RAND USR 16669
510 CLEAR
520 STOP
600 LET A=16533
610 PRINT "ADDRESS ";
620 INPUT A$
630 PRINT A$
640 POKE A+1,16*CODE A$+CODE A$(2)-476
650 POKE A,16*CODE A$(3)+CODE A$(4)-476
660 CLEAR
670 RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
A
10 PRINT " LIST "
20 GOSUB 600
30 RAND USR 16539
100 PRINT "WRITE"
110 GOSUB 600
120 INPUT A$
130 PRINT A$;" ";
140 RAND USR 16589
150 GOTO 120
200 PRINT "INSERT"
210 GOSUB 600
220 INPUT A$
230 PRINT A$;" ";
240 RAND USR 16687
250 GOTO 220
300 PRINT "DELETE"
310 GOSUB 600
320 LET A=16535
330 GOSUB 610
340 RUN USR 16732
400 DIM O$(USR 16635)
410 RAND USR 16651
420 SAVE "HEXLD%3"
500 RAND USR 16669
510 CLEAR
520 STOP
600 LET A=16533
610 PRINT "ADDRESS ";
620 INPUT A$
630 PRINT A$
640 POKE A+1,16*CODE A$+CODE A$(2)-476
650 POKE A,16*CODE A$(3)+CODE A$(4)-476
660 CLEAR
670 RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
