Beep

Date: 198x
Type: Program
Platform(s): TS 2068

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, 92LD 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, 7AND 07H: masks to 3 bits, giving a base value for the output register.
  • 14, 255LD C, 0FFH: loads the outer loop counter.
  • 38, 0LD H, 00H: initialises the high byte of the delay/pitch counter.
  • 68LD H, B (or similar register move): sets up the inner counter.
  • 203, 231SET 4, H (CB E4): sets the speaker bit.
  • 211, 254OUT (FEH), A: outputs to the beeper port, toggling the speaker.
  • 16, 254DJNZ FEH: inner delay loop (254 = −2 offset, tight loop back).
  • 203, 167RES 4, H: clears the speaker bit.
  • The pattern of SET/OUT/DJNZ/RES/OUT/DJNZ repeats to produce a square wave.
  • 36INC H: advances the pitch/duration counter.
  • 13DEC C: decrements the outer loop counter.
  • 32, 226JR NZ, E2H: loops back while counter is nonzero (offset −30).
  • 201RET: 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.

Content

Appears On

This tape is a compilation of programs from user group members (Robert Burton, David Baulch, Frank Bouldin, Chuck Dawson, Ryan

Related Products

Related Articles

Related Content

Image Gallery

Beep

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

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

People

No people associated with this content.

Scroll to Top