Hexload III

Date: 198x
Type: Cassette
Platform(s): TS 1000

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
1REM — stores the machine code routine
10–30LIST mode: display memory from address
100–150WRITE mode: accept hex byte string, poke into memory
200–250INSERT mode: insert byte(s) into memory
300–340DELETE mode: delete byte(s) from memory
400–420Save routine: dimension output buffer, save to tape
500–520Load/quit: calls USR 16669, then CLEAR and STOP
600–670Shared 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 AddressDecimal Offset in REMPurpose
16539146LIST — dump memory bytes in hex
16589196WRITE — write input hex string to memory
16635242Return buffer size for DIM at line 400
16651258Save helper
16669276Load helper
16687294INSERT — insert bytes into memory block
16732339DELETE — 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

Appears On

Related Products

Related Articles

Related Content

Image Gallery

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



Hexload III

Date: 198x
Type: Cassette
Platform(s): TS 1000

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
1REM — stores the machine code routine
10–30LIST mode: display memory from address
100–150WRITE mode: accept hex byte string, poke into memory
200–250INSERT mode: insert byte(s) into memory
300–340DELETE mode: delete byte(s) from memory
400–420Save routine: dimension output buffer, save to tape
500–520Load/quit: calls USR 16669, then CLEAR and STOP
600–670Shared 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 AddressDecimal Offset in REMPurpose
16539146LIST — dump memory bytes in hex
16589196WRITE — write input hex string to memory
16635242Return buffer size for DIM at line 400
16651258Save helper
16669276Load helper
16687294INSERT — insert bytes into memory block
16732339DELETE — 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

Appears On

Related Products

Related Articles

Related Content

Image Gallery

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.

Scroll to Top
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

Hexload III

Date: 198x
Type: Cassette
Platform(s): TS 1000

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
1REM — stores the machine code routine
10–30LIST mode: display memory from address
100–150WRITE mode: accept hex byte string, poke into memory
200–250INSERT mode: insert byte(s) into memory
300–340DELETE mode: delete byte(s) from memory
400–420Save routine: dimension output buffer, save to tape
500–520Load/quit: calls USR 16669, then CLEAR and STOP
600–670Shared 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 AddressDecimal Offset in REMPurpose
16539146LIST — dump memory bytes in hex
16589196WRITE — write input hex string to memory
16635242Return buffer size for DIM at line 400
16651258Save helper
16669276Load helper
16687294INSERT — insert bytes into memory block
16732339DELETE — 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

Appears On

Related Products

Related Articles

Related Content

Image Gallery

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.

Scroll to Top
C

Hexload III

Date: 198x
Type: Cassette
Platform(s): TS 1000

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
1REM — stores the machine code routine
10–30LIST mode: display memory from address
100–150WRITE mode: accept hex byte string, poke into memory
200–250INSERT mode: insert byte(s) into memory
300–340DELETE mode: delete byte(s) from memory
400–420Save routine: dimension output buffer, save to tape
500–520Load/quit: calls USR 16669, then CLEAR and STOP
600–670Shared 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 AddressDecimal Offset in REMPurpose
16539146LIST — dump memory bytes in hex
16589196WRITE — write input hex string to memory
16635242Return buffer size for DIM at line 400
16651258Save helper
16669276Load helper
16687294INSERT — insert bytes into memory block
16732339DELETE — 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

Appears On

Related Products

Related Articles

Related Content

Image Gallery

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.

Scroll to Top
AD

Hexload III

Date: 198x
Type: Cassette
Platform(s): TS 1000

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
1REM — stores the machine code routine
10–30LIST mode: display memory from address
100–150WRITE mode: accept hex byte string, poke into memory
200–250INSERT mode: insert byte(s) into memory
300–340DELETE mode: delete byte(s) from memory
400–420Save routine: dimension output buffer, save to tape
500–520Load/quit: calls USR 16669, then CLEAR and STOP
600–670Shared 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 AddressDecimal Offset in REMPurpose
16539146LIST — dump memory bytes in hex
16589196WRITE — write input hex string to memory
16635242Return buffer size for DIM at line 400
16651258Save helper
16669276Load helper
16687294INSERT — insert bytes into memory block
16732339DELETE — 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

Appears On

Related Products

Related Articles

Related Content

Image Gallery

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.

Scroll to Top
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

Hexload III

Date: 198x
Type: Cassette
Platform(s): TS 1000

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
1REM — stores the machine code routine
10–30LIST mode: display memory from address
100–150WRITE mode: accept hex byte string, poke into memory
200–250INSERT mode: insert byte(s) into memory
300–340DELETE mode: delete byte(s) from memory
400–420Save routine: dimension output buffer, save to tape
500–520Load/quit: calls USR 16669, then CLEAR and STOP
600–670Shared 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 AddressDecimal Offset in REMPurpose
16539146LIST — dump memory bytes in hex
16589196WRITE — write input hex string to memory
16635242Return buffer size for DIM at line 400
16651258Save helper
16669276Load helper
16687294INSERT — insert bytes into memory block
16732339DELETE — 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

Appears On

Related Products

Related Articles

Related Content

Image Gallery

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.

Scroll to Top
A\CB\F4\EDBE\C6\ED\E5

Hexload III

Date: 198x
Type: Cassette
Platform(s): TS 1000

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
1REM — stores the machine code routine
10–30LIST mode: display memory from address
100–150WRITE mode: accept hex byte string, poke into memory
200–250INSERT mode: insert byte(s) into memory
300–340DELETE mode: delete byte(s) from memory
400–420Save routine: dimension output buffer, save to tape
500–520Load/quit: calls USR 16669, then CLEAR and STOP
600–670Shared 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 AddressDecimal Offset in REMPurpose
16539146LIST — dump memory bytes in hex
16589196WRITE — write input hex string to memory
16635242Return buffer size for DIM at line 400
16651258Save helper
16669276Load helper
16687294INSERT — insert bytes into memory block
16732339DELETE — 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

Appears On

Related Products

Related Articles

Related Content

Image Gallery

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.

Scroll to Top
A\ED\E1\ED\E1\C9

Hexload III

Date: 198x
Type: Cassette
Platform(s): TS 1000

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
1REM — stores the machine code routine
10–30LIST mode: display memory from address
100–150WRITE mode: accept hex byte string, poke into memory
200–250INSERT mode: insert byte(s) into memory
300–340DELETE mode: delete byte(s) from memory
400–420Save routine: dimension output buffer, save to tape
500–520Load/quit: calls USR 16669, then CLEAR and STOP
600–670Shared 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 AddressDecimal Offset in REMPurpose
16539146LIST — dump memory bytes in hex
16589196WRITE — write input hex string to memory
16635242Return buffer size for DIM at line 400
16651258Save helper
16669276Load helper
16687294INSERT — insert bytes into memory block
16732339DELETE — 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

Appears On

Related Products

Related Articles

Related Content

Image Gallery

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.

Scroll to Top
A\EDB\A7\EDD\C9

Hexload III

Date: 198x
Type: Cassette
Platform(s): TS 1000

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
1REM — stores the machine code routine
10–30LIST mode: display memory from address
100–150WRITE mode: accept hex byte string, poke into memory
200–250INSERT mode: insert byte(s) into memory
300–340DELETE mode: delete byte(s) from memory
400–420Save routine: dimension output buffer, save to tape
500–520Load/quit: calls USR 16669, then CLEAR and STOP
600–670Shared 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 AddressDecimal Offset in REMPurpose
16539146LIST — dump memory bytes in hex
16589196WRITE — write input hex string to memory
16635242Return buffer size for DIM at line 400
16651258Save helper
16669276Load helper
16687294INSERT — insert bytes into memory block
16732339DELETE — 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

Appears On

Related Products

Related Articles

Related Content

Image Gallery

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.

Scroll to Top
A

Hexload III

Date: 198x
Type: Cassette
Platform(s): TS 1000

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
1REM — stores the machine code routine
10–30LIST mode: display memory from address
100–150WRITE mode: accept hex byte string, poke into memory
200–250INSERT mode: insert byte(s) into memory
300–340DELETE mode: delete byte(s) from memory
400–420Save routine: dimension output buffer, save to tape
500–520Load/quit: calls USR 16669, then CLEAR and STOP
600–670Shared 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 AddressDecimal Offset in REMPurpose
16539146LIST — dump memory bytes in hex
16589196WRITE — write input hex string to memory
16635242Return buffer size for DIM at line 400
16651258Save helper
16669276Load helper
16687294INSERT — insert bytes into memory block
16732339DELETE — 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

Appears On

Related Products

Related Articles

Related Content

Image Gallery

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.

Scroll to Top
\EB

Hexload III

Date: 198x
Type: Cassette
Platform(s): TS 1000

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
1REM — stores the machine code routine
10–30LIST mode: display memory from address
100–150WRITE mode: accept hex byte string, poke into memory
200–250INSERT mode: insert byte(s) into memory
300–340DELETE mode: delete byte(s) from memory
400–420Save routine: dimension output buffer, save to tape
500–520Load/quit: calls USR 16669, then CLEAR and STOP
600–670Shared 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 AddressDecimal Offset in REMPurpose
16539146LIST — dump memory bytes in hex
16589196WRITE — write input hex string to memory
16635242Return buffer size for DIM at line 400
16651258Save helper
16669276Load helper
16687294INSERT — insert bytes into memory block
16732339DELETE — 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

Appears On

Related Products

Related Articles

Related Content

Image Gallery

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.

Scroll to Top
A\EDB\ED\B0\C9

Hexload III

Date: 198x
Type: Cassette
Platform(s): TS 1000

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
1REM — stores the machine code routine
10–30LIST mode: display memory from address
100–150WRITE mode: accept hex byte string, poke into memory
200–250INSERT mode: insert byte(s) into memory
300–340DELETE mode: delete byte(s) from memory
400–420Save routine: dimension output buffer, save to tape
500–520Load/quit: calls USR 16669, then CLEAR and STOP
600–670Shared 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 AddressDecimal Offset in REMPurpose
16539146LIST — dump memory bytes in hex
16589196WRITE — write input hex string to memory
16635242Return buffer size for DIM at line 400
16651258Save helper
16669276Load helper
16687294INSERT — insert bytes into memory block
16732339DELETE — 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

Appears On

Related Products

Related Articles

Related Content

Image Gallery

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.

Scroll to Top
A

Hexload III

Date: 198x
Type: Cassette
Platform(s): TS 1000

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
1REM — stores the machine code routine
10–30LIST mode: display memory from address
100–150WRITE mode: accept hex byte string, poke into memory
200–250INSERT mode: insert byte(s) into memory
300–340DELETE mode: delete byte(s) from memory
400–420Save routine: dimension output buffer, save to tape
500–520Load/quit: calls USR 16669, then CLEAR and STOP
600–670Shared 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 AddressDecimal Offset in REMPurpose
16539146LIST — dump memory bytes in hex
16589196WRITE — write input hex string to memory
16635242Return buffer size for DIM at line 400
16651258Save helper
16669276Load helper
16687294INSERT — insert bytes into memory block
16732339DELETE — 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

Appears On

Related Products

Related Articles

Related Content

Image Gallery

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.

Scroll to Top
\EDB\EDB\ED\B0\C9

Hexload III

Date: 198x
Type: Cassette
Platform(s): TS 1000

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
1REM — stores the machine code routine
10–30LIST mode: display memory from address
100–150WRITE mode: accept hex byte string, poke into memory
200–250INSERT mode: insert byte(s) into memory
300–340DELETE mode: delete byte(s) from memory
400–420Save routine: dimension output buffer, save to tape
500–520Load/quit: calls USR 16669, then CLEAR and STOP
600–670Shared 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 AddressDecimal Offset in REMPurpose
16539146LIST — dump memory bytes in hex
16589196WRITE — write input hex string to memory
16635242Return buffer size for DIM at line 400
16651258Save helper
16669276Load helper
16687294INSERT — insert bytes into memory block
16732339DELETE — 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

Appears On

Related Products

Related Articles

Related Content

Image Gallery

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.

Scroll to Top
AE\CB\CB

Hexload III

Date: 198x
Type: Cassette
Platform(s): TS 1000

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
1REM — stores the machine code routine
10–30LIST mode: display memory from address
100–150WRITE mode: accept hex byte string, poke into memory
200–250INSERT mode: insert byte(s) into memory
300–340DELETE mode: delete byte(s) from memory
400–420Save routine: dimension output buffer, save to tape
500–520Load/quit: calls USR 16669, then CLEAR and STOP
600–670Shared 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 AddressDecimal Offset in REMPurpose
16539146LIST — dump memory bytes in hex
16589196WRITE — write input hex string to memory
16635242Return buffer size for DIM at line 400
16651258Save helper
16669276Load helper
16687294INSERT — insert bytes into memory block
16732339DELETE — 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

Appears On

Related Products

Related Articles

Related Content

Image Gallery

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.

Scroll to Top
\CF\C5

Hexload III

Date: 198x
Type: Cassette
Platform(s): TS 1000

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
1REM — stores the machine code routine
10–30LIST mode: display memory from address
100–150WRITE mode: accept hex byte string, poke into memory
200–250INSERT mode: insert byte(s) into memory
300–340DELETE mode: delete byte(s) from memory
400–420Save routine: dimension output buffer, save to tape
500–520Load/quit: calls USR 16669, then CLEAR and STOP
600–670Shared 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 AddressDecimal Offset in REMPurpose
16539146LIST — dump memory bytes in hex
16589196WRITE — write input hex string to memory
16635242Return buffer size for DIM at line 400
16651258Save helper
16669276Load helper
16687294INSERT — insert bytes into memory block
16732339DELETE — 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

Appears On

Related Products

Related Articles

Related Content

Image Gallery

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.

Scroll to Top
A\EDB\A7\EDD\E1\EDB\EB\ED\B8\CD\CD\C9

Hexload III

Date: 198x
Type: Cassette
Platform(s): TS 1000

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
1REM — stores the machine code routine
10–30LIST mode: display memory from address
100–150WRITE mode: accept hex byte string, poke into memory
200–250INSERT mode: insert byte(s) into memory
300–340DELETE mode: delete byte(s) from memory
400–420Save routine: dimension output buffer, save to tape
500–520Load/quit: calls USR 16669, then CLEAR and STOP
600–670Shared 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 AddressDecimal Offset in REMPurpose
16539146LIST — dump memory bytes in hex
16589196WRITE — write input hex string to memory
16635242Return buffer size for DIM at line 400
16651258Save helper
16669276Load helper
16687294INSERT — insert bytes into memory block
16732339DELETE — 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

Appears On

Related Products

Related Articles

Related Content

Image Gallery

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.

Scroll to Top
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

Hexload III

Date: 198x
Type: Cassette
Platform(s): TS 1000

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
1REM — stores the machine code routine
10–30LIST mode: display memory from address
100–150WRITE mode: accept hex byte string, poke into memory
200–250INSERT mode: insert byte(s) into memory
300–340DELETE mode: delete byte(s) from memory
400–420Save routine: dimension output buffer, save to tape
500–520Load/quit: calls USR 16669, then CLEAR and STOP
600–670Shared 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 AddressDecimal Offset in REMPurpose
16539146LIST — dump memory bytes in hex
16589196WRITE — write input hex string to memory
16635242Return buffer size for DIM at line 400
16651258Save helper
16669276Load helper
16687294INSERT — insert bytes into memory block
16732339DELETE — 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

Appears On

Related Products

Related Articles

Related Content

Image Gallery

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.

Scroll to Top
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.

People

No people associated with this content.

Scroll to Top