--- title: "Conversion" id: 56172 type: "computer_media" slug: "conversion" url: "http://localhost/computer_media/conversion/" markdown_url: "http://localhost/computer_media/conversion.md" published_at: "2024-07-21T01:56:16+00:00" modified_at: "2026-03-30T21:41:33+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/07/SCR-20240720-symg.png" excerpt: "A menu-driven unit converter handles eleven measurement types and hides a developer toolkit — renumber, rem-kill, and more — in unreachable lines at the end." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" indiv: - name: "Thomas Simon" slug: "simon-thomas" taxonomy: "indiv" url: "http://localhost/indiv/simon-thomas/" genre: - name: "Mathematics" slug: "mathematics" taxonomy: "genre" url: "http://localhost/type/mathematics/" media_type: "Program" programmers: - name: "Thomas Simon" slug: "simon-thomas" taxonomy: "indiv" url: "http://localhost/indiv/simon-thomas/" download_url: "https://archive.org/download/timex-sinclair-software-archive/Conversion%20%28198x%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/07/SCR-20240720-symg.png" media_type_tags: "Mathematics" --- This program is a unit-conversion utility offering eleven conversion types, including temperature (Celsius to Fahrenheit), length (centimeters to inches), and several pharmacist/apothecary-related measurements such as drams, grains, and milligrams. The main menu is displayed at lines 30–80, and user selection dispatches via a chain of IF/GO SUB statements to individual subroutines starting at line 210. Each conversion subroutine uses FLASH 1/FLASH 0 to highlight the result value on screen. Lines 770–820 reveal a hidden developer utility, accessible only by running those lines directly, that provides renumber, rem-kill, delete, and variable-list functions by calling machine code routines via RANDOMIZE USR with addresses computed using a bitmask technique. *** ## Program Analysis ### Program Structure The program divides cleanly into four regions: 1. **Menu display (lines 20–80):** Sets up the display and prints all eleven conversion choices. 2. **Dispatch (lines 90–200):** Reads the user’s choice into `A` and routes to the appropriate subroutine via a chain of `IF … THEN GO SUB` statements, falling through to `GO TO 30` if no valid option is entered. 3. **Conversion subroutines (lines 210–750):** Each subroutine follows the same pattern: `CLS`, print a heading, `INPUT` a value, compute the result, print it with `FLASH` highlighting, then call the shared “press any key” subroutine at line 250 before `RETURN`ing. 4. **Hidden developer utilities (lines 760–820):** A `SAVE`/verify block and a developer toolkit that is never reached during normal execution. ### Shared “Press Any Key” Subroutine Line 250 acts as a shared tail-end subroutine called by every conversion routine via `GO SUB 250`. It prints a prompt at the bottom of the screen using `PRINT AT 21,0`, waits for a keypress with `PAUSE 0`, clears the screen, and returns. The subsequent `RETURN` in the calling subroutine (e.g., line 300’s `GO SUB 250: RETURN`) correctly unwinds both stack frames. ### FLASH Highlighting of Results Each conversion result is bracketed with `FLASH 1` and `FLASH 0` inline within a single `PRINT` statement, so only the numeric answer blinks on screen while the surrounding label text remains static. This is a straightforward but effective way to draw the user’s eye to the converted value. ### Hidden Developer Toolkit (Lines 770–820) These lines are unreachable during normal program flow — line 760 is a `SAVE` command and line 200 loops back to 30 — so the toolkit can only be invoked by manually running from line 770 with `RUN 770` or `GO TO 770`. It offers four built-in utility functions: - **Renumber** — machine code at address 64048 - **Remkill** — machine code at address 64841 - **Delete (range)** — machine code at address 65017 - **Variable list** — machine code at address 65184 The target address is selected using a bitmask technique on line 770: `LET zzz=(64048 AND fff=1)+(64841 AND fff=2)+(65017 AND fff=3)+(65184 AND fff=4)`. In Sinclair BASIC, a boolean expression evaluates to 1 (true) or 0 (false), so multiplying the address by the boolean effectively selects exactly one address while zeroing out the rest. `IF NOT zzz THEN GO TO 770` rejects invalid input. Lines 810–820 pass parameters to the machine code via `POKE`s into system variables at addresses 23299–23302, then invoke the routine with `RANDOMIZE USR zzz`. The variable-list function uses `PRINT USR zzz: STOP` instead, suggesting it returns a value rather than performing an in-place operation. There is a minor bug on line 810: the first POKE calculates the low byte of `fff` as `fff - 265 * PEEK 23300` instead of the correct `fff - 256 * PEEK 23300`. This off-by-nine error would corrupt the parameter for the renumber start line when `fff >= 256`. ### Bugs and Anomalies | Line | Issue | | --- | --- | | 40, 260, 270, 290 | Consistent misspelling: “CENTEMETERS” should be “CENTIMETERS”. | | 490 | The drams-to-milliliters subroutine prints the result labeled “MILLIGRAMS” instead of “MILLILITERS”. | | 810 | Low-byte calculation uses multiplier 265 instead of 256, corrupting the parameter when `fff ≥ 256`. | | 30–80 | The menu heading and option 8 spell it “FARENHEIT”; lines 210 and 240 also use “FARENHEIT” — correct spelling is “FAHRENHEIT”. | ### Key BASIC Idioms - Chained `IF A=n THEN GO SUB …` without `ELSE` — standard dispatch pattern in Sinclair BASIC, which has no `SELECT CASE`. - Boolean arithmetic for address selection: `(address AND condition)` used as a multiply-by-boolean. - `PAUSE 0` as an indefinite wait for any keypress (line 250). - Inline `FLASH` attribute changes within a single `PRINT` to selectively highlight output. ## Source Code ``` 10 REM FECIT T. SIMON 20 BORDER 0: PAPER 0: INK 7: CLS 30 PRINT " THIS IS A CONVERSION PROGRAM"'" CHOOSE ONE OF THE FOLLOWING: "'''' 40 PRINT TAB 4;"1. CELSIUS TO FARENHEIT"';TAB 4;"2. CENTIMETERS TO INCHES";TAB 4;"3. GRAMS TO GRAINS" 50 PRINT TAB 4;"4. MILLILITERS TO OUNCES";TAB 4;"5. GRAINS TO MILLIGRAMS" 60 PRINT TAB 4;"6. DRAMS TO MILLILITERS";TAB 4;"7. DRAMS (AVDP) TO GRAINS" 70 PRINT TAB 4;"8. IMP.OZS. TO US.FL.OZ.";TAB 4;"9. IMP. GALLONS TO LITERS" 80 PRINT TAB 3;"10. POUNDS TO GRAMS";TAB 3;"11. OUNCES TO MILLILITERS" 90 INPUT A: IF A=1 THEN GO SUB 210 100 IF A=2 THEN GO SUB 260 110 IF A=3 THEN GO SUB 310 120 IF A=4 THEN GO SUB 360 130 IF A=5 THEN GO SUB 410 140 IF A=6 THEN GO SUB 460 150 IF A=7 THEN GO SUB 510 160 IF A=8 THEN GO SUB 560 170 IF A=9 THEN GO SUB 610 180 IF A=10 THEN GO SUB 660 190 IF A=11 THEN GO SUB 710 200 GO TO 30 210 CLS : PRINT "CONVERTING CELSIUS TO FAHRENHEIT"''' 220 INPUT "ENTER CELSIUS TEMPERATURE ";C 230 LET F=1.8*C+32 240 PRINT ''C;" CELSIUS= "; FLASH 1;F; FLASH 0;" FARENHEIT" 250 PRINT AT 21,0;"PRESS ANY KEY TO RESTART": PAUSE 0: CLS : RETURN 260 CLS : PRINT "CONVERTING CENTEMETERS TO INCHES" 270 INPUT "ENTER CENTEMETERS ";C 280 LET I=.3937*C 290 PRINT ''C;" CENTEMETERS = "; FLASH 1;I; FLASH 0;" INCHES" 300 GO SUB 250: RETURN 310 CLS : PRINT "CONVERTING GRAMS TO GRAINS" 320 INPUT ''"ENTER GRAMS ";G 330 LET N=15.432*G 340 PRINT ''G;" GRAMS = "; FLASH 1;N; FLASH 0;" GRAINS" 350 GO SUB 250: RETURN 360 CLS : PRINT "CONVERTING MILLILITERS TO OUNCES" 370 INPUT ''"ENTER MILLILITERS ";M 380 LET O=M/29.573 390 PRINT ''M;" MILLITERS = "; FLASH 1;O; FLASH 0;" OUNCES" 400 GO SUB 250: RETURN 410 CLS : PRINT "CONVERTING GRAINS TO MILLIGRAMS "''' 420 INPUT '"ENTER GRAINS ";N 430 LET G=N*64.799 440 PRINT N;" GRAINS = "; FLASH 1;G; FLASH 0;" MILLIGRAMS" 450 GO SUB 250: RETURN 460 CLS : PRINT "CONVERTING DRAMS TO MILLILITERS"'' 470 INPUT "ENTER DRAMS ";D 480 LET M=3.552*D 490 PRINT D;" DRAMS = "; FLASH 1;M; FLASH 0;" MILLIGRAMS" 500 GO SUB 250: RETURN 510 CLS : PRINT "CONVERTING DRAMS(AVDP) TO GRAINS" 520 INPUT "ENTER DRAMS ";D 530 LET G=27.334*D 540 PRINT ''D;" DRAMS = "; FLASH 1;G; FLASH 0;" GRAINS" 550 GO SUB 250: RETURN 560 CLS : PRINT "CONVERTING IMP.OZS. TO US.FL.OZS" 570 INPUT "ENTER IMPERIAL OUNCES ";I 580 LET U=1.041*I 590 PRINT ''I;" IMP. OUNCES = "; FLASH 1;U; FLASH 0;" US. OUNCES" 600 GO SUB 250: RETURN 610 CLS : PRINT "CONVERTING IMP.GALLONS TO LITERS"'' 620 INPUT "ENTER IMPERIAL GALLONS ";I 630 LET L=4.546*I 640 PRINT I;" IMP.GALS. = "; FLASH 1;L; FLASH 0;" LITERS" 650 GO SUB 250: RETURN 660 CLS : PRINT "CONVERTING POUNDS TO GRAMS"'' 670 INPUT "ENTER POUNDS ";P 680 LET G=453.59*P 690 PRINT P;" POUNDS = "; FLASH 1;G; FLASH 0;" GRAMS" 700 GO SUB 250: RETURN 710 CLS : PRINT "CONVERTING OUNCES TO MILLILITERS" 720 INPUT "ENTER OUNCES ";O 730 LET M=29.573*O 740 PRINT O;" OUNCES = "; FLASH 1;M; FLASH 0;" MILLILITERS" 750 GO SUB 250: RETURN 760 SAVE "CONVERSION" LINE 5: PRINT "REWIND TAPE AND VERIFY": VERIFY "": RUN 770 CLS : PRINT "1) Renumber"'"2) Remkill"'"3) Delete"'"4) Variable list": INPUT fff: LET zzz=(64048 AND fff=1)+(64841 AND fff=2)+(65017 AND fff=3)+(65184 AND fff=4): IF NOT zzz THEN GO TO 770 780 LET ttt=100: LET fff=ttt: IF zzz=64048 THEN INPUT "Start ";fff,"Step ";ttt 790 IF zzz=65017 THEN INPUT "From ";fff,"To ";ttt 800 IF fff>9999 OR fff<1 OR ttt>9999 OR ttt<1 OR (fff>ttt AND zzz=65017) THEN GO TO 770 810 POKE 23300,INT (fff/256): POKE 23299,fff-265*PEEK 23300: POKE 23302,INT (ttt/256): POKE 23301,ttt-256*PEEK 23302: IF zzz=65184 THEN PRINT USR zzz: STOP 820 RANDOMIZE USR zzz ```