This program is a loader and documentation stub for an interrupt-driven real-time clock implemented in machine code. The machine code block, 536 bytes long starting at address 64770, hooks into the system interrupt to maintain a running hours/minutes/seconds clock entirely in the background. Three USR entry points are provided: 64770 to enter the time interactively (accepting H, M, S, and ENTER keystrokes), 65303 to stop the clock, and 65296 to start it. POKEs at addresses 64970–64972 give direct read/write access to the seconds, minutes, and hours counters, while a POKE to 64887 toggles the display on or off and 64858 selects between 50 Hz (ZX Spectrum) and 60 Hz (TS2068) interrupt rates. The BASIC loader checks PEEK 23681 to detect whether the machine code is already resident before deciding whether to load or just list the documentation.
Program Structure
The BASIC listing is almost entirely comments and loader logic, with the real work performed by the 536-byte machine code block loaded separately. The program divides into four logical regions:
- Lines 10–170: REM-based API documentation for the machine code module.
- Lines 175–180: Residency check and graceful abort if the machine code is not yet present.
- Lines 9000–9020: The actual loader, reached either by direct RUN or by
LOAD "CLOCK" LINE 9000. - Line 9999: Combined
SAVEroutine that writes both the BASIC program and the machine code tape block.
Residency Detection
Line 175 uses PEEK 23681 as a sentinel. Address 23681 is the system variable FRAMES (low byte of the frame counter). The check IF PEEK 23681=0 is used loosely here as a proxy: if the machine code has not yet been loaded and started, this byte happens to be zero (or the interrupt hook is inactive), so the program clears the screen, lists the stub at line 9999, and stops. After a successful load and RANDOMIZE USR 65296 starts the clock, the interrupt routine keeps FRAMES non-zero, so re-running the BASIC program falls through to the documentation list instead of re-loading.
Line 9010 performs a complementary check after loading: IF PEEK 23681<>0 THEN RANDOMIZE USR 65296 starts the clock immediately if the environment looks live, then lists the documentation.
Machine Code API
| Address | Purpose |
|---|---|
| 64770 | Entry point: interactive time-set (H / M / S / ENTER keys) |
| 65296 | Start the interrupt clock |
| 65303 | Stop the interrupt clock |
| Address | POKE value / meaning |
|---|---|
| 64970 | Seconds counter (read/write) |
| 64971 | Minutes counter (read/write) |
| 64972 | Hours counter (read/write) |
| 64887 | 201 = display off; 33 = display on (likely a RET / INC opcode swap) |
| 64894 | Attribute byte controlling clock colour |
| 64858 | 60 = TS2068 (60 Hz); 50 = ZX Spectrum (50 Hz) interrupt divisor |
| 64888 | Column/row position of colour display |
| 64902 | Column/row position of digit display |
Notable Techniques
- Interrupt hook: The machine code installs itself into the IM 1 / IM 2 interrupt chain so the clock ticks without any BASIC involvement, a common but non-trivial technique in the upper RAM area near 64770 (0xFD02).
- 50/60 Hz configurable divisor: POKE 64858 lets the user correct for the different mains frequencies of PAL (50 Hz) and NTSC (60 Hz) machines, making the clock accurate on both.
- Display toggle via opcode swap: POKE 64887,201 writes a
RETopcode (0xC9), effectively disabling the display routine; POKE 64887,33 restores anLD HL,nnopcode (0x21), re-enabling it — a classic self-modifying code pattern. - Combined SAVE on one line: Line 9999 saves both the BASIC program (
SAVE "CLOCK" LINE 9000) and the 536-byte machine code block (SAVE "CLOCK Mc" CODE 64770,536), followed by twoVERIFYpasses for tape reliability. - High RAM placement: Locating the code above 64770 (0xFD02) keeps it well above normal BASIC/variable space and out of the way of most programs, while still being below the 65535 boundary.
Content
Source Code
10 REM INTERUPT CLOCK By Eric Boisvert ©1987 BYTE POWER
25 REM USR CALLS
30 REM 64770 ENTER TIME, Keys [H]our,[M]inutes,[S]econds and [ENTER]
40 REM 65303 STOP CLOCK
50 REM 65296 START CLOCK
60 REM USEFULL POKES
70 REM 64970,SECONDS
80 REM 64971,MINUTES
90 REM 64972,HOURS
100 REM 64887,201 NO DISPLAY
110 REM 64887,33 DISPLAY ON
120 REM 64894,COLOR OF CLOCK
130 REM 64858,60 T/S 2068
140 REM 64858,50 ZX SPECTRUM
150 REM SPECIAL POKES
160 REM 64888,COLOR POSITION
170 REM 64902,NUMBERS POSITION
175 IF PEEK 23681=0 THEN CLS : LIST 9999: STOP
180 STOP
9000 REM LOAD CODES
9010 LOAD "CLOCK Mc"CODE : IF PEEK 23681<>0 THEN RANDOMIZE USR 65296: CLS : LIST
9020 CLS : LIST 9999: STOP
9999 SAVE "CLOCK" LINE 9000: SAVE "CLOCK Mc"CODE 64770,536: VERIFY "": VERIFY ""CODE
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
