--- title: "Beep" id: 60844 type: "computer_media" slug: "beep" url: "http://localhost/computer_media/beep/" markdown_url: "http://localhost/computer_media/beep.md" published_at: "2025-10-05T23:35:34+00:00" modified_at: "2026-03-30T21:41:06+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2025/10/beep-1.png" excerpt: "A self-installing machine code beeper routine that carves its own RAM space, pokes 43 bytes of Z80, and plays a tone on every keypress via USR." 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: "Sound" slug: "sound" taxonomy: "genre" url: "http://localhost/type/sound/" media_contents: - id: 60550 title: "Fort Worth TS2068 Club Library Tape" type: "computer_media" url: "http://localhost/computer_media/fort-worth-ts2068-club-library-tape/" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/Beep%20%28198x%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2025/10/beep-1.png" media_type_tags: "Sound" --- # Beep This program installs and demonstrates a machine code routine that generates sound through the beeper port (port 254). It lowers RAMTOP by 43 bytes using CLEAR to carve out space just above the existing top of RAM, then POKEs 43 bytes of Z80 machine code into that reserved area. The routine directly manipulates the speaker bit of port 254 using OUT instructions (opcode 0xD3, 0xFE) combined with SET and RES bit operations on register H, producing a tone loop controlled by a register pair acting as a delay counter. The BASIC demonstration calls the routine repeatedly via USR whenever a key is pressed, and prints the USR address so users can call it from their own programs. *** ## Program Structure The program is divided into four clear phases, each annotated with REM blocks: 1. **Lower RAMTOP (line 30):** Reads the current RAMTOP from system variables at addresses 23730–23731, subtracts 43, and calls `CLEAR x` to move RAMTOP down, reserving space for the machine code. 2. **POKE machine code (lines 50–60):** Recalculates the base address as RAMTOP+1 (the first byte above the new RAMTOP) and reads 43 bytes from DATA statements into that block. 3. **Display USR address (line 80):** Prints the entry-point address so the user can call the routine independently from their own programs. 4. **Demo loop (lines 100–130):** Waits for a keypress with a busy-wait `INKEY$` loop, calls the routine via `USR x`, and repeats. ## Memory Layout System variables at addresses 23730 and 23731 hold the low and high bytes of RAMTOP respectively. The program uses the idiom `PEEK 23730 + 256*PEEK 23731` twice — once to compute the new RAMTOP (subtracting 43) and again to find the installation address (adding 1 to the new RAMTOP). The 43-byte block sits just above the lowered RAMTOP, where BASIC’s memory manager will not disturb it. ## Machine Code Analysis The 43 DATA bytes disassemble to a Z80 beeper tone routine. Key observations: - `58, 72, 92` — `LD A,(5C48H)`: loads the current border/speaker byte from the system variable BORDCR (0x5C48). - `31, 31, 31` — three `SRL A` shifts: isolates the lower 3 bits of the value. - `230, 7` — `AND 07H`: masks to 3 bits, giving a base value for the output register. - `14, 255` — `LD C, 0FFH`: loads the outer loop counter. - `38, 0` — `LD H, 00H`: initialises the high byte of the delay/pitch counter. - `68` — `LD H, B` (or similar register move): sets up the inner counter. - `203, 231` — `SET 4, H` (CB E4): sets the speaker bit. - `211, 254` — `OUT (FEH), A`: outputs to the beeper port, toggling the speaker. - `16, 254` — `DJNZ FEH`: inner delay loop (254 = −2 offset, tight loop back). - `203, 167` — `RES 4, H`: clears the speaker bit. - The pattern of SET/OUT/DJNZ/RES/OUT/DJNZ repeats to produce a square wave. - `36` — `INC H`: advances the pitch/duration counter. - `13` — `DEC C`: decrements the outer loop counter. - `32, 226` — `JR NZ, E2H`: loops back while counter is nonzero (offset −30). - `201` — `RET`: returns to BASIC. The routine produces a rising-pitch sweep: the inner DJNZ loop creates the half-period delay, and incrementing H on each outer iteration shortens the delay, raising the pitch progressively until the outer counter C reaches zero. ## Notable BASIC Techniques - Using `RESTORE` at line 30 ensures the DATA pointer is reset before the POKE loop at line 60, making the program safely re-runnable. - The address variable `x` is reused for both the RAMTOP calculation (line 30) and the installation address (line 50), keeping memory usage minimal but requiring two separate PEEK calculations. - The busy-wait keypress loop at lines 110–130 does not use `PAUSE 0`; it polls `INKEY$` directly in a `GO TO` loop, which is the standard ZX Spectrum idiom for this era. - `USR x` is used as a function (line 120) whose return value is stored in `a` but never used — the call is made purely for the side effect of producing sound. ## Potential Issues - The address stored in `x` after line 30 reflects the lowered RAMTOP, but line 50 re-reads PEEK 23730/23731. After `CLEAR x`, these system variables will have been updated to the new RAMTOP value, so the second calculation correctly yields the installation address. - There is no bounds checking: if RAMTOP is already very low (e.g. on a 16K machine with heavy usage), subtracting 43 could corrupt memory. - The machine code reads from BORDCR (0x5C48) but does not actually vary the output value with the speaker bit correctly isolated — the AND 7 masks bits 0–2, which correspond to the border colour, not the MIC/speaker bits (bits 3 and 4 of port 254). The speaker bit toggling is handled entirely within the machine code via SET/RES on H, so the initial LD A,(BORDCR) serves to preserve the border colour in the low bits of A during OUT instructions. ## Source Code ``` 10 REM Beep port routine 11 REM 20 REM Lower RAMTOP 21 REM 30 RESTORE : LET x=(PEEK 23730+256*PEEK 23731)-43: CLEAR x 40 REM 41 REM POKE Machine code 42 REM into memory 43 REM 50 LET x=(PEEK 23730+256*PEEK 23731)+1 60 FOR y=x TO x+42: READ z: POKE y,z: NEXT y 70 REM 71 REM Print USR Address 72 REM 80 PRINT AT 1,2;"The routine is called by the";TAB 7;"function USR ";x 90 REM 91 REM Example 92 REM 100 PRINT AT 12,10;"Press any key" 110 IF INKEY$="" THEN GO TO 110 120 LET a=USR x 130 GO TO 110 200 REM 201 REM Machine code data 202 REM 210 DATA 58,72,92,31,31,31,230,7,14,255 220 DATA 38,0,68,203,231,211,254,16,254,68 230 DATA 203,167,211,254,16,254,203,231,211,254 240 DATA 16,254,203,167,211,254,16,254,36,13 250 DATA 32,226,201 ```