Programming Utilities

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

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:

  1. Main menu (9035–9115): Displays five options and branches on numeric input.
  2. Hex-to-Dec converter (9120–9295): String parsing loop with character-code arithmetic.
  3. Dec-to-Hex converter (9305–9450): Successive division by powers of 16 with a lookup string.
  4. 2-Byte converter (9480–9645): Uses RAND and PEEK to split a 16-bit value.
  5. Shared subroutines: Border-drawing (9650–9695), scroll-clear (9455–9475), field-clear (9630–9645), and error display (9700–9720).
  6. 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 typeCode rangeOperationResult range
Digits 0–928–37C = C - 280–9
Letters A–F38–43C = 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 nibble
  • E = INT(R/256) — second nibble
  • H = INT(R/16) — third nibble
  • L = 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 — stores N as 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 400 rather than GOTO 9400 — a clear typo that would cause a runtime error for out-of-range decimal inputs.
  • The FAST/SLOW pairs 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

Appears On

One individual’s cassette containing a number of programs.

Related Products

Related Articles

Related Content

Image Gallery

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.

People

No people associated with this content.

Scroll to Top