--- title: "Hello!" id: 59221 type: "computer_media" slug: "hello" url: "http://localhost/computer_media/hello/" markdown_url: "http://localhost/computer_media/hello.md" published_at: "2025-03-01T01:22:59+00:00" modified_at: "2026-03-31T09:21:11+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "A scrollable, letter-indexed disk program launcher lets you browse and load up to 200 entries, with machine code routines handling drive selection and smooth screen scrolling." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Byte Power" slug: "byte-power" taxonomy: "post_tag" url: "http://localhost/tag/byte-power/" - 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/" indiv: - name: "Kristian Boisvert" slug: "boisvert-kristian" taxonomy: "indiv" url: "http://localhost/indiv/boisvert-kristian/" genre: - name: "Disk Drive Systems" slug: "disk-drive-systems" taxonomy: "genre" url: "http://localhost/type/disk-drive-systems/" media_contents: - id: 50507 title: "Byte Power February 1988" type: "computer_media" url: "http://localhost/computer_media/byte-power-february-1988/" media_type: "Program" programmers: - name: "Kristian Boisvert" slug: "boisvert-kristian" taxonomy: "indiv" url: "http://localhost/indiv/boisvert-kristian/" download_url: "https://archive.org/download/timex-sinclair-software-archive/Hello%20%281988%29%28Byte-Power%20February%201988%29%28TS2068%29%28CA%29%28Program%29.zip" mediadate: "1988" producer_company: - id: 25181 title: "Byte Power" type: "company" url: "http://localhost/company/byte-power/" article_media: - id: 59223 title: "HELLO!" type: "article" url: "http://localhost/article/hello/" related_products: - id: 38579 title: "Byte Power Feb 1988" type: "issue" url: "http://localhost/issue/byte-power-9/" media_type_tags: "Disk Drive Systems" --- # Hello! This program is a menu-driven file launcher that displays a scrollable directory of programs stored on a disk drive, allowing the user to select and load them by pressing a letter key. It uses machine code routines loaded at a computed address (derived from system variables at addresses 23635–23636) to handle hardware-level operations such as drive selection and screen scrolling. The directory is stored in a 200×9 DIM array `a$`, with entries differentiated by a `.Cx` suffix convention to distinguish between BASIC and CODE files, triggering different LOAD paths accordingly. Lines 8000–8120 provide utility subroutines that POKE machine code bytes to modify the behavior of `.Cx` file printing in the launcher. The program targets a TS2068 with a Larken disk drive. *** ## Program Analysis ### Program Structure The program is organized into a handful of logical blocks: 1. **Lines 0–1:** REM headers — line 0 contains embedded machine code (its content is binary data, not readable BASIC text), and line 1 contains a title/credit banner. 2. **Lines 10–109:** Initialization — sets display attributes, dimensions the name array, and computes the base address of the machine code from system variables. 3. **Lines 110–240:** Main interactive loop — draws the UI, polls the keyboard, handles scrolling and drive selection, and loads the selected program. 4. **Lines 8000–8120:** Utility patches — POKEs bytes into the machine code to toggle whether `.Cx` files are printed in the directory. 5. **Line 9999:** Save line — saves the program with auto-run from line 1. ### Machine Code Usage Machine code is embedded in the REM statement at line 0. Its base address is computed at line 109 as `USR (5+PEEK 23635+256*PEEK 23636)`, which is 5 bytes past the start of the BASIC program area — exactly where the payload inside the line-0 REM begins. This is the standard technique for self-relocating machine code on these systems. `RANDOMIZE USR 100` is used as a disk ROM entry point throughout the program (lines 107, 230, 240, 9999), consistent with disk interface conventions where address 100 is a jump into the disk operating system. Lines 170 and 180 call into the machine code at offsets +98 and +126 from the computed base address to perform hardware-assisted scroll-down and scroll-up operations respectively, avoiding slow BASIC scrolling of the display. ### Directory and Navigation The program directory is held in `a$(200,9)`, a two-dimensional string array of up to 200 entries each nine characters wide. The variable `L` holds the count of valid entries (set from the machine code’s output via `USR`). The variable `NAME` acts as the current scroll position, always pointing to the first of the currently displayed pair of rows. The display shows 8 pairs of entries (16 total) at a time, labeled A–P. Pressing a letter key A–P selects the corresponding entry relative to the current scroll position. Pressing `6` or cursor-down scrolls forward by two entries; pressing `7` or cursor-up scrolls back. ### Key BASIC Idioms - `(a$(NAME+X-65) AND NAME+X-65<=L)` — the Spectrum `AND` operator used to conditionally print a string: returns the string if the condition is true, or an empty string if false, avoiding an explicit `IF`. - `GO TO DRIVE-1` at line 107 — a computed `GO TO` targeting a line number derived from the selected drive number minus one (e.g., drive 1 → line 0, drive 2 → line 1). This is a valid technique for jumping to non-standard or pre-computed line numbers. - `POKE 23658,8` — sets the FLAGS2 system variable bit to enable cursor keys, so `CHR$ 10` (cursor down) and `CHR$ 11` (cursor up) are readable via `INKEY$`. - `POKE 23606,0: POKE 23607,60` — sets the system variable `RASP`/`PIP` area, commonly used to silence or adjust key click behavior. ### File Type Detection At lines 220–230, the program scans the selected filename `D$` for the first period character. Once found, it checks whether the character two positions later is `"C"`. If so, the file is treated as a CODE file and loaded with `LOAD D$CODE` followed by `PAUSE 0` and a return to the main menu. Otherwise, it is loaded as a BASIC program with `LOAD D$` (line 240), which transfers control entirely. ### Utility Patch Routines (Lines 8000–8120) These routines modify four bytes inside the machine code at offset +69 from the base address. Line 8010 zeroes those bytes (presumably NOPs), enabling `.Cx` file entries to appear in the directory listing. Line 8110 POKEs the values `254, 67, 40, 217`, which patch in a conditional branch or filter that suppresses `.Cx` files. Both routines end with `STOP`, indicating they are run standalone as maintenance utilities rather than called during normal program operation. ### Notable Anomalies - Line 105 loops back to itself on invalid input rather than using a structured loop, which is standard practice in this era of BASIC programming. - The `FOR F=1 TO 9` loop at line 220 uses `NEXT F` inside an `IF` — if no period is found within the 9-character filename, the loop exits naturally and `F` will equal 10, potentially causing an out-of-bounds substring access at `D$(F+1)`. This is a latent bug if filenames without a period are somehow stored in the array. - The `INK` and `PAPER` commas in `PRINT` statements (e.g., `PAPER 7,,`) use multiple separators to produce blank lines efficiently within a single `PRINT` statement. ## Source Code ``` 0 REM NEXT STEP bCODE 2 STEP FREE STEP { GO SUB [K\\! FOR !p FREE # RETURN IF (5 RETURN COPY PLOT FREE RETURN RETURN ( LET OR FREE # RETURN .(STR$ READ STR$ FREE RETURN A( INVERSE RETURN C( INK + FREE RETURN COPY IF OR # FREE IF STR$ OR CLS STEP INT <>H!#H> GO SUB VAL = PAUSE STICK RETURN P FOR <>O! OUT O> GO SUB LN +++= PAUSE z RETURN G FOR <>0 1 REM HELLO! WRITTEN BY KRISTIAN BOISVERT COPYRIGHT \*1988 BYTE POWER 10 INVERSE 0: OVER 0: INK 0: PAPER 7: BORDER 7: CLS 100 REM MAIN ROUTINE 102 POKE 23658,8: POKE 23606,0: POKE 23607,60: DIM a$(200,9): GO TO 109 105 INPUT "DRIVE [1-5]...................";DRIVE: IF DRIVE<1 OR DRIVE>5 THEN GO TO 105 107 RANDOMIZE USR 100: GO TO DRIVE-1 109 LET NAME=1: LET L=USR (5+PEEK 23635+256*PEEK 23636) 110 PRINT AT 0,0; PAPER 7,, PAPER 3; INK 7;TAB 13;"HELLO!",,,TAB 2;"WRITTEN BY KRISTIAN BOISVERT",,,TAB 3;"COPYRIGHT \*1988 BYTE POWER", 120 PRINT AT 18,0; INK 7; PAPER 1,,,,,,AT 20,0;"[7]- SCROLL UP","[6]- SCROLL DOWN";AT 19,5;"[LETTER]- LOAD PROGRAM";AT 18,7;"[1]- SELECT DRIVE" 130 PRINT AT 7,0; PAPER 2,,: LET X=65: FOR F=8 TO 15: PRINT AT F,0; INK 0; PAPER 6;CHR$ X;"- ";(a$(NAME+X-65) AND NAME+X-65<=L),CHR$ (X+1);"- ";(a$(NAME+X-64) AND NAME+X-64<=L),: LET X=X+2: NEXT F: PRINT AT 16,0; PAPER 2,, 150 LET B$=INKEY$ 160 IF B$="1" THEN GO TO 105 170 IF (B$="6" OR B$=CHR$ 10) AND NAME+16<=L THEN RANDOMIZE USR (PEEK 23635+256*PEEK 23636+98): LET NAME=NAME+2: PRINT INK 0; PAPER 6;AT 15,3;A$(NAME+14),AT 15,19;(A$(NAME+15) AND NAME+15<=L), 180 IF (B$="7" OR B$=CHR$ 11) AND NAME-2>=1 THEN RANDOMIZE USR (PEEK 23635+256*PEEK 23636+126): LET NAME=NAME-2: PRINT INK 0; PAPER 6;AT 8,3;A$(NAME),AT 8,19;A$(NAME+1), 190 IF B$<"A" OR B$>"P" THEN GO TO 150 200 IF NAME+(CODE B$-65)>L THEN GO TO 150 210 LET D$=A$(NAME+(CODE B$-65)): PRINT #1;AT 1,0;"LOADING... ";D$ 220 FOR F=1 TO 9: IF D$(F)<>"." THEN NEXT F 230 INK 0: PAPER 7: LET D$=D$(1 TO F+2): IF D$(F+1)="C" THEN RANDOMIZE USR 100: LOAD D$CODE : PAUSE 0: CLS : GO TO 109 240 RANDOMIZE USR 100: LOAD D$ 8000 REM PRINT ".Cx" FILES 8010 LET A=PEEK 23635+256*PEEK 23636+69: FOR F=A TO A+3: POKE F,0: NEXT F: STOP 8100 REM DON'T PRINT ".Cx" FILES 8110 LET A=PEEK 23635+256*PEEK 23636+69: POKE A,254: POKE A+1,67: POKE A+2,40: POKE A+3,217 8120 STOP 9999 RANDOMIZE USR 100: SAVE "HELLO!.B1" LINE 1 ```