All About Commodore's WAIT Instruction
Louis F. Sander, Pittsburgh
WAIT is one of Commodore BASIC'S most mysterious instructions — seldom seen in programs, rarely mentioned in magazines, and nearly impossible to understand in manuals. But it's available for VIC-20, PET/CBM, and 64 users. To find out how helpful it can be for all kinds of applications (program debugging, single-stepping, even a superior form of the common pause GET K$: IF K$ = " " THEN), read on.
WAIT allows a BASIC program to communicate with hardware and with certain software external to itself. It causes PET to suspend all apparent activity on receipt of a signal from the keyboard, an external device, or the computer's internal timers. PET's normal activity resumes when the signal is removed. Thus, WAIT provides a simple means of pausing until a key is pressed, an interval ends, or contacts open or close. We'll soon get to some useful examples.
When executed, WAIT examines a selected memory location and halts the program if the location contains a specified "trigger value." The program continues if, or as soon as, any other value appears in the selected location. Optionally, WAIT can be made to ignore some of the bits in the location it is testing.
In other words, WAIT halts a program if, and for as long as, selected bits in a chosen location have one specific pattern. Note carefully: the program waits if a specific pattern exists, not for a specific pattern to appear.
WAIT's format is:
WAIT ADDR, MASK, TRIG
ADDR, MASK, and TRIG can be any numeric constants, expressions, or variables in the range 0-65535 for ADDR, and 0-255 for MASK and TRIG. TRIG and its leading comma may be left out of the statement if desired, in which case TRIG defaults to zero.
Technically speaking, the WAIT statement reads the status of memory location ADDR, exclusive ORs it with TRIG, then ANDs the result with MASK, repeating these steps until a nonzero result is obtained. Practically speaking, few human minds can follow such logic, let alone comprehend its effect on their programs. If you prefer simplicity, think of WAIT as saying this: "Pause if the MASK bits in the contents of ADDR are the same as those in TRIG. Otherwise, continue." But Jet's illustrate some of its specific uses.
ADDR is the address of the memory location to be tested. WAIT halts the program if ADDR contains a preselected trigger value, resuming execution if and when ADDR's contents change. It follows that ADDR must be a location whose contents can change independently of the program, or there will be no way to resume program execution. Relatively few memory locations meet this criterion — mainly they are associated with the keyboard, the user and IEEE ports, and the computer's internal timers. Table 1 is a partial listing of such locations.
MASK determines whether WAIT tests all, or only some, of the bits in ADDR. If a given bit in MASK is set to one, the corresponding bit in ADDR will be tested. Otherwise, the bit will be ignored. If the entire contents of ADDR are to be tested, MASK must equal 255; any lower number will cause WAIT to ignore one or more bits. The various powers of two are often used in MASK, to monitor a single bit for a one or a zero. Zero is a legal value for MASK, but should never be used, since it always causes an endless halt. (Any number and zero equals zero.)
TRIG is the value that triggers a halt. If WAIT is executed when ADDR contains TRIG, the program will stop until TRIG is replaced by another value. Of course, if MASK is blocking out one or more bits, any number whose unblocked bits are identical to those in TRIG will have the same effect as TRIG, and will cause the program to halt. TRIG's default value is zero, so when TRIG is omitted from the WAIT statement, a halt occurs whenever all the unblocked bits are zero.
WAIT has three other notable properties. First, just as PRINT can be abbreviated as "?", WAIT can be abbreviated as "W shifted A". You can use this property to save keystrokes and line space. Second, the STOP key will not terminate a WAIT. That can only be done by satisfying the logical conditions in the argument; if a programming error has made this impossible, you must reset your machine to recover. So as soon as you put a WAIT statement into a program, save a copy on tape or disk; that will save you if you've made an error. Finally, WAIT does not affect the jiffy clock — TI and TI$ continue during WAITs, even though the computer and the STOP key are ostensibly dead. So by using the memory locations of the jiffy clock, you can precisely control WAIT's pauses.
Real World Applications
Table 2 lists some of WAIT's uses, along with the arguments used to implement them. To demonstrate these applications, the following examples can be inserted as line 25 of this little program:
10 TI$ = "000000" 20 PRINT TI 30 GOTO 20
Lines 20 and 30 cause a continuous screen printout while the program is running, making it easy to observe the effects of the WAIT in line 25. (The following examples use ADDResses from Original ROMs; if you have PET Upgrade, 4.0, or a VIC or a 64, use Table 1 to find the right ADDResses for your machine.)
WAIT 59410, 255, 251 stops the program when SPACE is depressed, and continues execution when it's released. No other key can make the program pause if these arguments are used. Different TRIGs, of course, will activate different "59410 keys."
WAIT 59410, 255, 255 stops the program until SPACE or one of the other "59410 keys" is depressed. Only these keys can change the contents of 59410, and any one of them will do it, thus ending the WAIT.
WAIT 516,255 is a simple way to pause until a key is pressed. Since 516 contains a zero until SHIFT is pressed, this line halts the program until you press SHIFT. Notice that the STOP key has no effect unless SHIFT is pressed and the program is running. Also notice that WAIT 516, 1 would have the same effect, using fewer bytes.
WAIT 59411, 8, 8 waits for a button on the tape drive to be pressed. While all the buttons are up, 5941l's eight-bit is set, and the program halts. Depressing PLAY or any other recorder button clears the eight-bit, resuming execution of the program.
WAIT 59411, 8 halts the program when the eight-bit is cleared, resuming when it's set. So, unlike the last example, this one stops when a button is down. Together, these two examples show how to use a one or a zero in any bit position to stop your program — just block out all the other bits and use TRIG to look for a one or a zero in the position of interest. This technique can be used to wait for a peripheral to signal that it is ready to proceed, assuming that the signal comes by way of a line going high or low.
WAIT 514,128 pauses until the jiffy counter hits 128. See Table 2 for other valid MASKs for this purpose (WAIT ADDR, T).
WAIT 525,1 : POKE 525,0 waits for any key to be pressed. This is simpler than the more common
25 GET A$ : IF A$ = " " THEN 25
and it allows other statements to follow it on the same program line. The POKE is there to clear the keyboard buffer and can be omitted if there are no subsequent GETs or INPUTs in your program.
WAIT 525,2 : POKE 525,0 waits for two keys to be hit. There is no easy way to wait for three.
WAIT 513,255,PEEK(513) waits for the 4.2 second timer to increment. The screen display will prove that this happens every 256 jiffies.
WAIT 516,1,PEEK(516) illustrates an interesting technique. Whether SHIFT is up or down, this line waits for it to change. (Careful — if you changed ADDR to accommodate your ROMs, the PEEK must be changed to match it.)
WAIT 515, 255, PEEK(515) does the same for any other key.
WAIT 59471, 1, 1 waits for the PA0 line on the user port to go low. Don't try this or the following examples unless you've configured the port for inputs and can control the lines.
WAIT 59471, 1 waits for PA0 to go high.
WAIT 59471, 1, PEEK(59471) waits for PA0 to change state.
WAIT 59471, 3, 2 waits if PA0 is low and PA1 is high. Otherwise, the program continues to run.
Of course, there are hundreds of other ways to use WAIT. If you understand the ones we've looked at here, you're ready to find and exploit the others. Here's one of them, to check your understanding: If X means we don't care whether a bit is 0 or 1, and if we want our program to pause as long as XXXX0101 appears in location 59471, but to continue on any other value, the proper statement is WAIT 59471, 15,5. If you understand exactly why 15 and 5 are the proper arguments, you really do know all about WAIT.
Table 2: Some Useful Applications
ADDR is the memory location to be tested.
CONT is ADDR's contents when tested.
WAITing On The VIC-20 And Commodore 64
Doug Ferguson, Elida, Ohio
Joysticks Can WAIT
One of my pet peeves involves a game that uses a joystick for virtually all movement, but when it's time to indicate whether to play again, I have to put aside the joystick and hit a function key, type Y for YES, or hit the space bar. Why not use the joystick?
End-of-the-program questions are well suited for the WAIT command. To replay or not to replay is hardly a "menu" of choices. With WAIT, the computer "waits" for the replay signal. Even if the player wants to quit, he can always RUN/STOP-RESTORE or turn off the power.
The most suitable replay signal is the fire button, as in this VIC-20 example:
6000 PRINT "YOU WIN!!": PRINT" PRESS FIRE-BUTTON TO PLAY AGAIN" 6005 WAIT 37137,32: REM IN CASE BUTTON IS ALSO USED IN THE GAME ITSELF 6010 WAIT 37137,32,32 6020 RUN
Here is a table showing the specific test values not only for the VIC-20 but also for the Commodore 64:
|VIC-20||Joystick 1||Joystick 2|
|ANY (except RIGHT on the VIC)||WAIT 37137,62,62||145,31,31||56464,31,31|
*POKE 37154,127 before and POKE 37154,255 after the WAIT statement on the VIC.
This table assumes you want to test if the joystick is pressed a certain way. If you want to test that a certain position is not pressed, just leave off the last number (as in line 6005).
Tracing With WAIT
Another way to use WAIT is in FOR/NEXT loops in either program or direct mode. For example, to examine the contents of the ROM memory containing BASIC, type in the following program:
100 FOR X = 12 * 4096 TO X + 8191: PRINT X, PEEK(X) 110 WAIT 197,64 120 NEXT
or the direct statement
FOR X = 12 * 4096 TO X + 8191: PRINT X, PEEK(X):WAIT 197,64; NEXT
(In both examples, substitute 10*4096 for the Commodore 64.)
A list of memory addresses and contents will begin to scroll by. To stop printing, press any key (except RESTORE, SHIFT, CTRL, or the Commodore key). Printing resumes when the key is released. If the WAIT is changed to WAIT 653,1,1, the SHIFT key alone becomes the control key. This has the advantage of providing a "hands off" pause by using the SHIFT LOCK key.
It is also possible to single-step (go through a program line by line) using the WAIT command. Simply change the WAIT to
WAIT 197,64: WAIT 197,64,64
for "any key" control or
WAIT 653,1,1: WAIT 653,1
for SHIFT key control, although the SHIFT LOCK is of no consequence when single-stepping.
Escape from examining memory by hitting the RUN/STOP key.