Your Spectrum
Issue 2, March 1984 - System Variables
Home Contents KwikPik


See also the second half of this article:
Issue 3"Variables on a Theme"


[There were a number of typographical errors in this article. I've corrected all the ones which I spotted.]

The system variables are bytes in the Spectrum ROM which allow the computer to know all the things it should do to operate in the way you've come to expect. The information, such as how the Spectrum's memory is laid out, is held in the system variables in these addresses so that the computer can get hold of it and update it as and when required.
We can make use of the information stored in these memory locations in our programs, either by reading information already there or changing it to make the computer do something it might not otherwise do, or sometimes do it more easily.
Not all of them are that much use to us. And certainly not all of them ought to be changed. Some will cause the computer to crash, or the computer may simply ignore you. Some can be happily changed under certain circumstances only, and most within strict limitations. I hope to give you some guidelines as to what can and can't be done, but hopefully you will learn your own little PEEKs and POKEs in time as well.

23552 to 23559 KSTATE reading the keyboard

When the processor is interrupted (50 times every second in the UK normally) one of the things done is to read the keyboard and store the results here. The bytes have different uses. Not all can be practically used by the programmer. You can use this program to examine what's going on in the eight bytes of KSTATE. Run it and press various keys to see what effect individual keys have, such as the Shift keys, and what effect going from one key to another has.
10 FOR A=23552 TO 23559
20 POKE 23692,0: REM KEEP SCROLLING
30 LET B=PEEK A
40 PRINT A; TAB 10;B; TAB 20;CHR$ B AND B>31
50 NEXT A
60 GO TO 10

The first four bytes of KSTATE deal with something called 'two key rollover' which allows you to press a second key before you actually let go of the first. The descriptions given to the main four bytes, 23556 to 23559, will apply to the first four also as long as you bear in mind that these only come into operation for two key rollover. PEEK 23556 can return the code of the upper case version of the key pressed, so if you pressed Symbol Shift A you would get the code of 'A', not the code of 'a' nor the code of 'STOP'.
This may be useful where it is essential that upper case be entered, etc. The effect of pressing a key is temporary and lasts only as long as the key is being pressed. The value in 23556 would be 255 if no key was being pressed at the time the interrupt had occurred. For the Enter key, a value of 13 is returned. For the Space key, a value of 32 is returned.
big title
System variables are bytes in memory which help the Spectrum remember certain things it needs to know about itself- if you like, the housekeeping routines. Delve deeper into the Spectrum ROM with Dilwyn Jones in this, the first of two articles which investigate the complete available set of system variables, giving comprehensive guidelines as to what you can and can't do with them.

PART ONE
Pressing both Shift keys simultaneously produces 14. This program will demonstrate this:
10 LET A=PEEK 23556
20 POKE 23692,0
30 PRINT A, CHR$ A AND A>31
40 GO TO 10

23557 is used for timing to prevent intermittent key contact, etc, causing problems - known as keyboard de- bouncing.
23558 is the auto repeat timer which times the pause before the keys start repeating, then the pause between repeats once the key has actually started repeating. The delays used are those in the system variables that hold these delays (23561/2).
23559 contains the code of the last character pressed on the keyboard. This depends on whether the Shift keys were pressed or not. The numbers produced are those that would be returned by PRINT CODE INKEY$ except that these are the last key pressed and not necessarily the key currently being pressed. Try this program to display what can happen - RUN it and try pressing various keys making use of the Shift keys.
10 LET A=PEEK 23559
20 POKE 23692,0
30 PRINT A, CHR$ A AND A>31
40 GO TO 10

See also under 23611 FLAGS.

23560 LAST_K Newly pressed key

Every time the keyboard is scanned, a key is found to have been pressed and proved valid, the value of this system variable is updated. Its content is the code of the last key pressed.
This system variable does not really
do much you could not do with INKEY$, except that it could be used to type ahead one character. If you try this program, you will find that if you press a key when invited to do so, the key is indicated on the screen in a short while even though the program may not have got as far as line 50 when you pressed a key. The code of the last key pressed is stored here and stays here until another key is pressed. It is possible to test for a newly pressed key by examining bit 5 of the system variable FLAGS 23611. This would be '1' for a key just pressed.
10 PRINT "Press a key now"
20 FOR A=1 TO 900
30 NEXT A
40 CLS
50 LET A=PEEK 23560
60 PRINT A: IF A>31 THEN PRINT CHR$ A

This could be used for testing for a y/n (yes or no) type situation - if you knew one was coming up, you could indicate your response before the program got there and the program would respond when it got round to it. Also, if two keys were pressed simultaneously, the program would respond if one were released without having to wait for the keyboard to be released completely.
Control characters can be generated using Caps Shift in conjunction with the number keys. Enter returns 13. Pressing both Shift keys together returns 14. To see this, try this program:
10 LET A=PEEK 23560
20 PRINT A, CHR$ A AND A>31
30 GO TO 10


23561 REPDEL Repeat delay

This system variable contains the length of time that a key must be held down before it starts to auto-repeat. The time

small title delay in the UK is one-fiftieth of a second and starts off at 35/50 of a second. You can happily POKE this if, for instance, you want the key to start repeating immediately. The cursors become rather difficult to control if you, say, POKE 23561,1. POKE 23561,0 effectively turns off the auto-repeat, actually giving a delay of about five seconds like POKE 23561,255.

23562 REPPER delay between repeats

This system variable controls the length of time between repeats once the auto- repeat has actually begun. The time is in fiftieths of a second in the UK. If you effectively want to turn off the auto- repeat for any reason, POKE 23562,0 or POKE 23562,255 gives about five seconds between repeats. If you wish to edit long program lines (eg. a long PRINT statement) then POKE 23562,1 will speed up moving the cursor to the right place. But beware of changing 23562 too much at the same time or you may speed up the cursor so much it becomes difficult to control. Its normal value is 5/50 to a second or one tenth of a second.

23563/4 DEFADD

The address of the argument of a user- defined function in a program; ie. if you had DEF FN A(B) in a program line, the value in 23563/4 would be the address of the letter B in the brackets in that line while only the function is being used. The best way to PEEK into 23563/4 to show this is to put the PEEK as a part of the FN to be evaluated as there is always a zero there unless the function is being evaluated. So the line:
10 PRINT PEEK 23563+256*PEEK 23564

would always return zero. On the other hand:
10 DEF FN A(B)=PEEK 23563 + 256*PEEK 23564
20 PRINT FN A(999)

would return the address of the B in line 10. The 999 is not significant, just something to actually give a value to B to prevent an error. In the case of a function with no argument:
10 DEF FN A()=PEEK 23563 + 256*PEEK 23564
20 PRINT FN A()

this would print the address of the closed bracket symbol.

23568 to 23605 STRMS

The first 14 bytes on a basic Spectrum contain addresses relating to channels and streams. Streams -3 to +3 are stored in two bytes each.

23606/7 CHARS

This system variable has as normal values:
23606 contains 0
23607 contains 60
This system variable points to the start of the character set that the computer uses for printing on the screen and the printer. SCREEN$ also uses this system variable. The normal address pointed to is 15360 which is 256 less then the address of the start of the ROM character set. (256 less because the character generator is accessed by something similar to PEEK 23606 + 256 * PEEK 23607 + CODE "A" * 8 and since the first character is a space, and the code of a space is 32 you can see that 8 * 32 is 256). The character generator is 768 bytes long, so if you wish to set up a new character set you must set aside this number of bytes in case it is overwritten by Basic - you wouldn't get a crash, you'd just end up with gibberish.
Mention was made of SCREEN$ using this system variable - in fact, you may be aware of the problem that SCREEN$ does not recognise user- defined graphics normally, unless they happen to be similar to an existing Spectrum character. In fact, SCREEN$ works by picking up the address of the start of the character generator and looking through the table until it finds a matching character. Now since the Spectrum screen is bit-mapped rather than memory-mapped like some computers, once anything is printed on the screen it stays the same even if you change the character in memory. So we could temporarily change the pointer to the character set to point to the user- defined graphics and look up there.
One snag is that although there is a system variable that tells us where the user-defined graphics start, this address is 256 or more - so we must subtract 256. This conveniently means we subtract one from the high byte. This program should demonstrate:
10 FOR X=144 TO 164
20 PRINT AT 0,0; CHR$ X
30 POKE 23606, PEEK 23675
40 POKE 23607, PEEK 23676-1
50 PRINT AT 20,0; SCREEN$ (0,0)
60 PAUSE 40
70 POKE 23606,0
80 POKE 23607,60
90 NEXT X

What we did was make the computer think the user-defined graphics are the normal character set. SCREEN$ will still produce characters with codes of 32-127, although this is easily overcome with a bit of fiddling. Since SCREEN$ starts off with CHR$ 32 and the UDGs start off at 144, we would need to add 112 to return characters
in the range of the user-defined graphics.
Here is one way to do this. X is the x co-ordinate across the screen and Y is the y co-ordinate down the screen of the location SCREEN$ is to examine. A check is first of all made that SCREEN$ does not find one of the normal characters there, then returns if one is found. The character at Y,X is returned in A$. Line 8025 is needed only if you are using a character set other than the ROM one. If you are using the ROM character set, then delete line 8025 and replace lines 8070 and 8080 with the alternative versions that follow.
8000 REM SCREEN$ FOR UDGs
8010 LET A$=SCREEN$ (Y,X)
8020 IF A$()="" THEN RETURN
8025 LET A=PEEK 23606: LET B=PEEK 23607
8030 POKE 23606, PEEK 23675
8040 POKE 23607, PEEK 23676-1
8050 LET A$=SCREEN$ (Y,X)
8060 IF A$()<>"" THEN LET A$=CHR$ (CODE A$+112)
8070 POKE 23606,A
8080 POKE 23607,B
8090 RETURN

8070 POKE 23606,0
8080 POKE 23607,60

The story does not finish there. There are only 21 user-defined graphics - if SCREEN$ does not find a match, it will continue looking up past the user-defined graphics until it has finished looking for the 32 to 127 range it thinks it's looking for. This could be embarrassing if there just happened to be some data stored above the UDGs for any reason which resembled any character. To help prevent this happening, although the UDGs are normally at the top of RAM anyway, this line could be added:
8065 IF A$>CHR$ 164 THEN LET A$=""

Incidentally, you should ensure that 23606/7 always points to the right character set when PRINTing, LISTing, etc, is done.

23608 RASP

Controls the duration of the buzz that sounds to warn you that you are running out of memory. At switch-on, this has a value of 64. This can be altered, but there seems little point. POKE 23608,0 gives a very short click rather than a buzz - useful if you hate the buzz that satirically mocks you when you run out of memory. Alternatively, POKE 23608,255 gives a very long buzz which immobilises the keyboard, preventing you typing any further than when the buzz sounded.

23609 PIP

Controls the length of the click emanated when a key is pressed in command mode or during an INPUT. It starts off at zero but may be changed. Any value between 30 and about 130 gives a pleasant, more audible bleep rather than the quieter click normally given. Values high than 130 tend to noticeably slow

small title down the keyboard response (since computing stops as the bleep is sounded). Usually, the one to use is POKE 23609,100.

23610 ERR_NR

Controls error report number and normally has a value of 255 unless an error arises, when it contains one less than the error report codes printed, eg. for error 4, out of memory, it would contain a three. The message printed out is contained in ROM starting at address 5010 decimal. The end of the message is signified by the last character in the message having bit 7 set to a one. After the error message comes the '© 1982 Sinclair Research Ltd.' message that you see after switch-on or NEW. You can POKE 23610 to generate an error to stop the program, but since the message printed is fixed and in ROM, you may end up with garbage.
If you wanted to simulate an 'out of memory' error you would end a program with POKE 23610,3. This would not work as any program line; you'd have to ensure that it was the last line, as once a condition arises to end a program, only then is 23610 looked at to determine what is printed.

23611 FLAGS

This system variable contains various flags controlling the Basic system and generally should not be POKEd. However, some of the flags can be usefully PEEKed.
Bit 0: Being a one indicates no space to be printed before the next keyword.
Bit 1: This bit being set to a one indicates that the print output is to be send to the printer. A zero would mean it is to be sent to the TV screen.
Bit 5: Any newly pressed key is indicated by its code being stored in 23560 (the LASTK system variable) and bit 5 of 23611 (FLAGS) is set to indicate that a new key has been pressed.
Bit 7: Syntax flag.
These will be of more use when using ROM routines in a machine code program.

23613/4 ERR_SP

Keeps track of the address on the machine stack where the appropriate return data lies. Try calling a few GOSUBs with no matching RETURNs and watch this point down the memory. Now you can see what happens and why this occurs when you run out of memory in a situation like this. Also, try PEEKing
the contents of the three addresses (the base of which is pointed to by 23613/4) to see what return data actually consists of.
10 LET A=PEEK 23613 + 255*PEEK 23614
20 PRINT PEEK A; TAB 10; PEEK (A+1); TAB 20; PEEK (A+2)


23617 MODE

Specifies cursor. Values zero, one, two or four specify the L/C mode, E mode, G mode or K mode respectively. POKEing this system variable will affect the appearance of the cursor - it may appear as a flashing letter, number, symbol or even a keyword. This is most apparent during an INPUT statement. The value is reset when the need arises, eg. a mode change made normally from the keyboard. So if you get into difficulties, press both Shift keys for E mode and then the same again to get back to normal L/C mode.
Try this program which POKEs all possible values into 23617. Most are variants on the four cursors, ie. you will find yourself in a particular mode after the POKE, such as everything coming as graphics as in G mode. 252 will give an L/C mode flashing '<' to point to
BORDER colour. Take a look at Table 1.
By POKEing various values into this system variable you could achieve a flashing, bright, multicoloured lower screen, or make both PAPER and INK the same colour to prevent other people getting at your programs - however, any alteration would have to be made blind. You could also make INPUTs extra bright to stand out.

23627/8 VARS

The pointer to the start of the variables store. Apart from finding your way into the variables area, you can find the length of the Basic program with this expression. This excludes screen, system variables, stacks and variables.
LET bytes=PEEK 23567 + 256*PEEK 23628 - PEEK 23635 - 256*PEEK 23636


23629/30 DEST

The address of the variable when it is assigned to. If the variable had been set up before, it would point to the start of where it was stored in the variables area. If it was being defined for the first time, it would point to the address of the start of the name of the variable in the
BIT7 BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0
FLASH
lower
screen
lower
screen
BRIGHT
BORDER colour
and lower screen
PAPER
lower screen INK
Table 1. The bits of system variable 23624 control the attributes of the lower screen and the BORDER colour.
where you're typing ...
10 FOR A=0 TO 255
20 PRINT A
30 POKE 23617,A
40 INPUT A$
50 NEXT A


23618/9 NEWPPC and 23620 NSPPC

23618/9 is a two-byte system variable containing the line number of the line to be jumped to. 23618 contains the lower byte of the line number and 23619 the higher, so the line number contained is read as PEEK 23618 + 256 * PEEK 23619. To POKE a line number in, say line X:
POKE 23618, X-256*INT (X/256)
POKE 23619, INT (X/256)

We now come to system variable 23620. With 23618/9 and 23620, we could actually simulate a GO TO command to a statement within a program line, should that ever be necessary. GO TOs cannot access individual statements within long program lines.
To jump to statement four in line X, first go through the motions described above then POKE 23620,4 and the jump is executed.

23624 BORDCR

The bits of this system variable control the attributes of the lower screen and the
program, eg. in 10 LET A = 5, it would point to the address of the letter A.
It can also be used to find the memory address of a numeric variable, if you use something like LET A=A as in the following program:
10 LET A=5
20 LET A=A
30 PRINT PEEK 23629 + 256*PEEK 23630


23631/2 CHANS

Stores the address of where the channel information area starts.

23633/4 CURCHL

The address of INPUT/OUTPUT information used at that moment. It normally points during an INPUT/ OUTPUT operation to a five byte block of data in the channel information area. Use this program to examine the contents.
1 FOR X=0 TO 3: PRINT #X; PEEK 23633 + 256*PEEK 23634: NEXT X: PAUSE 0: STOP

This article is extracted from Dilwyn Jones' book, Beyond Simple Basic - Delving Deeper Into Your ZX Spectrum. This book was first published by Interface Publications, n-nn xxxxxxxxxx xxxx xxxxxx, xxxxxx xn nxx, and is priced at £7.95.
Home Contents KwikPik