helpline |
Andrew Hewson suggests ways of producing continuous sound
A INTERESTING point about the Spectrum is raised by Michael Rodway, who writes: I have noticed that a small number of commercial games produce sound continuously while the program is running. How is that effect achieved?
The simplest technique is to call a sound routine at various points during the execution of the program but usually that creates an intermittent effect because it is difficult to arrange the calls to the routine so that they occur at regular intervals. The only alternative is to use the interrupt system built into the Z-80 microprocessor. This is a difficult task but the result is usually worth the effort involved.
The interrupt system, as its name implies, is a mechanism by which the processor can be diverted from the task it is undertaking to do something more urgent. When the processor has completed the more urgent task it resumes its previous job. All computers have an interrupt system and on more sophisticated machines they allow the computer to maintain a priority system for all the tasks it has in hand at any moment.
A low-priority task is deferred in favour of a more urgent one which, in turn, is suspended while a yet more urgent job is started, and so on. As each task is completed the machine reverts to a previous, half-completed job.
Two types of interrupts can occur in the Z-80. The more important is the Non-Maskable Interrupt - or NMI - so-called because the programmer is unable to prevent, or mask, the Z-80 from responding to such an interrupt when it occurs. The NMI is not of much interest to most Spectrum programmers because itis designed for use with external hardware.
The maskable interrupt is of more interest because it can be switched off, so that all subsequent interrupts are ignored, and because the Z-80 can beset to respond to it in any one of three modes. In mode zero the processor waits until it is directed by an external device to execute a routine somewhere in memory. In the Spectrum there is no provision for the use of this mode.
The Spectrum is designed to operate in mode one all the time. In that mode the Z-80 saves the contents of the program counter - so that it can later resume the task it was doing - and jumps to location 38h - 56 decimal. The Spectrum hardware forces the jump to be made by generating an interrupt 50 times per second.
The ROM routine at this address updates the clock by incrementing the FRAMES systems variable held at 23672 to 23674 and then scans the keyboard to see if a key is being pressed. If so, the appropriate code is stored in the system variables and various flags are altered. On completion of the keyboard routine all the registers are restored to their previous values and the processor resumes its previous task.
The final interrupt mode, mode two, is the most powerful. If the Z-80 is interrupted while in that mode it saves the program counter as previously and jumps to an address determined partly by software and partly by the hardware which caused the interrupt. To be more specific, the Z-80 takes the value in the I register and the value generated by the external hardware and calculates an address from them as:
Address = 256 * I register + hardware
It then looks at the contents of the calculated address and the subsequent one and calculates a new address from them as:
New address = Address + 256 (Address + 1)
It then jumps to the new address. Thus if the I register contained 143 and the hardware generated the value 27, the Z-80 would look at the contents of
256 * 143 + 27 = 36635 and 36636
If those two locations contained 137 and 93 respectively - i.e., PEEK 36635 = 137 and PEEK 36636 = 93-it would then jump to location:
137 + 256 * 93 = 23945
The rather complicated procedure is known, aptly, as an indirect jump and is not so cumbersome as it seems at first sight. It enables as many as 128 types of devices to be attached to the Z-80, each type generating its own value to contribute to the indirect jump address. The programmer then constructs a table containing 128 addresses, each held in two bytes and each pointing to the routine which handles a particular device. The I register points to the location of the beginning of the entire 256-byte table.
The Spectrum does not use interrupt mode two and the designers have used the I register for their own purposes connected with the scanning system for the TV screen. The initialising routine in ROM puts the value 63 into that register and if any value between 64 and 127 is loaded instead, interference occurs with the TV display.
|
To see the effect, load and run the program listed in table one. The program puts a short machine code routine into the printer buffer which loads a value into the I register. The Basic loop increments the value loaded into I and shows the effect on some PRINTed characters.
I know of no cure for the interference on the screen and would be interested to hear from anyone who might be able to suggest one. The effect is to restrict the area of memory which a Spectrum programmer may use to hold the pointer for a mode two interrupt. A few moments' calculation shows that any address between 16384 and 32767 inclusive will require the I register to be set to some value in the range 64 to 127. As that is the entire area of RAM available in the 16K Spectrum, it would appear that interrupt mode two cannot be used in these machines.
|
There is a way round the problem. If there is no hardware connected to the 16K Spectrum, the low byte of the indirect address will take the value 255 by default. We can safely set the I register to any value in the range 0 to 63 inclusive. Suppose we choose to set the I register to 37. When an interrupt occurs in mode two the Z-80 will then look at the two addresses:
256 * 37 + 255 = 9727 and 9728
to determine the location to which it should jump. The two addresses are, of course, in ROM and they contain 118 and 92 respectively so that the Z-80 will jump to:
118 + 256 * 92 = 23670
That location is in the system variables area and usually is used to hold the SEED for the generation of the next random number. A relative jump instruction to the printer buffer, or anywhere else close by, can be placed here instead of the seed without great loss. Provided the user takes care not to execute a RANDOMIZE command the instruction will not be over-written.
There are several other values which could be placed in the I register which would cause an indirect jump to an address in RAM but for my purposes here 37 is the most suitable. Table two lists three machine code routines designed to be loaded into the printer buffer which switch between interrupt modes one and two and make use of the technique. They can be loaded using the decimal loader given in table three.
|
The first routine, loaded at 23296, restores interrupt mode and re-sets the value in the I register to 63 if required. The second routine establishes the chain linking the SEED system variable, first to the end of the printer buffer and then to the address of the beginning of the third routine. It then alters the value in the I register to 37 and sets mode two.
Thus when the routine is executed the Spectrum no longer jumps to the ROM clock and keyboard routine, at address 50, 50 times per second. Instead it jumps via SEED and the end of the printer buffer to the third routine.
The third routine, just to prove that the system works, transfers from FRAMES into the attributes area, causing a single square on the screen to change colour rapidly. A call is then made to the ROM clock and keyboard routine so that the Spectrum continues to function correctly.
The third routine can be extended to generate continuous sound by adding a suitable call to the beeper routine which is located in the ROM at address 949. An example is given in table four. Note that the contents of many of the registers are saved by pushing them on to the stack before the beeper routine is called.
That step is necessary because the beeper routine uses those registers and the routine which was interrupted will have almost certainly been using them for its own purposes.
For more complex interrupt service routines it may be necessary to save all the registers and some of the system variables as well.
The tone produced by the beeper routine is determined by the contents of de and hl. The values shown give a note about two octaves above middle C. All completion of the routine by popping the values in reverse order from the stack.
A number of readers have written asking for an opinion on the Microdrive now that it has finally appeared.
A typical question is from Tom Pendlebury, who asks: Is it possible to pick out a single item from a Microdrive file or must the whole file be read into memory?
The software in the interface which controls the Microdrive is fairly elementary so that the use of a Microdrive file is restricted in a number of important ways. For example, if a file already exists on a cartridge it is possible only to read it, not to write to it, so that corrections can be made only by reading the file into memory, making the correction, erasing the Microdrive copy and then writing the corrected file back on to the cartridge.
Similarly, it is not possible to read a single item, as Pendlebury asks, although it is possible to read part of a file so that if the information required is near the beginning only the first part needs to be read.
There is no doubt that the Microdrive is another Sinclair value-for-money innovation and I am sure that software will be developed to extend the facilities provided.
To help set the ball rolling I have written the Basic Bootstrap program listed in table five, which allows the user to select whichever program he requires from the Microdrive cartridges.
|
The program generates a catalogue of the files on the cartridge selected by the user, reads the catalogue into memory and erases the cartridge copy, so that an up-to-date copy is always generated.
The Bootstrap program then loads the program selected by the user.
This rather convoluted approach is used because it would appear that the Microdrive does not maintain a catalogue of the files on each cartridge, so that the catalogue must be re-generated each time the program is used. I may be incorrect about this conclusion-I have not had the Microdrive long enough to be certain. If I am wrong I shall no doubt be deluged with letters pointing out the error.