This ZX81/TS1000 BASIC utility provides three number-base conversion tools for machine code programmers: hexadecimal-to-decimal, decimal-to-hexadecimal, and a two-byte (LSB/MSB) splitter. The hex-to-decimal converter manually parses each character of an input string using ZX81 character codes (digits map to codes 28–37, letters A–F to 38–43), then multiplies each nibble by the appropriate power of 16. The two-byte converter exploits the ZX81’s RAND statement, which stores its argument in the SEED system variable at addresses 16434–16435, to extract the least-significant and most-significant bytes of any 16-bit value without machine code. The program is explicitly designed to be renumbered and embedded into other programs using the Delphic Toolkit.
Program Structure
The program begins at line 9000, consistent with its stated purpose of being appended to existing programs and renumbered. It is organised into clearly delineated subroutines and sections:
- Main menu (9035–9115): Displays five options and branches on numeric input.
- Hex-to-Dec converter (9120–9295): String parsing loop with character-code arithmetic.
- Dec-to-Hex converter (9305–9450): Successive division by powers of 16 with a lookup string.
- 2-Byte converter (9480–9645): Uses
RANDandPEEKto split a 16-bit value. - Shared subroutines: Border-drawing (9650–9695), scroll-clear (9455–9475), field-clear (9630–9645), and error display (9700–9720).
- Save and exit (9725–9730).
Hex-to-Decimal Converter
The converter at lines 9215–9275 manually parses a hex string entered as H$. It iterates from the most-significant to least-significant character, converting each to a numeric nibble via ZX81 character codes:
| Character type | Code range | Operation | Result range |
|---|---|---|---|
| Digits 0–9 | 28–37 | C = C - 28 | 0–9 |
| Letters A–F | 38–43 | C = C - 28 (yields 10–15) | 10–15 |
There is a subtle bug at line 9255: after the first IF C>=28 AND C<=37 subtracts 28, the condition at line 9260 checks IF C>=38 AND C<=43, which can never be true after subtraction. However, line 9255 also has an erroneous GOTO 9270 guard (line 9255 does not branch, unlike 9260). In practice, letters A–F (codes 38–43) fall through correctly: the first IF at 9250 does not fire (38>37), so control reaches 9260 where subtraction of 28 yields 10–15. The logic accidentally works despite the redundant second condition check on line 9255.
Decimal-to-Hex Converter
This section (9350–9445) uses the string A$="0123456789ABCDEF" as a nibble lookup table. The 16-bit decimal value Q is decomposed by successive integer division:
D = INT(Q/4096)— most-significant nibbleE = INT(R/256)— second nibbleH = INT(R/16)— third nibbleL = R - 16*H— least-significant nibble
Each nibble indexes into A$ with A$(D+1 TO D+1), exploiting ZX81 BASIC’s one-based string slicing. Input of 123456 is used as a magic number to switch to the hex-to-dec converter (line 9385), and 0 returns to the main menu.
There is a bug at line 9395: GOTO 400 (without the 9000-block prefix) is almost certainly a typographical error for GOTO 9400. In context the intent is to re-prompt after a bounds error, but line 400 does not exist, which would cause an error at runtime for out-of-range values.
Two-Byte Converter
The most elegant technique in the program appears at lines 9610–9620. Rather than implementing bit-shifting arithmetic, the converter exploits the ZX81 system variable SEED (used by RAND) stored at addresses 16434 (LSB) and 16435 (MSB):
RAND N— storesNas a 16-bit integer into SEED.PEEK 16434— reads the least-significant byte.PEEK 16435— reads the most-significant byte.
This avoids any division or masking arithmetic and produces correct results for any value 1–65535. Zero is treated as an abort condition (line 9575) and redirects to the main menu.
Display and UI Techniques
The border-drawing subroutine at 9650–9695 uses PLOT to draw a rectangular frame: vertical sides by iterating Y from 0 to 43, and three horizontal lines (top, a mid-divider at Y=32, and bottom at Y=0). The % % sequences in PRINT statements produce flashing/inverse text effects by using ZX81 character alternation — here they animate the prompt text by printing the string twice in a short FOR loop (lines 9170–9205, 9525–9560), toggling between the percent-decorated version and a plain version to simulate flashing without FLASH.
The scroll-clearing subroutine at 9455–9475 clears result lines by printing spaces over rows 10–18, then resets the row counter A to 10. This prevents results from scrolling off the decorated border.
Notable Anomalies
- Line 9395 references
GOTO 400rather thanGOTO 9400— a clear typo that would cause a runtime error for out-of-range decimal inputs. - The
FAST/SLOWpairs around the border subroutine calls (e.g. lines 9140/9150, 9500/9510) draw the border quickly in FAST mode then return to SLOW for user interaction — a standard ZX81 speed optimisation idiom.
Content
Source Code
9000 REM ** ROCKETTER BBS **
9005 REM ** 714-630-2488 **
9010 REM 8/1/N 300/1200 BAUD
9015 REM % % % % % % %O%K% %T%O% %R%U%N% % % % % %
9020 REM PROGRAM IS DESIGNED TO AID IN CONVERTING NUMBERS FOR MACHINE CODE APPLICATIONS
9025 REM MAY BE ADDED TO ANY CURRENT PROGRAM AND RENUMBERED
9030 REM WITH THE DELPHIC TOOLKIT WITHOUT ANY CHANGE
9035 FAST
9040 CLS
9045 GOSUB 9650
9050 LET Y$="TIMEX 1000"
9055 PRINT AT 2,11;Y$
9060 PRINT AT 3,7;"PROGRAMING UTILITES"
9065 PRINT AT 8,3;"1) HEX TO DEC."
9070 PRINT AT 10,3;"2) DEC TO HEX."
9075 PRINT AT 12,3;"3) 2 BYTE CONVERTER."
9080 PRINT AT 14,3;"4) SAVE PROGRAM."
9085 PRINT AT 16,3;"5) STOP."
9090 PRINT AT 20,6;"% %E%N%T%E%R% %Y%O%U%R% %C%H%O%I%C%E% "
9095 INPUT B
9100 IF B=2 THEN GOTO 9315
9105 IF B=3 THEN GOTO 9480
9110 IF B=4 THEN GOTO 9725
9115 IF B=5 THEN STOP
9120 REM **** HEX TO DEC *****
9125 REM ***********************
9130 CLS
9135 LET A=8
9140 FAST
9145 GOSUB 9650
9150 SLOW
9155 PRINT AT 2,11;Y$
9160 PRINT AT 3,3;"** HEX TO DEC CONVERTER **"
9165 PRINT AT 7,10;"""0"" ABORTS";AT 8,6;"""T"" FOR DEC TO HEX"
9170 FOR F=1 TO 2
9175 PRINT AT 20,1;"% %E%N%T%E%R% %H%E%X% %N%U%M%B%E%R% "
9180 FOR J=1 TO 20
9185 NEXT J
9190 PRINT AT 20,1;" ENTER HEX NUMBER "
9195 FOR J=1 TO 20
9200 NEXT J
9205 NEXT F
9210 LET T=0
9215 INPUT H$
9220 LET D=1
9225 IF H$="0" THEN GOTO 9035
9230 IF H$="T" THEN GOTO 9325
9235 FOR P=LEN (H$)-1 TO 0 STEP -1
9240 LET C=CODE (H$(D TO D))
9245 LET D=D+1
9250 IF C>=28 AND C<=37 THEN LET C=C-28
9255 IF C>=28 AND C<=37 THEN GOTO 9270
9260 IF C>=38 AND C<=43 THEN LET C=C-28
9265 GOTO 9270
9270 LET T=T+C*16**P
9275 NEXT P
9280 LET A=A+2
9285 IF A>18 THEN GOSUB 9455
9290 PRINT AT A,4;"HEX: ";H$;" = ";T;" DEC"
9295 GOTO 9170
9300 REM ***********************
9305 REM **** DEC TO HEX *****
9310 REM ***********************
9315 CLS
9320 GOSUB 9650
9325 GOSUB 9455
9330 PRINT AT 3,3;"** DEC TO HEX CONVERTER **"
9335 PRINT AT 8,5;"123456 FOR HEX TO DEC"
9340 LET A=8
9345 LET A=A+2
9350 LET A$="0123456789ABCDEF"
9355 PRINT AT 20,1;"% %E%N%T%E%R% %D%E%C% %N%U%M%B%E%R% "
9360 FOR F=1 TO 20
9365 NEXT F
9370 PRINT AT 20,1;" ENTER DEC NUMBER "
9375 INPUT Q
9380 IF Q=0 THEN GOTO 9035
9385 IF Q=123456 THEN GOTO 9130
9390 IF Q>65535 OR Q<0 THEN PRINT "TRY AGAIN"
9395 IF Q>65535 OR Q<0 THEN GOTO 400
9400 LET D=INT (Q/4096)
9405 LET R=Q-4096*D
9410 LET E=INT (R/256)
9415 LET R=R-256*E
9420 LET H=INT (R/16)
9425 LET L=R-16*H
9430 IF A>18 THEN GOSUB 9455
9435 PRINT AT A,4;"DEC: ";Q;" = ";
9440 IF A>18 THEN GOSUB 9455
9445 PRINT A$(D+1 TO D+1);A$(E+1 TO E+1);A$(H+1 TO H+1);A$(L+1 TO L+1);" HEX"
9450 GOTO 9345
9455 FOR F=2 TO 10 STEP 2
9460 PRINT AT 8+F,4;" "
9465 NEXT F
9470 LET A=10
9475 RETURN
9480 REM ***********************
9485 REM ** 2 BYTE CONVERTER **
9490 REM ***********************
9495 CLS
9500 FAST
9505 GOSUB 9650
9510 SLOW
9515 PRINT AT 2,10;Y$
9520 PRINT AT 3,4;"** 2 BYTE CONVERTER **"
9525 FOR F=1 TO 2
9530 FOR J=0 TO 10
9535 NEXT J
9540 PRINT AT 20,1;"% %E%N%T%E%R% %N%U%M%B%E%R% ";AT 20,20;"""0"" ABORTS"
9545 FOR J=0 TO 10
9550 NEXT J
9555 PRINT AT 20,1;" ENTER NUMBER "
9560 NEXT F
9565 INPUT N
9570 GOSUB 9630
9575 IF N=0 THEN GOTO 9035
9580 IF N>65535 OR N<1 THEN GOTO 9700
9585 PRINT AT 8,12;N
9590 REM % %P%L%A%C%E%S% %N%U%M%B%E%R% %I%N%T%O%
9595 REM % %S%Y%S%T%E%M% %V%A%R%I%A%B%L%E% %"%S%E%E%D%"
9600 REM % %T%H%E%N% %H%A%S% %C%O%M%P%U%T%E%R% % % % %
9605 REM % %O%U%T%P%U%T% %C%O%N%T%E%N%T%S% %
9610 RAND N
9615 PRINT AT 10,8;"LEAST BYTE= ";PEEK 16434
9620 PRINT AT 12,8;"MOST BYTE= ";PEEK 16435
9625 GOTO 9525
9630 PRINT AT 8,12;" "
9635 PRINT AT 10,19;" "
9640 PRINT AT 12,19;" "
9645 RETURN
9650 FOR F=0 TO 43
9655 PLOT 0,F
9660 PLOT 63,F
9665 NEXT F
9670 FOR F=0 TO 63
9675 PLOT F,43
9680 PLOT F,32
9685 PLOT F,0
9690 NEXT F
9695 RETURN
9700 PRINT AT 20,1;"% %N%U%M%B%E%R% %T%O% %L%A%R%G%E% %O%R% %T%O% %S%M%A%L%L% % "
9705 FOR F=0 TO 100
9710 NEXT F
9715 PRINT AT 20,1;" "
9720 GOTO 9525
9725 SAVE "2 BYT%E"
9730 GOTO 9035
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
