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 **
\n9005 REM ** 714-630-2488 **
\n9010 REM 8/1/N 300/1200 BAUD
\n9015 REM % % % % % % %O%K% %T%O% %R%U%N% % % % % %
\n9020 REM PROGRAM IS DESIGNED TO AID IN CONVERTING NUMBERS FOR MACHINE CODE APPLICATIONS
\n9025 REM MAY BE ADDED TO ANY CURRENT PROGRAM AND RENUMBERED
\n9030 REM WITH THE DELPHIC TOOLKIT WITHOUT ANY CHANGE
\n9035 FAST
\n9040 CLS
\n9045 GOSUB 9650
\n9050 LET Y$="TIMEX 1000"
\n9055 PRINT AT 2,11;Y$
\n9060 PRINT AT 3,7;"PROGRAMING UTILITES"
\n9065 PRINT AT 8,3;"1) HEX TO DEC."
\n9070 PRINT AT 10,3;"2) DEC TO HEX."
\n9075 PRINT AT 12,3;"3) 2 BYTE CONVERTER."
\n9080 PRINT AT 14,3;"4) SAVE PROGRAM."
\n9085 PRINT AT 16,3;"5) STOP."
\n9090 PRINT AT 20,6;"% %E%N%T%E%R% %Y%O%U%R% %C%H%O%I%C%E% "
\n9095 INPUT B
\n9100 IF B=2 THEN GOTO 9315
\n9105 IF B=3 THEN GOTO 9480
\n9110 IF B=4 THEN GOTO 9725
\n9115 IF B=5 THEN STOP
\n9120 REM **** HEX TO DEC *****
\n9125 REM ***********************
\n9130 CLS
\n9135 LET A=8
\n9140 FAST
\n9145 GOSUB 9650
\n9150 SLOW
\n9155 PRINT AT 2,11;Y$
\n9160 PRINT AT 3,3;"** HEX TO DEC CONVERTER **"
\n9165 PRINT AT 7,10;"""0"" ABORTS";AT 8,6;"""T"" FOR DEC TO HEX"
\n9170 FOR F=1 TO 2
\n9175 PRINT AT 20,1;"% %E%N%T%E%R% %H%E%X% %N%U%M%B%E%R% "
\n9180 FOR J=1 TO 20
\n9185 NEXT J
\n9190 PRINT AT 20,1;" ENTER HEX NUMBER "
\n9195 FOR J=1 TO 20
\n9200 NEXT J
\n9205 NEXT F
\n9210 LET T=0
\n9215 INPUT H$
\n9220 LET D=1
\n9225 IF H$="0" THEN GOTO 9035
\n9230 IF H$="T" THEN GOTO 9325
\n9235 FOR P=LEN (H$)-1 TO 0 STEP -1
\n9240 LET C=CODE (H$(D TO D))
\n9245 LET D=D+1
\n9250 IF C>=28 AND C<=37 THEN LET C=C-28
\n9255 IF C>=28 AND C<=37 THEN GOTO 9270
\n9260 IF C>=38 AND C<=43 THEN LET C=C-28
\n9265 GOTO 9270
\n9270 LET T=T+C*16**P
\n9275 NEXT P
\n9280 LET A=A+2
\n9285 IF A>18 THEN GOSUB 9455
\n9290 PRINT AT A,4;"HEX: ";H$;" = ";T;" DEC"
\n9295 GOTO 9170
\n9300 REM ***********************
\n9305 REM **** DEC TO HEX *****
\n9310 REM ***********************
\n9315 CLS
\n9320 GOSUB 9650
\n9325 GOSUB 9455
\n9330 PRINT AT 3,3;"** DEC TO HEX CONVERTER **"
\n9335 PRINT AT 8,5;"123456 FOR HEX TO DEC"
\n9340 LET A=8
\n9345 LET A=A+2
\n9350 LET A$="0123456789ABCDEF"
\n9355 PRINT AT 20,1;"% %E%N%T%E%R% %D%E%C% %N%U%M%B%E%R% "
\n9360 FOR F=1 TO 20
\n9365 NEXT F
\n9370 PRINT AT 20,1;" ENTER DEC NUMBER "
\n9375 INPUT Q
\n9380 IF Q=0 THEN GOTO 9035
\n9385 IF Q=123456 THEN GOTO 9130
\n9390 IF Q>65535 OR Q<0 THEN PRINT "TRY AGAIN"
\n9395 IF Q>65535 OR Q<0 THEN GOTO 400
\n9400 LET D=INT (Q/4096)
\n9405 LET R=Q-4096*D
\n9410 LET E=INT (R/256)
\n9415 LET R=R-256*E
\n9420 LET H=INT (R/16)
\n9425 LET L=R-16*H
\n9430 IF A>18 THEN GOSUB 9455
\n9435 PRINT AT A,4;"DEC: ";Q;" = ";
\n9440 IF A>18 THEN GOSUB 9455
\n9445 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"
\n9450 GOTO 9345
\n9455 FOR F=2 TO 10 STEP 2
\n9460 PRINT AT 8+F,4;" "
\n9465 NEXT F
\n9470 LET A=10
\n9475 RETURN
\n9480 REM ***********************
\n9485 REM ** 2 BYTE CONVERTER **
\n9490 REM ***********************
\n9495 CLS
\n9500 FAST
\n9505 GOSUB 9650
\n9510 SLOW
\n9515 PRINT AT 2,10;Y$
\n9520 PRINT AT 3,4;"** 2 BYTE CONVERTER **"
\n9525 FOR F=1 TO 2
\n9530 FOR J=0 TO 10
\n9535 NEXT J
\n9540 PRINT AT 20,1;"% %E%N%T%E%R% %N%U%M%B%E%R% ";AT 20,20;"""0"" ABORTS"
\n9545 FOR J=0 TO 10
\n9550 NEXT J
\n9555 PRINT AT 20,1;" ENTER NUMBER "
\n9560 NEXT F
\n9565 INPUT N
\n9570 GOSUB 9630
\n9575 IF N=0 THEN GOTO 9035
\n9580 IF N>65535 OR N<1 THEN GOTO 9700
\n9585 PRINT AT 8,12;N
\n9590 REM % %P%L%A%C%E%S% %N%U%M%B%E%R% %I%N%T%O%
\n9595 REM % %S%Y%S%T%E%M% %V%A%R%I%A%B%L%E% %"%S%E%E%D%"
\n9600 REM % %T%H%E%N% %H%A%S% %C%O%M%P%U%T%E%R% % % % %
\n9605 REM % %O%U%T%P%U%T% %C%O%N%T%E%N%T%S% %
\n9610 RAND N
\n9615 PRINT AT 10,8;"LEAST BYTE= ";PEEK 16434
\n9620 PRINT AT 12,8;"MOST BYTE= ";PEEK 16435
\n9625 GOTO 9525
\n9630 PRINT AT 8,12;" "
\n9635 PRINT AT 10,19;" "
\n9640 PRINT AT 12,19;" "
\n9645 RETURN
\n9650 FOR F=0 TO 43
\n9655 PLOT 0,F
\n9660 PLOT 63,F
\n9665 NEXT F
\n9670 FOR F=0 TO 63
\n9675 PLOT F,43
\n9680 PLOT F,32
\n9685 PLOT F,0
\n9690 NEXT F
\n9695 RETURN
\n9700 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% % "
\n9705 FOR F=0 TO 100
\n9710 NEXT F
\n9715 PRINT AT 20,1;" "
\n9720 GOTO 9525
\n9725 SAVE "2 BYT%E"
\n9730 GOTO 9035
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
