Machine Code Loader/Editor

This file is part of and 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

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
 1000 CLS 
 1005 PRINT "THE CODE WILL BE COPIED INTO"
 1006 PRINT "MEMORY STARTING AT 16514."
 1010 PRINT "START ADDRESS: ";
 1020 INPUT ST
 1025 PRINT ST
 1030 PRINT "END ADDRESS: ";
 1035 INPUT EN
 1040 PRINT EN
 1045 LET SA=16514
 1050 FOR J=ST TO EN
 1055 POKE SA,PEEK J
 1060 LET SA=SA+1
 1070 NEXT J
 1080 GOTO 2
 1100 CLS 
 1110 PRINT "START ADDRESS OF CODE"
 1120 PRINT "THAT IS TO BE COPIED: ";
 1130 INPUT ST
 1140 PRINT ST
 1150 PRINT "END ADDRESS: ";
 1160 INPUT EN
 1170 PRINT EN
 1180 PRINT "ADDRESS TO BE COPIED TO: ";
 1190 INPUT C
 1191 PRINT C
 1193 LET N=0
 1194 FOR J=ST TO EN
 1195 POKE (N+C),PEEK J
 1196 LET N=N+1
 1197 NEXT J
 1198 GOTO 2
 1200 CLS 
 1202 PRINT "START ADDRESS FOR SEARCH: ";
 1203 INPUT A
 1204 PRINT A
 1205 PRINT "END ADDRESS FOR SEARCH: ";
 1206 INPUT E
 1207 PRINT E
 1208 PRINT "BYTE TO BE SEARCHED FOR: ";
 1209 INPUT Q$
 1210 PRINT Q$
 1211 LET N=((CODE Q$-28)*16+(CODE Q$(2)-28))
 1212 FOR J=A TO E
 1213 IF PEEK J=N THEN PRINT J
 1214 NEXT J
 1215 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% % % "
 1216 INPUT Q$
 1217 GOTO 2
 9000 SAVE "1000%3"
 9010 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