TRACER

This file is part of and CATS Library Tape 8. Download the collection to get this file.
Date: 198x
Type: Program
Platform(s): TS 2068

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:

LabelStart AddressPurpose
data A65218Entry: 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 B65261Token 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 S1365313Short routine: advance stored pointer, load BC pair, continue scanning (shared tail of data A logic).
data OUT65326Output 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:

AddressRole
65360–65361Current line number (low, high) returned by scanner
65362–65363Target line number (low, high) passed to USR 65218
65364–65365Current byte pointer within BASIC program area
65366–65367Secondary 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.

Content

Appears On

The power-user's tape. Assemble and disassemble Z80 code, manage databases with Quicksort, trace BASIC program flow, or decode resistor color codes — Tape 8 is an essential toolkit for the serious TS 2068 programmer.

Related Products

Related Articles

Related Content

Image Gallery

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 

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

People

No people associated with this content.

Scroll to Top