2. Application writing
The multi-application environment
One of the most important things to bear in mind when writing applications
for the Z88 is that each application must share the system with other activities
in the machine. It is vital that applications do not interfere with each
other and only access resources in a legal way; if this is not done some
applications may have the ground cut from under their feet. Providing legal
interfaces are used there are no problems with interference. Back door
techniques are dangerous on a system like the Z88 because things which
happen behind the systems back may have dire effects on other applications
in the machine, possibly meaning resources are lost to the system, that
some applications may not run, or in most cases that the system simply
crashes.
Whenever an application is waiting for a keypress it may be suspended.
This may take the form of the machine being switched off and back on again,
or in a more complex case the user may enter other applications, use them
for a while and return to the original application - this case is called
pre-emption. The application is largely unaffected by what takes place
during suspension and can carry on as normal, although occasionally routines,
such as the system get line routine, have to be set up again when suspension
occurs. In some circumstances the application's screen will have become
disrupted and in these cases the system informs the application that it
needs to regenerate its screen. Where this is not possible the system provides
a way of saving an entire screen image, although this is costly in time
and memory and cannot always be guaranteed. There is one case, however,
where what has occurred during suspension does, however, have a profound
effect on the application and this case is that of a kill request from
the Index. This is a request for the application to free all claimed resources,
ie. close files, filters, streams, and de-allocate memory, before gracefully
shutting itself down. Applications are morally obliged to respond to this
request.
Perhaps what makes the Z88 environment most different from other Z80
based environments is that applications can readily access as much memory
as is available to the machine, possibly up to 3M. Of course the Z80 can
only address 64K so the physical memory is divided into 256 16K banks,
four of which can be paged into the four 16K segments which make up the
Z80 address space. In fact, things are a little more complex, but this
is discussed more fully in 'Memory Management'. When applications require
memory they first open a memory pool, and get a memory handle. This handle
is then used to make requests for memory which can be between 2 and 256
bytes in size. The advantage of the memory pool is that all allocations
made within one pool can be de-allocated by simply closing the pool. The
memory which is allocated has an address within its 16K bank and a bank
number. To access the memory the appropriate bank must be bound to a segment.
To make things easier a particular memory allocation can be associated
with a particular segment, thus the address returned by the allocation
routine can be used to access the memory directly once the appropriate
bank has been bound to the appropriate segment.
Some readers may find it quite alarming that the maximum contiguous
memory allocation is restricted to 256 bytes. In practice this should not
be a problem, although it requires a change of style in writing code from
more conventional Z80 systems. It means that chunks of memory have to be
linked together - the system provides a set of linked list routines which
can be used if required - rather than using adjacency as an integral part
of a data structure. All but one of the built in applications are written
using the memory management system, and because of their adherence to the
rule they are called 'good'. Some applications do have a genuine need for
a large contiguous block of memory such as the BASIC supplied with the
machine. Because it is a version of BBC BASICZ80 which has been ported
across to the Z88, it assumes that contiguous memory is available. To meet
the needs of this kind of application the operating system provides a facility
to give applications between 8K and 40K of contiguous memory. Since much
of this memory is unlikely to be used for much of the time, when the application
is suspended memory can be given back to the system. In order to create
the contiguous memory environment a great deal of swapping of memory chunks
has to take place, and the system becomes generally clogged up which is
why applications which use this environment are said to be 'bad' and should
be avoided if possible. All this having been said there are cases where
a bad application is a good idea. If your application is likely to be the
only one running on the Z88 at any one time, ie. it dominates rather than
supplements the machine, then a bad application is a perfectly justifiable
route. Note that if a bad application is started as the first application,
and does not give memory back to the system, then ironically memory swapping
is reduced and the application cohabits better with existing facilities.
Note that when the memory resources of the machine begin to be used
up, it may not be possible to enter an application because there is not
enough memory to run it. This is especially true of bad applications which
tend to demand more memory than they actually need. The application writer
does not need worry about this because when memory is short the application
will simply not be entered. However it is necessary for the application
to cope with a situation where requests for memory fail. In such cases
the user should be informed. The system provides a set of error messages
which the application can use when resources are not available.
Some components of an application
-
All applications available to the user are listed in the index on the left
hand window. Associated with each application is a key letter which can
be used to select it in conjunction with the square key. If two applications
have the same key letter then the application with the higher slot number
will be preceded by a Z, or even two Z's, if there are three applications.
The suspended applications window automatically gives the name of all suspended
applications along with the time and date of suspension. If the application
is running in an external card then the slot number will be placed in the
card column to the right of the window. The 'Your Ref' column on the left
of the window is a 15 character wide slot which the application can set.
It is useful for distinguishing between different instantiations of the
same application. Finally the user can kill off applications by placing
the highlight bar over the appropriate application in the suspended applications
window and entering <>KILL. Note that on the Index menu the kill command
is a 'safe' one and so must be entered using its diamond sequence, and
not via the menu.
-
The Filer is a built in popdown for handling the RAM filing system. Each
application is associated with a default device and directory. These are
set when the application is started by looking at the default settings
in the panel. When the filer is called from an application it will inherit
these settings. If the settings are changed from within the filer, using
'Select Directory' and 'Select Device', then the application settings will
be altered correspondingly. Further, it is possible for these settings
to be changed by the application itself. The filer delivers mail to applications,
which consists of the name of the last marked file. Mailboxing is the way
in which Z88 applications can communicate with each other. Any application
can put a piece of mail in the mail box and each piece of mail has a type
associated with it. Applications expecting mail then look for specific
mail types and if they are present can read the message. The internal applications
PipeDream and the Diary can collect the filename the filer leaves in the
mailbox, th us providing a very friendly way of finding documents and diaries.
The Z88 currently only has two types of mail which are the name type, for
filenames, and the date type, used by the Diary, Calendar and Alarm.
-
The screen is accessed by the application by means of the screen driver.
All the screen functions, apart from high resolution graphics, can be accessed
by sending a series of codes to the screen device, which will normally
be standard output. The screen driver sequences are constructed from an
ASCII SOH character ($01) followed by a count character, indicating how
many parameters follow, a mnemonic function code (eg. 'B' for bold text)
and any other parameters. From the programmer's point of view the screen
driver allows very complex screen displays (including simple windows) to
be built up mainly by sending string constants to the display. High resolution
graphics are accessed by using system calls. The basic display is up to
256 pixels (96 in an unexpanded machine) across and 64 pixels deep.
-
The menu, topic, help system provides the application with a friendly user
interface for practically no programming cost at all. All the menu commands
and help pages are defined by a static data structure. The special key
sequences which correspond to the commands on the menus, and operating
the menus by hand (using the highlight bar) both have the effect of generating
the same unique key code which is returned to the application. The programmer
decides which commands should return which codes, inserts this in the data
structure, and the operating system will then automatically generate all
the menus and help pages, process the diamond and square sequences and
any special keys (eg. TAB) and simply pass a key code back to the application.
Also note that menu commands can be hidden, ie. not displayed, and safe
which means they are displayed, but are not accessible through the menu,
only through the key sequence. Hidden commands are used to build aliases,
where two or more key combinations perform the same function.
-
Each application must take care to look after any errors which occur. One
particular error code which every application must deal with is the RC_QUIT
code which is produced when the user uses <>KILL in the Index. In response
to a KILL request the application must close all open channels and de-allocate
all allocated memory before using a system call to close itself down.
Guidelines for application writing
-
when making requests for resources, such as memory, make sure you get back
what you asked for. You must not assume that resources will always be available,
but always check for error returns, and be able to cope if they occur.
-
be careful to clean up after yourself. Whatever has been opened or allocated
should be closed or de-allocated. If this is not done before an application
closes down resources, eg. handles and memory, may be lost permanently
to the system. Open files will be marked 'In Use' and will not be writeable
or deleteable. These resources can only be regained after a soft reset,
and since this should be a relatively rare event for the Z88 (unlike other
systems because it is never off, it never needs to reboot), so this kind
of loss of resources is very serious for the machine. Keep your system
tidy.
-
direct access to hardware can be useful in dealing with the screen and
serial port. However, it is important that any access does not interfere
with other applications. It may, for example, be necessary to prevent pre-emption
so that the operating system does not have the wrong picture about the
true state of the machine.
-
note that not every Z88 system is the same. If 128K or more RAM exists
in slot 1 (or slot 0 with V4 ROM) then the machine is said to be expanded
and this effects bad applications, graphics and user defined characters.
Not all Z88's in circulation have the same ROMs. In the UK most ROMs will
be v2.2 or v3.0 (which are identical), but continental machines ROMs differ
in many significant respects. However all versions of the ROM above 2.2
support all the features and calls documented in this book, so sticking
with these means that there will be no compatibility problems. The machine
version, the amount of memory and the expanded or not status can all be
read by examining the file status of a dummy channel with a handle of FFFFh
(65535d).
-
make sure you keep track of your own stack. The system stack is 2K in size,
and the application inherits this stack. However, some of it may already
be used by the operating system. Furthermore the static memory allowed
for the application is taken from the same bit of memory, and the mailboxing
system which allows for communication between applications, leaves its
messages in this memory. What is left after all these other uses is the
stack for the application. In practice it is usually around 1.5K. There
is no checking for over running stacks so the application is responsible
for keeping the stack within bounds.
-
avoid splitting strings and other resources across bank boundaries. This
applies especially for bad applications that has large contiguous RAM memory.
Even though RAM is all yours, the system cannot cope with information that
crosses bank boundaries, or crossing a segment (eg. start address of a
string begins at $7F00 and end at $8050). Large BBC BASIC programs sometimes
behave strangely because of this.
-
try to avoid cutting the user off. The user should be able to switch out
of an application at most times. When heavy processing is going on it is
a good idea for the user to be able to interrupt this, and at the very
least be informed that it is taking place eg. by a flashing on screen message
such as PipeDream uses when doing file transfer or calculating a spreadsheet.
-
if interrupts are to be disabled the calls provided must be used. This
is due to a bug in the Z80 processor which means that the old interrupt
status can sometimes be lost. The machine must not be allowed to enter
coma while interrupts are disabled since it relies on the keyboard interrupt
to wake it up again. Generally while interrupts are disabled you should
ensure that the other applications never get to see this and that you use
system calls with great care. If interrupts are disabled remember that
non-maskable interrupts still occur. These are caused by the machine timing
out and power failure.
-
software timing loops are not recommended because they are both unreliable,
generally and due to interrupts, and because they mean the machine is in
the awake state but doing nothing, and thus wasting power. The system provides
a delay routine which sends the machine into snooze and then returns to
the program after the delay period.