EXOS 2.1 Kernel Specification

9. System Extension Interface

When EXOS does a cold start it builds up a list of all extension ROMs which are plugged in. Each of these ROMs has a single entry point which is called under various circumstances with an action code to indicate what function the ROM is to carry out. This chapter describes all the action codes and what the response to them should be.

The first 8 bytes of an extension ROM must contain the characters "EXOS_ROM" in ASCII. This string is used by the kernel to recognise a valid ROM at cold start time. Following this string is the 2­byte address of the first in a chain of pseudo device descriptors (see section 6.3). The next byte (offset 000Ah) is the entry point mentioned above. Here is a summary start of an extension ROM in assembler source form:

    0C000h:  DB   "EXOS_ROM"
    0C008h:  DW   DEVICE_CHAIN    ; Zero if no devices
    0C00Ah:                       ; ROM entry point   

There is a facility to load programs into RAM and link them in as system extensions, as described in section 10.5. Once loaded these RAM extensions are treated exactly as if they were ROM extensions, and will only be removed when a cold reset is done.

There is an EXOS call provided to pass a string around all system extensions to give them a chance to carry out some function. This results in the extensions being called with action code 2 (command string) or 3 (help string), the meaning of which will be explained in this chapter. Details of the scan system extensions EXOS call itself are given in section 11.24.

9.1 Calling System Extensions - General

System extensions are called by the EXOS kernel and will always be entered in Z80­page 3 at their single entry point. Page 2 will contain the system segment (segment 0FFh) which will include the stack, and page 0 will of course contain the page zero segment. ROM extensions can be allocated an area of RAM at cold reset time (see section 9.2.7). The segment containing this RAM will be in page 1, and will be pointed to by register IY. For RAM resident extensions, page 1 and register IY will be undefined.

Note that ROM extensions are allowed to make scan extension EXOS calls while in their allocate RAM routines. This can result in a ROM being entered with action code 2 or 3 before it has any RAM allocated. This case can be detected by testing for segment number zero in Z80­page 1, which can only occur before RAM is allocated, or if no RAM is requested.

An action code is always passed in register C, and register B and DE are used for passing various parameters to, and returning results from, the system extension. All other registers (AF, HL, IX, AF', BC', DE', HL') can be corrupted if desired.

System extensions are normally called by doing an extension scan, which may originate from a user EXOS call or be generated by the kernel. This involves passing the same action code and parameters to each system extension in turn. If the system extension returns the action code unchanged, then the values passed back in BC and DE will be passed on to the next extension in the list. Thus if a system extension does not support a given action code or command it should return BC and DE unchanged to ensure that the scan continues.

If a system extension returns with register C set to zero then the extension scan will stop, and the values returned in registers BC and DE will be considered as the results - the interpretation depending on the action code. In this case, the value returned in register A is a status code indicating success or failure using the normal EXOS status code values.

The extension scan calls any RAM resident extensions first, followed by any extension ROMs. The very last extension in the chain is the built in word processor program.

9.2 Action Codes

Below are the details of each of the action codes. Any values not included here are reserved for future extensions and should be ignored by all system extensions, simply returning BC and DE unchanged. The action codes are described in numerical order although the initialisation and RAM allocation ones are rather special cases.

A system extension can ignore any of these action codes which it wants to, they are all optional. Any action code which is not supported should be ignored by returning with DE and BC preserved. It is acceptable (although not very useful) for a system extension to consist of just a RET instruction at its entry point.

The action codes provided are:

  1. Cold reset
  2. Command string
  3. Help string
  4. EXOS variable
  5. Explain error code
  6. Load module
  7. RAM allocation
  8. Initialisation

9.2.1 Action Code 1 - Cold Reset

This action code is passed around all ROM extensions at cold reset time, when the copyright display program terminates, in order to allow one of them to select itself as the current applications program. The only other time when this action code can be received is when an attempt to load a new applications program fails (see section 10.6). No parameters are passed and no results are returned with this action code.

If the extension wants to set itself up as the current applications program then it simply goes through the normal startup procedure (described in section 9.3) and does not return from this call. If the extension does not want to do this then it just returns from this call with register C (the action code) preserved.

9.2.2 Action Code 2 - Command String

This action code results from a scan extensions EXOS call (code 26). It is passed a pointer to a string in register DE. This string will have a length byte first and will be stored in a buffer on the stack, so the scan extensions call is re­entrant. The first word of the string (up to the first space character) will have been uppercased and register B will contain a count of how many bytes there are in the first word.

The first word is the name of a command, service or program. Each extension will have a set of commands which it recognises. If the extension does not recognise this command then it should return from the call, preserving DE and BC. If it does recognise the command then it should respond to it, possibly interpreting the rest of the string as parameters, returning with register C=0, and a status code in A, unless it wishes other extensions to also respond to this command.

In carrying out the command the system extension can make any EXOS calls required, including further scan extension calls. It is often useful to make use of the default channel number for doing screen input/output since it cannot know what other channels are available.

The extension can interpret the command string as a cue to start itself up as the current applications program. For example the strings "BASIC", "LISP", and "FORTH" will be interpreted in this way by the appropriate language cartridges. In order to do this the extension behaves exactly as if it has received action code 1 (cold start), except that a different setting of the reset flags is used. (see section 9.3).

9.2.3 Action Code 3 - Help String

This action code also results from a scan extensions EXOS call, where the first word of the string was "HELP". The "HELP" (and any trailing spaces) will have been removed from the string and then the rest of the string treated exactly as if it was the original string passed to the EXOS call. The parameters for this action code are thus identical to those for action code 2 (command string) described above.

If the string is null (register B will be zero), then this is a general HELP call to all extensions. In this case the extension should just write its name and version to the default channel (using channel number 255) and return with BC and DE preserved.

If the string is not null, and the first word is any of the action code 2 commands recognised by this extension, then specific help information about that command should be printed to the default channel, and register C returned as zero, with a status code in register A (normally zero). If desired the rest of the string can be interpreted as further parameters to control what information is displayed.

If the string is not null and the first word is not a valid command for this extension then registers BC and DE should be returned unchanged.

9.2.4 Action Code 4 - EXOS Variable

This action code results when a read/write/toggle EXOS variable call was made with a variable number not recognised by the internal ROM (see chapter 8). It allows system extensions to implement additional EXOS variables and may be particularly useful for extension ROMs which also contain extension devices. The parameters passed are:

    B = 0, 1 or 2 for READ, WRITE and TOGGLE (ones complement)
    E = EXOS variable number
    D = New value to be written (only if B = 1)

If the variable number is not recognised then the extension should return with BC and DE preserved. If the variable number is one supported by this extension then the appropriate function should be performed and the following parameters returned:

    A = status (normally zero)
    C = 0
    D = New value of EXOS variable. 

To avoid conflict with the internal EXOS variables, and any others which may be added in future versions or extensions, system extensions should only use EXOS variable numbers of 128 and above.

9.2.5 Action Code 5 - Explain Error Code

This action code results from a user explain error code function call (code 28). The error code is passed around all system extensions to give them a chance to provide an explanation string. The internal ROM provides explanations for many of the error codes which can be generated by the EXOS kernel or any of the built in devices, unless a system extension returns a string first.

The error code is passed in register B and if it is not recognised the extension should just return with register BC preserved. To avoid conflict with the built in error codes, and any new ones in future versions or extensions, extension ROMs should only use error codes below 7Fh for errors which they generate themselves.

If the error code is recognised then a pointer to an ASCII explanation string (length byte first, maximum length 64 characters) should be returned. This can be in any segment and need not be paged in to the Z80 memory space when the extension returns. The results returned are:

     A = not required, can be any value
     B = Segment number containing message
     C = 0
    DE = Address of message string (can be in any Z80 page)

9.2.6 Action Code 6 - Load Module

The details of the Enterprise file module format are described in chapter 10. This action code is passed around system extensions when a module header of an unrecognised type is read in by EXOS, before returning an error to the user. It allows a system extension to handle loading of its own module types without requiring any special commands.

The extension is passed a pointer to the module header (16 bytes) which will be in the system segment, and also the channel number to load from:

     B = Channel number to load from
    DE = Pointer to 16 byte module header

The type byte (at DE+1) should be examined to see if this is a module type recognised by this extension. If not then it should return with DE and BC preserved. If the module type is recognised then the rest of the module should be read in from the specified channel, possibly using other parameters from the header, and initialised if this is necessary. Register C should be returned zero, and a status code in A which should be zero if the loading was successful and some error code if not.

9.2.7 Action Code 7 - RAM Allocation

This action code is rather special since it is only ever called at cold start time, and is only received by ROM extensions. It will only be called once and will always be the first call which the EXOS kernel makes to the ROM. However, as noted above, it is possible for a ROM to be entered with action code 2 or 3 before having any RAM allocated, so if the ROM expects to have RAM it must test for this case by looking for segment zero in Z80­page 1.

If the ROM does not require any RAM allocation then it should simply ignore this action code, returning register C unchanged. In this case, when future calls are made to this ROM, Z80 page 1 and register IY will be undefined since there is no RAM area for them to point to.

If the ROM does require RAM to be allocated then it should return the following results:

     C = 0 (To indicate RAM is required)
     B = RAM type flags.

             b0 - set for page 2 RAM
             b1 - set for page 1 RAM
         b2..b7 - not used. zero.

    DE = Number of bytes required       

The ROM can be allocated one of two types of RAM. Page 2 RAM is allocated in the system segment and so the extension can address it regardless of what it puts in Z80­page 1. The amount of page 2 RAM is limited since it must all be in one segment and this segment is used for many other purposes. The other type of RAM allocation is page 1 RAM. This is allocated in a segment which the system marks as a device allocated segment, and can be up to very nearly 16K. If this type of allocation is used then more RAM is available, but a whole segment will be taken away from the user. Several extension RAM areas can be put in one segment, and the same segment can also be used for loading the code of relocatable or absolute system extensions into (see section 10.5).

The type of RAM allcation required is specified by a pair of flags passed back in register B. If the page 2 flag (bit 0) is set then the RAM will be allocated in the system segment if possible. If the page 1 flag (bit 1) is set then a separate device segment will be used. If both flags are set then the system segment will be used if there is enough space, otherwise a separate device segment will be used.

If the RAM allocation is successful then the address and segment of the RAM area will be saved in the ROM extension list along with the ROM number. Whenever the ROM is called in future the RAM segment will be put in Z80­page 1 and register IY will point to the RAM area. If the page 1 flag (bit 1 of register B) was clear, so the RAM was allocated in the system segment, then register IY will point to the RAM in Z80­page 2. In all other case IY will point to the RAM in Z80­page 1, even if the RAM is actually in the system segment (both flags set). If n bytes of RAM were requested then they can be accessed at addresses:

IY+0, IY+1, ... , IY+n-1

If the RAM allocation failed because there was not enough RAM available the this extension ROM will be marked as invalid in the ROM list and will never be entered again.

Note that the call with this action code is made very early on in the system initialisation, before device drivers have been linked in or initialised. Some EXOS calls are allowed but any of the device related calls (open channel, link device and so on) are not. Generally care should be exercised with the EXOS calls made during RAM allocation. As mentioned before, a scan extensions call is allowed, and it will scan all EXOS extensions, even those which have not yet had RAM allocated. This is the only case in which an extension ROM can be entered before having its RAM allocated - care must be taken with this.

9.2.8 Action Code 8 - Initialisation

System extensions are initialised immediately after devices have been initialised. This is done initially at cold reset time (for ROM extensions), and again whenever an EXOS reset call with the appropriate flags set (see section 11.2) is made. This occurs when a warm reset happens and also when a new applications program takes control. RAM resident extensions are also initialised immediately after they have been loaded. No parameters are passed to the extensions and no results are returned. Register C (the action code) should be preserved but all other registers can be corrupted.

9.3 Starting a New Applications Program

A system extension may decide to start itself up as the current applications program as a result of a call with action code 1 or 2. To do this the following procedure should be carried out. The only difference between the two action codes is he value of the reset flags used in step 1. For action code 1 (cold start) a value of zero should be used since the system is already in a reset state. For action code 2 a value of 60h is used to ensure that any devices, channel or allocated RAM remaining from the previous application program are tidied up. The meaning of these flags is explaind in section 11.2.

  1. Do an EXOS reset call with the reset flags set to 60h for action code 2, or 00h for action code 1 (as explained above). This ensures that the system is in a defined state with no user device or user RAM, and no channels open. It will return with interrupt disabled.

  2. Set up a user stack somewhere in the page zero segment, since no other RAM is available, and then re­enable interrupts.

  3. Allocate any additional RAM segments which are needed, and open any default channels.

  4. Set up a warm reset address for when the reset button is pressed. This should be done even if the program does a complete restart for a warm reset, to ensure that any RAM resident system extension will remain resident.

  5. Set up the default channel number to the program's normal screen I/O channel (usually an editor channel), to allow system extensions to print their help messages.

After doing this, it is in full control as the current applications program and can make any EXOS calls.

Next Chapter: Enterprise File Format and EXOS Loading Functions.

David Bouman. (dsbouma@cs.vu.nl)