Andrew Hewson investigates the memory map and puts the tick into a Spectrum screen clock using machine codes
THE INSPIRATION for the column this month comes from a letter from Peter Green who writes: "I was recently given a Spectrum and I want to learn how it works. I have been reading the manual, particularly Chapter 24 on the internal workings, but it does not make much sense to me."
A computer is a machine which is capable of storing a sequence of instructions and then executing them. To do so requires a memory in which the instructions can be stored. Most home micros contain two distinct types of memory. The first type is read-only-memory - ROM - which contains the fixed set of instructions implanted in the machine by the manufacturer. The second type is random-access-memory - RAM.
RAM is the notepad of the computer. When it is performing a task it is continually looking at what is in RAM - 'reading' from memory - and altering the contents of RAM 'writing' to memory. The notepad is not used haphazardly - different parts of RAM are used to store different sorts of information.
A Basic program entered by the user, for example, is stored in one part of RAM, whilst the variables used by the program are stored elsewhere. In Sinclair machines, the size of the notepad is limited so the machine is careful to allocate just the right amount of space required to hold a given piece of information.
Spare space is always collected in one place so that if, for example, the user wants to add a line to his program the information in RAM is shuffled along so that some spare space is used up and just enough space is created at the location at which the line is to be added.
There are 16384 memory locations in RAM in the 16K ZX Spectrum the 48K machine has a further 32768 locations making 49152 in all. Each location can hold a single whole number between 0 and 255 inclusive and is identified by its 'address' which is a positive whole number.
Addresses 0 to 16383 are assigned to the fixed form of memory, the ROM, and so the first address assigned to RAM is 16384. Table one shows the memory map of the Spectrum: how RAM is used starting at 16384. The display file, for example, which holds the information which is currently displayed on screen, occupies locations 16384 to 22527. The attributes, which determine the colour, brightness and so on, of the screen display, follow immediately afterwards in locations 22528 to 23295.
The first five addresses in the first column of table one are all fixed because the display file and the attributes all occupy a fixed amount of space. The fifth area is assigned to the microdrive maps. If a microdrive is attached to the Spectrum that area contains the information on the layout of the data on the cartridge.
If a microdrive is not attached, the area is not needed in which case the sixth area, channel information, lies immediately after the fourth, the system variables, in line with the practice of saving space wherever possible. Hence the starting address of the channel information area and all subsequent areas is not fixed but can 'float' up and down RAM.
The Spectrum keeps track of the starting address of all those areas by storing the current value of each address within the system variables area. The system variables area is the fourth in the sequence, between the printer buffer and the microdrive maps at locations 23552 to 23733. The address within the system variables area which holds the starting address of each 'floating' area is listed in column two of table one. The address of the Basic program area, for instance, is held at 23635 within the system variables area.
Referring to each system variable by the address at which it is held is rather awkward and so each is given a name - PROG in the case of the location which holds the address of the Basic program area. Those names are for the user's convenience only. They are not recognised by the Spectrum. Thus entering the line:
will cause the error message '2 Variable not found' to be PRINTed unless a Basic variable called PROG has been generated coincidentally by a program or by the user. The value of such a Basic variable would in general have nothing to do with the value of the PROG system variable.
Simon Carver also has a Spectrum. He writes: "Can you explain the difference between PEEK and POKE?"
The memory map is the key to understanding the use of RAM by the Spectrum but the keys to exploring RAM are the Basic keywords, PEEK and POKE, which allow the user to look at the contents of a memory location and alter it respectively.
PEEK is a function of the form:
The address can be a positive whole number between 0 and 65535 or an arithmetic expression which when evaluated gives such a positive number. It is important to enclose an arithmetic expression in brackets because
PEEK 16384 + 2
is integrated as 2 added to the result of:
PEEK (16384 + 2)
is interpreted as
The value returned by the PEEK function is the number currently held at the address in question which will always be a positive whole number between 0 and 255 inclusive. It was explained above the PROG system variable is held at address 23635 but that is not strictly correct. The value of PROG, being an address in RAM, is always much larger than 255, and therefore two adjacent addresses, 23635 and 23636, are needed to hold it. The value of PROG can be PRINTed by entering:
PRINT "PROG =";PEEK 23635 + 256 * PEEK 23636
All addresses are held in two adjacent locations in this fashion and can be inspected by entering:
PRINT PEEK first address + 256 * PEEK subsequent address
For example, if a Spectrum is used without a microdrive attached the microdrive map will be non-existent and the channel information will follow immediately after the system variables areas. Thus the value of the CHANS system variable will be the same as the starting address of the microdrive map, were it to exist, that it, 23734. CHANS is held at 23631 and 23632 and so entering
PRINT PEEK 23631 + 256 PEEK 23632
will yield the value 23734.
The PEEK function can be used to look at the contents of any location in memory, including the fixed instructions in ROM. It is therefore a very important tool. PEEKing any location will not cause the Spectrum to crash or corrupt a program or variables. Very occasionally, the results of a PEEK can be misleading because the contents of the location being PEEKed may alter during or immediately after the execution of the instruction. For example, if the contents of the locations which are assigned to the top left-hand corner of the screen display are PEEKed and the results PRINTed in the top left hand corner of the screen, the information will already be out-of-date by the time the user views it.
The POKE command is altogether more dangerous than the PEEK function because by invoking it the user is likely to interfere in the functioning of the Spectrum. It is quite possible using this command to make a nonsense of the information in RAM causing the machine to crash, or to halt and display an error code.
The form of that command is:
POKE address, number
Once again, the address is a positive whole number between 0 and 65535 inclusive, or an arithmetic expression which gives such a number when evaluated. Unlike PEEK is is not essential to enclose an arithmetic expression in brackets because POKE is a command, not a function, and therefore cannot be evaluated as a whole. The number POKEd into a location must lie between 0 and 255 inclusive.
Both the ZX-81 and the Spectrum will accept and execute a POKE command directed at an address in ROM - an address between 0 and 16383 inclusive. However, the number will never reach its destination because the contents of ROM are fixed. That fact can be demonstrated by RUNning the following program:
10 PRINT PEEK 0 20 POKE 0,92 30 PRINT PEEK 0
Line 10 PRINTS the contents of the first location in ROM. Line 20 attempts to alter the contents to 92 but line 30 will show that no effect has registered.
The final letter comes from Michael Mehta. He writes: "Could you supply a machine code routine on the Spectrum which shows the elapsed time in minutes and seconds on the screen? I know how to do the job in Basic but the routine takes too long to run."
The machine code routine to display minutes and seconds is listed in table two. As usual, I have listed the code in decimal so that those people who do not have an assembler can POKE it straight into memory.
Please note that the routine runs under the interrupt system. This is achieved by setting the Z80 into interrupt mode two and then vectoring the call to the beginning of the routine.