Every device driver has a device descriptor in RAM somewhere which defines the device's name, the address of the device driver code and various other details. They are kept in a linked list (called the device chain), and whenever a channel is opened, EXOS searches this list for a device with the correct name and opens the channel to that device.
The device chain is rebuilt whenever a reset EXOS call is made with the reset flags set to relink devices (see section 11.2). This occurs at cold reset time and when a new applications program takes control. The chain is initially created with a descriptor for each of the built in device drivers, and also for any device drivers contained in extension ROMs.
The user, or a system extension, can link in new devices with a simple EXOS call. These will be added to the device chain but will be lost when the chain is rebuilt.
The format of a device descriptor is given here. Each element is one
byte, apart from the device name which is of a variable size. The offsets
given are offsets from the
DD_TYPE field since this is where
the device chain pointers point to.
-3 DD_NEXT_LOW | 24-bit address of DD_TYPE field of next -2 DD_NEXT_HI | descriptor. Address will be in Z80-page -1 DD_NEXT_SEG | 1. End of chain indicated by | DD_NEXT_SEG=0. +0 DD_TYPE Must be zero. +1 DD_IRQFLAG Defines device interrupt servicing. +2 DD_FLAGS b0 set for video device. b1-b7 clear. +3 DD_TAB_LOW | 24-bit address of device entry point +4 DD_TAB_HI | table. Address must be in Z80-page 1. +5 DD_TAB_SEG | +6 DD_UNIT_COUNT Normally zero. Non-zero to allow multiple devices with this name. +7.. DD_NAME Device name string.
DD_TYPE field is provided to allow for future expansion
and also to enable a device to be disabled. This happens for example when
a new device is linked in with the same name as an existing one. The old
device will be disabled (unless
nonzero - see below).
DD_IRQFLAG field has one bit for each of the four
sources of interrupts in the
If the appropriate bit is set then this device driver's interrupt routine
will be entered whenever an interrupt of that type occurs. Any
combination of bits can be set. The bit assignments are:
b1 - Programmable sound interrupts b3 - 1Hz interrupts b5 - Video interrupts (50Hz) b7 - External interrupts (network) b0,2,4,6 - Should be zero.
Bit0 of the
DD_FLAGS byte is used to control channel
RAM allocation, which is different for video and nonvideo devices,
as explained in section 7.3.
The entry point table address
DD_TAB_LOW) points to a table of two byte entry addresses,
one for each function which a device has to perform. The address given in
the descriptor must be in Z80page 1 since EXOS accesses the table
there. However the entries in the table itself must be in Z80page 3
since when EXOS calls a device it puts the devices code segment in page
3. The entry points themselves must all be in the same segment as the
entry point table. The entries in the table are listed here and will be
explained in the section on device drivers.
+00 -Interrupt (Need not be valid if
+02 - OPEN CHANNEL
+04 - CREATE CHANNEL
+06 - CLOSE CHANNEL
+08 - DESTROY CHANNEL
+10 - READ CHARACTER
+12 - READ BLOCK
+14 - WRITE CHARACTER
+16 - WRITE BLOCK
+18 - CHANNEL READ STATUS
+20 - SET CHANNEL STATUS
+22 - SPECIAL FUNCTION
+26 -Buffer moved
The entry points printed in
CAPITALS correspond directly to
the relevant EXOS calls, the others are generated inside EXOS.
DD_UNIT_COUNT field is normally zero but can be set
nonzero to allow multiple devices of the same name to be handled by
translating unit numbers. This is explained fully in
DD_NAME field is the device name itself. The first byte
of this is a length byte, followed by the characters of the name in
ASCII. The name can be set up to 28 characters long and must consist of
upper case letters only.
0008/9h in every extension ROM is a pointer to the
start of a chain of devices. If there are no devices drivers in the ROM
then this pointer should be zero. Each element in the chain is basically
a device descriptor as defined above, but with certain fields missing,
or replaced by other information. The layout of one of these
pseudodescriptors is :
XX_NEXT_LOW | 16-bit pointer to XX_SIZE of next pseudo- XX_NEXT_HI | descriptor. Must be in Z80-page 1. XX_RAM_LOW | Amount of device RAM required. XX_RAM_HI | DD_TYPE | These fields are exactly as in a complete DD_IRQFLAG | device descriptor defined above. DD_FLAGS | DD_TAB_LOW | The DD_TAB_SEG field can have any value DD_TAB_HI | since EXOS fills this in when it links the (DD_TAB_SEG) | device DD_UNIT_COUNT | DD_NAME | --> XX_SIZE Size of pseudo-descriptor (see text)
The device chain pointer at the start of the ROM points to the
XX_SIZE field of the first pseudodescriptor, in
Z80page 1. Similarly the chain pointer (
XX_NEXT_HI) in each pseudodescriptor points to the
XX_SIZE field of the next one, in Z80page 1. The end
of the chain is marked by a pseudodescriptor with both
DD_NEXT_LOW set to zero.
XX_SIZE field is a count of the number of bytes in the
DD_TYPE to the device name. Thus if the
device name was one character long,
XX_SIZE would be 9.
The main descriptor fields (all those starting with
will simply be copied into RAM when the device is linked in, and a three
byte link added to the start to create a complete device descriptor. Note
however that EXOS fills in the
DD_TAB_SEG field, since a ROM
on the expansion stack cannot know what segment it will be in. This means
that the entry point table must be in same segment as the
XX_RAM_LOW fields define a
16bit number which is the amount of device RAM which this device
requires in the system segment. This number must be stored in two's
complement and with an offset added to allow for the three byte link
which EXOS puts on the start of the descriptor. If no device RAM is
required then the value should be
FFFEh (-2). If one byte is
required it should be
FFFDh(-3) and so on.
Whenever the device is entered register IY will point to its device descriptor, as will be explained in the section on device drivers. Since the device RAM is allocated immediately below the descriptor, the device RAM can be accessed relative to IY. If n bytes are requested then these can be accessed at addresses:
User devices are those which are linked in with a
link device EXOS call (code 21) which
can be made either by the user or by a system extension. To link in a
user device a complete device descriptor must be set up in RAM. All
fields of this must be complete except for the 24bit link
DD_NEXT_LOW). The EXOS call is then made with DE
pointing to the
DD_TYPE field of this descriptor, which can
be in any Z80page.
An area of device RAM can be requested by simply setting register BC to the amount required. This RAM will be allocated below the device RAM for any ROM extension devices. The device driver will be passed the address of this RAM area in register IX when it is first initialised. If n bytes are requested then they can be accessed at:
Note that this address will only be passed in IX on the first initialisation. It is the responsibility of the device driver to remember the address for future use, even when it is reinitialised such as after a warm reset.