--- title: "Calculator" id: 51864 type: "computer_media" slug: "calculator" url: "http://localhost/computer_media/calculator/" markdown_url: "http://localhost/computer_media/calculator.md" published_at: "2023-08-16T01:42:19+00:00" modified_at: "2026-04-03T07:59:13+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "A keyboard-driven calculator interface with eight labeled rows, block-graphic borders, and PEEK/POKE memory tracking — all packed into compact, variable-optimized BASIC." 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: "Timex Computer Corporation" slug: "timex-computer-corporation" taxonomy: "post_tag" url: "http://localhost/tag/timex-computer-corporation/" - name: "TS 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" genre: - name: "Home" slug: "home" taxonomy: "genre" url: "http://localhost/type/home/" media_type: "Cassette" download_url: "https://archive.org/download/timex-sinclair-software-archive/Calculator (1982)(Timex)(US)(TS1000)(Cassette).zip" mediadate: "1982" producer_company: - id: 11401 title: "Timex Computer Corporation" type: "company" url: "http://localhost/company/timex-computer-corporation/" related_products: - id: 13030 title: "Keyboard Calculator" type: "product" url: "http://localhost/product/keyboard-calculator/" media_type_tags: "Home" --- This program implements a multi-row calculator display interface with labeled rows A through H, each capable of storing a numeric or string value. Navigation and data entry are handled via single-key presses, with keys such as V (scroll), R/L (move right/left), T (toggle a mode flag M), and X (execute a calculation pass). The program uses POKE with PEEK-based address arithmetic to store the current row identifier (Z) into memory, suggesting a machine-code or system-variable table is being maintained in parallel with the BASIC display. Block graphics characters are used to draw bordered panels for each row, and a `FAST` mode directive at line 90 speeds up display rendering. A SAVE routine at line 9000 uses USR 8192, pointing to a machine code entry point in RAM. *** ## Program Analysis ### Program Structure The program is organized into several functional blocks, using computed line-number arithmetic throughout rather than hard-coded targets. This is a common memory-saving idiom where variables initialized elsewhere encode key line numbers. | Line Range | Role | | --- | --- | | 90–160 | Display initialization: draws bordered rows A–H using block graphics | | 200–290 | Main input loop: polls INKEY$ and dispatches on key press | | 300–330 | Row selection handler: updates Z to selected row, refreshes display | | 500–570 | Name/label entry for a row (INPUT S$, then POKEs row ID) | | 600–650 | Value entry for a row (INPUT S$, truncates to O chars, POKEs row ID offset) | | 800–840 | Numeric INPUT Y for a row, stores B=Y, POKEs row ID | | 900–995 | Calculation pass: iterates all rows A–H, evaluates VAL S$ for each | | 1000–1070 | Subroutine: displays computed value for current row | | 1100–1120 | Subroutine: refreshes header/status line | | 1200–1220 | Subroutine: POKEs a specific memory slot, restores S$ from B$ | | 1300–1320 | Subroutine: POKEs a different memory slot, restores S$ from P$ | | 9000–9010 | Save routine using USR 8192 (machine code); loops via GOTO U | ### Variable Conventions and Computed Line Numbers The program makes heavy use of pre-initialized numeric variables (P, Q, R, W, K, L, U, V, O, J, X, T, S, M) as both display constants and line-number components. None of these are initialized within the visible listing, implying they are set in lines not shown (likely below line 90). This technique allows `GOTO P-R`, `GOTO R+W`, `GOSUB P+W`, etc., to encode target line numbers compactly. `VAL "number"` forms like `GOTO VAL "910"` are also used as a memory optimization. Key inferred variable roles (from context): - `P` — base line number (likely 1000, since `GOSUB P` calls line 1000) - `R` — main loop line (likely 200, since `GOTO R` returns to input loop) - `W` — step increment (likely 100, making `P+W`=1100, `P+R`=1200/1300) - `Q` — a display row constant; used in `PRINT AT Q,L` - `L` — likely 0 (column start) - `U` — likely 0 or 1 (used in `U-M` toggle and `U-U` zero test) - `K` — a column or width constant - `O` — maximum string length for value entries - `J` — row offset adjustment in `AT Z+Z-J` - `S`, `T` — PEEK base addresses for the memory table ### Display Technique Rows A through H are drawn by iterating `Z` from `CODE "A"` (65) to `CODE "H"` (72). Each row uses block graphic characters — `▐▀▀▀▀▀▀▀▀▀▀▀▀▀▀▌` for a top border line and `▌` for the left edge — to create a bordered panel effect. The cursor position for each row’s data is computed as `AT Z+Z-J`, which linearly maps character codes to screen rows, with `J` providing the offset to align `Z=65` to the first display row. The bottom border uses `▝▀▀▀▀▀▀▀▀▀▀▀▀▀▘` with corner block graphics for a clean rounded appearance. The `FAST` directive at line 90 suppresses display during the drawing loop for speed. ### PEEK/POKE Memory Table Several lines use the pattern `POKE PEEK S + X*PEEK T + offset, Z` to write the current row identifier into a memory location. This strongly suggests a small machine code routine or data table resides in RAM (with its address stored as a two-byte value at addresses S and T, read via `PEEK S + X*PEEK T` as a 16-bit address: `low + 256*high`). The offsets (`+L`, `+K-V`, `+CODE "▒"`) select different fields within the table. The character code of `▒` (an inverse block graphic, char code in the 130s range) used as an offset reinforces that specific numbered slots are being indexed. ### Input Dispatch and Navigation The main loop at lines 200–290 uses a `PAUSE X*R` then `INKEY$` idiom to poll the keyboard. Dispatch is handled by a chain of `IF` tests: - `CHR$ VAL "118"` = `"v"` — triggers a scroll/view action (`GOTO P-R`) - `S$>="A" AND S$<="H"` — row selection jump (`GOTO R+W`, i.e. line 300) - `"X"` — jumps to line 910 (calculation pass, bypassing the mode guard at 900) - `"T"` — toggles mode flag `M` via `LET M=U-M` - `"R"` — jumps to `L*W` (likely line 0 or a specific entry handler) - `"L"` — jumps to `L*W+W` ### Calculation Pass (Lines 900–995) Line 900 guards the pass with `IF M=U-U THEN GOTO R`, which evaluates to `IF M=0` — skipping calculation when the mode flag is off. Lines 920–980 iterate Z over all eight row codes, calling `GOSUB P+R` (line 1200 or 1300 depending on P and R values) to load each row’s stored string into S$. If S$ is non-empty, it evaluates `VAL S$` as a numeric expression (stored in H) via line 960, then calls `GOSUB P` (line 1000) to display the result. ### USR 8192 Save Routine Line 9000 calls `USR 8192`, which transfers execution to machine code at address 8192 (the start of the free RAM area on a 16K machine). The result is printed alongside a `"SAVE:P:CALCULATOR:"` string. This is a common pattern for invoking a machine code SAVE helper. Line 9010 loops with `GOTO U`, likely returning to the start of the program. ### Notable Idioms and Anomalies - `VAL CHR$ Z` at line 1000 converts the numeric character code in Z back to a character (e.g., Z=65 → “A”) and then applies VAL — this only works if the character stored is a digit, suggesting rows may be remapped to digit codes during calculation. - `W$(LEN S$+U TO Y)` at line 630 uses a string slice of W$ (likely a padding/blank string) to erase trailing characters after a shorter replacement entry. - The `S$=S$( TO O)` truncation at line 620 enforces a maximum entry width of O characters. - Lines 1200 and 1300 each restore S$ from a saved string variable (B$ and P$ respectively), acting as context-switching subroutines for different row data fields. - The variable `Y` is used both as a saved row-cursor register (`LET Y=Z` / `LET Z=Y`) and as a numeric INPUT target at line 810, which could cause conflicts if the two uses overlap — a potential latent bug depending on call ordering. ## Source Code ``` 90 FAST 100 PRINT "(C)1982 J. GISHEN", 102 LET Y=Z 105 FOR Z=CODE "A" TO CODE "H" 110 PRINT "▐▀▀▀▀▀▀▀▀▀▀▀▀▀▀▌","▐"; 120 GOSUB P 122 GOSUB O*W 125 PRINT TAB Q-L;"▌ ";CHR$ Z;TAB K;S$ 130 NEXT Z 140 LET Z=Y 160 PRINT "▝▀▀▀▀▀▀▀▀▀▀▀▀▀▀▘",,,,,"RULE:" 170 GOSUB P+W 200 PRINT AT Z+Z-J,CODE "(";" ";CHR$ (Z+CODE "█");" " 210 PAUSE X*R 220 LET S$=INKEY$ 230 IF S$=CHR$ VAL "118" THEN GOTO P-R 240 IF S$>="A" AND S$<="H" THEN GOTO R+W 250 IF S$="X" THEN GOTO VAL "910" 255 IF S$="T" THEN LET M=U-M 260 IF S$="R" THEN GOTO L*W 270 IF S$="L" THEN GOTO L*W+W 290 GOTO R 300 PRINT AT Z+Z-J,CODE ")";CHR$ Z 310 LET Z=CODE S$ 320 GOSUB P+W 330 GOTO R 500 PRINT AT Q,L;"[>]" 510 INPUT S$ 560 POKE PEEK S+X*PEEK T+L,Z 562 LET H$=S$ 565 GOSUB P+W 570 GOTO P-W 600 PRINT AT Z+Z-J,K-U;"[>]" 605 GOSUB O*W 607 LET Y=LEN S$ 610 INPUT S$ 620 IF LEN S$>O THEN LET S$=S$( TO O) 630 PRINT AT Z+Z-J,K;S$;W$(LEN S$+U TO Y) 635 POKE PEEK S+X*PEEK T+L,Z+K-V 640 LET O$=S$ 650 GOTO R 800 PRINT AT Z+Z-J,CODE "(";"[<]" 810 INPUT Y 820 POKE PEEK S+X*PEEK T+L,Z 830 LET B=Y 840 GOSUB P 900 IF M=U-U THEN GOTO R 910 LET Y=Z 920 FOR Z=CODE "A" TO CODE "H" 930 GOSUB P+R 940 IF S$="" THEN GOTO P-Q 950 POKE PEEK S+X*PEEK T+L,Z 960 LET H=VAL S$ 970 GOSUB P 980 NEXT Z 990 LET Z=Y 995 GOTO R 1000 PRINT AT Z+Z-J,U;W$( TO K-L);AT Z+Z-J,U;VAL CHR$ Z; 1070 RETURN 1100 GOSUB P+R 1110 PRINT AT Q,L;W$( TO V);W$;AT Q,L+U;S$ 1120 RETURN 1200 POKE PEEK S+X*PEEK T+CODE "▒",Z 1210 LET S$=B$ 1220 RETURN 1300 POKE PEEK S+X*PEEK T+K-V,Z+K-V 1310 LET S$=P$ 1320 RETURN 9000 PRINT USR 8192;"SAVE:P:CALCULATOR:" 9010 GOTO U ```