SLEEP
Temporarily put the CPU to sleep to save electrical power.
| Opcode | Bytes | Cycles | Form |
|---|---|---|---|
| $13 | 1 | 2 | SLEEP |
Notes
-
This instruction temporarily stops the virtual computer's clock, preventing any instructions from being executed.
-
Whenever certain events occur, the hardware automatically sets corresponding bits in the
IO::IRQ_PENDINGI/O location. ("IRQ" stands for interrupt request, although Hybrix currently does not yet provide interrupt handlers.) -
After executing a
SLEEPinstruction, the CPU will wake when one of theIO::IRQ_PENDINGvalues matchesIO::IRQ_WAKE_MASK; that is, if the bitwiseANDof these two values becomes nonzero. -
The total timing cost for
SLEEPis 1 cycle transitioning to sleep, plus 1 cycle transitioning to wake, plus whatever time was spent waiting. -
This instruction does not affect the CPU condition flags.
Example usage
The framework's ENGINE::WAIT_FOR_PAINT() function uses the SLEEP instruction to wait for the Palix video display to finish painting:
# ---------------------------------------------------------------------------
# WAIT FOR THE NEXT VIDEO FRAME TO GET PAINTED.
# THIS ALSO SYNCHRONIZES THE MAIN LOOP TO AT MOST 30 FPS.
FUNC WAIT_FOR_PAINT()
1 -> IO::IRQ_PENDING # "WRITE 1 TO CLEAR" IRQ_PENDING
3 -> IO::PAINT_MODE # REQUEST PAINT
1 -> IO::IRQ_WAKE_MASK # SLEEP UNTIL THE PAINT FINISHES
KERNEL::SLEEP()
END FUNC
Note that IO::IRQ_PENDING must be reset before sleeping. We clear its bits by writing 1s instead of 0s, which is the so-called "Write 1 to Clear" (W1C) convention. (W1C avoids a hardware race condition that could otherwise occur if a program had to read the old value, clear some of its bits, and then store the new value.)
Also, note that we clear IO::IRQ_PENDING before requesting a paint. This avoids another race condition that might occur if painting happened immediately before SLEEP. In general, IO::IRQ_PENDING should be cleared before starting whatever operation it will be tracking.
Here's another example that sleeps while waiting to generate audio events:
FUNC START()
SOUND::INIT()
VAR TRACK_INDEX: INT
IO::CPU_EVENT_VALUE -> TRACK_INDEX
SOUND::PLAY_SONG(ART::SONGS[TRACK_INDEX])
LOOP
2 -> IO::IRQ_PENDING # "WRITE 1 TO CLEAR" IRQ_PENDING
SOUND::THINK()
2 -> IO::IRQ_WAKE_MASK # SLEEP UNTIL NEXT JAMDAC READ
KERNEL::SLEEP()
END LOOP
END FUNC
I/O definitions
MODULE IO
. . .
# USED WITH IRQ_WAKE_MASK BELOW. WHENEVER THE SPECIFIED EVENT OCCURS,
# THE HARDWARE SETS THE CORRESPONDING BIT. THE PROGRAM CAN CLEAR A BIT
# BY SETTING IT (THE "WRITE 1 TO CLEAR" OR "W1C" CONVENTION).
# +1 = WHENEVER PALIX PAINTS A VIDEO FRAME (BUFFERED OR UNBUFFERED)
# +2 = WHENEVER JAMDAC ADVANCES AN IO_AUDIO_QUEUE::READ_ADDRESS
VAR IRQ_PENDING: BYTE LOCATED AT $D000_0010
# TO SAVE ELECTRICITY, THE CPU CAN BE TEMPORARY PAUSED USING THE "SLEEP"
# INSTRUCTION. THE CPU WILL WAKE UP AGAIN WHEN IRQ_PENDING MATCHES ANY OF
# THE IRQ_WAKE_MASK BITS (LEVEL TRIGGERING).
VAR IRQ_WAKE_MASK: BYTE LOCATED AT $D000_0012
. . .
END MODULE