Hexload I & II

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

Two BASIC tools for typing machine code in as hexadecimal. HEXLOAD I is eight lines long: it POKEs pairs of hex digits into memory from address 30000 until you enter S. HEXLOAD II takes a four-digit hex start address, echoes each byte as it is entered, and adds a text mode in which characters typed between semicolons are stored as ZX81 character codes. It also has a routine that saves a block of code starting at 4C00 hex by copying it into a string array, so the block is saved with the program. The later stages of HEXLOAD II add a prompt for a hex address and a RAND USR 16539 call meant to list memory through machine code held in REM lines.

The handwritten label reads “HEXLOAD”. The tape holds HEXLOAD I and three successive saves of HEXLOAD II. Part 1 is the write-and-save version. Part 2 replaces the restore routine with an address prompt and a machine-code call. Part 3 is the same as part 2 with three REM lines added at the top to hold machine code. Hexload III, a later program, is also in the archive.

Program Analysis

Hex Conversion

Both programs convert hex with a single expression that relies on the ZX81 character set, where the digits 0–9 (codes 28–37) are followed directly by A–F (38–43). A byte is 16*CODE A$+CODE A$(2)-476, where 476 = 17 × 28. A four-digit address is 4096*CODE A$+256*CODE A$(2)+16*CODE A$(3)+CODE A$(4)-122332, where 122332 = 4369 × 28. Input can be a long string of pairs, which the loop works through two characters at a time with A$=A$(3 TO ).

HEXLOAD II

  • Write (lines 10–140): asks “WRITE TO” for a hex address, then accepts hex pairs, printing each as it is stored. S stops the program.
  • Text mode (lines 300–380): an entry starting with ; (ZX81 code 25) switches to storing each following character’s own code until the next ;. The ** token (216) is stored as 118, the ZX81 NEWLINE character.
  • Save (lines 500–640): asks for the end address of a block starting at 4C00 hex (19456), copies the bytes into O$ with PEEK, and runs SAVE. When the tape is loaded again, the program continues at line 600, POKEs the bytes back into place and runs CLEAR to discard the array.
  • List (parts 2 and 3, lines 10–30 and 600–670): asks for a hex address, POKEs it high byte to 16534 and low byte to 16533, and calls RAND USR 16539. In part 3, those addresses fall inside the first of three REM lines (255 bytes reserved), which was meant to hold the listing routine.

Notable Techniques

  • The save routine copies code into a dimensioned string, which is saved with the program’s variables, and copies it back after loading. This keeps code stored in unreserved memory above the BASIC area across a save.
  • Text mode lets ZX81 strings and messages for machine-code routines be typed as characters instead of hex.

Potential Issues

  • In part 3, the reserved REM lines still hold the placeholder digits 1234567890…, so the listing routine called by RAND USR 16539 isn’t on this save. In part 2 there is no REM at all, and 16533–16539 fall inside the BASIC lines themselves.
  • In parts 2 and 3, line 660 runs CLEAR before returning, which erases A$. Line 40’s GOSUB 200 then has no string to convert.
  • Parts 2 and 3 keep the SAVE at line 590 but replace the restore loop at 600 with the address prompt, so a block saved from those versions isn’t put back after loading.
  • Neither program lowers RAMTOP. Code at 30000 or 4C00 sits in free memory, and the DIM O$ in the save routine is allocated in that same area, so a long program or a large block could overwrite the code before it is copied.
  • Neither program checks its input. An odd number of digits or a character outside 0–9 and A–F produces a wrong byte or an error.

Related Content

Image Gallery

Source Code

  10 PRINT "WRITE TO ";
  20 INPUT A$
  30 PRINT A$
  40 GOSUB 200
  50 PRINT 
  60 LET A$=""
  70 IF A$="" THEN INPUT A$
  80 IF A$="S" THEN STOP
  90 IF CODE A$=25 THEN GOTO 300
 100 PRINT A$( TO 2);"  ";
 110 POKE X,16*CODE A$+CODE A$(2)-476
 120 LET X=X+1
 130 LET A$=A$(3 TO )
 140 GOTO 70
 200 LET X=4096*CODE A$+256*CODE A$(2)+16*CODE A$(3)+CODE A$(4)-122332
 210 RETURN
 300 LET A$=A$(2 TO )
 310 PRINT ".";A$(1);"  ";
 320 POKE X,CODE A$
 330 IF CODE A$=216 THEN POKE X,118
 340 LET A$=A$(2 TO )
 350 LET X=X+1
 360 IF CODE A$<>25 THEN GOTO 310
 370 LET A$=A$(2 TO )
 380 GOTO 70
 500 PRINT "4C00 TO ";
 510 INPUT A$
 520 PRINT A$
 530 GOSUB 200
 540 LET Y=X-19456
 550 DIM O$(Y)
 560 FOR X=1 TO Y
 570 LET O$(X)=CHR$ PEEK (19456+X)
 580 NEXT X
 590 SAVE "█"
 600 FOR X=1 TO Y
 610 POKE 19456+X,CODE O$(X)
 620 NEXT X
 630 CLEAR
 640 STOP

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.