--- title: "TRACER" id: 55094 type: "computer_media" slug: "tracer" url: "http://localhost/computer_media/tracer/" markdown_url: "http://localhost/computer_media/tracer.md" published_at: "2024-06-16T13:57:58+00:00" modified_at: "2026-03-30T21:46:04+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "A BASIC flow tracer that injects Z80 machine code to walk your program's GOTO, GOSUB, and IF…THEN branches, displaying the full execution path line by line." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" - name: "Utilities" slug: "utilities" taxonomy: "category" url: "http://localhost/category/software/utilities/" 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_contents: - id: 51214 title: "CATS Library Tape 8" type: "computer_media" url: "http://localhost/computer_media/cats-library-tape-8/" media_type: "Program" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/06/SCR-20240714-exfu.png" media_type_tags: "Programming" --- # TRACER This program is a BASIC control-flow tracer that disassembles and displays the execution path of another BASIC program merged with it. It embeds 135 bytes of Z80 machine code (POKEd into addresses 65218–65352) that scans through the BASIC program area, identifies token bytes for GOTO (236), GOSUB (237), RETURN (254), STOP (226), and IF…THEN (250), and reports each line’s branching behavior. The machine code entry points at USR 65218 and USR 65261/65345 perform address resolution and token scanning without the speed overhead of pure BASIC. A 50-element array `s(50)` implements a software call stack to track GOSUB/RETURN nesting. The utility is intended to be merged into a target program, then activated via GO TO 9800 or GO TO 9900 to visualize flow without modifying the target code. *** ## Program Analysis ### Program Structure The program is divided into two logical phases: a machine code loader (lines 9800–9870) and the BASIC-language flow tracing engine (lines 9900–9980), with a final `SAVE` at line 9999. Line 9799 is a `STOP` acting as a firewall so that a merged host program running sequentially does not accidentally fall into the utility. The REM at line 9800 documents the intended merge workflow. 1. **Lines 9807–9870:** Machine code loader — checks if code is already resident, clears memory to 65217, READs DATA blocks into addresses 65218–65352, then drops to the tracer. 2. **Lines 9900–9901:** Entry point guard — verifies the machine code sentinel byte at 65350 is `201` (Z80 RET opcode) before proceeding. 3. **Lines 9902–9916:** Initialization — dimensions the call stack array, prompts for a starting line number, POKEs it into the machine code parameter block, and calls USR 65218 to resolve the BASIC line’s address. 4. **Lines 9917–9980:** Main tracing loop — reads the token byte returned by the machine code scanner, dispatches on its value, prints the flow event, and loops. ### Machine Code Layout The DATA is loaded into a contiguous block at 65218–65352 and annotated with four REM labels in the listing: | Label | Start Address | Purpose | | --- | --- | --- | | data A | 65218 | Entry: resolve line-number address, advance pointer past line header and number bytes, scan for CR (13) to find line end; store next-line address. | | data B | 65261 | Token scanner: reads bytes sequentially, branches on GOTO (236), GOSUB (237), RETURN (254), STOP (226), IF (243), THEN (235), and END (226); also checks for CR to move to next line. | | data S13 | 65313 | Short routine: advance stored pointer, load BC pair, continue scanning (shared tail of data A logic). | | data OUT | 65326 | Output helper: stores current pointer into 65364/65365, returns token byte in A via RET (201). | The sentinel check at line 9807 tests whether address 65350 already holds `201` (RET), which is the last meaningful byte of the OUT routine. This allows re-entry via GO TO 9900 without reloading. The guard at line 9901 repeats the same check and prints a diagnostic if the code is absent. ### Parameter Passing Convention Communication between BASIC and the machine code uses a dedicated scratchpad in high RAM: | Address | Role | | --- | --- | | 65360–65361 | Current line number (low, high) returned by scanner | | 65362–65363 | Target line number (low, high) passed to USR 65218 | | 65364–65365 | Current byte pointer within BASIC program area | | 65366–65367 | Secondary address (used for operand extraction) | Lines 9913–9914 POKE the desired starting line and the BASIC program base address (read from system variables at 26710/26711) before calling USR 65218. After each USR call the BASIC layer reads back these locations to recover the scanner’s state. ### Call Stack Implementation Line 9902 dimensions `s(50)` as a 50-element numeric array and uses the scalar variable `s` as a stack pointer. When a GOSUB token (237) is encountered (line 9937), the *return* line number `l+1` is pushed onto `s(s)` and `s` is incremented. On RETURN (254) at line 9923, `s(s)` is popped and `s` is decremented. This cleanly mirrors the runtime call stack of the host interpreter. ### Token Dispatch and Display The BASIC tracer at line 9919 onwards dispatches on the token byte `c` returned by the machine code: - `c=250` — IF…THEN: handled by the sub-loop at lines 9950–9965, which scans forward past `203` (CB prefix used as internal marker) to find the THEN clause token and its operand. - `c=254` — RETURN: pops the call stack and continues tracing from the saved return address. - `c=235` or `c=243` — EX DE,HL or EI opcodes repurposed as token sentinels; printed as their CHR$ equivalents. - `c=226` — STOP: prints “STOP” and halts the tracer. - `c=236` — GOTO: extracts the numeric literal operand (scanning for the ZX number-embedding marker byte 14) and updates `l`. - `c=237` — GOSUB: same operand extraction as GOTO, plus call-stack push. ### Numeric Literal Extraction Lines 9930–9935 implement the standard technique for reading the hidden floating-point copy of a numeric literal embedded in the tokenized BASIC line. The code advances `a` byte-by-byte until it finds the marker byte `14`, then skips three bytes (the exponent and sign) to reach the two-byte integer portion at offsets `a` and `a+1`, which give the branch target line number directly. ### Display Formatting Line 9905 uses `AT 0,0` combined with `OVER 1` to print a decorative separator line over the heading without erasing it — a compact screen-decoration idiom. Line 9921 checks whether the current line `l` equals the last-printed line `ll`; if so it prints a colon separator rather than a newline, compressing multiple tokens from the same line onto one screen row. ### Notable Anomalies - Line 9910 filters out starting line numbers ≥ 9800 to prevent the tracer from tracing itself, but this check uses a simple `GO TO 9907` loop with no error message, silently re-prompting. - The variable name `s` is used both as the array `s()` and as the scalar stack pointer `s`; this is legal BASIC (arrays and scalars occupy separate namespaces) but is visually confusing. - The DATA at line 9825 contains two zero-padding bytes at the end, and line 9820 reads exactly 135 bytes (65218 to 65352 inclusive), meaning the OUT routine’s trailing `0,0` bytes are loaded but never executed — they serve as alignment padding. ## Source Code ``` 9799 STOP 9800 REM Merge this program to aBASIC program.GOTO 9800 to tracethe BASIC program 9807 IF PEEK 65350=201 THEN GO TO 9902 9810 CLEAR 65217 9812 PRINT "Please wait..."''"Machine Code Loading" 9815 RESTORE 9825 9820 FOR q=65218 TO 65352: READ a: POKE q,a: NEXT q 9823 REM data A: 9825 DATA 42,80,255,237,91,82,255,167,237,82,0,56,1,201,42,84,255,35,35,35,0,0,62,13,35,190,32,252,35,34,84,255,70,35,78,237,67,80,255,24,215,0,0 9830 REM data B: 9835 DATA 42,84,255,35,35,35,35,126,254,250,40,63,254,235,40,59,254,243,40,55,254,237,40,51,254,254,40,47,254,236,40,43,254,226,40,39,35,126,254,13,40,10,254,58,40,216,254,34,40,15,24,240 9840 REM data S13: 9845 DATA 35,34,84,255,70,35,78,237,67,80,255,24,191 9850 REM data SEE: 9855 DATA 1,0,2,35,62,34,237,177,24,218 9860 REM data OUT: 9865 DATA 6,0,78,34,86,255,201,0,0,42,84,255,24,203,201,0,0 9870 CLS 9900 REM Flow Utility 9901 IF PEEK 65350<>201 THEN PRINT "Machine Code not Loaded..."''"GOTO 9800": STOP 9902 DIM s(50): LET s=0: LET ll=s 9905 PRINT "Basic Program Flow:";AT 0,0; OVER 1;"_________ _________" 9907 INPUT "Starting Line Number? ";l 9910 IF l>=9800 THEN GO TO 9907 9912 LET l2=INT (l/256): LET l1=l-l2*256 9913 POKE 65362,l1: POKE 65363,l2 9914 POKE 65364,86: POKE 65365,104: POKE 65360,PEEK 26711: POKE 65361,PEEK 26710 9915 RANDOMIZE USR 65218: LET a=PEEK 65364+256*PEEK 65365: LET l=PEEK (a+1)+256*PEEK a 9916 LET c=USR 65261 9917 LET l=PEEK 65360+256*PEEK 65361: IF l>=9800 THEN PRINT "END of BASIC": STOP 9918 LET a=PEEK 65366+256*PEEK 65367 9919 IF c=250 THEN GO TO 9950 9921 IF l=ll THEN PRINT ": "; 9922 IF l<>ll THEN PRINT : PRINT l;" ";: LET ll=l 9923 IF c=254 THEN PRINT "RETURN";: LET l=s(s): LET s=s-1: GO TO 9912 9925 IF c=235 OR c=243 THEN PRINT CHR$ c;: GO TO 9980 9927 IF c=226 THEN PRINT "STOP": STOP 9930 LET a=a+1: LET g=PEEK a 9933 IF g<>14 THEN GO TO 9930 9935 LET a=a+3: LET g=PEEK a+256*PEEK (a+1) 9937 IF c=237 THEN PRINT "GOSUB ";: LET l=l+1: LET s=s+1: LET s(s)=l 9940 IF c=236 THEN PRINT "GOTO "; 9945 PRINT g;: LET l=g: GO TO 9912 9950 LET a=a+1: IF PEEK a<>203 THEN GO TO 9950 9952 LET c=PEEK (a+1) 9954 IF l<>ll THEN PRINT : LET ll=l 9955 PRINT l;" IF...THEN ";CHR$ c;: IF c=236 OR c=237 THEN GO TO 9960 9957 LET a=a+1: GO TO 9980 9960 LET a=a+1: LET g=PEEK a 9962 IF g<>14 THEN GO TO 9960 9965 LET a=a+3: LET g=PEEK a+256*PEEK (a+1): PRINT g;: LET a=a+1: GO TO 9980 9980 LET l2=INT (a/256): LET l1=a-l2*256: POKE 65364,l1: POKE 65365,l2: LET c=USR 65345: GO TO 9917 9999 SAVE "tracer": LIST ```