01 / THE BUILDING BLOCK
Wait for a bit to change.
BASIC provides a compact way to watch a memory location:
WAIT address,mask[,invert]
address selects the byte to read. mask selects the bits we care about. The optional invert flips selected bits before the test; its default is zero. Execution continues as soon as this result is nonzero:
(memory byte XOR invert) AND mask
WAIT WF,32 waits for bit 5 to be set. WAIT WF,32,32 waits for it to be clear. With a mask of 34 (32 OR 2), either selected bit can satisfy the test.
02 / A BYTE BETWEEN TWO WORLDS
Machine language publishes. BASIC reacts.
The runtime owns a byte called notifyFlag. Each bit has a meaning. Here are three used by the graphics viewer:
| Value | Binary | Meaning | Protocol |
|---|---|---|---|
| 2 | 00000010 | Mouse notification | A pending flag to consume |
| 4 | 00000100 | Clock tick | A bit that toggles |
| 32 | 00100000 | Vessel update ready | A pending flag to consume |
Source: notification constants in Basic8Config.asm.
Once the vessel-update fields are ready, the manager publishes the notification by setting its bit. ORA preserves the other bits:
lda notifyFlag
ora #MESSAGE_FLAG
sta notifyFlag
See the payload being published before the flag.
The IRQ services time, mouse sampling and serial buffering. Message decoding and vessel-update publication happen in the main runtime path, reached through the BASIC statement hook. A separate wake-up bit lets the IRQ release WAIT when buffered serial data needs draining; clock ticks also bring BASIC back into the loop. BASIC dispatches the resulting notifications to its UI routines.
For the scheduling behind this arrangement, read One loop, two languages: IGONE.
03 / THE ACTUAL LOOP
Choose. Wait. Handle.
These are the first three statements of BASIC line 113, separated here for readability:
MK=PEEK(MP)
WAIT WF,MK,MS
WM=PEEK(WF) AND MK
- WF
- Address of the runtime's notification byte.
- MP / MK
- The shared interest-mask address, and the mask copied for this wait.
- MS
- The last handled values of state bits, including the toggling tick.
- WM
- The selected bits sampled after WAIT returns.
The runtime supplies the addresses through its API; they are not arbitrary spare RAM. These fragments assume AIS4CBM is already initialized. They are extracts to study, not a standalone program.
Address setup · Full WAIT and dispatch loop
Pending flags and changing state
A pending mouse flag leads to the mouse handler:
114 IF (WM AND 2) THEN GOSUB 600:GOTO 113
The handler consumes the click notification, then BASIC returns to WAIT. The full loop gives serial draining and interactive work priority before handling vessel updates.
The tick uses a different handshake. The IRQ toggles bit 2 with EOR; BASIC remembers the value it has handled in MS:
lda #TICK
eor notifyFlag
sta notifyFlag
119 IF (XOR(WM,MS AND MK) AND 4) THEN MS=XOR(MS,4):GOSUB 200:GOTO 113
After handling a tick, the remembered bit matches the current bit. WAIT blocks again. The next toggle makes them differ, whether the transition is 0 → 1 or 1 → 0.
Tick publication and its guard · State-change handlers in BASIC
A dialog can choose its events
BASIC changes the shared mask as the UI changes. For example, the following isolates the operation used to turn off interest in vessel updates:
POKE MP,(PEEK(MP) AND 223)
223 = 255 - 32. The actual dialog temporarily excludes several bits and restores vessel interest once its drawing transition is complete. The ML producer also checks the mask and defers eligible deliveries. A mask alone would only change what wakes WAIT.
04 / TRY THE BITS
Make WAIT return.
Signal a mouse click or vessel update, then handle it. Try a tick, handle it, and toggle it again. Both tick edges wake BASIC. Uncheck an event to see how the mask changes the test.
2. Publish a notification
- Flag byte · PEEK(WF)
- 0
- Interest mask · MK
- 38
- Last tick handled · MS
- 0
(0 XOR 0) AND 38 = 0
WAIT is pollingNo selected event differs from its handled state.
A browser model of three flags. “Handle” clears selected mouse/vessel flags and remembers the selected tick. Changing a checkbox evaluates a new WAIT condition; real BASIC reads the arguments when WAIT starts. The real program has separate handlers and producer-side delivery rules.
05 / TAKE IT INTO YOUR OWN PROGRAM
Keep the handshake explicit.
- Publish data before the flag. Once the consumer sees “ready”, its associated data must be usable.
- A flag is not an event queue. Repeated sets can merge, and two toggles can cancel before they are observed. Use a counter or queue when every occurrence matters.
- Define who acknowledges each bit. A BASIC PEEK/POKE read-and-write is not atomic against interrupts. Use an interrupt-safe ML acknowledgement when concurrent writers require it.
- Keep the producer running. WAIT cannot advance if the selected condition never occurs. IRQ notifications require the relevant interrupt to remain enabled.
The result is a small interface between fast machine-language work and readable BASIC handlers: a byte of notifications, a mask of interests, and a clear agreement about what each bit means.
Once WAIT releases the handler, how does BASIC read the vessel’s data? The companion tutorial, Ask ML, get a BASIC value: USR, follows a field request through the numeric and string return paths.
Read the code
Links point to main in the public GitLab repository. Source line numbers may move as the project develops.
- aiscbm8.bas — WAIT, dispatch and UI masks.
- Basic8Config.asm — notification bits and BASIC API.
- irqhandlers.asm — IRQ work and the toggling tick.
- ais4cbmManager.asm — publish and defer vessel updates.
Further reading: Commodore 128 System Guide: WAIT and the C128 ROM's WAIT routine, whose polling loop performs XOR, then AND.