--- title: "Tourist C" id: 72774 type: "computer_media" slug: "tourist-c" url: "http://localhost/computer_media/tourist-c/" markdown_url: "http://localhost/computer_media/tourist-c.md" published_at: "2026-10-27T12:29:14+00:00" modified_at: "2026-10-27T12:29:14+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2026/10/t-1.png" excerpt: "A bank-switching disassembler that titles and disassembles code in any memory bank, with calculator-literal decoding and a printer module for Epson-class printers." 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/" - name: "WIDJUP Company" slug: "widjup-company" taxonomy: "post_tag" url: "http://localhost/tag/widjup-company/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" indiv: - name: "William J. Pedersen" slug: "william-j-pedersen" taxonomy: "indiv" url: "http://localhost/indiv/william-j-pedersen/" genre: - name: "Machine Language" slug: "machine-language" taxonomy: "genre" url: "http://localhost/type/machine-language/" media_type: "Program" programmers: - name: "William J. Pedersen" slug: "william-j-pedersen" taxonomy: "indiv" url: "http://localhost/indiv/william-j-pedersen/" download_url: "https://archive.org/download/timex-sinclair-software-archive/Tourist%20C%20%281986%29%28Pedersen%2C%20William%20J.%29%28TS2068%29%28US%29%28Program%29.zip" tsrun_member: "Tourist C (1986)(Pedersen, William J.)(TS2068)(US)(Program)/Tourist C (1986)(Pedersen, William J.)(TS2068)(US)(Program).tap" mediadate: "1986" producer_company: - id: 27769 title: "WIDJUP Company" type: "company" url: "http://localhost/company/widjup-company/" images: - url: "http://localhost/wp-content/uploads/2026/10/t-1.png" - url: "http://localhost/wp-content/uploads/2026/10/t-3.png" related_products: - id: 27805 title: "Tourist C" type: "product" url: "http://localhost/product/tourist-c/" related_content: - id: 72908 title: "WIDJUP Mandelbrot Plotter" type: "computer_media" url: "http://localhost/computer_media/widjup-mandelbrot-plotter/" media_type_tags: "Machine Language" license: false --- # Tourist C Tourist C is a disassembler written in BASIC that can read any of the TS2068’s memory banks: the HOME bank (255), the EXROM (254), the DOCK cartridge bank (0) and any other bank number from 1 to 253. You give a group name, a bank number, a routine name and a start and stop address, in decimal or hexadecimal, then choose one of four modes: CODE disassembles Z80 instructions, CALC decodes the ROM’s floating-point calculator literals that follow `RST 40`, DATA lists bytes with their characters, and NOTE adds a comment line. Each line goes to the screen and to the printer, so the result is a printed, titled listing of the code. William J. Pedersen’s WIDJUP Company sold Tourist C in 1986 for $32.50, describing it as an extended bank-switching disassembler with a database of information about the 2068 ROM and a universal printer driver. The program on the disk carries no credit; the attribution comes from the product listing. A second program, `INTFC.BT`, sets up the printer interface: it offers TASMAN Type A and B, AERCO/Oliger, A&J or a general Z80 PIO interface, builds a 242-byte machine code driver in the printer buffer at 23296 and saves it as the string array `PmodEb.A$`. ## Program Analysis ### Structure On loading, the program starts at line 9853. It pokes a short bank-reading routine into the TS2068’s RAM-resident bank-switching code (lines 9855–9858), then loads four string arrays: the printer module `u$()`, the printer command table `j$()`, and the mnemonic tables `x$()` and `w$()`. Line 7770 copies the 242-byte module into the printer buffer and patches the channel pointers so that output goes through it. Reading a byte from another bank goes through a 12-byte routine built at line 350 and placed at 24627 or, if the system is in a different configuration, 38848 higher. ### Disassembly The disassembler at 9729–9784 decodes one instruction at a time from the opcode tables in `w$()`, handling the `CB`, `DD`, `FD` and `ED` prefixes, index displacements and relative jumps, whose targets it computes. `RST 40` switches to calculator mode, which names each literal, reading the names from address 3941, until the end-calculation byte. Lines 9832–9836 accept hexadecimal input. A line counter at 1111 restarts every 90 printed lines. ### Notable Techniques - Numeric constants held in variables (`i`, `ii`, `z0`, `vii`, `o`) to save memory, a common space-saving style. - Subroutine addresses stored in variables (`Wscr`, `Disa`, `Init`, `Err`) and called with `GO SUB`. - Printer output through a machine code module built from DATA with an `FN` that computes relocated addresses, so one program serves several interfaces. - `DEF FN C$` renders control and graphics codes readably (`^A`, `g1`, `DEL`). ### Potential Issues - In the original, pressing ENTER at the first Group Name prompt stopped the program with “2 Variable not found”, because the flag `Lkf` was only set when a new group was entered. The tape version sets it at start-up. - Every disassembled line is printed, so without a printer connected the program waits after the first line. - Line 9998, which lists the program to a wide printer, uses stream 5, which the program never opens. This copy came from a Larken disk. For tape, the LKDOS prefixes were removed, the option to read the Larken DOS banks 256–263 was taken out (the bank prompt now accepts 0–255), the disk catalogue routine was emptied, and the four arrays follow the program on the tape. The disk extraction had left a three-byte variable header at the start of each array, which was removed. The supplied printer module is set up for the AERCO interface; run the second program on the tape to make one for another interface. Tested in ZEsarUX. ## Source Code ``` 10 ON ERR GO TO 9854: LET I$=j$(1,1) 218 LET Wscr=9721 219 LET Disa=9729: LET Err=9784 224 LET Init=7770 255 LET Disk=7000 300 DEF FN C$(W)=("^" AND W<32)+("g" AND (W>127 AND W<165))+("DEL" AND (W=127 OR W=255))+CHR$ (W+(64 AND W<32)+(-79 AND (W>143 AND W<165))+(-95 AND W=127)+(-216 AND W=255)) 305 DEF FN D$(W)=("^" AND W<32)+("g" AND (W>127 AND W<165))+("DEL" AND (W=127 OR W=255))+CHR$ (W+(64 AND W<32)+(-79 AND (W>143 AND W<165))+(-95 AND W=127)+(-216 AND W=255)) 349 LET Wx=24627+(38848 AND PEEK 23746) 350 RESTORE 350: DATA VAL "33",z0,z0,VAL "6",VAL "255",VAL "205",VAL "22",VAL "99",VAL "175",VAL "71",VAL "77",VAL "201" 351 FOR n=Wx TO Wx+11: READ Byte: POKE n,Byte: NEXT n 352 LET Banknm=VAL "255": LET e$="": LET m$="": LET Lkf=z0: GO SUB Init 356 GO TO 1000 449 FOR n=i TO 11: POKE (Ld0+CODE o$(n)),CODE j$(Select,n): NEXT n 450 RANDOMIZE USR (Ld0+CODE o$(12)): RETURN 451 LET select=i: GO TO jj 452 LET select=ii: GO TO jj 453 LET select=i+ii: GO TO jj 454 LET select=ii+ii: GO TO jj 455 LET select=VAL "5": GO TO jj 456 LET select=VAL "6": GO TO jj 1000 LET Line=z0 1010 GO SUB 9902: GO SUB Wscr: PRINT PAPER 6;" This program titles and disass-embles the contents of any bank.HOME......255","EXROM.....254","DOCK........0","LKDOS..256-263","OTHERS..1 to 253", 1011 PRINT AT 5,z0;" Group Name: ";M$,'" Bank # ";BANKNM,,: INPUT " New Group Name or ENTER:";E$: IF E$="" THEN GO TO 1013 1012 LET Lkf=z0: LET M$=E$: INPUT "Bank # (0-255): ";BANKNM: IF BANKNM>255 THEN GO TO 1012 1013 POKE Wx+4,BANKNM: PRINT AT 5,z0;" Group Name: ";M$," Bank # ";BANKNM;: INPUT "Routine name:",E$: PRINT " Name:";E$,: IF Lkf THEN OUT vii,BANKNM-256 1015 INPUT "From(HEX)(->DEC):";I$: IF LEN I$ THEN GO SUB 9832: LET Wb=Wbb: GO TO 1017 1016 INPUT "From(DEC)(0,->HEX):";Wb: IF Wb=z0 THEN GO TO 1015 1017 PRINT AT 8,z0;" From address (DEC): ";Wb,,, 1018 INPUT "Stop(HEX)(->DEC):";I$: IF LEN I$ THEN GO SUB 9832: GO TO 1020 1019 INPUT "Stop(DEC)(0,->HEX):";Wbb: IF Wbb=z0 THEN GO TO 1018 1020 PRINT AT 9,z0;" Stop address (DEC): ";Wbb,,,"1 CODE 2 CALC 3 DATA 4 NOTE"''"SELECT",, 1021 INPUT "Which? ";Wt: IF Wtii+ii THEN GO TO 1021 1022 IF Wt=4 THEN INPUT P$(i): PRINT AT o,z0;P$(i): GO SUB 453: GO SUB 1111: GO TO 1011 1023 LET Dd=Wt=i+ii: LET Calc=Wt=ii: GO SUB 9839 1024 PRINT AT 13,z0;" READY Press ENTER to procede."''" To correct entries, BREAK and GO TO 1011 ": PAUSE z0 1025 INPUT "Print title? Y?";I$ 1026 IF LEN i$ THEN IF I$( TO i)="Y" OR I$( TO i)="y" THEN GO SUB 1100 1027 IF Dd THEN GO TO 2000 1028 GO TO 9822 1100 PRINT AT o,z0,,,,AT o,z0;"Bank#";Banknm;"\";M$;"\";E$: REM dwdh 1110 GO SUB 454: LET Line=Line+i 1111 LET Line=Line+i: IF Line>89 THEN LET Line=z0: LPRINT ".."; 1112 RETURN 1120 LET w=INT (Y/16): PRINT AT o,z0,,,,AT o,z0;Wb;TAB 8;H$(W+i);h$(Y-16*W+i);TAB 18;"DC";TAB 33;: IF Y>159 AND Y<251 THEN PRINT ":"; INVERSE i;CHR$ (Y-128); INVERSE z0; 1125 PRINT ":";FN c$(Y);":";: IF y<32 THEN LET W=3*Y+17: PRINT H$(W TO W+ii) 1130 GO SUB 453: GO TO 1111 2000 LET Y=Wb: GO SUB 3000: GO SUB 1120 2001 LET Wb=Wb+i: IF Wb221 AND Wp<>253 THEN GO TO 9733 9731 IF Wfk THEN GO TO Err 9732 LET Wf=1+(1 AND Wp=253): LET Wfk=1: LET Wb=Wb+1: LET Y=Wb: GO SUB 3000: LET Wp=Y: GO TO 9730 9733 IF Wp<>203 THEN GO TO 9737 9734 LET Wfn=0: LET Wj=345: LET Wb=Wb+Wfk+1: LET Y=Wb: GO SUB 3000: LET Wp=Y: LET W1=INT (Y/64): LET Y=Y-64*W1: LET W2=INT (Y/8): LET W=Y-8*W2: IF Wfk AND W<>6 THEN GO TO Err 9735 LET W$(Wj, TO 3)=CHR$ (W2+49)+CHR$ (W+1)+"a": IF W1 THEN LET W$(Wj, TO 3)=CHR$ (W1+97)+CHR$ (W2+17)+CHR$ (W+1) 9736 LET Y=Wb-1: GO SUB 3000: LET Wdis=Y: GO TO 9743 9737 IF Wp<>237 THEN GO TO 9741 9738 LET Wb=Wb+1: LET Y=Wb: GO SUB 3000: LET Ww=Y: LET Wj=193+Ww-(36 AND Ww>159) 9739 IF Ww>123 AND Ww<160 OR Wj>344 THEN GO TO Err 9740 GO TO 9742 9741 LET Wj=1+Wp: LET Ww=0 9742 LET Y=Wb+1: GO SUB 3000: LET Wdis=Y 9743 LET V$="": LET W0=CODE W$(Wj,1): IF W0=116 THEN GO TO Err 9744 IF W0=108 THEN LET Wv=VAL (X$(CODE W$(Wj,2))): LET G$=" " 9745 GO SUB 9763: LET B$=I$+" ": LET W0=CODE W$(Wj,2): GO SUB 9763: IF I$="" THEN GO TO 9752 9746 IF Wp=211 THEN LET I$="(N)": LET G$=" " 9747 LET B$=B$+I$: LET W0=CODE W$(Wj,3): GO SUB 9763: IF I$="" THEN GO TO 9750 9748 IF Wp=219 THEN LET I$="(N)": LET G$=" " 9749 LET B$=B$+","+I$ 9750 IF Wfk AND NOT Wfw THEN GO TO Err 9751 LET V$=STR$ Wv: IF NOT LEN G$ AND Wv=0 THEN LET V$="" 9752 LET P$(1)=STR$ Wia: LET P$(1,19 TO )=B$: LET P$(1,34 TO )=V$+G$ 9753 PRINT AT o,z0;P$(i) 9754 LET Wb=Wb+1+Wfs*Wfn 9757 RETURN 9763 LET I$=X$(W0): FOR j=LEN I$ TO i STEP -i: IF I$(j)=" " THEN NEXT j 9764 LET I$=I$( TO j): IF W0=117 THEN GO SUB 9776 9765 IF W0<>118 THEN GO TO 9768 9766 LET Wb=Wb+Wfk+1: LET Wfn=0: LET Y=Wb: GO SUB 3000: LET Wv=Y: IF Wp=211 OR Wp=219 THEN GO TO 9768 9767 LET G$=":"+FN C$(Wv)+":": IF Wv<32 THEN LET W=3*Wv+17: LET G$=G$+" ("+H$(W TO W+2)+")" 9768 IF W0<119 THEN GO TO 9770 9769 LET Wb=Wb+2: LET G$=" ": LET Wfn=0: LET Y=Wb-1: GO SUB 3000: LET Wv=Y: LET Y=Wb: GO SUB 3000: LET Wv=Wv+256*Y 9770 IF NOT Wfk THEN GO TO 9774 9771 IF W0=7 OR W0=61 OR W0=112 THEN LET Wfw=1 9772 IF W0=7 THEN LET Wfs=1: GO SUB 9777: LET I$=X$(112+Wf, TO 3)+I$+")" 9773 IF W0=61 THEN LET I$=X$(112+Wf,2 TO 3) 9774 IF W0=112 THEN LET I$=X$(112+Wf) 9775 RETURN 9776 LET Wb=Wb+1 9777 LET W=Wdis: IF W<128 THEN GO TO 9779 9778 LET W=W-256 9779 IF NOT Wfk THEN LET W=W+2 9780 IF W>=0 THEN LET I$="+"+STR$ W 9781 IF W<0 THEN LET I$=STR$ W 9782 IF B$( TO 2)="JR" OR B$( TO 2)="DJ" THEN LET Wv=Wia+W 9783 RETURN 9784 PRINT AT o,z0,,,,AT o,z0;Wia;AT o,18;"CODE ERROR ": RETURN 9822 LET Y=Wb: GO SUB 3000: LET Wp=Y: IF Calc THEN PRINT AT o,z0,,,,AT o,z0;Wb;TAB 8;H$(INT (Wp/16)+i);H$(Wp-16*INT (Wp/16)+i);TAB 18;"DC";TAB 33;"CALCULATOR": LET Calc=NOT (Wp=56): LET Wt=CALC+i: GO SUB 9839: LET Wb=Wb+i: GO TO 9826 9823 GO SUB Disa: GO SUB 9830: IF B$( TO ii)<>"RS" THEN GO TO 9826 9824 LET B$=B$+" ": IF B$( TO 6)="RST 40" THEN LET Calc=i: LET Wt=ii: GO SUB 9839: GO TO 9826 9825 IF B$( TO 5)="RST 8" THEN PRINT AT xx,i;"ERROR CALL": GO SUB 9840: LET Wt=i+ii: GO SUB 9839: GO SUB 9841 9826 GO SUB 9840: IF Wb127 THEN GO TO 9842 9845 GO TO 9843 9846 LET Wn=PEEK n: LET n=n+i: PRINT CHR$ (Wn-(128 AND Wn>127));: IF Wn>127 THEN LET Wb=Wb+i: LET Wt=i: GO TO 9839 9847 GO TO 9846 9853 REM tape version: the printer module PmodEb.A$ follows on the tape 9854 ON ERR RESET : LET z0=0: LET i=1: DIM p$(1,64): LET Ii=i+i: LET Vii=7: LET o=19: LET Xx=20: LET jj=449 9855 POKE 25408,213: POKE 25610,40: POKE 25611,36: POKE 25614,40: POKE 25615,55: POKE 25617,40: POKE 25618,39: POKE 26128,9: POKE 26474,95 9856 RESTORE 9856: DATA 193,209,115,35,114,43,14,255,219,255,230,128,40,18,24,8,14,255,219,255,230,128,32,8,219,244,47,24,ii,219,244,79 9857 FOR j=z0 TO 5: READ W: POKE 25424+j,W: NEXT j 9858 FOR j=z0 TO 25: READ W: POKE 25648+j,W: NEXT j 9859 LOAD "PmodEb.A$" DATA u$(): LOAD "J$T.A$" DATA j$() 9860 LOAD "x$().A$" DATA x$(): LOAD "w$().A$" DATA w$(): GO TO 200 9902 LET H$="0123456789ABCDEFNULSOHSTXETXEOTENQACKBELBS HT LF VT FF CR SO SI DLEDC1DC2DC3DC4NAKSYNETBCANEM SUBESCFS GS RS US ": RETURN 9908 PRINT AT 19,8; PAPER 6; INK II;" PRESS ANY KEY ";: PLOT 72,VII: DRAW 120,z0: DRAW z0,9: DRAW -120,z0: DRAW z0,-9: RETURN 9998 INPUT "Date, Comment? ";I$: LPRINT "lN";CHR$ 6;: LPRINT #5'"TURIST.BW Listing, ";I$'': LLIST #5: LPRINT CHR$ 12;: STOP 9999 SAVE "w$().A$" DATA w$(): SAVE "x$().A$" DATA x$(): SAVE "J$T.A$" DATA j$(): CLEAR : SAVE "TURIST.BW" LINE 9853: GO TO 9854 ```