Machine Code Loader/Editor

This file is part of Timex Sinclair Public Domain Library Tape 1001 . Download the collection to get this file.
Date: 198x
Type: Program
Platform(s): TS 1000

This program is a machine code loader and editor for the ZX81/TS1000, providing a 12-option menu for working with raw memory. Features include writing hex-encoded bytes to arbitrary addresses, listing memory contents as hexadecimal, editing individual bytes, moving and copying memory blocks, deleting (zeroing) ranges, running routines via RAND USR, adjusting RAMTOP by directly POKEing system variables 16388/16389, and searching memory for a specific byte value. Hex input and output are handled using a custom encoding where hex nibbles are represented as characters offset by 28 from their ASCII code values (since ZX81 character codes begin at 28 for ‘0’). The move function uses a 300-element DIM array as a buffer and supports both upward and downward displacement.


Program Analysis

Program Structure

The program is organized as a main menu dispatcher followed by numbered subroutine blocks. Lines 2–31 handle the menu display and dispatch; all functional routines begin at line 200 or higher and return to the menu via GOTO 2. The REM at line 1 is a ruler of digit characters used for column alignment during development.

LinesFunction
2–31Menu display and dispatch
200–290Write code (hex input)
300–397List code (hex output)
400–470Save program to tape
500–590Run machine code via RAND USR
600–696Edit a single byte
700–791Delete (zero) a memory range
800–870Move a block of code (up or down)
900–960Adjust RAMTOP
1000–1080Copy code to address 16514
1100–1198Copy code to arbitrary address
1200–1217Search memory for a byte value
9000–9010Auto-save and auto-run stub

Hex Encoding Scheme

All hex input and output uses a character-offset encoding. On the ZX81/TS1000, the character code for '0' is 28, so the digit characters '0'–'9' map to codes 28–37 and the hex letters 'A'–'F' map to codes 37–42 (since ‘A’ follows the digits in the ZX81 character set). A two-character hex pair is decoded as:

(CODE A$-28)*16 + (CODE A$(2)-28)

The same arithmetic is reversed for display: Q=INT(P/16) gives the high nibble and NIC=((P/16)-Q)*16 gives the low nibble, then CHR$(Q+28)+CHR$(NIC+28) prints the hex digits. The variable name NIC is notable as a named variable rather than a single letter, unusual for ZX81 BASIC space economy.

Write Code Routine (Lines 200–290)

The write routine accepts a multi-character string at a time and processes it two characters per iteration. The loop strips consumed characters using A$(3 TO ), allowing the user to type a run of hex pairs before pressing ENTER. Entering "S" terminates entry and returns to the menu. A blank input loops back to re-prompt, so the user can enter pairs across multiple INPUT statements, advancing the address pointer N after each byte.

Move Routine (Lines 800–870)

The move function allocates a DIM D(300) array as a staging buffer, limiting moves to 299 bytes. It reads bytes from the source range into D(), then writes them to the destination. The direction ("UP" or "DOWN") determines whether the destination is BEG+DIS or BEG-DIS, and the vacated source region is zeroed after the copy. This two-pass approach avoids overlap corruption for non-overlapping moves, but overlapping moves of more than one byte in the same direction may still corrupt data depending on offset.

RAMTOP Adjustment (Lines 900–960)

The RAMTOP system variable is stored as a 16-bit little-endian value at addresses 16388 and 16389. The routine splits the user-supplied value NE into its low byte (NE-256*INT(NE/256)) and high byte (INT(NE/256)) and POKEs them directly. This is the standard ZX81 technique for reserving space above RAMTOP for machine code that survives NEW.

“Move Code Down to Save It” (Lines 1000–1080)

Option 9 copies a user-specified address range to a fixed destination of 16514, which is the start of the ZX81 display file in a standard 1K RAM configuration. This is intended to relocate machine code to a predictable low address before saving. The label in the menu says “MOVE CODE DOWN TO SAVE IT,” but the routine is actually a copy (the source is not zeroed).

Notable Techniques

  • Inverse-video text in PRINT statements (lines 201–203, 570, 1215) is rendered using the %X escape convention, making banners stand out without cursor positioning tricks.
  • The delay loop at lines 530–540 (FOR I=1 TO 20: NEXT I) before running machine code gives a brief pause and performs a final CLS before RAND USR at line 560.
  • The auto-run stub at lines 9000–9010 uses SAVE "1000" (where is an inverse character acting as the auto-run flag byte) followed by RUN, the standard ZX81 auto-run save idiom.
  • The search routine (lines 1200–1217) accepts hex input in the same two-character encoding used throughout, keeping the interface consistent.

Bugs and Anomalies

  • The move-down zeroing loop at lines 866–868 uses FOR J=(END-DIS) TO END rather than FOR J=(BEG-DIS) TO (BEG); this zeros the wrong region (end of destination rather than the vacated source tail), leaving old bytes in place.
  • The variable name END at line 816 shadows the BASIC keyword END (not used in ZX81 BASIC, but the tokeniser may handle it unpredictably on some variants).
  • The listing routine (lines 300–397) reassigns Q (already used as the high-nibble integer) at line 395 to hold the user’s Y/N response string, mixing numeric and string use of the base name — however, since Q$ and Q are distinct variables in BASIC this is not an error.
  • Option 8 (“SAVE SPACE ABOVE RAMTOP”) adjusts RAMTOP but does not perform any actual SAVE; the user must separately invoke option 11 to save.

Content

Appears On

Assembled by Tim Ward from many sources. Contains programs 10001 – 10050.

Related Products

Related Articles

Related Content

Image Gallery

Machine Code Loader/Editor

Source Code

   1 REM 111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999000000000011111111112222222222333333333344444444445555555555666666666677777777778888888888999999999900000000001111111111222222222233333333334444444444555555555566666666667777777777888888888899999999990000000000
   2 CLS 
   3 PRINT "T/S 1000 MACH CODE LOADER/EDITOR"
   4 PRINT AT 2,0;"DO YOU WISH TO...",,,
   5 PRINT " 1)...WRITE CODE?"
   6 PRINT " 2)...LIST CODE?"
   7 PRINT " 3)...EDIT CODE?"
   8 PRINT " 4)...MOVE CODE?"
   9 PRINT " 5)...COPY CODE?"
  10 PRINT " 6)...DELETE CODE?"
  11 PRINT " 7)...RUN CODE?"
  12 PRINT " 8)...SAVE SPACE ABOVE RAMTOP?"
  13 PRINT " 9)...MOVE CODE DOWN TO SAVE IT?"
  14 PRINT "10)...SEARCH FOR A GIVEN BYTE?"
  15 PRINT "11)...SAVE PROGRAM AND CODE?"
  16 PRINT "12)...QUIT PROGRAM?",,,
  17 PRINT "ENTER NBR. OF SELECTION."
  18 INPUT A
  19 IF A<1 OR A>12 THEN GOTO 18
  20 IF A=1 THEN GOTO 200
  21 IF A=2 THEN GOTO 300
  22 IF A=3 THEN GOTO 600
  23 IF A=4 THEN GOTO 800
  24 IF A=5 THEN GOTO 1100
  25 IF A=6 THEN GOTO 700
  26 IF A=7 THEN GOTO 500
  27 IF A=8 THEN GOTO 900
  28 IF A=9 THEN GOTO 1000
  29 IF A=10 THEN GOTO 1200
  30 IF A=11 THEN GOTO 400
  31 IF A=12 THEN STOP 
 200 CLS 
 201 PRINT ,,"%E%N%T%E%R% %A%D%D%R%E%S%S% %I%N% %D%E%C%I%M%A%L% % % % % % % % "
 202 PRINT "%E%N%T%E%R% %C%O%D%E% %I%N% %H%E%X%A%D%E%C%I%M%A%L% % % % % % % "
 203 PRINT "%E%N%D% %C%O%D%E% %B%Y% %E%N%T%E%R%I%N%G% %"%S%"% % % % % % % % "
 210 PRINT ,,"ADDRESS TO WRITE TO:";
 220 INPUT N
 225 PRINT N
 230 LET A$=""
 240 IF A$="" THEN INPUT A$
 250 IF A$="S" THEN GOTO 2
 260 POKE N,((CODE A$-28)*16+(CODE A$(2)-28))
 270 LET N=N+1
 280 LET A$=A$(3 TO )
 290 GOTO 240
 300 CLS 
 302 PRINT "START ADDRESS: ";
 310 INPUT W
 320 PRINT W
 330 PRINT "END ADDRESS: ";
 340 INPUT Y
 350 PRINT Y
 360 FOR M=W TO Y
 370 LET P=PEEK M
 380 LET Q=INT (P/16)
 390 LET NIC=((P/16)-Q)*16
 391 PRINT M;"     ";CHR$ (Q+28)+CHR$ (NIC+28)
 392 NEXT M
 393 PRINT 
 394 PRINT "ANY MORE LISTING? (Y/N)"
 395 INPUT Q$
 396 IF Q$<>"Y" THEN GOTO 2
 397 GOTO 300
 400 CLS 
 410 PRINT "SAVE AS: ";
 420 INPUT S$
 430 PRINT S$
 440 PRINT "START TAPE AND PRESS ENTER"
 450 INPUT Q$
 460 SAVE S$
 470 GOTO 2
 500 CLS 
 501 PRINT "ADDRESS OF ROUTINE: ";
 510 INPUT ADR
 520 PRINT ADR
 525 CLS 
 530 FOR I=1 TO 20
 540 NEXT I
 550 CLS 
 560 RAND USR ADR
 570 PRINT AT 20,0;"%T%O% %R%E%T%U%R%N% %T%O% %M%E%N%U% %P%R%E%S%S% %E%N%T%E%R% % % "
 580 INPUT Q$
 590 GOTO 2
 600 CLS 
 610 PRINT "ADDRESS OF BYTE: ";
 620 INPUT BY
 630 PRINT BY
 632 PRINT "PRESENT VALUE: ";
 633 LET P=PEEK BY
 634 LET Q=INT (P/16)
 635 LET NIC=((P/16)-Q)*16
 636 PRINT CHR$ (Q+28)+CHR$ (NIC+28)
 640 PRINT "CHANGE TO: ";
 650 INPUT C$
 660 PRINT C$
 670 POKE BY,((CODE C$-28)*16+(CODE C$(2)-28))
 673 FOR J=1 TO 15
 674 NEXT J
 680 PRINT "ANY MORE EDITING? (Y/N)"
 690 INPUT Q$
 695 IF Q$<>"Y" THEN GOTO 2
 696 GOTO 600
 700 CLS 
 710 PRINT "START ADDRESS: ";
 720 INPUT ST
 730 PRINT ST
 740 PRINT "END ADDRESS: ";
 750 INPUT EN
 760 PRINT EN
 770 FOR J=ST TO EN
 780 POKE J,0
 790 NEXT J
 791 GOTO 2
 800 DIM D(300)
 801 CLS 
 802 LET TOT=1
 805 PRINT "MOVE ""UP"" OR ""DOWN""?"
 806 INPUT M$
 807 PRINT M$
 809 PRINT 
 810 PRINT "START ADDRESS: ";
 811 INPUT BEG
 813 PRINT BEG
 814 PRINT "END ADDRESS OF CODE: ";
 816 INPUT END
 817 PRINT END
 818 IF END-BEG>299 THEN PRINT "YOU MAY ONLY MOVE 299 BYTES."
 819 IF END-BEG>299 THEN GOTO 800
 820 PRINT "DISPLACEMENT: ";
 821 INPUT DIS
 822 PRINT DIS
 823 FOR J=BEG TO END
 824 LET D(TOT)=PEEK J
 825 LET TOT=TOT+1
 827 NEXT J
 829 IF M$="DOWN" THEN GOTO 860
 835 LET TOT=1
 836 FOR J=(BEG+DIS) TO (END+DIS)
 837 POKE J,D(TOT)
 838 LET TOT=TOT+1
 839 NEXT J
 840 FOR J=BEG TO (BEG+DIS-1)
 841 POKE J,0
 850 NEXT J
 851 GOTO 2
 860 LET TOT=1
 862 FOR J=(BEG-DIS) TO (END-DIS)
 863 POKE J,D(TOT)
 864 LET TOT=TOT+1
 865 NEXT J
 866 FOR J=(END-DIS) TO END
 867 POKE J,0
 868 NEXT J
 870 GOTO 2
 900 CLS 
 910 PRINT "NEW RAMTOP IS: ";
 920 INPUT NE
 930 PRINT NE
 940 POKE 16388,NE-256*INT (NE/256)
 950 POKE 16389,INT (NE/256)
 960 GOTO 2
\n1000 CLS 
\n1005 PRINT "THE CODE WILL BE COPIED INTO"
\n1006 PRINT "MEMORY STARTING AT 16514."
\n1010 PRINT "START ADDRESS: ";
\n1020 INPUT ST
\n1025 PRINT ST
\n1030 PRINT "END ADDRESS: ";
\n1035 INPUT EN
\n1040 PRINT EN
\n1045 LET SA=16514
\n1050 FOR J=ST TO EN
\n1055 POKE SA,PEEK J
\n1060 LET SA=SA+1
\n1070 NEXT J
\n1080 GOTO 2
\n1100 CLS 
\n1110 PRINT "START ADDRESS OF CODE"
\n1120 PRINT "THAT IS TO BE COPIED: ";
\n1130 INPUT ST
\n1140 PRINT ST
\n1150 PRINT "END ADDRESS: ";
\n1160 INPUT EN
\n1170 PRINT EN
\n1180 PRINT "ADDRESS TO BE COPIED TO: ";
\n1190 INPUT C
\n1191 PRINT C
\n1193 LET N=0
\n1194 FOR J=ST TO EN
\n1195 POKE (N+C),PEEK J
\n1196 LET N=N+1
\n1197 NEXT J
\n1198 GOTO 2
\n1200 CLS 
\n1202 PRINT "START ADDRESS FOR SEARCH: ";
\n1203 INPUT A
\n1204 PRINT A
\n1205 PRINT "END ADDRESS FOR SEARCH: ";
\n1206 INPUT E
\n1207 PRINT E
\n1208 PRINT "BYTE TO BE SEARCHED FOR: ";
\n1209 INPUT Q$
\n1210 PRINT Q$
\n1211 LET N=((CODE Q$-28)*16+(CODE Q$(2)-28))
\n1212 FOR J=A TO E
\n1213 IF PEEK J=N THEN PRINT J
\n1214 NEXT J
\n1215 PRINT "%P%R%E%S%S% %E%N%T%E%R% %T%O% %R%E%T%U%R%N% %T%O% %M%E%N%U% % % "
\n1216 INPUT Q$
\n1217 GOTO 2
\n9000 SAVE "1000%3"
\n9010 RUN 

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

People

No people associated with this content.

Scroll to Top