--- title: "Variable Area" id: 71250 type: "computer_media" slug: "variable-area" url: "http://localhost/computer_media/variable-area/" markdown_url: "http://localhost/computer_media/variable-area.md" published_at: "2026-08-31T09:25:17+00:00" modified_at: "2026-08-31T09:25:18+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2026/08/Variable-Area.png" alt: "Variable Area screen" excerpt: "A memory explorer that walks the variable area and decodes every variable type — including floating-point math and FOR-NEXT loop control blocks — into plain English." 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/" genre: - name: "Programming" slug: "programming" taxonomy: "genre" url: "http://localhost/type/programming/" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/Variable%20Area%20%28198x%29%28-%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2026/08/Variable-Area.png" alt: "Variable Area screen" media_type_tags: "Programming" --- # Variable Area This program dumps and decodes the entire variable area in human-readable form, walking through memory starting at the address stored in system variables VARS (23627–23628). It identifies all seven variable types — single-letter numerics, multi-character named numerics, numeric arrays, FOR-NEXT loop control blocks, strings, and string arrays — by inspecting the high three bits of each entry’s first byte. Numeric values are decoded from the Spectrum’s five-byte floating-point format, including the sign bit, biased exponent (offset 128), and mantissa reconstruction across bytes 2–5. The FOR-NEXT loop handler extracts the current value, limit, step, line number, and statement counter from the control block, displaying them with labeled column alignment using TAB. *** ### Program Structure The program is organized as a dispatcher with a main loop and a set of subroutines. Lines 10–70 form the main loop: they read the current byte at pointer `p`, determine the variable type from the upper three bits, and branch to one of six handlers. Line 25 detects the end-of-variable-area sentinel byte (128). Lines 100–650 are the six type handlers, and lines 800–940 are shared utility subroutines. | Lines | Role | | --- | --- | | 1–5 | Initialization: screen colors, dimension work array | | 10–70 | Main dispatch loop | | 100–120 | Handler: single-letter numeric variable (type 3) | | 200–270 | Handler: multi-character numeric variable (type 5) | | 300–330 | Handler: numeric array (type 4) | | 400–465 | Handler: FOR-NEXT loop control block (type 7) | | 500–550 | Handler: string variable (type 2) | | 600–650 | Handler: string array (type 6) | | 800–875 | Subroutine: read and decode 5-byte float/integer | | 900–945 | Subroutine: read array header (dimensions and total element count) | ### Variable Area Navigation The starting address is fetched via `PEEK 23627+256*PEEK 23628`, which reads the two-byte system variable VARS. The pointer `p` is advanced manually after each field is consumed. This byte-by-byte traversal mirrors what the Spectrum ROM itself does when searching for variables. ### Type Dispatch Mechanism At line 30, `p2 = INT(p1/32)` extracts the top three bits of the first byte (equivalent to a right-shift by 5). The resulting value identifies the variable type: - `p2=3` — single-letter numeric (bits 011) - `p2=5` — multi-character numeric name (bits 101) - `p2=4` — numeric array (bits 100) - `p2=7` — FOR-NEXT loop control (bits 111) - `p2=2` — string variable (bits 010) - `p2=6` — string array (bits 110) ### Five-Byte Floating-Point Decoder (Lines 800–875) The Spectrum stores all numeric variables in a five-byte format. Subroutine 800 first reads five bytes into array `b()`. If `b(1)` is zero, the value is a short integer stored in `b(3)` and `b(4)`, with `b(2)=255` signaling a negative value (two’s complement adjusted by subtracting 65536). For true floating-point values, `b(1)` holds the biased exponent (bias 128), `b(2)` holds the sign in its high bit plus the implicit leading mantissa bit, and bytes 3–5 hold the remaining mantissa. The reconstruction at line 855 iterates `j=2 TO 5`, accumulating `b(j)/256^(j-1)`. After restoring the implicit bit and adjusting the exponent at line 860, the result is scaled by `2^b(1)`. The sign flag `m` is applied last. ### Multi-Character Variable Name Decoding (Lines 200–260) In the Spectrum variable area, multi-character names encode the first letter with bit 6 set (adding 64) and the last letter with bit 7 set (adding 128), while intermediate letters are stored as plain ASCII. The handler subtracts 64 from the first byte and 128 from the last byte to recover the original characters, printing them in sequence. ### FOR-NEXT Loop Block Handler (Lines 400–465) A FOR-NEXT control block stores five values in sequence: the current loop value, the limit (TO value), the step, the line number (two bytes), and the statement number within that line. The handler calls subroutine 800 three times to decode the floating-point current, limit, and step values, then reads the two-byte line number and one-byte statement index directly with PEEK. ### Array Header Subroutine (Lines 900–940) Subroutine 900 reads the two-byte total byte-length field, then the dimension count `d`, then iterates over each dimension’s two-byte element count. It computes the total number of elements `t` as a running product (line 920), and prints the dimension sizes separated by commas before the closing parenthesis. The pointer is left one byte before the first element so that subsequent loops calling subroutine 800 (which pre-increments `p`) land correctly. ### Notable Techniques - The array `b(5)` (line 5) is reused on every call to subroutine 800, avoiding repeated variable declarations. - `TAB` columns are used consistently for value alignment: column 16 for numeric values, column 22 for labels, giving the output a structured columnar appearance. - The main loop uses `GO TO 20` rather than a `FOR` loop, since the step between entries is variable-length and depends on the type just processed. ### Bugs and Anomalies - **String array elements (lines 610–640)**: The handler reads only one byte per element (`CHR$ PEEK p`), which is incorrect for multi-character string array elements. Each element in a string array occupies a fixed number of characters defined by the last array dimension, so only the first character of each element is shown. - **Typo at line 60**: The REM comment reads “string aray” (missing ‘r’), which is cosmetic only. - **Floating-point sign bit handling (line 850)**: When `b(2)` is less than 128 the sign flag `m` is set to 0 (positive) and 128 is added back to `b(2)` to restore the implicit leading mantissa bit. This logic is inverted from what the comment might suggest but is arithmetically correct for the Spectrum’s format. ## Source Code ``` 1 PAPER 0:BORDER 0:INK 9 5 DIM b(5) 10 LET p= PEEK 23627+256* PEEK 23628 20 PRINT p; TAB 6;:LET p1= PEEK p 25 IF p1=128 THEN PRINT TAB 7;"END OF VARIABLE AREA":STOP 30 LET p2= INT (p1/32) 35 IF p2=3 THEN GO TO 100:REM number (single-letter name) 40 IF p2=5 THEN GO TO 200:REM number (multi-character name) 45 IF p2=4 THEN GO TO 300:REM number array 50 IF p2=7 THEN GO TO 400:REM loop control 55 IF p2=2 THEN GO TO 500:REM string 60 IF p2=6 THEN GO TO 600:REM string aray 70 STOP :REM error if this line is reached 100 REM number:- 105 PRINT CHR$ p1; 110 GO SUB 800 115 PRINT TAB 16;n 120 LET p=p+1:GO TO 20 200 PRINT CHR$ (p1-64);:REM first letter 210 LET p=p+1 220 LET p1= PEEK p 230 IF p1 >=128 THEN GO TO 260 240 PRINT CHR$ p1;:REM middle letters (if any) 250 GO TO 210 260 PRINT CHR$ (p1-128);:REM last letter 270 GO TO 110 300 PRINT CHR$ (p1-32);"("; 305 GO SUB 900 310 FOR k=1 TO t 315 GO SUB 800 320 PRINT TAB 3;"element #";k; TAB 16;n 325 NEXT k 330 LET p=p+1:GO TO 20 400 PRINT CHR$ (p1-128); 410 GO SUB 800 420 PRINT TAB 9;"(LOOP)"; TAB 16;n; TAB 22;"Current" 425 GO SUB 800 430 PRINT TAB 16;n; TAB 22;"Limit (TO)" 435 GO SUB 800 440 PRINT TAB 16;n; TAB 22;"STEP" 450 LET l= PEEK (p+1)+256* PEEK (p+2):LET s= PEEK (p+3):LET p=p+4 455 PRINT TAB 16;l; TAB 22;"Line No." 460 PRINT TAB 16;s; TAB 22;"Statement" 465 GO TO 20 500 PRINT CHR$ p1;"$"; TAB 16; 510 LET l= PEEK (p+1)+256* PEEK (p+2):LET p=p+2 520 FOR j=1 TO l 530 PRINT CHR$ PEEK (p+j); 540 NEXT j:PRINT 550 LET p=p+j:GO TO 20 600 PRINT CHR$ (p1-128);"$("; 605 GO SUB 900 610 FOR k=1 TO t 620 LET p=p+1 630 PRINT TAB 3;"element #";k; TAB 16; CHR$ PEEK p 640 NEXT k 650 LET p=p+1:GO TO 20 800 REM integer 805 FOR j=1 TO 5 810 LET p=p+1:LET b(j)= PEEK p 815 NEXT j 820 IF b(1) THEN GO TO 845 825 LET n=b(3)+256*b(4):IF b(2)=255 THEN LET n=n-65536 830 RETURN 845 REM floating point 850 LET m=1:IF b(2)<128 THEN LET m=0:LET b(2)=b(2)+128 855 LET n=0:FOR j=2 TO 5:LET n=n+b(j)/256^(j-1):NEXT j 860 LET b(1)=b(1)-128 865 LET n=n*2^b(1) 870 IF m THEN LET n=-n 875 RETURN 900 REM arrays 905 LET p1= PEEK (p+1)+256* PEEK (p+2):LET p=p+3 910 LET d= PEEK p:LET p=p+1 915 LET t=1:FOR j=1 TO d 920 LET el= PEEK p+256* PEEK (p+1):LET t=t*el:PRINT el 925 IF d <>1 AND j <>d THEN PRINT ","; 930 LET p=p+2:NEXT j:PRINT ")" 940 LET p=p-1 945 RETURN ```