Spectrum Operating System The
Spectrum Operating System The
SYSTEM
^ ._
^^,'
^ —
---•e^^
GB f NET +095.95 ■■■■
111111■■
ISBN 0 - 7447 - 9019 - 1
00595
The Spectrum
Operating System
The Spectrum
Operating System
Steve Kramer
Getting Started
While this book is primarily aimed at those people who have a
reasonable understanding of assembly language programming,
there will be a considerable amount of information which will be
of use to the uninitiated programmer who would like to be able to
gain access to the versatility of machine code, without having to
learn how to write it. If you belong to the latter group I hope that
this book will whet your appetite, an d prompt you to start
learning a little about assembly language programming. With the
minimum amount of knowledge an d using the routines in the
following chapters, sho rt machine code routines can be written
and used very easily.
For anybody not familiar with the operating system of the
Spectrum or who is basically bone idle (like me) and who prefers
to use ROM routines an d existing facilities — rather than
re-inventing the wheel every time they want to write a program—
I will be discussing how to use ROM calls in both the 16K ROM,
which is in the Spectrum, and in the 8K ROM in the Microdrive
Interface. In some cases, I shall give examples as well as
descriptions of how to use them, except where they are just a
simple CALL.
I shall also look at the system variables an d show how to use
them to advantage, and explain the use of interrupt-driven
routines, which can allow sprites to be used on the st an dard
Spectrum.
Unless you wish to convert the assembly language routines by
hand into numbers an d then poke them into your computer's
memory, a prerequisite to being able to use this book is an
Assembler program. I can recommend the Picturesque Editor
Assembler and also their Monitor/Disassembler programs,
which are both very easy to use an d fast. I can also recommend
Highsoft's Devpack 3 which will be even better with a few
improvements which will probably have been made by the time
2 The Spectrum Operating System
you read this chapter. For the more experienced user, the Chapter Two
Devpack (which contains both Monitor/Disassembler and Editor/
Assembler) is, in my opinion, at present unsurpassed. The latest
versions of both these programs are Microdrive-compatible.
It is not my intention to teach assembly language programming
Useful Call Addresses
as there are a great many books already available which cover this
in detail. Two that I can recommend are Rodnay Zaks'
and How to Use Them:
Programming the Z80 and Spectrum Machine Language for the
Complete Beginner. The first is not related to the Spectrum, but
the 16K ROM
goes into far more detail than the second and also has concise
descriptions of all the available op-codes.
To call a machine code program from BASIC you can either use
a RANDOMIZE USR NN, a PRINT USR NN or a LET V = USR
NN command, where NN is the entry point to the machine code It is important before using ROM routines always to save the H'
program and V can be any numeric variable. On return from the and L' registers, and restore them afterwards before a return to
machine code routine, the variable in the LET command will be BASIC is made. Also the IY register must always contain the
equal to the BC register pair on exit, and with the PRINT address of the system variable ERR NR 23610 (5C3Ah) whenever a
command the value in the BC register pair will be printed to the ROM routine is used.
current stream. In all cases the BC register pair will contain NN on
entry to the machine code program.
Whenever a machine code program is called, it is advisable to
save the contents of the H'L' register pair since the contents of Printing: RST 16 (10h)
this are necessary for a successful return to BASIC. The IY register
pair should not normally be used as the ROM uses this to index The character whose code is in the A register will be printed to
the system variables, but it can be used so long as the interrupts whichever stream is currently open. This can also be used to
are off and no ROM routines are used before it is restored to 'print' control codes (i.e. TAB, INK, OVER, etc.; see the Spectrum
holding 23610 (5C3Ah). manual for details).
This book is intended to be a reference work which you will
turn to for information for as long as you have your Spectrum. I
have made no attempt in the main text to be chatty or to hold your
hand, but I hope the information required is there. Obviously it Opening and Closing Streams (for RST 16 (10h)):
would be impossible to detail all the ROM routines and all the CALL 5633 (1601h)
ways they could be used, so I have selected those that I am asked
about most often and find most useful. Further reading for the CALL 5633 (1601h) sets the output for RST 16 (10h) to the stream
serious programmer must be Dr Ian Logan's Complete Spectrum held in the A register when called. Normally A = 2 will print to
ROM Disassembly. the main screen, A = 3 will print to the printer and A = 1 or 0
will print to the lower screen. With the Interface 1 connected,
other streams can be used for output to the Microdrives, network
or other devices. Details are given on how to divert streams for
your own purposes (e.g., for controlling an interface for other
uses such as the Kempston or other Centronics printer interface)
4 The Spectrum Operating System Useful Call Addresses and How to Use Them: the 16K ROM 5
in the section on Expanding Tokens for Output later in this calling 5633 (1601h). Caution needs to be exercised on the last line
chapter. of the main screen as a scroll message will be generated after
printing on the last available position. This will cause a return to
BASIC if answered with 'n' or SPACE. In addition to this, any
Detecting if Break is Being Pressed: CALL 8020
attempt to print to stream 1 will cause scrolling up of the lower
(1F54h)
screen when the available space set up by the system variable DF
SZ (23659) has been filled. This can produce some very
This call will return with the car ry flag set if it is not being
unexpected results.
pressed, and with the car ry flag reset if it is being pressed. (Note:
Obviously when printing to a printer you cannot set a line
This call tests for both CAPS SHIFT and SPACE being pressed.) If
number so the B register is not used.
you want to test for SPACE alone see the section later on Getting a
Character from the Keyboard for full details but, for the time
being, you could use:
Clearing the Screen (Whole Screen): CALL 3435
LD A,7FH (D6Bh)
IN A (OFEH)
RRA This call will clear the whole screen and reset the attributes to
JP NC,PRESSED those in system variable AFIR P for the main screen and
BORDCR for the lower screen (23693 and 23624, respectively; see
the Spectrum manual for how these are made up).
Setting the Position for Printing Using RST 16
(10h): CALL 3545 (DD9h)
Clearing the Screen (Lower Screen): CALL 3438
This routine requires the B register to hold the screen line (D6Eh)
number in the form:
This will clear the lower screen only and reset the attributes.
B = 24 – line number
Note: Both 3435 (D6Bh) and 3438 (B6Eh) reset DF SZ to 2 and can
(i.e. if B = 24, this is the top line of the screen; if B = 1 this is the corrupt the current channel used by RST 16 (10h) so this will need
bottom line). Unfortunately due to an oversight in the writing of to be reset. The current print positions are set to the top left of the
the ROM, you cannot use lines 23 an d 24 for printing on the main respective screens.
screen. So you must use the lower section by setting up the
output stream for RST 16 (10h) to be 1, and using the top two lines
of the lower screen. Scrolling the Screen: CALL 3582 (DFEh)
C = 33 – column number This scrolls the screen up by one line, but leaves the current print
position unaffected. Therefore if you continually print to the
(i.e. if C = 33 this is the left-most column; if C = 2 is the right- same line, scrolling the screen at the end of each line, you will
most). have an effect like typing using a typewriter (with the printing
This call automatically updates the system variables for the taking place at the bottom and the print being moved up after a
print positions on whichever stream you are using, as set up by carriage return).
6 The Spectrum Operating System
Useful Call Addresses and How to Use Them: the 16K ROM 7
So, for example, to read the keyboard for EN'T'ER being pressed INPUTF and if the program is entered (or just this section of it)
the program would be: the problem can be demonstrated by pressing CAPS SHIFT and
SYMBOL SHIFT to go into EXTENDED MODE. The last line that
LD A,OBFH was typed in from the keyboard will then appear at the bottom of
IN A,(OFEH) the screen.
AND 1
When using these routines to read from the keyboard the
JR Z, ENTER PRESSED
interrupts must be on and the normal interrupt routine at 56 (38h)
called within the interrupt cycle, otherwise no input will ever be
To see if more than one key is being pressed you could use the received.
logical operators AND, OR, etc. if they are on the same line or bit
test instructions. See the next CALL 5598 (15DEh) for getting
normal characters easily.
Screen Copy to Printer: CALL 3756 (EACh)
This is a most useful routine which allows for input from any
stream that has an input address. Before use the stream from
which the input is required must be opened by the routine at
Printing Graphics to Printer: CALL 3789 (ECDh)
5633, described earlier. When the Wait Input routine is CALLed,
This is similar to the screen copy routine in that it uses the printer
it in turn calls the input routine of the current channel. On return
buffer and outputs its contents to the printer. It is used by the RST
from this the carry flag is checked, if set the main CALLing
16 routine which normally treats the buffer as one screen line
program is returned to. If the carry flag was not set the 0 flag is
(eight pixels high). If you place your graphics into the buffer one
then checked, and if set the process is repeated.
line at a time and then make a CALL to this address, the printer
The routine is used by the Spectrum as the control for the will copy the buffer to the printer.
current input subroutine, normally the keyboard input, but if
CURCHL is set to point to a channel with the input address Note: The layout is 32 bytes per pixel line with the next pixel line
pointing to your input subroutine this will be used. (How to do following immediately and not as the screen. The buffer is also
this is explained in Chapter 5.) When used with stream 1 (the cleared to Os after a CALL.
keyboard and lower screen), the routine will wait for a key to be
pressed and return its code in the A register. This use is demon-
strated in the DeBASE program in the Appendix G. Clearing the Printer Buffer: CALL 3807 (EDFh)
There is, however, a problem when using this to read the
keyboard if the mode is changed. Each time the routine is called, This simply clears the buffer to Os.
TV FLAG 23612 (5C3Ch) IY + 2 is checked and if bit 3 is set the
input buffer is copied to the edit area of the screen. This can be
overcome by using the Key Input routine at 4264 (10A8h) directly Using the Beep: CALL 949 (3B5h)
and not via the Wait Input routine, as shown in the DeBASE
program in Appendix G at the label INPUT. The program dupli- The DE register pair holds the length of the output and the HL
cates the Wait Input routine but ensures the MODE CHANGE register pair the frequency. 0 is high for frequency and FFFFh is
flag is always reset. The Wait Input routine is used at the label low. The problem with this routine is that the duration is
12 The Spectrum Operating System Useful Call Addresses and How to Use Them: the 16K ROM 13
This would print to the current stream at the current position the
The reason why the 30.125 is taken away from the HL calculation message <EN'I RY > . To print <ENTRY 2 >, the A register would
is that the routine itself takes 120.5 T states actually to generate
hold 1. The chevrons are only to show the limits of what will
the note and amend its own registers, etc.
actually be printed, and will not appear when a message is
Middle C is approximately 261 Hz so the value for HL would be
printed. This is the routine used by the ROM to expand tokens
about 1646 decimal and DE for one second would be about 261
and generate error messages when called from another routine at
decimal.
2898 (B52h). The DeBASE program (see Appendix G) makes
Remember that the interrupts from the ULA will occur 50 times
extensive use of this routine.
a second (60 times in the USA) and they will corrupt the sound
output if the routine is in the bottom 16K of RAM.
INIT LD HL, (23631) ; CHANS (address of channel This program is a very basic one; if you wish to send any printer
data) control codes, it will not print them. To get round this you will
LD BC,15 ; offset for stream 3
(printer) have to carry out further checks and act accordingly. The first
ADD HL,BC ; HL now points to the section only needs to be called once as it permanently alters
location holding the where output to stream 3 is sent. The only times it needs re-
address to be called with initialising are either after a NEW command from the keyboard or
output on this stream
if the output has been changed by another part of the program.
LD BC,START ; START = address of the
start of your 0/P routine
LD (HL)BC
INC HL Expanding Block Graphics: CALL 2878 (B3Eh)
LD (HL),B
RET ; stream three is now
initialised to send its
If you want to create from the code of a block graphic the block
output to your routine graphic itself, the routine at 2878 (B3Eh) will do it for you. On
entry the base address of eight spare bytes where you want the
START LD B, A ; save the ASCII code in B graphic constructed should be in the HL register pair, and the B
CP 165
expansion routine in ROM
register should contain the code of the block graphic. Two CALLs
JP NC,B52H
CP 13 need to be made, the second immediately after the first, as each
JR Z,CRLF carriage return & line CALL constructs four bytes of the character. The first byte of your
feed eight-byte block will be the top of the block graphic and HL will
CP 32 point to the byte after the last byte of the graphic. The register
RET C anything below 32 is an
unprintable control code pairs altered by this routine are AF, HL and BC; no others are
CP 129 used by it.
JR C, PRINT must be normal character
anything left here is a
graphic, and you must
deal with it as you wish
Drawing Circles: CALL 9005 (232Dh)
PRINT your 0/P routine comes
here The routine to draw a circle requires the parameters of the circle to
RET go back for next be on the calculator stack of the Spectrum. Thus the first thing to
character, if there
do is put the details onto the calculator stack. A routine located at
isn't one execution will
return to the original 11560 (2D28h) will do this for us if we put the number we wish to
calling program stack into the A register (see Chapter 8 for fuller details on Use of
the Calculator). All you need to know now is that it resets the IY
register to point to ERR NR and corrupts most of the other
registers so you should save them before calling this routine.
The parameters must be saved onto the calculator stack in the
order X,Y,Z (Z = radius). The circle-drawing routine updates the
system variables COORDS so if you do not want them changed
16 The Spectrum Operating System Useful Call Addresses and How to Use Them: the 16K ROM 17
you should save them before drawing your circle and restore The machine code equivalent to the BASIC line DRAW 0,175
them afterwards. Thus, the routine to draw a circle would look would look like this:
something like this:
LD BC,AFOOH ; 175,0
LD DE,0101H;+
LD HL,(23677) ;COORDS CALL 24BAH
PUSH HL ;SAVE COORDS Or to DRAW -255,0
LD A,X ;WHERE X = 0 — 255 LD BC,OOFFH ; 0,255
CALL 2D28H ;STACK A ROM ROUTINE LD DE,01FFH ; +,-
LD A,Y ;Y0-175
CALL 2D28H Note that these will draw from the current COORDS, and no
LD A,Z ;Z = RADIUS (MAKE SURE THAT attempt has been made to save them or alter them. After running
THERE IS ROOM ON THE SCREEN the routine they will point to the last point plotted while drawing
OTHERWISE YOU WILL GET AN the line and an error will occur if you try to draw off the screen.
ERROR REPORT)
CALL 2D28H
CALL 232DH ;DRAW CIRCLE Finding the Address of a Pixel: CALL 8874
POP HL (22AAh)
LD (23677),HL ;RESTORE COORDS
To find the address of the byte holding the pixel for a PLOT
If you wanted to draw your circle round the current COORDS command this routine can be called with the BC register pair
holding the X and Y coordinates (Y 0-175 in B and X 0-255 in C)
position, you could have placed these onto the calculator stack,
will return with the HL register pair holding the address and the
but you would still have to save them to the machine stack if you
A register holding the bit position.
want to restore them unaffected.
must be scrolled. Lines are again counted from the bottom of the Byte 1 is always 00 for a header and the last byte is a parity byte
full screen. which is generated within the routine, so there is no need to
worry about it. Byte 2 holds a type number:
There are a number of entry points to the SAVE routine which data block. The first thing that this routine does is preload the
can be used and each has its own merits and disadvantages. The machine stack with the address of the SAVE/LOAD RETURN
first entry point to be considered is perhaps the easiest, but also routine. The SAVE/LOAD RETURN routine enables the inter-
the most fraught with problems. It is used by setting the IX rupts then looks to see if BREAK has been pressed. The error-
register to point to the start of the header (byte 2 as described in handling routine is called in with an RST 8 if BREAK has been
the header information above) and the HL register pair must be pressed, thereby making a return to BASIC. If BREAK has not
set to point to the start of the main block to be saved. Once these been pressed return is to the original RETURN address, put onto
registers have been set a CALL can be made to 2416 (0970h) and the stack by the calling routine.
SAVEing of both the header and the main block will take place. If the instructions to place the SAVE/LOAD RETURN routine
The problems are as follows: are bypassed, the RETURN address on the machine stack will be
that of your calling program, and control will be returned to that
1) The message "Start tape then press any key" will appear. If
on exit from SAVEing, with the carry flag reset if there has been
any key except BREAK is pressed all will be well, otherwise
an attempt to BREAK into the SAVEing process, or set if not, and
control will be returned to BASIC via the error-handling
the interrupts will be off, so they must be re-enabled. You will
routine.
also have to organise some form of message to make sure that the
2) The BREAK key is periodically tested during the SAVE
tape has been started, perhaps by using the message printing and
routine. If pressed, a premature return is made to the BASIC
Wait Key routines detailed elsewhere in this chapter.
error-handling routine, which can be embarrassing.
To save a block of code by this method, the IX register must
3) The header is saved in such a form so as to ensure that the
point to the start of the block, and the DE register must hold the
SAVEd material can be loaded back by BASIC. Under some
length. The A register must hold either FFh for a data block or 00
circumstances, this may be regarded as an advantage not a
for a header. A direct CALL can then be made to 1222 (04C6h).
problem.
Remember that the DE register pair will have to hold 17 (11h) if a
The next entry point can be regarded as the same as the last standard header is being saved. Blocks of data can be saved by
with the exception that it does not ask for or wait for a key to be this method without a header, but can only be loaded back if the
pressed. This must be accessed via a subroutine in the calling length is known.
program because correct operation depends upon correct loading If a return to BASIC is not a worry, or is an advantage, then the
of the machine stack. First set the IX and HL register pairs as same routine can be used, but from the start, which is at 1218
above, then CALL the following routine from your program: (04C2h). If BREAK is pressed control will then be returned to
BASIC. Again you will have to make sure the tape is running.
SAVE PUSH HL
JP 2436 (0984H)
LOADing and VERIFYing
The return after SAVEing is complete will be made to the location
following the CALL to SAVE. This is a neat way of SAVEing Data on tape can be loaded into the Spectrum in two forms: either
several successive blocks complete with headers, as repeated with a header or without. Where there is a header this can be used
'start tape' messages are avoided. either to provide all the parameters for the loading of the main
To SAVE without the possibility of BREAKing into the SAVE data block to follow or, as when loading from BASIC, only the
routine to return to BASIC, the normal start must be bypassed, details which are either unknown, known and definitely correct,
and the header and data saved separately as blocks. The routine or to ensure that the correct data is being loaded. Where there is
SA_BYTES located at 1218 (04C2h) is normally called to do any no header, all the details that would have been in the header
SAVEing, with the A register holding 00 for a header or FFh for a section must be known before the data can be loaded.
22 The Spectrum Operating System Useful Call Addresses and How to Use Them: the 16K ROM 23
It is possible to create a different type of header from that used whereas for a BASIC array, byte 15 will be ignored and byte 16
by the Spectrum, to define the parameters of the following data, will be the name of the array in the same form as when SAVEing.
by SAVEing a fixed length of data as a main data block and For a BASIC program, byte 15 will be 0 and byte 16 80h. The last
writing one's own decoding routine, which will furnish the bytes can be effectively ignored.
details when the main block is loaded. This is often a good idea as Before attempting to use the dummy header, the low byte of
it prevents the possibility of a block being lost, because you have the system variable T ADDR must be set to contain 01 to LOAD or
forgotten the length or where it was on the tape, and hence cannot set to 2 in order to VERIFY.
reload it. This will also prevent the code being loaded by an The HL register pair must contain the address to which the
'unauthorised' user, unless he takes the time to write his own main block is to be accepted, or 0 if the information in the tape
code to examine what you have done and manages to interpret it. header is to be used. For an existing BASIC array, this will be the
A routine which creates a special header is given in the DeBASE start of the array data, following the array name and length bytes
program in Appendix G. in the variables area of a BASIC program.
To load a data block preceded by a normal header the first thing Finally the IX register must be set to point to the first byte of the
that must be done is allocate a space of 34 bytes in memory. In the dummy header. The ROM routine at 1889 (761h) can now be
first 17 bytes of this a 'dummy' header must be created. This called to LOAD or VERIFY both the header and main data block
defines details which are required to match, before the following from the tape.
block is loaded. Once a match of the required details is made any LOADing or VERIFYing without a header can be achieved only
non-matching information will be checked against the real if the full parameters of the block to be accepted are known, when
header and, assuming that the changes are acceptable, these it is a very simple process.
details for the LOADing will be taken from the 'dummy' header. First the A register is loaded with FFh which signals that a main
Should the changes be unacceptable, a BASIC error report will be block is to be accepted. Next the DE register pair is loaded with
generated by an RST 8 instruction. The second 17 bytes will be the total length of the block to be accepted. Then the IX register is
filled from the tape with headers for comparison. Only when a set to point to the address to start LOADing or VERIFYing the
match is made will this area become free for use again. main data block. This followed by the carry flag being set,
The dummy header is made up in exactly the same manner as signalling a LOAD or reset to VERIFY. Finally, the ROM routine
the header saved on the tape and again, the first and last bytes of at 1366 (556h) is called to do the actual operation.
the full 19 are generated internally, so are not included in the The start of this routine preloads the machine stack in the same
17-byte specifier. The first byte must be the same identifier as the way as the SAVEing routine detailed earlier, giving an error
first byte in the header of the data to be loaded (i.e. the type must return in the event of BREAK being pressed. It can be bypassed
match). This is held in the A register on entry to the LOAD BYTES by CALLing the following short subroutine in your own
subroutine and need only be set if calling this directly. If the types program:
do not match, a new leader is waited for and the process repeated
until the types do match. The second byte (the first of the 17 that
need to be set up in the dummy header) again must match: 0 for a LOAD INC D ;RESET 0 FLAG
BASIC program, 1 for a numeric array, etc. If there is no match the EX AF,A'F'
next block will be waited for. The next ten bytes are the name. If DEC D ;RESTORE D
the name is to be disregarded then the first of these bytes must be DI ;THE INTERRUPTS MUST BE
FFh, the names will then be taken as matching. The next two OFF TO ENSURE THAT THE
bytes are the length, if this is set at 0 then the length will be taken TIMING IS CONSTANT. THEY
from the tape header otherwise the two lengths must match. For a ARE NOT TURNED ON BY THE
block of code, bytes 15 and 16 will be the start address to load to, ROM ROUTINE BEFORE RETURN
24 The Spectrum Operating System
The OUT instruction sets the BORDER colour to white with the
The 81( Interface ROM
three low bits; these can be changed as required to give a
different colour. Bit 5 should be left set as this initialises the EAR
port for indication of anything coming from the tape prior to the
leader.
With the addition of the 8K ROM in the Microdrive interface,
A tape-loading error can be detected by the carry flag being
Sinclair have opened up the possibility of expansion in the form
reset on return to the calling routine and, as an attempt to BREAK
of sideways ROM as used in the BBC microcomputer, as well as
will result in an immediate return, if the test break routine is
an easy route to expansion of the Sinclair BASIC. The first thing
called after checking for errors this can be catered for.
that needs to be understood is the mechanism by which the Z80
CPU can be used to address memory outside its normal direct
Note: The interrupts will be off on return from loading.
addressing range of 64 kilobytes.
The routine can also be used to read in a header, instead of a The CPU has two sets of information lines — A 1-16 (which it
main data block, by loading the A register with 0 prior to calling uses to tell the memory which byte it wishes to use) — called the
address bus, and D 0-7, the data bus, which is used to read and
it. This can be useful if you wish to create a different type of
write to the memory location pointed to on the address bus.
header and read it with your own routine. This is demonstrated
Normally it would be impossible to access outside the 64K range,
in the DeBASE program in Appendix G.
so some form of interception must be made which substitutes a
different bank of memory in the same address range.
This is quite easy to do by choosing a byte of memory, looking
for its address on the address bus, and when a match is made
switching to the alternative memory. Execution will then
continue at the next address as the program counter will move on
to point to the next location as normal, but the data will be fetched
from the new bank of memory.
In the Spectrum this is done by looking at the address bus for
the program counter addressing location 8, which is the error-
handling routine. Since this address is reached only by a restart
(RST 8), the top of the stack will always hold the address of the
instruction following the calling instruction (i.e. the return
address). This is fetched by the shadow ROM routine, and the
contents of that memory location examined. Values in the range
00 to lAh cause a return to the 16K ROM as these are normal error
codes, but numbers between 1Bh and 32h are used as `hook
codes'. These call shadow ROM routines and will now be
detailed. To use a hook code use RST 8 followed by DEFB hook
code. All locations relate to the shadow ROM.
26 The Spectrum Operating System The 8K Interface ROM 27
Inputs the time allowed for a packet to be received has elapsed, there is a
checksum error. Alternatively, if BREAK is pressed, the carry flag
Get Key: Hook Code 1Bh, Location 6617 (19D9h) would be set.
Because of the problem inherent in this routine, it is easier to
This is similar to the GET command in some BASICs (although use the 16K ROM routine at 5606 (15E6h). Remember to preserve
the Sinclair BASIC does not have this command). It waits until a the IX register before calling this routine as it would be corrupted
key is pressed and then returns with the code of the key pressed otherwise. The carry flag will be set if the A register does not hold
in the A register. The maskable interrupt should be on as the 16K a received code.
ROM routine is used to scan the keyboard.
Outputs
RS232 Input: Hook Code 1Dh, Location 2945 (B81h)
Print to Screen: Hook Code 1Ch, Location 6636 (19ECh)
To use this routine, first the BAUD rate must be set using the
system variable BAUD 23747/8 (5CC3/4h) calculated as 3 500 000/ To use this the character code must be in the A register prior to
(26 x baud rate) — 2, 3 500 000 being the clock frequency of the calling the routine. This routine is a direct equivalent to the 16K
Spectrum. Next SER_FL 23751 (5CC7h) should be set to 0, and ROM routines for setting output to stream 2 (main screen) and
then the input routine can be called. The A register will hold the RST 16 printing to current stream, which actually uses these 16K
code of the character received and the carry flag will be set. The ROM routines. Used in connection with the Get Key routine (see
routine will wait for only a certain period for a code to be Inputs section above) you can create a sort of 'dumb terminal'.
received. If it has to wait too long, or if the space key is pressed, it The program to do this would look something like this:
will return, but without the carry flag set.
RST 8
DEFB 1BH
Network Input: Hook Code 2Fh, Location 6705 (1A31h) RST 8
DEFB 1CH
Before use, a network channel must be opened and made current
The first RST 8 will wait for a key to be pressed and return with the
by the use of the Open Channel routine described later (see
code in the A register, and the second RST 8 will echo the
Network Output section). This routine will read a packet from the
character to the main screen (or whatever output to stream 2 has
network, on entry the IX register should be set to the start of the
been directed to).
network area and IX + 11, IX + 12, and IX + 13&14 must be set to
the correct values for the block to be received (see the details on
the network header in the section on Network Output using hook Print to the Printer: Hook Code 1Fh, Location 6652 (19FCh)
code 30H). The block number in IX + 13&14 will be incremented
This is identical to the print-to-screen routine above except that it
after each block is successfully received.
It would appear that it was intended that the carry flag should uses stream 3 (normally the printer) instead of stream 2.
indicate if a packet has been read or, if there was an error, when
the return to the calling routine is made. However, the carry flag RS232 Output: Hook Code 1Eh, Location 3162 (C5Ah)
can be corrupted by the resetting of the border colour on exit from
the routine. A return will be made from this routine when a Again this is used by putting the code to be output in the A
packet has successfully been received, with the carry flag reset. If register, but using the RS232 output port on the interface. The
28 The Spectrum Operating System The 81( Interface ROM 29
baud rate is picked up from the system variable BAUD and the routine (see Close Network Channel below), which will send any
border colour from the system variable IOBORD (see Chapter 4 remaining buffer contents and reclaim the buffer area. It will not
for the settings of these). No information will be sent unless the close any streams attached to the network channel, and care must
D'lR (Data Terminal Ready) line is high. be exercised to ensure that other streams and channels are not
The main entry point called by the hook code allows any value corrupted.
of the A register to be output; care therefore needs to be taken to
avoid sending control codes unintentionally. The other useful
entry point is at 3132 (C3Ch) which looks for unprintable ASCII Send Packet: Hook Code 30h, Location 3530 (DB2h)
codes and intercepts them: any codes below 32 (20h) will cause an
immediate return, except for code 13 (0Dh) (carriage return) This CALL allows a 'packet' to be sent over the network. Before
which will be output and followed by a line feed code 10 (0Ah). use a network channel must be opened, the header and system
Codes from 128 (80h) are treated according to their type. Graphics variables must be set up, and the data to be sent placed in the
characters will be output as a '?' and tokens will be expanded by a buffer. To open a network channel use hook code 2Dh (see details
call to the 16K ROM routine at 3088 (C10h), which requires 165 above).
(A5h) to be subtracted from the code prior to its being called. On calling this routine, first a 'scout' is sent which claims the
network if it is free. Then the header is sent followed by the main
data block. The header is held in the front of the network channel
Network Output and is addressed by the IX register which points to the first
location in the channel. Bytes IX + 00 to IX + 10 are set up by the
Open Channel: Hook Code 2Dh, Location 3753 (EA9h) channel-operating routine and bytes IX + 11 to IX + 18 are the
header. The header is made up as follows:
Before any data can be sent or received on the network, a network
channel must be opened. This is done by using this call after first IX + 11 The station receiving
setting D S'I'R123766 (5CD6h) and NSTAT 23749 (5CC5h) system IX + 12 The station sending
variables to be the destination and sending station numbers, IX + 13 & 14 The block number
respectively. A network channel will then be created at the end of IX + 15 1 for the last block otherwise 0
the CHANS area, and everything from the address contained in IX + 16 The length of the buffer (0-255)
the PROG 23635/6 (5C53/4h) system variable to that in the IX + 17 Checksum for the data block
STKEND 23653/4 (5C65/6h) system variable will be moved up by IX + 18 Checksum for the header
276 bytes and the relevant system variables will be reset, IX + 19 & 20 USED FOR RECEIVING ONLY
assuming there to be room below RAMTOP 23730/1 (5CB2/3h). If IX + 19 The position of the last code taken from the buffer
there is not enough room, an error will be caused. IX + 20 The number of bytes available in the buffer
On return the IX register will point to the start of the new IX + 21 to IX + 275 are the data for sending, up to 255 bytes.
channel. The newly created channel is temporary and signified as
such by bit 7 of IX + 4 being set. To make it permanent this bit The checksums are created by the routine itself so do not have to
should be reset, and it can now be used to send by loading be inserted and IX + 15 is loaded from the A register on entry to
CURCHL 23633/4 (5C51/2h) with the address in the IX register the routine, but all the other details must be set by the user. In
and using the RST 16 (10h) routine in the 16K ROM to output addition to setting the header, the system variables D S I R1
data, a byte at a time. 23766 (5CD6h) must be the destination station number and
After the final data has been passed to the RST 16 (10h) routine, NTSTAT 23749 (5CC5h) the sending station number. On each call
the channel should be closed by the use of the hook code 2Eh to this routine the block number will be incremented. The base
30 The Spectrum Operating System The 8K Interface ROM 31
address of the network channel is returned in the IX register by LD HL,5C16H ;BASE ADDRESS OF STREAMS
the channel open routine. LD D,0 ;OFFSET FOR S STREAM TO THE DE
LD E,A ;REGIS"IER PAIR
ADD HL,DE ;NOW HL = STREAM LOCATION
PUSH HL ;SAVE IT
Close Network Channel: Hook Code 2Eh, Location 6692 (1A24h) RST 8 ;CALL HOOK CODE
DEFB 22H ;22 (OPEN CHANNEL/FILE)
If this routine is called after a send operation, it will transmit any PUSH HL ;ON RETURN FROM THIS ROUTINE
data remaining in the network buffer, marking it as an end-of-file
HL = STREAM DISPLACEMENT
block, but after a receive operation it will discard any remaining XOR A ;THE OPEN CHANNEL ROUTINE
data in the buffer. The 270 bytes of the buffer area will then be LEAVES THE
reclaimed using the 16K ROM routine at 6632 (19E8h) but the
RST 8 ;MICRODRIVE MOTOR RUNNING
channel information is left.
DEFB 21H ;SO IT MUST BE TURNED OFF
POP DE ;DE = STREAM DISPLACEMENT
POP HL ;HL = STREAM LOCATION
Microdrive Output LD (HL),E ;SET S STREAM TO CORRECT'
DISPLACEMENT
Open Ch an nel/Open File: Hook Code 22h, Location 6953 (1B28h) INC HL
LD (HL),D
Before data can be sent to a Microdrive, a Microdrive channel and RES 7,(IX + 4) ;ON RETURN FROM THE HOOK
a map area for the drive selected must be created. Hook code 2Bh CODE 22 IX = START OF CHANNEL
was intended to serve this purpose, but there was an error in the AREA. RESETTING (IX + 4) MAKES
program, although this hook code can be used to perform the THE CHANNEL PERMANENT
operation. First set D STR1 23766/7 (5CD6/7h) to contain the EXX ;RESTORE THE RETURN ADDRESS TO
drive number (1-8), N_S I R1 23770/1 (5CD4/5h) the length of the BASIC
file name and T_STR1 23772/3 (5CD6/71-i) to the start address of POP HL
the file name in memory. The H'L' register pair must then be EXX
saved and the hook code can then be called. RET ;FINISHED
The channel will be opened as a read channel if the file name
exists, otherwise it will be opened as a write channel. To make the
channel a permanent one, the data must be incorporated into the
STREAMs information. The following subroutine achieves this: To write to or read from a Microdrive, the channel created must
be made current by loading the system variable CURCHL 23633/4
EXX ;SAVE THE RETURN ADDRESS TO (5C51/2h) with the base address, returned in the IX register after
BASIC opening the channel. The cartridge can then be written to with
PUSH HL the 16K ROM RST 16 (10h) routine, or read from with the 16K
EXX routine at 5606 (15E6h), which returns with each character in the
LD A,S ;S IS THE STREAM NUMBER FOR THE A register. If it is required to SAVE, VERIFY, MERGE, or LOAD
CHANNEL with the Microdrive as opposed to using the cartridge as a file,
RLA ;DOUBLE IT this is explained later in this chapter.
32 The Spectrum Operating System The 81( Interface ROM 33
Write Record: Hook Code 26h, Location 4607 (11FFh) Microdrive Input
This hook code will write the contents of the Microdrive buffer to All the following 'read' routines return with the Microdrive motor still
the next free sector on the Microdrive cartridge. Before calling the running and the maskable interrupt off.
routine, the buffer must contain the information to be saved, the
IX register must point to the start of the Microdrive channel.
IX + 11 must contain the length of the data, IX + 13 the sector Read Print Record: Hook Code 27h, Location 6679 (1A17h)
number (starting at 0 for the first sector of a record and auto-
matically incremented each time a record is either sent or This will read a record from a print file, the record number of
received), IX + 14 to IX + 23 the record name and IX + 25 the drive which is held in IX + 13. The IX register must point to the start of
to be used. Locations IX + 82 to IX + 593 are available for the data the Microdrive channel, IX + 25 must hold the drive number and
to be placed for sending. IX + 14 to IX + 23 the record name. Assuming the record sector to
be present, it will be read into the buffer otherwise an error will
be caused.
Write Sector: Hook Code 2Ah, Location 6801 (1A91h)
This performs the same action as above but looks for a sector of a
Read Next Print Record: Hook Code 25h, Location 6665 (1A09h)
record with the sector number in IX + 13 and, if it exists,
overwrites it with the information currently in the buffer. If the
This is as above but, when used after the previous Hook Code, it
sector does not exist, a 'FILE NOT FOUND' error will be
will automatically read in the next record of a print file, if there is
generated. No check is made as to whether the sector is free or
one. Otherwise an error will be caused.
not, so care must be exercised to ensure that nothing that you
want is already on the sector.
Motor on/Motors off: Hook Code 21h, Location 6135 (17F7h) When the hook code is used, the address in HD_11 23789/90
(5CED/Eh) is put on the machine stack followed by the return
The A register should be loaded either with 0, to turn off any address for the 8K ROM to 16K ROM switchover (1792 (700h)). If
motors that are running, or with the drive number whose motor you make the address in HD_11 point back to your own program,
is to be started. If the drive is not present, an error will be caused. you can then 'POP' the two return addresses off the stack and
If the drive is present, the motor will be started and a return have the 8K ROM paged in, with your program in control. Any
made, with the interrupts off. registers can now be used freely with 8K routines. To return to the
16K ROM all that you need to do is to CALL 1792 (700h), and the
8K ROM will be switched out.
Reclaim Microdrive Channel: Hook Code 2Ch, Location 4292
(10C4h) Note: Many routines look at the syntax/run flag in FLAGS 23611
(5C3Bh) IY + 1, and cause a return to the BASIC interpreter in
The Microdrive channel area currently pointed to by the IX syntax time. Some of the Microdrive routines also return to
register will be reclaimed. Any streams currently using the BASIC via the address in ERR SP 23613/4 (5C3D/Eh) if they are
channel will be closed and the Microdrive map area is also completed successfully, or via an 8K ROM error if they have
reclaimed if not in use from another channel. All memory above failed. The 16K error can be diverted to point back to the calling
the reclaimed channel up to RAMTOP is moved down by the 627 routine by altering the address in ERR SP so that it points to the
bytes freed by the reclamation. return address of your routine on the machine stack. This is
demonstrated in the DeBASE program in Appendix G, in the
Microdrive SAVE/LOAD routines.
Keyscan: Hook Code 20h, Location 6657 (1A01h)
The following routines are called by the RST 8 DEFB 32h hook
This returns with the carry flag set if any key is being pressed.
code after putting the location into HD_ll.
Perhaps this is the most useful of all the hook codes as it allows Format Cartridge: Hook Code 32h, Location 7022 (1B6EH)
the 8K ROM to be paged in at will; therefore any routine can be
called. To use it the location of the routine you want accessed Once again, before use the H'L' registers must be saved. N S'lR1
must be placed in the system variable HD_11, the hook code can must hold the length of the name to be given to the cartridge, and
then be used. Unfortunately, the only register that can be passed T STR1 the address of the first character of the name when the
directly by this hook code is the A register, but this is no real routine is CALLed. The H'L' registers should be restored
problem. afterwards for a successful return to BASIC.
36 The Spectrum Operating System The 8K Interface ROM 37
details of how to use RST 10h and the other ReSTarts (RST) in the 0081H LD E,(HL) ;PUT THE ADDRESS TO BE
8K ROM are given below: CALLED IN THE
INC HL ;16K ROM INTO DE
LD D,(HL)
RST 0 POP HL ;REMOVES THE RETURN
INC HL ;HL NOW HOLDS THE
ADDRESS FROM THE
RETURN ADDRESS AF 1 ER
MACHINE STACK
LD THE DEFW
(IY + 124),00 ;THIS IS FLAGS 3
JP 700H EX (SP),HL ;MAKE THIS THE NEW
;700H IS THE RETURN TO
RETURN ADDRESS
THE 16K ROM
EX DE,HL
LD HL,O ;THIS WILL LET THE RST 8
The address at the top of the stack at this stage should be the ROUTINE KNOW
return to the routine that originally called the 8K ROM. PUSH HL ;IT IS A RETURN FROM A
8K TO A 16K CALL
RST 8 LD HL,(CH_ADD) ;THIS HAS NO EFFECT LD HL,8 ;THE ERROR RESTART
WHEN CALLED FROM 16K PUSH HL ;ONTO THE STACK FOR A
POP HL ;THE ADDRESS OF THE LA 1 ER RETURN
ERROR CODE LD HL,5CB9H ;THE START OF THE
PUSH HL ;SAVE IT AGAIN SUBROUTINE
JP 009AH ;THIS WILL CHECK WHAT IS ;ONTO THE STACK FOR A
PUSH HL
BEING EXECUTED AND RETURN
EITHER RETURN TO A 16K JP 0700H ;A RET INS I RUCTION
ERROR, EXECUTE A HOOK THAT SWITCHES IN THE
CODE OR ACCESS A 16K ROM
CHANNEL. 0700H RET ;PAGE IN THE 16K ROM
AND RETURN
This is of no practical use when the 8K ROM is switched in.
The RST 16 (10h) in the 8K ROM CALLs a 16K ROM routine, the
I have given the full listing for this as it is an interesting method
address of which is held in a DEFined word (DEFW) after
of transferring control.
ReSTart. After the 16K routine has been executed control is
When the RETurn at 0700h is made, switching in the 16K ROM,
returned to the address after the DEFW in the CALLing routine.
the address collected from the stack is 5CB9h. This address
contains 21h, the instruction LD HL,NN. As can be seen above
RST 16 LD (5CBAH),HL ;SAVE HL FOR the NN was the value in HL when the ReSTart was made. The
RESTORATION AH ER next location — 5CBCh — contains CDh, the instruction CALL
RETURN NN. Again this address was loaded above, from the DEFW after
(10H) POP HL ;COLLECT IN HL THE the RST 16 (10h). The return from the 16K routine will be to 5CBFh
ADDRESS OF THE DEFW which contains 22h, the instruction LD (NN),HL. The NN in this
PUSH DE ;SAVE DE ON MACHINE case is 5CBAh, so the new value in the HL register is saved where
STACK the original value was. Finally there is the instruction RET. This
JR 0081H will be a return to the address on the top of the machine stack,
40 The Spectrum Operating System The 8K Interface ROM 41
now 8 (i.e. the error ReSTart). This time when the address for the ;THIS IS TV FLAG
DEFBs is 'POPped' off the stack i t will be 0. This will tell the ROM (28H) JR 0040H ;THIS WILL CHECK IF THE
(8K now) that the HL register has to be loaded from (5CBAh), and ERROR OCCURRED IN
after this there is yet another RETum, this time to the address SYNTAX OR RUN TIME. IF
after the two DEFBs after the RST 16 (10h), seemingly so long ago. IN RUN TIME IT WILL
The following ReSTart can be used to generate the shadow RETURN TO THE 16K
ROM error messages in the same way as the RST 8 in the main ERROR ROUTINE
ROM: OTHERWISE IT WILL
JUMP TO 0068H, AS
RST 24 BIT 7,(IY + 1) ;THIS IS FLAGS EXPLAINED ABOVE.
(18H) RET ;THE ZERO FLAG WILL BE RST 48 JP 01F7H ;CHECKS TO SEE IF THE
SET IF A BASIC LINE IS INTERFACE
BEING CHECKED FOR (30H) VARIABLES ARE PRESENT
SYNTAX AND IF NOT INSERTS
RST 32 RST 24 ;CHECK IF SYNTAX OR THEM.
PROGRAM RUN RST 56 EI ;THIS IS THE NORMAL
(20H) JR Z,0068H ;THIS WILL RESET THE MASKABLEINIERRUPT
STACK POINTER TO THE (38H) WHICH WOULD SCAN
ADDRESS IN ERR_SP SET THE KEYBOARD IF THE
X_PTR TO CH_ADD AND 16K ROM WAS PAGED IN.
RETURN TO THE MAIN RET NO 1 E THAT THE
ROM LINE INPUT KEYBOARD WILL NOT BE
ROUTINE VIA THE CLEAR SCANNED WITH THIS.
CALCULATOR ROUTINE,
AND INDICATE THE The non-maskable interrupt routine at 102 (66h) consists of the
POSITION OF THE single instruction RETN.
ERROR. More 8K ROM routines are discussed in Chapter 7 but there are
JR 003AH ;THIS WILL GENERAIE AN few routines that are of use for other purposes. Their use and
ERROR REPORT. THE locations have already been detailed in the hook codes section.
SHADOW ROM ERROR
CODE WILL BE
COLLECTED FROM THE
BYTE AF 1ER THE
RESTART.
Chapter Four CAPS SHIFT code of the key being pressed will be saved in the
first location. The second location is set to 5 (the countdown to
free, which also se rv es to debounce the keyboard), the third
The System Variables location is loaded with the repeat delay REPDEL. The ASCII code
of the key pressed is decoded, saved in the last location and
copied into LAST K, bit 5 of FLAGS is set to signal a new key
press and a return to the calling routine made. When neither set is
free then a counter in the second byte of each set is decremented
and the calling routine is returned to.
The BASIC interpreter requires some means of keeping track of Once one of the counters reaches 0, the code of the key being
where information is stored, and what it is supposed to be doing, pressed (if any) is saved and a comparison is made between the
since it is located in ROM (Read-Only Memory) and has to use code of the keys in the two sets. If they match a key is being held
RAM (Random Access Memory) to store this information. Since down and then the routine allows for repeating of the key. This is
the ROM is unalterable, the addresses of the system variables not the key-debouncing routine, but the repeating key routine.
have to be predefined in such a way that they can be accessed on a The repeat delay being held in the third byte and initially loaded
regular basis. In the Spectrum, this is achieved both by having from the system variable REPDEL.
their locations fixed in particular area of memory and also by Once the delay for the first repeat is over (the routine must be
indexing them with the IY register, which always points to called the number of times set by the delay counter), if the match
5C3Ah (ERR NR). has been continuous then the third byte is loaded from the
system variable REPPER, the code is again passed to the system
variable LAST K, bit 5 of FLAGS set and a return to the calling
16K System Va ri ables routine made. On subsequent calls to the keyboard-scanning
routine, the whole process is repeated but with the shorter delay
KSTATE: Locations 23552-23559 (5C00h-5C07h) from REPPER until the codes no longer match. If the keys do not
match then the treatment is the same as for a free set.
These locations are used in reading the keyboard. They can be The net result of all this is that there is a two-key rollover,
divided into two sets of four, and each set is treated the same as which allows for a second key being pressed before the delay for a
the other. Which set is actually used depends upon the state of the repeat on the first set has elapsed, avoiding the loss of the second
other set. key if it is not held down long enough for the original set to
The CAPS SHIFT value of a key being pressed is stored in the become free.
first location of each set or, if no key is pressed, 255 (FFh) which
flags the set as free for use. The count down to a set being free is
stored in the second byte, initially set to 5, free when O. The
LAST K: Location 23560 IY – 50 (5C08h)
repeat delay is in the third byte, initially loaded from REPPER.
The ASCII code of the key pressed when a set was in use is in the This contains the code of the last key pressed.
last location of that set until the countdown to the set being free
reaches O. In order to try to make some sense of this I will explain
the routine that uses these va ri ables. REPDEL: Location 23561 IY – 49 (5C09h)
If a key is pressed, the scanning subroutine looks to see
whether the first set is empty. If it is it will then use this set, The number of times the keyboard-scanning routine must be
otherwise it will look at the second set. When a set is free then the called before a key repeats is contained at this location.
44 The Spectrum Operating System The System Variables 45
REPPER: Location 23562 IY – 48 (5COAh) The last valid ASCII code is 127 (7Fh), but the Spectrum uses
the remaining 128 values of the full eight-bit range for tokens.
This contains the number of times the keyboard scan must be These are dealt with separately and do not comprise part of this
called before a repeating key repeats. character set.
These locations hold either the address of a user-defined function This contains the length of the buzz generated when a basic line
being evaluated or O. exceeds 22 lines or memory has run out.
This is used as temporary storage of the colour information when This contains the duration of the beep whenever a key is pressed.
colour controls are being entered (i.e. the second byte, the colour
number, after the E shift).
ERR NR: Location 23610 IY + 0 (5C3Ah)
TVDATA: Location 23566/7 IY – 44 (5COE/Fh) This contains one less than the report code that will be generated
on an error. It can be used to generate your own reports or use the
These are as above but for output and used with AT and TAB resident reports for your own purposes (see Chapter 2 for details).
values as well, hence the two bytes.
details on Scanning the Keyboard in Chapter 2 and for KSTA'I E can be restored after automatic listing is completed. This is
system variable). necessary because the listing can be terminated at different
places, with different amounts on the machine stack (e.g., by a 'n'
Bit 6 is used to indicate if an expression is numeric or a string, in response to a 'Scroll?'.
being set for numeric and reset for a string, and is used by the
BASIC interpreter.
MODE: Location 23617 IY + 7 (5C41h)
Bit 7 is reset when the BASIC interpreter is checking a line for
syntax on entry and is set when the program is being run.
This determines the cursor used in an input, but it will only affect
the first key press except when changed to force the graphics
mode. However, it can be useful to get different cursors for input
TV FLAG: Location 23612 IY + 2 (5C3Ch)
(e.g., if you POKE MODE with 32 you will get a flashing graphics
input). Experimentation is the best way to make use of this
Bit 0 is set if handling the lower screen and is reset for the main
facility as the system will not crash.
screen.
Bit 3 signals that the current mode may have changed and needs
to be rechecked. NEWPPC: Locations 23618/9 IY + 8 (5C42/3h)
Bit 4 is set when an automatic listing is being printed, otherwise This contains the line number of the next statement to be inter-
it is reset. preted.
Bit 5 signals that the lower screen needs to be cleared (e.g. when a
report is about to be printed).
NSPPC: Location 23620 IY + 10 (5C44h)
ERR SP: Locations 23613/4 IY + 3 (5C3D/Eh) This is the number of the statement in the line to be evaluated
next. Poking first the line number then the statement number
These locations hold the address on the machine stack of the forces a jump in execution to that place.
RETurn to be used in the event of an error in a BASIC command
being executed. It is picked up by an error ReSTart and frequently
changed by BASIC. It can be changed from machine code to make PPC: Locations 23621/2 IY + 11 (5C45/6h)
an error go to your own routine, as demonstrated in the DeBASE
program in Appendix G, in the Microdrive SAVE/LOAD section. This contains the line number of the statement currently being
If an error occurs this must be reset and the error cancelled by evaluated. Also it is used by an auto-run program loaded from the
making ERR NR hold 255 (FFh). Note that 0 OK is counted as an header.
error.
LIST SP: Locations 23615/6 IY + 5 (5C3F/40h) SUBPPC: Location 23623 IY + 13 (5C47h)
LIST SP is used to save the address of the stack pointer so that it This contains the statement number currently being evaluated.
48 The Spectr u m Operating System The System Variables 49
This contains the value for the border colour *8 plus the attri- This is the address of the start of the BASIC program area, which
butes for the lower screen. Bits 7 and 6 can be used to make the will be the byte following the channel information area and any
lower screen fl ash or bright. input/output buffers being used by Interface 1.
This is the address of the start of the next BASIC line in a program.
E PPC contains the number of the current line (i.e. the line that
will be displayed with the cursor and brought into the editing
area addressed by E LINE by an EDIT command). DATADD: Locations 23639/40 IY + 29 (5C57/8h)
This is the address of the terminator of the last data item used, or
VARS: Locations 23627/8 IY + 17 (5C4B/Ch) the start of the line given by a RESTORE command, or the first
after it if it does not exist. This keeps track of which data item is to
This contains the address of the start of the variables area. When be used next and if there are no more data after this pointer it will
it is used in conjunction with E LINE, the total length of a BASIC cause an 'out of data' error.
program's variables can be calculated.
DEST: Locations 23629/30 IY + 19 (5C4D/Eh) E LINE is the address of the start of the editing area, which will be
the start of anv line in the edit area.
This contains the address of the first letter of the name of the
variable currently in use. If a new variable is to be used, it is the
80h end marker immediately before the address in E LINE where K CUR: Locations 23643/4 IY + 33 (5C5B/Ch)
the start of a new variable is being placed.
This is the address of the cursor in the current line. It is used to
edit or to create a new line in the edit area.
failed when entering a new BASIC program line, marked by a '?'. Bit 1 is set if the printer buffer has been used by a 16K ROM
It is also used to store information temporarily by the interpreter. routine and is reset after it is cleared by the Clea ri ng Printer
Buffer routine described in Chapter 2.
WORKSP: Locations 23649/50 IY + 39 (5C61/2h) Bit 2 set signals that the screen is clear.
system variable (location 23611 (5C3Bh)) and is used in its place in time the normal interrupt routine is called. The least significant
the interpreter when INPUT commands are being executed. byte is in 23672 (5C78h).
This normally holds the address of the next item in the syntax PR CC: Location 23680 IY + 70 (5C80h)
tables located from 6728 (1A48h) in the main ROM. However, it is
also used for other purposes by some routines. This is the low byte of the printer buffer current address. In effect,
this is identical to DF CC: Locations 23684/5 IY + 48 (5C84/5h)
and the printer buffer can be moved by changing the so-called
unused byte below, which is in fact the high byte of the PR CC
SEED: Locations 23670/1 IY + 60 (5C76/7h)
system variable. Unfortunately this is reset at the end of each
print line to point to the original address; care therefore needs to
This is the seed for a random number. It is taken from the low two
be exercised if it has been moved.
bytes of FRAMES if a RANDOMIZE command has no number,
otherwise it is taken from the RANDOMIZE number.
ECHO E: Locations 23682/3 IY + 72 (5C82/4h) high value since a machine code program could be broken into or
crashed, if a negative response is given.
As S POSN: Locations 23688/9 IY + 78 (5C88/9h) this is the
column and line number for the next print position, but for the
input buffer. It is used when entering a BASIC line. ATTR P: Location 23693 IY + 83 (5C8Dh)
These locations hold column and line number for the next PRINT
MASK T: Location 23696 IY + 86 (5C90h)
position on the main screen and set up by the CALL 3545 (DD9h)
routine detailed in Chapter 2 (where 33 is left column and 24 is top
This is used as a mask to discriminate between transparent colour
line).
items and colour items to be taken from ATTR T: Location 23695
IY + 85 (5C8Fh). For any bit set to 1, the attribute bit will be taken
SPOSNL: Locations 23690/1 IY + 80 (5C8A/Bh) from the screen attribute for the current position, otherwise it
will come from A 1"1 R T.
Like S POSN: Locations 23688/9 IY + 78 (5C88/9H), these
locations hold the column and line number for lower screen.
P FLAG: Location 23697 IY + 87 (5C91h)
SCR CT: Location 23692 IY + 82 (5C8Ch) This is the flag used to discriminate between the print parameters
for any output to the screen by the ROM. The even bits are
This holds 1 more than the number of times the screen can be temporary bits, whereas the odd ones are permanent bits, each
scrolled without a 'scroll?' question. It should always be kept to a relating to the same items.
56 The Spectrum Operating System The System Variables 57
Bit 0/1 is set if OVER 1 is to be used. FLAGS3: Location 23734 IY + 124 (5CB6h)
Bit 2/3 is set if INVERSE is to be used. Bit 0 is set if an extended command is being executed.
Bit 4/5 is set if INK 9 is to be used. Bit 1 is set if a CLEAR# is being executed.
Bit 6/7 is set if PAPER 9 is to be used. Bit 2 is set if the ERR SP system variable has been altered by the
8K ROM.
This is the area used by the calculator to store values which Bit 4 is set for LOAD routines by the 8K ROM.
cannot conveniently be kept on the calculator stack (see Chapter
8). Bit 5 is set for SAVE routines by the 8K ROM.
Not Used: Locations 23728/9 IY + 118 (5CB0/1h) Bit 7 is set for VERIFY routines by the 8K ROM.
There now follow the 8K ROM system variables which are only This is the value used to set the BAUD rate for RS 232 input/
present when inserted by the Microdrive interface. output. It is calculated as follows:
58 The Spectrum Operating System The System Variables 59
This holds the colour for the border during input/output NTNUMB: Locations 23760/1 (5CD0/1h)
operations, and is loaded with the colour number. It is normally 0
for black, but can be changed. This contains the number of the network block currently being
passed.
This is used during RS232 input. The first byte is a fl ag, set to 0 on This holds the identifier for a network block, 0 for a normal block
entry to the input routine and set to 1 when a byte has been or 1 for the final block.
received. The second byte is the received byte, on return from the
input routine.
NTLEN: Location 23763 (5CD3h)
This is used by the 8K ROM to count Microdrive sectors. NTDCS: Location 23764 (5CD4h)
D_STR1: Locations 23766/7 (5CD6/7h) D_STR2: Locations 23774/5 (5CDE/Fh) to T_STR2: Location
23780/1 (5CE4/5h)
For Microdrive transactions, this provides the drive number (as
two bytes). These eight bytes are the same as previous eight which make up
the first file specifier.
For network transactions, this provides the destination station
number. The following bytes are direct equivalents to the header bytes for
the 16K ROM routines, but they are used by the 8K ROM (for an
For RS232 transactions, this provides the baud rate. explanation of their uses see Chapter 3).
This contains the stream number (0 - 15). HD_0B: Locations 23783/4 (5CE7/8h)
This holds the auto-start line number. It can also be used by hook
code 32h (see Chapter 3).
T_STR1 holds the address of the start of the file name.
The next eight bytes are used by LOAD and MOVE commands. COPIES: Location 23791 (5CEFh)
Ports and bit4. Each bit is returned high (1) unless a key is being pressed, in
which case the respective bit is low (0).
The address lines are used to determine which half row is read
Channels by an IN instruction. The bit to be set low for each line is set out
below:
Port 231 (E7h) handles the Microdrive data for both read and
Note: Extreme care needs to be used when reading for more than
write.
one key pressed at a time. Sinclair have not put any protection
This last port is one reason for some peripherals being incom- against feedback between lines on the keyboard. This means that
patible with the Microdrive interface. The Spectrum manual if, for example, the 'A', 'S' and 'W' keys are pressed at the same
failed to mention that it would be used. I shall now consider the time, a scan of the line Q to T will show Q as being pressed, even
details of the more useful ports in turn. though it is not. This is because while pressing two keys on
i
64 The Spectrum Operating System Input and Output Ports and Channels 65
different address lines but with the same data bit the lines are Bit 1 OUTPUT high (1) slows the motor, low (0) speeds it up again.
effectively connected together. Therefore any other key pressed
on either line, will set the respective bit low on both lines, so long Bit 2 OUTPUT low (0) starts the motor.
as both the other keys are being pressed.
Bit 6 is the input from the tape socket and has a tendency to stay Bit 6 INPUT high (1) if the printer is not connected.
low, although it can be reset by an OUT instruction. Care needs to
be exercised since any output to bits 0-2 will set the border Bit 7 OUTPUT high (1) does the actual printing, one bit at a time.
colour. The safest way of setting all bits to 1 is to output 248 (F8h),
but (1) it will only be temporary, and (2) it should never be
necessary if proper decoding is practised.
For the output, bits 0,1 an d 2 control the border colour, bit 0
controls the blue, bit 1 the red and bit 2 the green, all colours Port 247 (F7h) 11110111 BIN
being made up from a mix of these.
Bit 0 OUTPUT serial data for both network and RS232;
Colour Number Binary INPUT serial data from network.
BLACK 0 00000000 Bit 7 INPUT serial data from RS232.
BLUE 1 00000001
RED 2 00000010
MAGENTA 3 00000011
GREEN 4 00000100
CYAN 5 00000101 Port 239 (EFh) 11101111 BIN
YELLOW 6 00000110
WHILE 7 00000111 The write protect tab on a Microdrive cartridge can be checked by
IN A,(239) AND 1; the 0 flag will be set if the cartridge is
Bit 3 controls the microphone socket. Remember that to get protected.
anything more than a click this needs to be turned on and off The presence of a drive can be checked by reading bit 2 of port
repeatedly to give a tone. The 'MIC' printed on the rear of the 239, after selecting the drive to be checked; it will be reset if the
Spectrum is slightly misleading, since this gives output to the drive is present.
mic input of a tape recorder and plugging a microphone in would The RS232 D'1 R line is on bit 3 of port 239 and the CTS line is on
be a waste of time. bit 4 of port 239.
Bit 4 controls the loudspeaker inside the Spectrum an d the It is most unlikely that it will be necessary to use ports 247, 239
same comments as above regarding use apply. and 231, other than from within the 8K ROM with the exception
A program that demonstrates the use of the internal speaker of checking the presence of an ancillary device.
and the 'EAR' input by reading speech or music in, storing it in
memory and allowing its subsequent replay through the loud- The remaining po rt s are available for use by other ancillary
speaker is given at the end of this chapter. devices. Remember that if a printer or other interface is con-
nected it will use a po rt or po rt s for information transfer. Two of
the most common parallel printer interfaces are the MOREX
Port 251 (FBh) 11111011 BIN (which also has a bidirectional RS232 interface built in, and
which I can highly recommend) and the Kempston, which use the
Bit 0 INPUT is the busy line of the ZX printer, low (0) is busy. following ports:
66 The Spectrum Operating System Input and Output Ports and Channels 67
Morex Ports 251 (FBh) 11111011 BIN & 127 (7Fh) Port 58303 (E3BFh)
01111111 BIN
Bits 0-3 OUTPUTS Centronics strobe.
Port 251 (FBh) 11111011 BIN
Standard Streams
Bits 0-7 OUTPUT Centronics Data.
Stream K –3/253 (FDh) is a duplicate of streams 0 and 1.
Bit 0 INPUT Centronics Busy.
Stream S –2/254 (FEh) is a duplicate of stream 2.
Bit 1 INPUT RS232 DIR. Stream R –1/255 (FFh) is used to write to workspace, and will
place the code currently in the A register into the address con-
Bit 7 INPUT RS232 RX data. tained in the system variable K CUR 23643/4 (5C5B/Ch), and
increment the address in K CUR. This is not as useful as it seems
at first, since the make room routine is called first, and this moves
Port 127 (71711) 01111111 BIN
up all memory above the address in K CUR as far as RAMTOP,
making the stream useless for putting anything into anywhere
Bit 0 OUTPUT Centronics strobe.
above RAMTOP, or anywhere else that must not be moved. The
routine starts at 3969 (F81h) and the stream can be used only for
Bit 1 OUTPUT RS232 TX data. output; any attempt to use it for input will cause an error.
Bit 2 OUTPUT RS232 CTS. Stream 0 and Stream 1 K are normally attached to the lower
screen, and the keyboard. They also allow input to be made to
their channels.
Chapter Six therefore hold a value which has the top two bits set in this
manner, in other words any number from 64 to 127 (40h to 7 Fh)
inclusive, if this break-up of the picture is to be avoided.
Using the Interrupts By setting IM2, it is possible to use the interrupts for your own
purposes, so long as you do a RST 56 (38h) at the end of your own
interrupt-servicing routine, which will enable the interrupts
before returning to the CALLing program — if you want the
keyboard scanned and frames counter updated — and end with a
RETI instruction.
The start-up sequence in the Spectrum, which clears the memory If you have not used the RST 56 (38h) within the interrupt
and sets the system variables, also initialises the interrupt routine, you must execute an EI instruction before the RETI if you
register to hold 63 (3Fh) and sets the interrupt mode to 1 (IM1). want the interrupts enabled to CALL the interrupt service routine
The setting of the I register appears unnecessary since the IM1 again. Remember that you will have to reset the IM1 mode and
mode has no use for it — because in this mode any interrupt does enable the interrupts before you return to BASIC unless you are
a RST 56 (38h) — but the novel manner in which the ULA in the using a RST 56 (38h) within the interrupt routine.
Spectrum handles the display makes bits 6 and 7 of the I register The IM2 mode is somewhat convoluted. On receipt of an
important. interrupt, which occurs 50 (60 in the USA) times a second, the
On every machine instruction cycle, the Z80 executes a CPU saves the address of the next instruction in the program that
memory refresh operation during which the contents of the I it is executing on the machine stack, and disables any further
register are put out on high eight bits of the address bus and the interrupts. It then looks at the location pointed to by the data
memory request line is activated. The ULA generates an interrupt bus + (256 x the I register) and jumps to the address which is
each time it wishes to update the screen. This makes the CPU contained in this location + (256 times the contents of the
execute the interrupt service routine, assuming the interrupts are following location). It is normally regarded as bad practice to
enabled. This is normally the keyboard scan and frames counter have bit 0 on the data bus high for use as a pointer in IM2 since the
update, but if the Interface ROM is switched in all that happens is vector should always start in an even numbered address, but
the interrupts are enabled and an immediate RETurn made, unfortunately with the Spectrum there is no choice.
without the keyboard being scanned or anything else done.
When the interrupt routine is completed the CPU returns to Example. The I register contains 10 (0Ah) and the data bus will
whatever it was doing previously. If this involves a read or write hold 255 (FFh). 10 x 256 = 2560 and 2560 + 255 = 2815, therefore
instruction to the memory between 16384 (4000h) and 32767 the address to be jumped to will be taken from the contents of
(7FFFh), which the ULA checks by looking at the top two lines of address 2815 + (256 x the contents of address 2816). Address 2815
the address bus, and the MREQ line, the ULA stops the clock on contains 34 and address 2816 contains 128. You can see this for
the CPU while it completes the screen update. yourself by PEEKing on your Spectrum, as these are in the ROM.
If the I register has the top bit reset and bit 6 set the ULA gets So the address jumped to will be 34 + (256 x 128), which is 32802.
confused, due to the refresh of dynamic memory during T3 and Similarly, if the I register held 6:
T4 of an Ml (instruction fetch) cycle. This activates the MREQ line
and causes the I register to be put out on the top eight bits of the 6 x 256 = 1536, and 1536 + 255 = 1791.
address bus. The ULA then thinks that the CPU is doing a read or 1791 contains 221 and 1792 contains 113.
write operation to this area of the RAM, even though it has tried
to stop this, and the ULA omits its own read to update the 221 + (113 x 256) = 29149, so the jump will be to 29149.
display, causing break-up of the picture. The I register cannot
72 The Spectrum Operating System Using the Interrupts 73
Alternatively, if you have a 48K Spectrum and the I register Typical uses of interrupt routines are SPRJ 1 E control and
held 200: 200 x 256 = 51200, and 51200 + 255 = 51455. So the jump CONTINUOUS SOUND within a program. Since it is known
will be to the address that you put into this and the following how often an interrupt will be generated, it is easy to calculate the
location, in normal Z80 fashion low byte first. speed of movement for a SPRITE and, since it will be indepen-
This can be represented by imagining the interrupt as an dent of any other operation within the program, the speed will
invisible instruction in the program being run. At the moment of normally remain constant.
the interrupt the invisible instruction is executed as if it were a DI The use of ROM routines within an interrupt routine is compli-
followed by a CALL instruction in the address immediately prior cated by the possibility of the interface ROM being switched in at
to the address pointed to by the I register and the data bus, the the time of the interrupt, and this must be allowed for when the
address being CALLed is in the next two bytes in the standard routine is written. For example, if a SPRITE routine relies on a
Z80 low byte first order. The instruction, being invisible, cannot 16K ROM call to plot the sprite to the screen by use of the
place its own return address on the machine stack, hence the PLOTting CALL at 8933 (22E5h) when the Interface ROM is paged
address after the last instruction executed in your program goes in, the CALL will be to 8933 in the Interface ROM. This is an
onto the stack, and it is this address that will be returned to after address that does not exist. This will inevitably cause the
the RETI instruction at the end of the interrupt service routine. program to crash.
The RETI instruction must be preceded by an EI instruction. One way of solving the problem is to incorporate into the
The reason for the DI being incorporated in the CALL performed interrupt routine a check to see which ROM is present. The
by the interrupt is to ensure that, should the interrupt service easiest way of checking is to look at a ROM address which
routine be longer in execution time than the delay between two contains a different value in each ROM. I tend to use address 20
interrupts, the program does not become tied up in a loop. (14h), which contains 213 (D5h) in the Interface ROM and 255
It is quite easy to write a program which changes the address (FFh) in the 16K ROM. The appropriate action for each ROM can
jumped to by an interrupt by loading the vector bytes (the two then be taken.
addresses looked at to determine where the jump is made to) with If the ROM call is to the 16K ROM, it can be called directly when
the desired address within the program. the 16K ROM is present and via the RST 16 instruction when the
8K ROM is paged in. For the 8K ROM, this can be used with hook
Note: Whenever interrupt routines are used it is of vital impor- code 32h (details are given in Chapter 3).
tance that any registers which are used by the interrupt routine I have given a simple SPRITE program in Appendix G. This
are preserved on entry, and restored before going back to the program moves a group of four pixels, bouncing them off the four
main program. No attempt should be made to pass data to and edges of the screen, emitting a sound and changing the border
from the interrupt routine in registers. colour, demonstrating this way round the problem.
Because of the limitation on the values that can be held in the I As a full understanding of how to use interrupts is so
register, there are only a limited number of addresses that can be important, if any use at all is to be made of them, I suggest that
jumped to in the 16K Spectrum, and these are dictated by the you enter the program, using your assembler. The listing is taken
contents of the ROM. An added problem when using ROM-
direct from my assembler to ensure that there are no errors; it is
vectored interrupts is caused by the Microdrive interface which slightly unusual in that hex numbers are prefixed by a # and binary
changes the vector whenever it is paged in. A list of the vectors numbers by a % in the source code. The routine can be relocated
for the Issue 2 Spectrum and the Issue 1 Microdrive interface is if a new vector is calculated and the I register is changed to suit.
given in Appendix F, but if you are unsure which issue you have, Once you have entered and assembled the program, before
or you have a different issue, these must be checked. For com- attempting to run it, turn back to this page and read on.
mercial software, it is dangerous to use ROM vectors as any The first problem you may encounter is, if you have a 16K
changes and future additions could make your software unusable. Spectrum, that the vector will have to be ROM-based. Unfortu-
74 The Spectrum Operating System
nately at the time of writing this I have found no way that a 16K Chapter Seven
Spectrum with the Microdrive Interface can be used.
Before doing anything further save both the source and the
object code to tape or Microdrive and, if you have a Microdrive,
remove the cartridge. To initiate the SPRITE the routine labelled
Extending BASIC with
SETUP in the listing must be called. If the vector has not been
changed, RANDOMIZE USR 51457. You should now be able to
Interface 1
see a single black dot moving about the screen. Should it not be
there check your code again. The presence of the SPRI'I E should
have no effect on anything else the computer is doing, so a
program can be entered and run as normal, as long as it does not
encroach on the memory used by the interrupt routine. With the addition of Interface 1, any BASIC instruction which
Some of the BASIC instructions that act on the interrupts can fails the Sinclair syntax checking is normally vectored back to the
now be demonstrated. Enter the BASIC line: error-handling routines, via the address held in the new system
variable VECTOR. This can be changed to point to an address in
10 BEEP 5,60: FOR N = 1 TO 100: NEXT N: LOTO 10
RAM. This allows a program to be written which can check
When this is run you will see that the SPRITE stops while the further, and act upon any instructions that it is programmed to
BEEP is being executed. Other commands which disable the deal with. Before any use can be made of this facility it is neces-
interrupts are those involved with SAVEing and LOADing. sary to understand the method by which lines are checked, so
The SPRI I E will travel at the rate of 50 pixels per second in the that the extra routine can make the same checks.
UK (60 pixels per second in the USA), so in the UK it will take 3.5 As soon as EN l ER is pressed after entering a BASIC line into
seconds to travel from the bottom of the screen to the top. the input buffer, the ROM interpreter is called into action. This
RUNs the line, but stops short of actually doing the commands,
because the syntax flag (bit 7 in FLAGS) is reset. If any error
occurs, it is flagged with a '?', and the error must be corrected
before the line can be inserted into a program.
The same process is carried out in run time but, since the
syntax flag is set, the command is acted upon. Remember that
whenever a routine in RAM is being used as part of the BASIC
interpreter, the 8K ROM will be paged in.
There are routines in both the ROMs which check for the syntax
flag and return to the calling routine only in run time. These are
most useful when adding commands, as demonstrated by the
routines at the end of this chapter. The basic (no pun intended)
criteria for checking the syntax are given below, and ROM
routines have been used as far as possible.
The address of the character at which the syntax failed, so far as
the ROM is concerned, will be present in the system variable
CI-LADD on arrival at the extended syntax checker in RAM.
Because of this it is important to ensure that the first character of
the added BASIC command fails normal syntax. If this was not
76 The Spectrum Operating System Extending BASIC with Interface 1 77
the case, the interpreter would start execution during run time, When evaluation is completed, a CALL 1463 (5B7h) will check
and it would be almost impossible to regain control. For this that the current character is the end (a colon or carriage return
reason, it is simplest to use a non-alphabetic character to start the code 13 (ODh)), and return to the interpreter in syntax time, or to
additional command, which gets the system out of the normal K your routine for execution in run time, if it is, and generate an
or command mode, ensuring syntax failure. The '*' and '!' error if not.
symbols are ideally suited to this. In run time, your routine will have to act upon the command,
The first thing that must be checked is the command collecting information from the calculator stack as necessary, and
characters. This is done by getting each character in turn and then return to the interpreter via a JP 1473 (5Clh) instruction,
ensuring that it is the one expected. The 16K ROM routine at 24 with CI-LADD pointing to the next character for interpretation.
(18h) will get the current character in the a register, and the To demonstrate the addition of commands the following
routine at 32 (20h) will collect the next character and advance program adds !CALLnn and !FRE. !CALLnn will call a machine
CH_ADD by one. Each character can then be checked and, if it is code routine at the address after the !CALL. !FRE will return the
not correct, the error handler can be called in by jumping to the free memory.
original VECTOR which was 496 (1F0h).
!CALL RST 16
DEFW 24 get character
Then: CF' is it a !
JR NZ,ERROR if not allow error
1) If there should be a numeric expression next, the 16K
CALL NEXT_CH get next character
routine at 7298 (1C82h) can be used. This evaluates the next CP "C" is it C
expression as numeric; if it is not an error will be caused. In JR NZ,!FRE if not, jump and see
run time it will also put the value onto the calculator stack. if it's a !FRE
2) If there should be two numeric expressions next separated CALL NEXT_CH
CP each character is
by a comma, the 16K routine at 7290 (1C7Ah) can be used. JR
NZ,ERROR checked, the error is
This acts as above but stacks both numbers in run time.
CALL NEXT_CH allowed to pass if
3) If there should be a string expression next (either in quotes CP "L" a match fails
or a $) then the 16K routine at 7308 (1C8Ch) can be used. JR NZ,ERROR
CALL NEXT_CH
Again this acts as above, but generating an error if the CP
expression is not a string, and in run time stacking the JR NZ,ERROR
string parameters as described at the end of Chapter 8. JR ISCALL to reach here the word
must match
'FRE CP same again for !FRE
Note: In all three of the above routines, the first character of JR NZ,ERROR
CALL NEXT_CH
the expression to be evaluated must be in the A register, and
CP
CH_ADD must contain its address, before CALLing the routine. JR NZ,ERROR
After the evaluation, the A register will contain the first character CALL NEXT_CH
after the expression and CH_ADD its address. Mathematical CP "E"
operators are allowed as are the use of variables in the expressions CALL NEXT_CH
JR Z,ISFRE ; it is !FRE
evaluated, and this can be used to advantage to find details of ERROR
JP 496 ; the original 'VECTOR'
variables. For example, the expression X$(1,4 TO 9) or A*(B + (C/ ISCALL CALL NEXT_CH
(D + E))) would be allowed, the result being stacked in run time. RST 16
78 The Spectrum Operating System Extending BASIC with Interface 1 79
DEFW 7298 ; evaluates next basic Normally extended BASIC commands or functions will be ended
expression as numeric. by a jump back to the main interpreter as above and it is most
causes error if not.
important that it is the 8K ROM which is switched when this
In run time value is
put on calc. stack
jump is made, otherwise the program will crash.
CALL 1463 ; checks for end of
basic statement.
and returns only in
RST 16 ; run time
DEFW 11682 ; stack to BC, see chap 8
JR ' C,ERROR ; carry set if over 65535
LD (DEST),BC; the address to CALL
RST 16
DEST DEFS 2 ; and put it here
JR FINIS 16K ROM will be present
when called routine is
executed
ISFRE CALL 1463 ; exits in syntax time
LD HL,OO ; clear HL
ADD HL,SP ; add the address in SP
LD DE,(23653);this is STKEND
SBC HL,DE sub from address in
PUSH HL SP to give free space
for basic
POP BC ; result now in BC
RST 16
DEFW 11563 stack BC, see chapt 8
RST 16
DEFW 11747 ; prints value on stack
FINIS JP 1473 return to basic
NEXT_CH RST 16
DEFW 32 ; ROM NEXT_CH routine
AND 223 make it upper case
RET
The Calculator 81
Chapter Eight right. It takes seven moves to the left to make the most significant
set bit on the right of the binimal point. To follow the process:
0 moves 0 1 1 1 1 1 1 0
The Calculator 1move 0111111.0
2 moves 0 1 1 1 1 1.1 0
3 moves 0 1 1 1 1.1 1 0
and so on until after
7 moves 0.1 1 1 1 1 1 0
The Spectrum contains a powerful calculator in the ROM which Any bits left to the left of the binimal point will always be reset
can be used to advantage by the machine code programmer. As it and so can be discarded, as can the binimal point since it is
has 66 different routines, I shall be examining in detail only the known where it is and it will always be there for any number. We
more useful ones. To use the calculator it is important to under- normally do this ourselves with decimal numbers, albeit
stand the form in which the Spectrum handles numbers, how to unknowingly, by not showing a decimal point to the right of an
place them so that the calculator can access them and how to integer (a whole number) as everybody knows that that is where
it would be.
retrieve the answer to the completed calculation.
This process gives us the part of the number known as the
All numbers being used by the calculator are stored as five
bytes in either binary floating point representation or small
mantissa which, for the example given, is 11111100 in binary and
the exponent (the number of times the binimal point has been
integer representation.
moved to the left) is seven. The most significant bit of the
mantissa will always be set so this bit can be used to show the
Small Integer Representation sign of the number; it is set for a negative number and reset for a
positive number.
The first byte is always 0. The exponent is expressed in signed binary, bit 7 set if the
The second byte is the sign, 255 (FFh) for negative or 0 for binimal point has been moved to the left, and reset if it has been
positive. moved to the right. Thus, for the example above the mantissa was
The third and fourth bytes are the actual number in standard Z80 7, binary 00000111, but the point was moved to the left so bit 7
format, low byte first. must be set giving 10000111 or 135 decimal. Now the number can
The final byte is always 0. be shown in its full five-byte form:
The number 0 is regarded as being positive. Exponent Mantissa
Binary 10000111 01111100 00000000 00000000 00000000
Decimal 135 124 0 0 0
Floating Point Representation Hex 87 7C 0 0 0
numbers to be manipulated onto the calculator stack. This can be CALL 11419 (2C9Bh)
tackled in three basic ways:
Whenever the BASIC interpreter comes across a number in a
1) A number can be placed on the stack from a register or BASIC line being entered, it places the five-byte binary form
register pair, using a ROM routine to convert it to the form of the number after the ASCII version, ready for use later
that the calculator requires. when the program is being run. The routine used for this
2) The number can be changed into the form that the calculator can be made to do the conversion for a machine code
understands and then put onto the stack. program written by the user. This saves all the problems of
3) The number can be written to memory in ASCII representa- converting numbers manually or writing a routine to
tion and the BASIC syntax checker used to read it and place convert them in your program, and is well worthy of
it onto the calculator stack in the correct form. detailed consideration.
To use this routine to load the calculator stack the BASIC
Each method has its own advantages and disadvantages and each system variable CI-LADD 23645 (5C5Dh) must contain the
lends itself to different types of numbers. I shall now consider address of the first character of the number to be stacked,
their use in turn. and the A register must hold the code of the character
pointed to by CHLADD. The first character will normally be
1) For small integers, there are two routines that can be used: the most significant digit of a decimal number but, because
the routine is that used for BASIC line scanning, it could be
CALL 11560 (2D28h)
the BIN token 196 (C4h) if the following digits are a binary
This is employed by putting the number to be transferred to number. A binary number can only be evaluated to 16
the calculator stack into the A register. Obviously the range digits, decimal 65535 (FFFFh). Any attempt to exceed this
is limited to 0-255 (0–FFh) and the number must be will result in a jump to the BASIC error-handling routine. E
positive. format can be used if it is so wished, and the number should
be arranged exactly as it would be in a BASIC line.
CALL 11563 (2D2Bh) After the characters comprising the number, and the
This will accept numbers in the range 0-65535 (0–FFFFh) exponent if used, a defined byte of value 13 (0Dh) should be
from the BC register pair. Again the number can only be added. This lets the routine know that it has reached the end
positive, unless the start of the routine is bypassed. The of the number and that there is nothing else to look at.
CALL is then made to 11569 (2D31h) with the A register
holding 0, and the E register set to 255 (FFh) and the number
will be transferred to the calculator as negative. There are two ROM routines the reverse of the two routines to
Stack A and Stack BC. These take the last entry on the calculator
2) For numbers in five-byte form ready for use by the calculator
stack and compress it into a rounded integer if possible. If the
the following routine is used:
number was too large then the carry flag will be set on return, and
CALL 10934 (2AB6h) if the number is negative the 0 flag is reset. For a positive number
the 0 flag will be set. The number will be deleted from the stack by
The five-byte representation of the number as described
changing the pointer, but the DE register pair still points to it in
above in Floating Point Representation must be in the
memory allowing it to be reclaimed if recovery was not success-
registers A, E, D, C, B; the exponent in the A register and the
ful, although it is easier to duplicate the number before
mantissa in the other four registers in order.
attempting recovery, and then delete the copy on a successful
3) ASCII representation operation. The call addresses are:
84 The Spectrum Operating System The Calculator 85
During the time that the calculator is switched on, its op-codes 02 DELETE Removes Y from the stack. Z = X
are taken from the memory following the RST 40. These are a (STACK CH. –5)
series of DEFined Bytes in a normal Z80 program. When the 03 SUB'T'RACT X – Y = Z (STACK CH. –5)
calculator gets an ENDCALC instruction, control is returned to 04 MULTIPLY X * Y = Z (STACK CH. –5)
the Z80 and this continues execution of the program from the 05 DIVIDE X / Y = Z (STACK CH. –5)
address following the ENDCALC. Some op-codes require 06 TO POWER X ^ Y = Z (STACK CH. –5)
operands, and some can be used only at the start of a series, since 07 BINARY OR X OR Y. If = 0 then Z = X, otherwise Z = 1
they require the Z80 registers to be set in a particular manner in (STACK CH. –5)
order to operate. 08 BINARY AND X AND Y. Both X and Y must be numbers.
Each time the stack is used its size changes by five bytes. If Y = 0 then Z = 0, otherwise Z = X. There
Therefore, every time a number is placed on the stack a check is is a separate op-code to deal with strings
made to see that there is room. Should there be inadequate space 16 (10h)
a BASIC error will be caused. (STACK CH. –5)
The calculator is not limited to numeric operation, it is also The sequence of op-codes from 09 to 14 (0Eh) deals with numeric
used to perform the BASIC string and VAL functions. These will values. Each code can be used only as the first operation after the
be discussed later. rst 40 (28h) as the b register must contain the op-code at the
The op-codes that the calculator understands are set out below moment the actual operation is performed.
with descriptions of their operation. In each case the change to There is a second set of op-codes for string comparisons; all
the calculator stack is given in bytes — five bytes are used for each return Z = 1 if true or Z = 0 if false (STACK CH. –5).
value — for the calculator's execution of a single op-code.
X is the value below Y on the calculator stack, Y being the last 09 Y <= X 10 (0Ah) Y >=, X 11 (0Bh) Y<> X
value put onto the calculator stack. The result of a calculation is 12 (0Ch) Y > X 13 (0Dh) Y < X 14 (0Eh) Y = X
always left on the top of the calculator stack, and this result is 15 (OFH) ADDITION X+Y= Z (STACK CH. –5)
represented by Z. For example, for the subtract op-code (03) if
X = 5 and Y = 9, X would be placed onto the calculator stack In the following sequence of op-codes, one or both of the X and
followed by Y, the RST 40 (28h) would be followed by a defined Y values must hold the parameters of a string. Details of how to
byte 03. After the operation, the calculator stack is –5, the get these parameters and put them on the calculator stack are
answer is on the top as Z. Therefore both X and Y have been given later. The part or parts that are string parameters are shown
deleted. with a $ symbol.
Jumps are made from the location of the distance operand, the
standard Z80 manner.
Op-code Function Operation
Op-code Function Operation
16 (10h) $ AND No. X$ and Y. If Y = then Z$ will be an
00 JUMP I RUE Jumps the distance (2s complement empty string, otherwise Z$ = X$
notation) in the operand (the defined byte (STACK CH. –5)
after the 00 op-code) if Y is non-zero.
(STACK CH. –5) The op-codes 17-22 (11h-16h) are the string equivalents of op-
01 EXCHANGE Reverses the order of X and Y on the stack codes 09-14 (0Eh), called with the B register holding the op-code.
(STACK CH. 0) Again Z = 1 if true or Z = 0 if false. (STACK CH –5)
88 The Spectrum Operating System The Calculator 89
17 (11h) Y$ <= X$ 18 (12h) Y$ >= X$ 19 (13h) Y$ <> X$ 28 (1Ch) CODE Z = CODE Y$. As used by the
20 (14h) Y$ > X$ 21 (15h) Y$ < X$ 22 (16h) Y$ = X$ BASIC interpreter (STACK CH. 0)
29 (1Dh) VAL Z = VAL Y$. As used by the BASIC
23 (17h) ADDITION X$ + Y$ = Z$. The two Strings are interpreter and in fact accesses the
concatenated in workspace and the line scanner to get the result into Z.
new parameters are returned in Z$. Subject to BASIC errors.
Remember that if there is
(STACK CH. 0)
inadequate room for the two strings
30 (1Eh) LEN Z = LEN Y$. This is easier to do
to be copied into an expanded
without using the calculator, all it
workspace a BASIC error will be
does is stack the length bytes of the
caused (STACK CH. –5).
string parameters
24 (18h) VAL$ VAL$ Y$ = Z$. The new string is
(STACK CH. 0)
created in workspace in the same
manner as above. The op-code The following algebraic functions all return the answer (Z) on the
must also be contained in the B top of the calculator stack and the stack size is unchanged.
register at the time of use. Any
errors will cause a BASIC error. This Op-code Operation
is the routine used by the BASIC
31 (1Fh) Z = SIN Y
interpreter and is subject to all the
32 (20h) Z = COS Y
syntax checking procedure
33 (21h) Z = TAN Y
(STACK CH. 0)
34 (22h) Z = ASN Y
25 (19h) USR$ Z = USR$. Again used by the BASIC
35 (23h) Z = ACS Y
interpreter and subject to syntax
36 (24h) Z = ATN Y
checking. Y$ must contain the
37 (25h) Z = LN Y
parameters of a String containing a
38 (26h) Z = EXP Y
single letter from A to U. Z will be
39 (27h) Z = INTY
the address of that user-defined
40 (28h) Z = SQR Y
graphic on completion
41 (29h) Z = SGN Y
(STACK CH. 0)
42 (2Ah) Z = ABS Y
26 (lAh) READ IN This routine allows a single byte to
be put into WORKSPACE through 43 (2Bh) PEEK Z = PEEK Y. As used by the BASIC
any stream 0-15 (0Fh), taken from interpreter (STACK CH. 0)
Y. The byte is regarded as a string 44 (2Ch) IN Z = IN Y. This performs the Z80 IN
and Z$ is the parameters of this A,(C) instruction after taking Y
string. If the carry flag is not set by from the stack into the BC register
the input routine, no action is taken pair as an integer (STACK CH. 0)
and Z$ is returned as a null string 45 (2Dh) USR No. Caution This will cause an execution
27 (1Bh) NEGATE Z = Y but with the sign changed jump to the address Y. Used by
(STACK CH. 0) BASIC to jump to machine code.
The return address will be 11563
(2D2Bh), the stack BC routines
90 The Spectrum Operating System The Calculator 91
which will put the value in the BC bytes which follow to make the
register on return on the calculator mantissa, 00 BIN for 1 to 11 BIN for
stack. This is an interesting op-code 4. The floating point number is then
since it opens up the possibility of read to the calculator stack
using routines in ROM and RAM (STACK CH. +5)
recursively from within the 53 (35h) DEC JR NZ This is a direct equivalent to the Z80
calculator (STACK CH. 0) DJNZ op-code, but for the
46 (2Eh) S1 R$ Z$ = Y. The top value on the calculator. The B register is taken as
calculator stack is printed to being BREG system variable. Not
WORKSPACE and evaluated as a safe to use, since this routine is
string, the parameters of which are extensively used within the
then put on the calculator stack calculator for its own purposes, and
(STACK CH. 0) the value of BREG cannot be
47 (2Fh) CHR$ Z$ = CHR$ Y. If 0 < Y < 255 then a guaranteed (STACK CH. 0)
single space is made in 54 (36h) Y < 0 Z = 1 if Y < 0, otherwise Z = 0
WORKSPACE and the value (STACK CH. 0)
transferred there as one byte. This 55 (37h) Y > 0 Z = 1 if Y > 0, otherwise Z = 0
is then interpreted as a string and (STACK CH. 0)
the parameters returned as Z$ 56 (38h) ENDCALC Returns control to the Z80 at the
(STACK CH. 0) next address (STACK CH. 0)
48 (30h) NOT Z = 1 if Y = 0, otherwise Z = 0 57 (39h) GET ARGT Used internally to the calculator to
(STACK CH. 0) establish the value Y (which for the
49 (31h) DUPLICATE Z = Y. Y is duplicated purposes of Z being the result will
(STACK CH. +5) be Z) of SIN Y or COS Y
50 (32h) X MOD Y This returns Z = INT (X/Y) and (STACK CH. 0)
underneath Z (where X was 58 (3Ah) TRUNCATE Z = INT Y, where Z is Y truncated
originally) X – INT (X/Y) towards 0 (STACK CH. 0)
(STACK CH. 0) 59 (3Bh) FP CALC 2 Used by the interpreter to perform a
51 (33h) JUMP This simply does the equivalent of a single calculator operation. Of no
Z80 JR (Jump Relative) instruction, practical use for the purposes of this
but for the calculator. The jump book
length is taken from the location 60 (3CH) E TO F.P. Z = Y E (Exponent) A register
following the op-code. The (STACK CH. 0)
calculator stack is untouched 61 (3Dh) RE STACK Z = the floating point version of Y,
(STACK CH. 0) where Y could have been a small
52 (34h) STK DATA This allows a value to be read in integer (STACK CH. 0)
from the locations following the op- 62 (3Eh) SERIES Used internally to the calculator to
code. Bits 6 and 7 of the first byte generate a Chebyshev polynomial.
(the exponent) following the Of no practical use as it is called by
op-code determines the number of the routines that need it
92 The Spectrum Operating System
will allow experimentation with the calculator is given in the 3 12288 12544 12800 13056 13312 13568 13824 11080 11336 14592 11048 15104 15360 15616 15872 16128
Useful Subroutines appendix. 4 16384 16640 16896 17152 17408 17664 11920 18176 18432 18688 18944 19200 19156 19712 19968 20224
5 20480 20736 20992 21248 21504 21760 22016 22212 22528 22784 23040 23296 23552 23808 24064 24320
6 24576 24832 25088 25344 25600 25856 26112 26368 26624 26880 27136 27392 27648 27904 28160 28416
7 28672 28928 29184 29440 29696 29952 30208 30464 30720 30976 31232 31488 31744 32000 32256 32512
8 32768 33024 33280 33536 33792 34048 34304 34560 34816 35072 35328 35584 35040 36096 36352 36608
9 36864 31120 37376 37632 37888 38144 38400 38656 38912 39168 39424 39680 39936 40192 40448 40704
A 40960 41216 41412 41728 41984 42240 42496 42752 43008 43264 43520 43776 44032 44288 44544 44800
B 45056 45312 45568 15824 46080 46336 46592 46848 47104 47360 47616 47812 48128 48304 48640 48896
C 14152 49408 49664 44920 50176 50432 50688 50944 51200 51456 51712 51968 52224 52480 52736 52992
D 53248 51504 53760 54016 54212 54528 54784 55040 55296 55552 55808 56064 56320 56576 56832 57088
E 57344 57600 57856 58112 50368 58624 58880 59136 59392 59648 59904 60160 60416 60672 60928 61184
F 61440 61696 61952 62208 62464 62720 62976 63232 63480 63744 64000 64256 64512 64768 65024 65280
94 The Spectrum Operating System
LSB
Appendix B
0 1 3 4 5 6 7 8 9 A E F
0
1 16
0
V
I
HI
2
19
3
20 21
5
22
6
23
7
24
8
25
9 10
26
II
27
12
28
13
29
14
30
15
31
The Spectrum
Memory Map
2 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
3 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
4 64 65 66 67 68 69 70 71 72 73 74 75 77
76 78 19
5 80 8I 82 83 84 65 86 87 88 89 90 91 94
92 93 95
VARIABLE FIXED
6 96 97 99 99 100 101 102 103 104 105 106 107 108 109 110 Ill
7 112 113 114 115 116 III I18 119 120 121 122 123 124 125 126 127
I' RAMT FFFFH OR7FFFH
8 128 129 130 131 132 133 n5535 33767
134 135 136 137 138 139 140 141 142 143 (23675) UDG
9 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 (237301 RAMTOP
A 160 161 162 163 164 165 166 167 168 169 170 171 172 123653) STK END
173 174 175
B 116 117 178 179 180 181 182 183 184 185 186 187 188 189 190 191 CALCULATOR STACK
C 192 193 194 195 196 197 198 149 200 201 202 203 204 205 206 207 (23651) STK BOT
D 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 WORKSPACE
E 224 225 226 227 228 229 230 231 132 233 234 235 236 237 238 239 (23649) WORKSI'
F 240 241 242 243 , 244 245 246 247 248 249 250 251 252 253 254 255 EDIT AREA
(23641) E LINE
IV I E3BLES VARIABLES
MICRODRIVE MAPS
5CEFH 23731 LAST BYTE OF
8K SYSTEM VARIABLES
Appendix C
The Spectrum
Screen Map
81 4840H 5940H 137 5020H 5A20H
82 4940H 138 5120H
83 4040H 139 5220H
84 41340H 140 5320H
85 4C40H 141 5420H
The Spectrum screen is divided into 192 rows of 256 pixels. Each 86 4040H 142 5520H
87 4E40H 143 5620H
line comprises 32 bytes of memory in ascending order. Below are 88 4F40H 144 5720H
listed the addresses of the first byte of each screen line with the B9 4860H 5960H 145 5040H 5A40H
90 4960H 146 5140H
address of the attribute that controls the first byte. Line 1 91 4060H 147 5240H
92 41360H 148 5340H
represents the top line on the screen. 93 40601-1 149 5440H
94 4D60H 150 5540H
95 4E60H 151 5640H
LINE PIXEL ATTRIBUTE 96 4F60H 152 5740H
1 400014 5800H 41 400014 5800H 97 4880H 5980H 153 5060H 5A60H
2 4100H 42 4100H 98 4980H 154 5160H
3 4200H 43 420014 99 4A80H 155 5260H
4 430014 44 43AOH 100 4B80H 156 5360H
S 4400H 45 4400H 101 4C80H 157 5460H
6 4500H 46 4500H 102 4080H 158 5560H
7 4600H 47 4600H 103 4EBOH 159 5660H
8 4700H 48 4800H 104 4F80H 160 5760H
9 4020H 5820H 49 4000H 58C0H 105 480011 5900H 161 5080H 5080H
10 4120H 50 41COH 106 49AOH 162 5180H
11 4220H 51 42COH 107 4AAOH 163 5280H
12 4320H 52 43COH 108 4BAOH 164 5380H
13 4420H 53 44COH 109 4CAOH 165 5480H
14 4520H 54 45C01-1 110 4000H 166 5580H
15 4620H 55 46COH 111 4EAOH 167 5680H
16 4720H 56 47COH 112 4F0011 168 5780H
17 4040H 5840H 57 40EOH 58E0H 113 48COH 59COH 169 5000H 5000H
18 414014 58 41EOH 114 49COH 170 51AOH
19 4240H 59 42E0H 115 4ACOH 171 5200H
20 434014 60 43E0H 116 4BCOH 172 53AOH
21 4440H 61 44E0H 117 4000H 173 5400H
22 4540H 62 45E0H 118 4000H 174 55AOH
23 4640H 63 46E0H 119 4ECOH 175 5600H
24 4740H 64 47E0H 120 4FC0H 176 5700H
25 4060H 5860H 65 480014 5900H 121 48E0H 59EOH 177 5000H SACOH
26 4160H 66 4900H 122 49E0H 178 51COH
27 4260H 67 4000H 123 4AEOH 179 52COH
28 4360H 68 4BOOH 124 4BEOH 180 53COH
29 4460H 69 4000H 125 4CEOH 181 54COH
30 4560H 70 4000H 126 4DEOH 182 55COH
31 4660H 71 4EOOH 4EEOH 183 56COH
127
32 4760H 72 4FOOH 4FEOH 184 57COH
128
33 4080H 5880H 73 4820H 5920H SAEOH
129 5000H 5000H 185 50EOH
34 4180H 74 4920H 130 5100H 186 51EOH
35 4280H 75 40208 131 5200H 187 52E0H
36 4380H 76 4B20H 132 5300H 188 53E0H
37 4480H 77 4C20H 133 5400H 189 54E0H
38 4580H 78 4D20H 134 5500H 190 55E0H
39 4680H 79 4E20H 135 5600H 191 56E0H
40 4780H 80 4F20H 136 5700H 192 57E0H
Appendix D Appendix E
12 DELE'T'E As above for CAPS SHIFT and '0'. codes 32 to 126 conforming to standard ASCII and these are
ASCII Form Feed code shown in the Spectrum manual.
13 EN'I ER Returned when the EN 1 ER key is
Code 127— the Spectrum copyright symbol — is the ASCII delete
pressed, performs a carriage return
and line feed when printed to the code, be careful!!
screen. Is also the ASCII code for
carriage return
14 Precedes a number in a BASIC
program line. Not of any practical
use. ASCII Shift Out code
15 Not used in the Spectrum. ASCII
Shift In code
16 Ink control code used to precede the
number for the INK colour. For
example to change the on-screen
printing colour for all following
characters to red, you would use the
RST 16 routine with the A register
holding 16 followed by 2. Note NOT
ASCII 2 but value 2. This is
demonstrated in the DeBASE
program.
17 As above but for PAPER
18 As above for FLASH, the following
code can be only 0 or 1
19 As above for BRIGHT
20 As above for INVERSE
21 As above for OVER
22 AT control code, must be followed
by the line and column values
23 As above but TAB, needing only
the column value
F75C 2048F5 5280 DELETE LD HL,(CUPOS) 1 THIS WORKS THE SAME AS THE DELETE LD 0,10 : THE HELP PAGE
F7D2 3EOA 5980
F75F 27 5290 INC HL ; RECORD BUT FOR ONE CHARACTER CALL FMESS
F7D4 CD5EF5 5990
F760 7E 5700 LD A,(HL)
F7D7 3EBF 6000 WAITE LD 0,88F
F761 C87F 5710 BIT 7.0 A,(#FE)
F7D9 DBFE 6010 IN
F767 C271F5 5320 JP NZ,INFUT
F708 E601` 6020 AND 1
F766 E5 5730 PUSH HL
F7DD 20F8 6030 JR NZ,WAITE
F767 ES 5740 PUSH HL
F7DF 2A48F5 6040 LD HL,(CUFOS)
F768 2AIFF5 5750 LE HL,(LIMIT) (LOCFND),HL
F7E2 2253F7 6050 LD
F768 D1 5360 POF' DE
F7E5 27 6060 INC HL
F76C A7 5770 AND A
F7E6 7E 6070 LD A,(HLI
F760 ED52 5780 SBC HL,DE
F76F E5 5790 F7E7 2108F6 6080 LD HL,SCHAR
PUSH HL
F770 Cl 5400 F7EA 77 6090 LD (HL),A
POF BC
F7E8 27 6100 INC HL
F771 D1 5410 POP DE
F7EC 36FF 6110 LD (HL),#FF
F772 DA71F5 5420 JP C. INPUT
F7EE C353F7 6120 JF' REENTR
F775 CA71F5 5430 JP Z,INPUT
F778 D5 5440 PUSH DE
F779 El 5450 FOP HL Fass 2 errors: 00
F770 27 5460 INC HL
F778 EDBI) 5470 *WARNING* LIMIT absent
LOIR
F77D 2822F5 *WARNING* CHFOS absent
5480 LD HL,(CHPOS)
F780 28 *WARNING* FRINAT absent
5490 DEC HL
F781 2222F5 *WARNING* CUFOS absent
5500 LD (CHPOS),HL
F7B4 21048F5 *WARNING* OPEN1 absent
5510 LD HL,(CUPOS)
F787 27 *WARNING* PRINT absent
5520 INC HL
F788 CDEIFS *WARNING* PMESS absent
5570 CALL BACK:
F788 C355F6 *WARNING* WFLAG absent
5540 JP FINRET
*WARNING* OPEN: absent
5550
*WARNING* BACK absent
5560
F7BE 2048F5 *WARNING* SAVEL absent
5570 AND LD HL.(CUPOS) : AND THIS IS THE SAME IN REVERSE
F791 27 *WARNING* XREC absent
5580 INC HL
F792 E5 *WARNING* FINDIT absent
5590 PUSH HL
F793 2AIFF5 *WARNING* MEMFOS absent
5600 LD HL,(LIMIT)
F796 DI *WARNING* CURSE absent
5610 FOP DE
F797 A7 5620 *WARNING* SCHAR absent
AND A
F798 ED52 *WARNING* IN_LIM absent
5630 SBC HL,DE
F79A E5 *WARNING* CONTLK absent
5640 PUSH HL
F798 Cl *WARNING* LOCFND absent
5650 POF' BC
F79C 135 *WARNING* PRINTP absent
5660 PUSH DE
F79D ED5B1FF5 5670 Table used: 751 from 1219
LD DE,(LIMIT)
F7A1 D5 5680 PUSH DE
F7A2 El 5690 POP HL
F7A3 28 5700 DEC HL 1 errors: 00
Fass
F7A4 EDB8 5710 LDDR
F7A6 20(22F5 5720 LD HL,(CHPOS) 6130 : THIS IS THE START OF THE SAVE AND LOAD ROUTINES
F7A9 27 5730 INC HL 6140
F7AA 2222F5 5740 LD (CHFOS),HL 6150 : FIRST THE LENGTH OF THE RECORDS IS CALCULATED,
F7AD El 5750 POP HL 6160 : WITH AN OVERHEAD FOR AN END-MARKER
F7AE 3E20 5760 LD A,32 6170 AND LENGTH BYTES FOR RE-ENTRY AFTER LOADING
F780 77 5770 LD (HL),A 6180
F781 CDEIFS 5780 CALL BACK 6190 :
F784 C355F6 5790 JP FINRET F7F1 6200 MC5 ORG #F7F1
5800 : F7F1 2AF1F7 6210 SAVEL LD HL,(CHPOS) : FIRST THE END OF RECORDS IS PUT INTO
5810 : F7F4 222E75 6220 LD (29998),HL ; THE START OF THE AREA TO 8E SAVED OR
F787 2A48F5 5820 LPRINT LD HL,(CUPOS) : THIS USES STREAM THREE IN AN IDENTICAL 112E75 6230 LD DE,29998 ; LOADED
F7F7
F78A 23 5830 INC HL ; WAY AS STREAM 2 FOR THE SCREEN, F7FA A7 6240 AND A
F788 CDE1F5 5840 CALL BACK: ; IF AN INTERFACE IS CONNECTED F7F8 ED52 6250 SBC HL, DE
F7BE C5 5850 PUSH BC : WHICH RECOGNISES LFRINT IT WILL WORK:: 6260 INC HL
F7FD 23
F7BF 3E03 5860 LD 0,3 6270 INC HL
F7FE 23
F7C1 CD0116 5870 CALL #1601 6280 PUSH HL
F7FF E5
F7C4 DI 5880 POP DE 7E0B 6290 LD 0.11
F800
F7C5 D5 5890 PUSH DE 6300 CALL PMESS
F802 CD02FB
F7C6 1B 5900 DEC DE 6310 LD 8,25 : 25 INTERRUPTS 1/2 SECOND
F805 0619
F7C7 AF 5910 XOR A EI , JUST IN CASE
F807 FB 6320
F7C8 CDC8F7 5920 CALL FRINTF' 6330
F7CB CI 5930 POP BC 6340
F7CC C355F6 5940 JP FINRET 6350 : THIS WOULD BE BAD PLANNING
5950 , 6360 BUT IT IS TO DEMONSTRATE THE
5960 : 6370 : USE OF THE HALT FOR TIMING
F7CF CD6BOD 5970 HELP CALL 3435 6380
122 The Spectrum Operating System Appendix G 123
F808 76 6390 HOLDIT HALT ; TO MAKE SURE THAT S IS NOT TAKEN Pass 1 errors: 00
F809 10FD 6400 DJNZ HOLDIT ; FROM THE MAIN MENU l:EYFUSH
6410 : NOW THE KEYBOARD IS SCANNED 6790 ;
6420 ; 6800 ; THIS PAGES OUT THE 16K R.O.M.
F808 3E6F 6430 SOLDEC LD A,#BF SEE CHAPTER 3 FOR FULL DETAILS
6810 ;
F800 DBFE 6440 IN A,(#FE) 6820
F8OF E602 6450 AND 2 6830 ;
F811 CA11F8 6460 JP Z,LOAD F838 6840 ORG #F838
F814 3EFD 6470 LD A,#FD F838 2149E8 6850 RSWAP LD HL,ROMOUT
F816 DBFE 6480 IN A,(#FE) THE SUBROUTINE USED BY THE R.O.M.
F838 22ED5C 6860 LD (23789),HL :
F818 E602 6490 AND 2 IS USED BY HOOK CODE 32
6870
F810 20EF 6500 JR NZ,SOLDEC SO SET TO RETURN TO THIS ROUTINE
6880 ;
6510 ; THE STACK IS TO BE MUCKED ABOUT
F83E D9 6890 EXX
F83F .23FF8 6900 LD (HLSAV),HL : SO IT IS SAFER THIS WAY
Fass 2 errors: 00
F842 D9 6910 EXX
F843 ED4343F8 6920 LD (BCSAV),BC
*WARNING* CHPOS absent USE THE HOOK CODE
F847 CF 6930 RST 8 ;
*WARNING* PMESS absent
F848 6940 DEFB #32
*WARNING* LOAD absent
F849 El 6950 ROMOUT POP' HL THE TWO RETURN ADDRESSES
*WARNING* M_OR_T absent MUST BE REMOVED
F84q EI 6960 POP HL
*WARNING* LORET absent
F848 DI 6970 POP DE AND THE RETURN FROM THIS SUBROUTINE
*WARNING* HLSAV absent
F84C 2A3D5C 6980 LD HL,123613) THIS IS ERR SP SEE CHAPTER 4
*WARNING* ECSAV absent SAVE THE POSITION OF THE ERROR RETURN
F84F E5 6990 PUSH HL ;
*WARNING* MHEAD absent
7000 ; ON THE STACK FOR LATER
Table used: 243 from 521
F850 216AF8 7010 LD HL,MSLRET
F853 ES 7020 PUSH HL STACK THE NEW ERROR RETURN ADDRESS
F854 ED73305C 7030 LD (23613),SP ; AND POINT ERR SP TO THAT
F858 D5 7040 PUSH DE ; RESTORE THE RETURN ADDRESS
Fass 1 errors: 00 RET
F859 C9 7050
Pass 2 errors: 00
Fass 2 errors: 00
*WARNING* M OR T absent
*WARNING* RSWAP absent
*WARNING* LORET absent
*WARNING* MHEAD absent
*WARNING* HLSAV absent
*WARNING* VARSET absent
*WARNING* ECSAV absent
*WARNING* HLSAV absent
*WARNING* MHEAD absent
*WARNING* LORET absent
Table used: 160 from 407 Table used: 99 from 188
124 The Spectrum Operating System Appendix G 125
F934 3603 FAB6 454E5445 9320 MESS5 DEFM "ENTER DETAILS TO FIND"
8620 LD (HL).3
F936 C5 FA98 8D 9330 DEFB #8D
8630 PUSH BC
F937 060A FA9C 1002 9340 MESS6 DEFW #210
8640 LD 8,10
F939 3E20 FA9E OD 9350 DEFB 13
8650 LD A,32
F936 23 FA9F 454E4420 9360 DEEM "END OF RECORD. NO MORE INPUT"
8660 SETHED INC HL
F93C 77 FREE OD 9370 DEFE 13
8670 LD (HL),A
F93D 10FC FABC 504F5353 9380 DEEM "POSSIBLE"
8680 OJNZ SETHED
F93F E5 FRC4 8D 9390 DEFB #8D
9690 PUSH HL
FAC5 1001 9400 MESS7 DEFW #110
F940 2264F9 8700 LD (IN_LIM),HL
FAC7 50524553 9410 DEFM "PRESS "
F943 El 8710 POP HL
FACD 1002 9420 DEFW #210
F944 CI 8720 POP BC
F945 27 FACE 53544F50 9430 DEFM "STOP "
8730 INC HL
F946 71 FAD4 1001 9440 DEFW #110
8740 LD (HL),C
F947 23 FAD6 464E5220 9450 DEFM "FOR MENU,
8750 INC HL
FAEO 1002 9460 DEFW #210
F948 70 8760 LD (HL),B
FAE2 02 9470 DEFB 2
F949 CD6B1iD 8770 CALL 3435
F94C 3E0D FAE3 544E20 9480 DEFM "TO "
8780 LD 5,13
F94E CD4EF9 FAE6 1001 9490 DEFW #110
8790 CALL F'MESS
FAE8 544E2050 9500 DEEM "TO PRINTOR "
F951 El 8800 POF' HL
F952 23 FAF3 1002 9510 DEFW #210
9810 INC HL
FAFS 53544550 9520 DEFM "STEP "
F952 CD53F9 8820 CALL INPUTF
F956 3620 FAFA 1001 9530 DEFW #110
9830 LD (HL),32
F958 DDEI FAFC 464E5220 9540 DEFM "FOR HELP"
8840 POF' IX
F95A CI 8850 POF' BC F804 AO 9550 DEFB #A0
F956 C9 B860 EST E805 1003 9560 MESS8 DEFW #310
8870 7 FB07 594E5520 9570 DEFM "YOU ARE IN EDIT MODE"
8880 FB18 8D 9580 MC9 DEFB #8D
8890 i F81C 1002 9590 MESS9 DEFW #210
F950 0000 8900 BCSAV DEFW 0 FB1E 594F5520 9600 DEFM "YOU JUST RAN OUT OF MEMORY"
F95E 0000 8910 CUPOS DEFW 0 F838 OD 9610 DEFB 13
F960 3175 8920 CHPOS DEFW 30001 F839 53415645 9620 DEFM "SAVE THE RECORDS OR SOMETHING"
F962 0000 8930 HLSAV DEFW 0 F856 1000 9630 DEFW #10
F964 0000 8940 IN_LIM DEFW 0 F858 80 9640 DEFB #8D
F966 30E2 9950 LIMIT DEFW 62000 F859 5748454E 9650 MESS10 DEFM "WHEN YOU ARE IN EDIT MODE"
F968 0000 8960 LOCCNT DEFW ii FE72 OD 9660 DEFB 13
F96A OO(IO 8970 LOCFND DEFW 0 FB73 50524553 9670 DEFM "PRESSING
F96C 00 8980 WFLAG DEED 0 FE7C 1002 9680 DEFW #210
F96D 3175 8990 MEMPOS DEFW 30001 F87E 4E4F5420 9690 DEFM "NOT "
F96F 2118 9000 CURSP DEFW #1821 F882 1000 9700 DEFW #010
F971 9010 SCHAR DEFS 33 F884 57494C4C 9710 DEEM "WILL FIND THE NEXT OCCURENCE OF THE LAST STRING"
F992 E10 9020 MESSM1 DEFB #80 F883 20202020 9720 DEFM " THAT WAS SOUGHT"
F992 80 9030 MESS DEFB #80 FBC6 ODOD 9730 DEFW #0DOD
F994 44654241 9040 ME551 DEFM "DeBASE COPYRIGHT SGK 1984" FEC8 1002 9740 DEFW #210
F9AD BD 9050 DEF8 #BD FBCA 414E4420 9750 DEFM "AND "
F9AE 1001 9060 MESS2 DEFW #110 FBCE 1000 9760 DEFW #010
F980 50524553 9070 DEFM "PRESS SPACE TO ABORT" FBDO 57494242 9770 DEEM "WILL INSERT A CHARACTER"
F9C4 OD 9080 DEFB 13 FBE7 OD 9780 DEFB 13
F9C5 5820544F 9090 DEEM "X TO ERASE OR N FOR NEXT RECORD" FEES 41542054 9790 DEFM "AT THE CURRENT CURSOR POSITION."
F9E4 1000 9100 DEFW #10 FC07 ODOD 9800 DEFW #0DOD
F9E6 9D 9110 DEFB #8D FC09 44454245 9810 DEFM "DELETE WILL REMOVE THE CHARACTER"
F9E7 1002 9120 MES53 DEFW #210 FC29 OD 9820 DEFB 13
F9E9 4E4E5420 9130 DEFM "NOT FOUND" FC2A 41542054 9830 DEEM "AT THE CURRENT CURSOR POSITION."
F9F2 1000 9140 DEFW #10 FC49 ODOD 9840 DEFW #0DOD
F9F4 8D 9150 DEF6 #8D FC48 49462054 9850 DEEM "IF THERE IS NO SPACE IN A RECORD"
F9F5 1001 9160 MESS4 DEFW #110 FC68 OD 9860 DEFB 13
F9F7 20202020 9170 DEFM " MENU" FC6C 594E5520 9870 DEFM "YOU ARE ALTERING USE THE INSERT"
FAOA ODOD 9180 DEFW #0DOD FC88 OD 9880 DEFB 13
FAOC 50524553 9190 DEFM "PRESS" FC8C 46554E43 9890 DEFM "FUNCTION TO MAKE SOME SPACE."
F511 ODOD 9200 DEFW #ODOD FCA8 °DOD 9900 DEFW #0000
FAI3 46202020 9210 DEFM "F TO FIND" FCAA 54484520 9910 DEFM "THE CURSOR KEYS ALLOW YOU TO"
FA21 ()DOD 9220 DEFW #ODOD FCC6 OD 9920 DEFE 13
FA23 45202020 9230 DEFM "E TO ERASE" FCC7 4D4F5645 9930 DEFM "MOVE THROUGH THE TEXT BUT YOU"
F532 ODOD 9240 DEFW #0DOD FCE4 OD 9940 DEFB 13
FA34 43202020 9250 DEEM "C TO CONTINUE SEARCH" FCE5 43414E4E 9950 DEFM "CANNOT GO BACK PAST AN ENTER."
FA4D ODOD 9260 DEFW #0000 FD02 ODOD 9960 DEFW #0DOD
FA4F 454E5445 9270 DEEM "ENTER TO MAKE ANOTHER ENTRY" FDO4 1004 9970 DEFW #410
FA6B ODOD 9280 DEFW #000D FD06 50524553 9980 DEEM "PRESS ENTER TO RETURN TO TEXT"
FA6D 53202020 9290 DEFM "S TO SAVE OR LOAD" FD23 1000 9990 DEFW #10
FA83 1000 9300 DEFW #10 FD25 8D 10000 DEFE #8D
F585 3D 9310 DEFB #8D FD26 5052455' 10010 MESSII DEFM "PRESS S TO SAVE L TO LOAD"
128 The Spectrum Operating System
FD3F BD 10020 DEFB #8D
F040 50524553 10030 MESS12 DEFM "PRESS M FOR M/DRIVE"
FD53 OD 10040 DEF6 13
FD54 4F522054 10050 DEFM "OR T FOR TAPE"
FD61 BD 10060 DEFB #8D
FD62 494E5055
F071 BD
FD72 BD
10070 ME8513 DEFM "INPUT FILE-NAME"
10080
10090 ZEND
DEF6 #8D
DEFT( #80
Index
Fass 2 errors: 00
C register 6 Reclaim Microdrive Channel MOREX Interface 65, 106-7 microdrive output 31-2
current channel 18 (2Ch) 34 Motor on/Motors off routine 34 network output 28-30
ROM 2 (32h) 34 MREQ line 70 output 27-8
data bus 25 RS232 Input (1Dh) 26 ROM interpreter 75-7
Data Terminal Ready 28 RS232 Output (lEh) 27 network channel 28-9 RS232 Input routine 26
Run (32h) 36 Network Input routine 26 RS232 Output routine 27
DeBASE program 10, 13, 22, 24, 35,
Send Packet (30h) 29 NN command 2 RST
111-28
Write Record (26h) 32 numbers 6-8 10h 38
DE register 21
DEFined word 39-40 Write Sector (2Ah) 32 16(10h) 3-4
H' register 3 Open Channel/Open File routine 30 56 (28h) 8
DI instruction 72
Open Channel routine 26, 28 Run routine 36
IM1 mode 71 opening and closing streams 3 run time 77
EI instruction 71-2
IM2 mode 71
ENDCALC instruction 86 Picturesque Editor Assembler 1 SAVE/LOAD RETURN routine 21
indexing 84
Erase File routine 32 pixels 11, 17, 54, 73, 74, 96 saving 18-21
INPUT commands 52
E register 6 plotting to the screen 6 screen 6, 10
input routine 58
exponent 81 clearing 17
Inse rt Variables routine 34 ports
Interface 1 75-9 Kempston 66-7 lower 5
file name 60 Morex 65-6 scrolling 5, 17
interrupts 8-9, 11, 21, 41, 53, 70-4
floating point representation 80-2, 127 66 whole 5
interrupt vectors 102-3
91 screen copy 11
I register 70-3 231 62
Format Cartridge routine 35 239 62, 65 screen map 54
IX register 20-1, 23, 26-9, 32-4
IY register 2, 3, 9, 15, 42 247 62, 65 scrolling 5, 17
Get Key routine 26-7 251 62,64-5 Send Packet routine 29
graphics 11, 13, 15 Kempston Interface 3, 65, 106-7 254 62-4 shadow ROM 25, 40
keyboard 8-9 57535 66 Sinclair BASIC 25-6
header 18-24,29,59 map 98 58047 66 small integer representation 80
dummy 22-3 scanning 43, 63 58303 66 Spectrum Machine Language for the
microdrive 36-41 key-debouncing routine 43 PRINT command 2 Complete Beginner (Zaks) 2
hex to decimal conversions 93-4 Key Input routine 10 printer 11, 45, 65 Spectrum Pocket Book 7
Highsoft's Devpack 3-4 Keyscan routine 34 buffer 11, 51, 53 SPRITE 73-4
HL register 40 print positions 4-5 standard streams 66-7
hook codes 25-36 LET command 2 Print to Printer routine 27 start-up sequence 70
Catalogue Cartridge (32h) 35 line-drawing 16 Print to Screen routine 27 stream number 60
Close Microdrive Ch an nel line feed code 28 Programming the Z80 (Zaks) 2 string operations 92
(23h) 32 LOAD BYTES subroutine 22 subroutines 36, 38, 84, 104-28
Close Network Channel (2Eh) 30 loading 18-24 random numbers 52 calculator routines 104-6
Erase File (24h) 32 L' register 3 Read Next Print Record routine 33 DeBASE 11-28
Format Cartridge (32h) 35 Read Next Record Sector routine 33 interrupt driven sprite
Get Key (1Bh) 26 machine code program 1, 2, 38, 55, Read Print Record routine 33 routine 107-11
Insert Variables (31h) 34 80, 83 Read Record Sector routine 33 Kempston Interface 106-7
Keyscan (20h) 34 machine crash 38 Reclaim Microdrive Channel Morex Interface 106-7
Motor on/Motors off (21h) 34 mantissa 81, 91 routine 34 syntax checking 88
Network Input (2Fh) 26 memory 25, 42 record deletion 111 syntax flag 75
Open Channel (2Dh) 28 memory map 95-7 repeating key routine 43 syntax/run flag 35
Open Channel/Open File (22h) memory request line 70 ReSTarts 38-41 system variables 1, 42-61
30-1 message printing 12-13, 21 RET inst ru ction 40 8K system 56-61
Print to Printer (1Fh) 27 Microdrive 30-1, 56, 72, 74, 111 RETI inst ru ction 71-2 16K system 42-56
Print to Screen (1Ch) 27 channel 33, 36 ROM 2 routine 34 ALI R P 55
Read Next Print Record (25h) 33 header 36-41 ROM, 8K 25-41 A1 1RT 55
Read Print Record (27h) 33 Interface 1, 62, 67 inputs 26-7 BAUD 26, 57-8, 60
Read Next Record Sector (29h) 33 microphone socket 64 microdrive header 36-41 BORDCR 48
Read Record Sector (28h) 33 MODE CHANGE flag 10 microdrive input 33-6 BREG 50
132 The Spectrum Operating System
CH ADD 49 N_STR1 60
CH_ADD 75-66, 83 NI 1 YPE 59
CHADD_ 58 NXTLIN 49
CHANS 48 OLDPPC 51
CHARS 44 OSPCC 51
COORDS 53 P FLAG 55
COPIES 61 PIP 45
CURCHL 10, 18, 48 PPC 47
DATADD 49 P POSN 53
DEFADD 44 P_RAMT 56
DEST 48 PR CC 53
DF CC 54 FROG 49
DFCCL 54 RAMTOP 56, 67
DFSZ 51 RASP 45
DSTRI 60 REPDEL 43
DSTR2 61 REPPER 42-4
ECHO E 54 S BRT 57
E LINE 48-9 SCR CT 54
EPPC 48 SECTOR 58
ERR NR 45 SEED 52
ERR SP 46 SEED_FL 58
FLAGS 45 S POSN 54
FLAGS 2 50 SPOSNL 54
FLAGS 3 57 S TOP 51
FLAGX 51 STRLEN 52
FRAMES 52 STRMS 44
HD_OB 61 SSTR1 60
HD_OD 61 STKBOT 50
HD_OF 61 STKEND 50
HD_00 61 SUBPPC 47
HD_11 61 T ADDR 52
IOBORD 58 T_STR1 60
K CUR 49, 67 TVDATA 44
KDATA 44 TVFLAG 46
KSTATE 42 UDG 53
LAST K 43 VARS 48
LIST SP 46 VECTOR 57, 75-6
L_STR1 60 WORKS P 50
MASK P 55 X PTR 49
MASK T 55
MEM 50 tape socket 64
MEMBOT 56 tape-loading error 24
MODE 47 token code 13
NEWPPC 47
NOT USED 53 ULA 70
NSPPC 47
NTDCS 59 verifying 21-4
NTDEST 59
Wait Input routine 10
NTHCS 59
Wait Key routines 21
NTLEN 59
workspace 18
NTNUMB 59
Write Record routine 32
NTRESP 59
Write Sector routine 32
NTSRCE 59
NTSTAT 58 Z80 6, 70, 72, 86