Jim Butterfield, Associate Editor
Machine language programs are fast. So fast, in fact, that for many applications we can consider them to be instantaneous. That's good, of course, but sometimes we have to take steps to restrain the program's speed.
The first moon lander program that I wrote was carefully coded, and the calculations were carefully checked to see that they were correct. I was rather taken aback to discover that the instant I pressed GO I found myself crashed on the lunar surface. All the calculations had taken place correctly, but everything worked too fast.
Waiting For The World
In most cases, your machine language program is controlled by the speed of external events. If you're waiting for a user to type a line at the keyboard, chances are that machine language is running at about a ten thousandth of its potential speed. It can do nothing until the next key is pressed; and chances are that it will do little until a line has been completed by pressing the RETURN (or ENTER) key.
Even when we're not waiting for the operator, we are usually waiting for some external process. Using the printer? Your program will spend most of its time waiting for the printer to be ready for the next character. Disk? Same thing. Communications lines fall into the same category, but there's a difference: even though the transfer rate of characters to and from the communications interface is relatively slow, there will often be a need to check it very frequently.
The result is that your program speed is usually determined by the speed of external events. In this case, the "instantaneous" assumption is quite legitimate.
Let's take another example: you're printing material on the screen. Now you can deliver characters at blinding speed; but there's a limit to how fast a user can read. Better slow it down, or your program will be useless.
Programs that spend most of their time waiting for external events are called I/O-bound. Sounds like a good name for a sailing ship, but it really means that if you could get a faster printer, disk, or whatever, your program would run significantly faster. Your speed is bound to the speed of these devices.
There are other programs that do a great deal of computation: they tend to be compute-bound. No, that doesn't mean that you plan to submit them to your favorite magazine; it means that if you could calculate faster, you'd get more work done. Compute-bound programs are often mathematical in nature: to calculate the millionth prime number you won't care much about your printer speed; you want the computation to be fast. Sorting programs are often compute-bound: there's a lot of calculation needed there.
It's often wise to think about your program in terms of its potential: will it be I/O-bound or compute-bound? It will give you an idea of where you might place extra effort in order to speed things up.
There are many cases where we deliberately wish to slow down the speed of a machine language program. Animation is a prime example: you don't want your space ships, bombs, or cats to always travel at supersonic speed. Indeed, if you used maximum speed you'd never see them.
There are technical reasons to want to slow down certain activities. Some types of interfaces want you to hold a voltage at a certain level for a minimum amount of time before you take it away again. You may need to "stall" for a few instructions (or a few dozen) to make sure that you're doing the job right.
The Stall Loop
The simplest way to slow things down is to kill time in a stall loop. If you're not doing anything else anyway, this is quite sensible and easy to do. We might code:
LDX #$00 LOOP DEX BNE LOOP
At a typical clock rate of 1 Mhz (a million cycles per second) the above routine will waste a little over a millisecond of time. You could make the time shorter by changing the LDX value at the start. For longer delays, you use a loop within a loop:
LDY #$00 LDX #$00 LOOP DEX BNE LOOP DEY BNE LOOP
This will waste almost a third of a second as written above; change the LDY to reduce the delay.
If the time is moderately long and you have other things to do, you may set the desired time into a timer and check it occasionally to see how the time has been going. Timers are part of the interface chips — the 6522 VIA has two of them, for example. They work a little like kitchen timers: you put the desired time in and it runs downward toward zero, showing you the time remaining. Time runs very quickly in these, however: the maximum time is often something like a fifteenth of a second. Don't try to time a boiled egg unless you either call the timer many times or you like it really soft-boiled.
When you have more than one event to time, it's nevertheless often best to stay with just one timer. Juggling various timers can be more work than just setting the next expected event into a single one. When you have numerous different things going on, you can often still work by a single timer, as we'll explain.
It's often convenient to have a single timer, and clock all events on a "countdown" basis. The timer can run at fixed intervals — on the PET, you can often use the interrupt timing of 1/60 second to clock many events.
The trick is this: whenever your timer signals, count one for each event you have going. You can count up or down; but when you have counted a fixed value, it's time to handle that particular process.
An example: you have a game involving tanks, planes, bombs and bullets (the usual destructive thing). On a sixtieth-of-a-second timer, you might move a tank every 20 time units; a plane, every 10 time units; a bomb, every eight; and a bullet every five. You don't need a dozen different timers: every time the bullet counter reaches five, you move it to the next spot of the screen and see what you've shot down.
Machine language is fast, and often seems instantaneous. It's often so much faster than other processes in the computer that we don't need to worry about speed calculations at all.
Sometimes machine language is too fast. When that happens, there are ways of slowing it down.
It's hard to believe that you can be so speed rich that you have to rein back your program, but it can happen.