DPS Programmers Reference Manual


 This is the description of the DPS operating system.
 The following text is implies DPS 1.1. running on a
Nukeman 226D, unless otherwise noted.


 1. Abstract

 DPS is a multi task, real time OS. It supports multiple windows with 
various graphic functions, has a global (system wide) object access
system, as well as (automatic) new type learning conventions.
 While offering the programmer over 500 system functions plus many
library modules along with increased performance (it was written 
in 68K assembler), the system resources it occupies for itself are
pretty modest - DPS 1.1, with one shell running in a single 
window, occupies about 150 K of memory.

 Memory and secondary storage resources (e.g. disks) are accessed
using dynamic allocation/deallocation, applying worst-fit strategy.
Cluster allocation tables (CATs) are bit-per-cluster type which allows
the smallest possible cluster size on devices. Thus, memory cluster
can be as low as 1 Kbyte; an 8 Gbyte hard disk has a CAT of 256 Kbytes
at a cluster size of 4 Kbytes. File and memory size limits are 2^32;
the number of logical units a device can have is limited to 2^16.

   Files are accessed via the registered file access functions in nearly
 all cases; that is, DPS keeps a list of files which are open and  prevents
reservation conficts (making a file publically available,  i.e. r/w accessible
for multiple tasks, is also possible - this is how,  for example, directories
are accessed). A file can be locked by a given task, which prevents (wether
it is publically available or not) any other task from accessing this
file while locked. 

 If a device is not of a random access type, it cannot have a file
system. These devices may be accessed the same way as a file, but
in the non-file mode (random access devices also can be accessed in
this mode). In the following specification, "file" means a file
from the file system of some device, which has one, while an 
"i/o nexus" means either a file or a non-file mode device access.


 2. Theory of operation

 DPS 1.1 allows up to 64 tasks running concurrently in the same system.
Every task, which is running, has:

 - a task descriptor (internal to the system),

 - a corresponding program module in memory (called also task PSCT),
   typically relocatable/position independent code so it can be run
   as multiple tasks simultaneously (it may be neither relocatable nor
   position independent, though up to date such code has not been written),
 [ Not all the code a task needs to execute must be in the program module
  it was started with. A task may call named functions from specified
  files (default suffix being .plm). When such a function is called, the
  respective file is loaded as a program module (if not already loaded),
  and control is given to the location specified by the function name
  the way a subroutine is called. Upon return from the function, if there
  is no other reason to keep this module, it is discarded. ]

 - a system data section (also called system DSCT), where the system
   stack is; also, some task related parameters, as well as the task 
   history record, are in this section,

 - a common data section (possibly shared with other tasks). Except for
   its header, usage of this area is application specific. The group of
   tasks, connected to the same common DSCT, is sometimes called a
   "process"; the tasks connected to the same common do not necessarily
   have anything to do with each other, though.

If (as in practically all cases) a task will run at user level, it
also has:

 - a user data section (also called user DSCT). Here is the stack
   while running at user level, as well as the memory, initially
   allocated to the task (as requested in the PSCT header). A part of
   this section can be "initialized", that is, read from the PSCT related
   file before spawning the task.

 A task also may have (and practically always has):

 - a standard input (STDI) i/o nexus, 
 - a standard output (STDO) i/o nexus,
 - a standard error (STDERR) i/o nexus.

 Tasks, which need graphic I/O, can open one or more windows.

 Every task, which is running, has a pair of priorities - basic and
current. The current priority is used only by the scheduler, which
gives control to the tasks in a prioritized round-robin fashion, that
is, tasks of highest & equal current priority are given control
sequentialy. Task switch occurs every time slice (which can be as low
as 2mS @ a 16 MHz 68340) and every time a task exits voluntarily; all
tasks, which lose the arbitration, have their current priority incremented
by one (max. is 2^16, protected against rollover). The task, which wins
the arbitration, has its current priority preset to its basic one, and is
given control to.

 There are 2 general types of system calls: those which execute
at user level (wcall, acall) and during whiches execution the scheduler
can interrupt the task in order to give control to another, and those
which execute at supervisor level (scall), during which period a task
will not be forced out (but still may exit for arbitration at its own
will - a device driver, for example, may exit (executing a xtask$) 
while waiting for some event or for any reason).

 Any task may execute a scall, while a wcall/acall may be executed only
by a task which has a user DSCT. The difference between wcall and acall
is that wcall replaces on call time caller's A3 with the address of
the current window descriptor, while acall leaves it unchanged.

 DPS 1.1 freezes any window, which is covered (even by 1 pixel) by
another; that is, if the task, to which this window belongs, attempts
to write to it, it is stopped until the window is unfrozen. Notice that
this is not guaranteed to be the case on other versions, which do not have 
to run on small systems, and should not be used for syncronisation or 
other purposes.

 There are 3 ways for non-I/O based intertask communication:
 - signalling (message passing),
 - using some global variable(s),
 - application proprietary - through the common DSCT.

 The applicaton proprietary intertask communication is not subject
of this specification.
 The global variables can be accessed from any task and thus can be
used for intertask communication.
 The signalling method of communication is most commonly used - 
this is how, for example, the mouse actions are distributed from
the "win" task to other tasks. To send a signal, a task calls the "sign$" 
or "signto$" function; then, with some additional system created data 
being passed, a predefined point of the target program module (of the 
task being signalled to) is called. How the signal is received then is
up to the code of the receiving task; if it is the "qstd" code, it will
place the signal on a queue in the receving task's user DSCT and
return; the latter will, when given control to, eventually find
it there and process it.

 3. DPS global object types

 The DPS object access system is simple and straight forward - an object
is something with which certain actions can be done - how they are done 
depends on the object. When a program wants to do something with an
object, it points to it, indicates the action and calls the "do$" or
the "qact$". Every object is of some type - that is, it is a kind of
some other, known at the point of learning, object; the basic type of
object is "something". Doing an action with some object is done the same
it was done with its "prototype" object unless declared differently.

 Object designation follows a standard format - 16 bytes (usually used
as ASCII text) designate the type. The actions are designated by
8 bytes each (again, usually used as text). Object descriptors are
kept on a linked list, where search links are different from the type
links; this allows the most frequently used objects to be checked first,
regardless of their type or moment of learning. Action code is found
from the descriptor in 3 ways:
 - relative - code is relative to the descriptor,
 - absolute - code is at an absolute address (never used until now),
 - file - code is a named function in a file, which is loaded as a
   module, if not present, and the code is then called. The module is
   released afterwards, if no longer needed for another reason.


 3.1. Type learn on demand

 To teach DPS what a new object is, a program has merely to attempt an
action (possible or not) with such an object. As it is not found on the
linked list, a file (with a name made of the first 8 alphanumeric characters
of the object type) with a .type suffix is searched first in the 
calling task's spawn directory (the directory where the program module
was loaded from), then in \wwdir\, and the object descriptor(s) found
in this file is (are) put on the list; then, the "install" action is done
with the object which initiated the search (the "something" type "install"
action returns without doing anything), and finally, the requested
action is attempted. Type search is recursive; that is, if a type
found in a file is not known at this point, another search is initiated
before installing the new type.


 Upon system start, DPS goes through the following steps: 

 - initializes the MCAT (memory cluster allocation table), the system
   timer, the processor vectors, installs the SCSI device driver,
   synchronizes internal timing with the real time clock,

 - processes the setup.syst file, which can be used to:
   - load device drivers as densely as possible (not on a cluster
     basis),
   - setup the system time slice,
   - setup the stdi/stdo of the initial shell which will be spawned,
   - spawn the "win.com", which is the task dealing with mouse actions,
     manual window limits change, keyboard polling, input (from mouse and
     keyboard) distribution to the input owning task etc.,
 
 - spawns the "shell.exec", which, in turn, executes the "turnon.bat"
   command script, upon whiches termination waits for user commands.

 The shell is the program which starts other tasks as applications 
in order to start a new task, it does the following:

 - calls the "xload$" function, which checks if the respective 
   program module is resident in memory and loads it if it is not, 

 - calls the "spawnn$" function, which:
   - allocates the user DSCT,
   - allocates the task's system DSCT, at the top of which 
     it places certain task unique variables and sets the system 
     stack pointer just below this area,
   - connects the task to the parent's (i.e. the shell's) common DSCT, 

 - prepares the standard input, standard output and standard error
   (stdi, stdo and stderr) I/O nexi for the new task and registers
   it for access into each;

 - calls the "start$" function, which places the new task among those 
   which are given control to by the scheduler and waits the task 
   to exit or be aborted (from another shell using the "kill" command or 
   killed because it did some illegal access etc) unless having been told 
   to start the task in background, in which case it comes back immediately.

 Upon task exit (while executing the "kill$ function code), the following
is done:

 - the resources taken by the task and denoted so in its history
   record are released, possibly one or more exit subroutines
   are called, if declared (at least one if the task has open
   windows),

 - all I/O nexi to which the task was registered are "left" - that
   is, the task is unregistered and, if the nexus has no more
   tasks registered to it, it is closed and removed from the list,

 - all memory blocks to which the task is connected are left - the task
   is unregistered from them all and after which memory blocks having
   no other tasks connected to them are deleted (memory deallocated,
   corresponding swap file deleted),

 - the history record is processed on a second pass,

 - the task's user DSCT is deallocated,

 - the task is unregistered from its common DSCT, which is deallocated,
   if no more tasks are connected to it,

 - the task is unregistered from its program module, which is removed
   (deallocated) if no oter task is connected to it,

 - the task's system DSCT is deallocated and the task is removed from
   those being given control by the scheduler (i.e., the task descriptor
   is released) - the task is dead.


 On boot time, DPS 1.1 always installs the following object types:

 - "something", with the following actions defined:
   - "install" - does nothing,
   - "create" - create such an object in memory,
   - "remove" - remove such an object from memory,
   - "readobj" - read (learn) a new object - see the paragraph above,
   - "getsize1" - used by "create" to determine the size of the
     object being created,

 - "memory_block" , which is "something", and is used by DPS to keep
   object descriptors into. (It must not be confused with the internal
   DPS memory block, which can be declared for swapping - they are
   quite different things).

 If the "create" action is done with "something" (e.g. by using the
"make" statement from a command script), the "object_segment" type is
learned; it is a kind of memory block with some more encapsulation
data, and makes sure that the created object, which is inside this
"object_segment", can be locked for access, properly removed and/or
located during cleanup operations.



 4. The DPS I/O system.

 4.1. Abstract

 In this section is discussed the DPS I/O system, which runs without
accessing any DPS objects and does not require the calling task to
have a user DSCT. Also, the device driver standards, necessary to
write a device driver, are described here.

 Generally, DPS I/O is performed between an application (a task) and an
I/O nexus. An I/O nexus is described by an IOCB (Input/Output Control
Block), which contains the device independent data about the I/O nexus
and a pointer to a DD (Device Descriptor) , which contains the device 
dependent data. During registered I/O operations, the IOCB is part of
the IOCB list DPS maintains; while it is possible to write code, which
uses the non-registered I/O functions, this is discouraged.

 In order to establish an I/O nexus, the task must call either the
fetch$ or the xopen$ with a valid directory being passed; as a result,
a "registration" is returned, which is used for further accesses to this
I/O nexus (until leaving it via the leave$). Actually, the registration 
is the address of the IOCB from the system IOCB list, but this may change
in later versions.

 A registration defines a unique I/O nexus name for the given device
(from the given directory in the case of file mode I/O). When attempting
to fetch$ or xopen$ an I/O nexus, the system IOCB list is first checked
for existance of an already created IOCB with the same name, device,
LUN (Logial Unit Number) and directory (directory is the registration
of the directory the file is located into and is at IO$DIR, being open
while there is at least one IOCB referencing it). If such an IOCB does
not exist, it is created, reserved and opened, and its address is returned
as the registration of the requested I/O nexus. If such an IOCB already
exists and is open in a mode allowing the requested access, the calling
task is checked in for access to that IOCB and its address is returned
as the registration. In both cases, the IOCB corresponding to the returned
registration is locked by the calling task upon return.

 Once the requested registration has been successfully returned,
it is ready for access; see RD$, WR$, READ$, WRITE$, GET1$, PUT1$,
GET$/GETB$, PUT$ descriptions for details.

 4.2 Input Output Control Block (IOCB)

 The IOCB has the following format:



Offset (bytes, decimal)
| 
| Length (bytes)
|  |
|  |   Name        Function
|  |    |           |
|  |    |           |
 0  2 IO$FLAG    Flags for internal DPS use
 2  2 IO$STA     For internal DPS status storage 
 4  2 IO$DTT     Data transfer type flags
 6  2 IO$OWN     Present owner - ID of task which has locked the IOCB
 8  4 IO$MLB     Maximum Logical Byte Number accesses since open$
22  4 IO$BBS     Block buffer memory start address
16  4 IO$BBE     Block buffer memory end address
20  4 IO$BBI     Block buffer internal address
24  4 IO$LBN     Current logical block number
28  2 IO$TYPE    File type and access restriction flags
30  4 IO$EOF     End Of File Logical Byte Number
44  4 IO$SG0     Segment 0 starting physical block number
38  4 IO$S0E     Segment 0 length (blocks)
42  4 IO$SG1     Segment 1 starting physical block number
46  4 IO$S1E     Segment 1 length/ RIB buffer size & address
50  4 IO$DIR     Directory IOCB address
54  2 IO$DEN     Directory entry number
56  4 IO$DEV     Device name/ DD address
60  2 IO$LUN     Logical unit number
62 12 IO$NAME    File name & suffix      
74  8 IO$LEN     Registration map (a bit per task) / IOCB length
82  0  RG$LEN    Registered IOCB length


 4.2.1 IO$FLAG consists of 2 bytes (called byte 0 and 1 below) of
flags (true if 1 unless otherwise noted):

Byte 0:

 Bit   Name         Function

 7  FF$RSV       IOCB is reserved to a device
 6  FF$OPEN      Open/closed flag ( 1=open)
 5  FF$RIB       File has a RIB (Retrieve Information Block)
 4  FF$LCK       IOCB is locked
 3  FF$WRR       RIB write pending
 2  FF$WRD       Directory entry update pending
 1  FF$RIBM      RIB resident in memory (IO$SG1=size, IO$S1E=address)
 0  FF$WR        Write was written to since last open

Byte 1:

 Bit   Name         Function

 7  F1$PND       Buffer is write pending
 6  F1$EOF       End Of File reached
 5  F1$DEL       Delete upon close if DT$TRU is also set
 4  F1$REG       Registration entry in system IOCB list busy
 3  reserved
 2  F1$LCK2      Lock counter overflow detecting bit (always 0)
 1  F1$LCK1      Lock counter bit 1
 0  F1$LCK0      Lock counter bit 0

 All these flags are maintained by DPS. "Manual" interventions are
1. not guaranteed to work with future versions,
2. require good programming skills and knowledge of DPS.

 4.2.2 IO$STA is used by DPS for internal storage of status data on
in different moments. The calling task receives status in D0.

 4.2.3 IO$DTT consists of 2 bytes (called byte 0 and 1 below) of
flags (true if 1 unless otherwise noted) related to the I/O:

Byte 0:

 Bit   Name         Function

 7  DT$NONF       Non-file mode IOCB
 6  DT$TRU        Truncate file size to the value in IO$MLB upon closing
 5  DT$DEL        Delete directory entry next update
 4  DT$PUB        Publically accessible (registered IOCB only)
 3  DT$NEW        If file exists during open, report error
 2  DT$CRE        If file does not exist, create it
 1  DT$OUT        Output (write) mode valid
 0  DT$IN         Input (read) mode valid

Byte 1:

 Bit   Name         Function

 7  DT$DMOD       Directory search mode (0=compare all, 1=masked)
 6  DT$DATE       Write date passed in D1-D3 upon create and close
 5  DT$FDAT       Force date write to directory entry
 4  DT$TIME       If set, DIRSRCH$ returns DE$DATE in D1-D3 (.W)
 3  DT$NWAI       Return with error instead of waiting if locked by another
 2  reserved
 1  DT$GTP1       Internal GET1$ flag
 0  DT$PATH       Internal PATH$ flag

 4.2.4 IO$OWN - owning task ID. The LOCK$ writes here the calling task
ID after having successfully locked the IOCB on its behalf. Allows locking
of the same IOCB multiple times by the same task.

 4.2.5 IO$MLB - Maximum Logical Byte accessed in the file since OPEN$.
During write calls, if IO$MLB updates with a higher value tha IO$EOF,
the latter is also updated.

 4.2.6 IO$BBS, IO$BBE, IO$BBI - memory buffer pointers. Automatically
maintained by DPS as long as no GET$/ GETB$ or PUT$ are called and,
if GET1$ / PUT1$ are used, once the SFPOS$ has been properly called.

 4.2.7 IO$LBN - current Logical Block Number. This is the block starting
with which GET$ / PUT$ will continue to read or write, respectively.

 4.2.8 IO$SG0 - IO$S1E - file segmentation data. If the file is in 1 or
2 pieces, then they completely describe the segmentation, if not,
a RIB is used and IO$SG0 contains (again) the PBN (Physical Block Number)
of the block after the RIB block (block 0 of the file). In the second
case, IO$SG1 and IO$S1E are used for internal purposes.

 4.2.9 IO$DIR - file's directory IOCB. Must be a valid and open IOCB
before the OPEN$ and stay so until after the CLOSE$. When using the
registered file functions, IO$DIR is automatically maintained.

 4.2.10 IO$DEN - directory entry number. The number (0 being the first)
of the directory entry corresponding to this file. Directory search 
starts with this entry, and it is updated by DIRSR$ if a match is found.

 4.2.11 IO$DEV - device name/ device descriptor address. Until the
RESRV$ call, these must contain the 4 character (case dependent, upper
case) device name. The RESRV$ replaces the name by the DD (Device 
Descriptor) address. This entry is automatically maintained by the
registered file functions.

 4.2.12 IO$LUN - logical unit number. This is strictly device associated;
it is found in the IOCB, because DPS allows two types of LUN / DD
relationship, which are device dependent. Maintained by DPS.

 4.2.13 IO$NAME - file name. During directory search, these bytes are
compared as they are to the DE$NAME bytes. If DT$DMOD in IO$DTT is 1,
bytes from IO$NAME, containing a 0, will always match (regardless of
the IO$NAME byte at this position). The file name processing functions
can automatically translate text into IO$NAME data, along with
group information (AFNAM$, PFNAM$, FNAME$ ).

 4.2.14 IO$LEN is the length of the IOCB; in the system IOCB list,
maintained for the registered I/O operations, another 4 bytes are
found at this offset. They are treated a a bit field, with bit 7 of byte
0 being bit 63 and bit 0 of byte 3 being bit 0. If a task is registered
for access to this file, its corresponding bit will be set (automatically
by the FETCH$ and XOPEN$). The KILL$ unchecks a task from any file
on the list (via the LEAVE$).



 4.3 The Device Descriptor (DD).

 In order to open an I/O nexus, DPS needs to know which device to access,
which is done by maintaining the IO$DEV entry in the IOCB. The DD is the
data structure describing what can be done with a device and how this is
to be done. A new DD can be installed in 3 ways:

 1. by placing the file name, containing the DD, in setup.syst after
    the "device" statement,
 2. by invoking the "install" command with the file name as an argument,
 3. by a program, which prepares the DD in memory and calls the ATTCH$.

 The DD has the following format:

Offset (bytes, decimal)
| 
| Length (bytes)
|   |
|   |  Name        Function
|   |   |           |
|   |   |           |
 0  2 D$FLAG     Device / DPS interaction related flags
 2  2 D$STA      Status (not used)
 4  4 D$IOCB     Currently connected IOCB address
 8  4 D$INIT     Device initialization (later modification) routine address
12  4 D$ON       "ON" routine address (called every OPEN$)
16  4 D$OFF      "OFF" routine address (called every CLOSE$)
20  4 D$CHK      Check if (more) data available routine address
24  4 D$GET      Get data routine address
38  4 D$PUT      Put data routine address
32  4 D$NAME     Device name (4 upper case alphanumeric characters)
36  2 D$LUNS     Following stuck (one per LUN) device descriptors (0=none)
38  2 D$CLUS     Allocation Cluster Size (number of blocks)
40  4 D$DDA      Device Dependent Area (DDA) address
44  4 D$DDAE     DDA and address +1 (DDA size = D$DDAE-D$DDA )
48  4 D$CAP      Device capacity (blocks)
52  4 D$BSZ      Device Block Size (number of bytes per block)
56  4 D$RATE     Max. transfer rate (bits/second)
56  1 D$TYPE     Device type related flags
57  1 D$MODE     Reserved
58  2 D$MLUN     Highest valid LUN
60  8 D$EXT      DD Extension address (0 if none)
68  0 D$LEN      Device descriptor length

 If the device allows random access (i.e. can have a file system),
then it has an extension in the following format:

Offset (bytes, decimal)
| 
| Length (bytes)
|   |
|   |      Name        Function
|   |       |           |
|   |       |           |
 0      4 XD$DSR     Directory search routine address for alien data formats
 4      4 XD$CDE     Create alien format directory entry routine address
 8      4 XD$RMS     Remote device directory search routine address
12      4 XD$REC     Remote device create directory entry routine address
16      4 XD$CTLN    Device's CAT file size (bytes)
20 IO$LEN XD$CAT     Device CAT IOCB - always open
94 IO$LEN XD$ROOT    Device root directory IOCB - always open.

 The first 4 entries of the above extension are not used by DPS 1.1.

 4.3.1 D$FLAG  - the following flags are defined:

Byte 0:

 Bit   Name        

 7  FD$RSV        Reserved (fot an IOCB; task link via D$IOCB -> IO$OWN )
 6  FD$LCK        Locked - not used by DPS 1.1.
 5  FD$INIT       Set by the initialization routine (called via ATTCH$)
 4  FD$ROP        Root IOCB open
 3  FD$COP        CAT IOCB open
 2  reserved
 1  reserved
 0  reserved

 FD$RSV is the only flag affected by DPS; it is set every time a task tries
to reserve the DD for itself and cleared when the DD is released. The
device driver code may, though, at its own convenience decide to reset the
flag and thus allow other tasks to gain access to the DD before DPS has
released it. FD$RSV is set by DPS every time before a call to any of the
D$ON, D$OFF, D$GET, D$PUT entries is done. If it is found set, the owner
of the current IOCB (from D$IOCB) is examined; if the same as the task
attempting to reserve the DD, access is allowed, otherwise the task waits.
Every time access is granted to the task, the D$IOCB is updated.

 FD$INIT is used by the initialization routine typically to indicate
initialization was done.

 FD$ROP and FD$COP indicate that the root directory and the CAT IOCB
respectively are open.


 4.3.2 D$STA is not used by DPS 1.1.


 4.3.3 D$IOCB contains the address of the IOCB to which the DD was last
reserved.


 4.3.4 D$INIT - initializaton routine address. Called once by DPS
during the ATTCH$ call execution; if the device will support the SETP$
and GETP$, it is up to the initialization routine to overwrite this entry
by the address of the DMO (Device Modification Offsets) and indicate
it has done so by setting the DD$PARS in D$TYPE.


 4.3.5 D$ON contains the address of a routine called every OPEN$ call.
Status must be returned in the common DPS format.


 4.3.6 D$OFF contains the address of a routine called every CLOSE$
call. Status must be returned in the common DPS format.


 4.3.6 D$CHK contains the address of the routine checking if more data
is available. If data is available (calling the D$GET entry for getting
at least getting 1 byte is possible), the routine must return successfull
status (carry clear); otherwise, carry must be set and D0 must be 0
to indicate no data can be got. If some other error has occured, it will
be distinguished by the non-0 error status in D0.


 4.3.7 D$GET contains the address of the "get" routine. It is called
in order to read from the device; it will never be called if the
DD$IN in D$TYPE is 0. 

 The entry is called with:

 D1.L - number of bytes to get (0 is no error; just returns),
 D2.W - device LUN being accessed,
 D3.L - block number to start reading from,
 A0.L - memory start address where to read into,
 A4.L - device descriptor address.

 It returns with:

 On success (carry clear):

 D0 - impredictable,
 D1 - number of bytes actually read (i.e. unchanged),
 the remainder of the registers is unchanged.

 If an error has occured (carry set):

 D0 - error status,
 D1 - number of bytes actually read,
 the remainder of the registers is unchanged.

 Notice that the "get"  code does not need to support read starting 
not on a block boundary (DPS does the buffering when using the
RD$ call), but it has to support reading into memory any number of 
bytes (not a multiple of the block size).


 4.3.8 D$PUT contains the address of the "put" routine. It is called
in order to write to the device; it will never be called if the
DD$OUT in D$TYPE is 0. 

 The entry is called with:

 D1.L - number of bytes to write (0 is no error; just returns),
 D2.W - device LUN being accessed,
 D3.L - block number to start writing from,
 A0.L - memory start address to be written (to the device),
 A4.L - device descriptor address.

 It returns with:

 On success (carry clear):
 D0 - impredictable,
 D1 - number of bytes actually written (i.e. unchanged),
 the remainder of the registers is unchanged.

 If an error has occured (carry set):
 D0 - error status,
 D1 - number of bytes actually written,
 the remainder of the registers is unchanged.


 Notice that the "put"  code does not need to support write starting 
not on a block boundary (DPS does the read/merge/write buffering
of the first and last block when using the WR$ call), but it has to support
writing any number of bytes starting from a block boundary, the last
block being zero-padded.


 4.3.9 D$NAME contains the device name, which must be 4 upper case
alphanumeric characters (space filled if less than 4).


 4.3.10 D$LUNS is the number of stuck device descriptors following
the one from which the value of D$LUNS has been read from. If non-0,
when reserving a device to an IOCB, the LUN from the IOCB, multiplied
by D$LEN and added to the DD corresponding to a LUN 0 is the address
of the DD which is written to IO$DEV.
 If D$LUNS is 0, but D$MLUN is >0, then there is a single DD for all
LUNs and it is up to the device driver code to distinguish and
process the LUN information.


 4.3.11 D$CLUS contains the number of blocks a cluster on that device
consists of. A cluster is the allocation unit, that is, a bit in the
CAT (Cluster Allocation Table) corresponds to a single cluster, and
it (the cluster) consist of sequential blocks.

 4.3.12 D$DDA and D$DDAE describe the Device Dependent (memory) Area.
Upon attaching the DD, D$DDAE contains the number of bytes this DD
needs allocated (0 is also an option); D$DDA at this point may be 0
to allow memory to be allocated wherever DPS's ALLCM$ decides (this
should be the preferred way) or non-0, thus designating the address
where the DDA is to be positioned.
 Once the DD has been attached, D$DDA contains the address of the
DDA memory allocated to this device, and D$DDAE contains the address
immediately following the last address of the DDA.


 4.3.13 D$CAP - device capacity, number of blocks the device contains.
Wherever non-applicable (e.g. an UART), this should be (2^32)-1 
($ffffffff) DPS uses this entry to update the IO$EOF when opening
a non-file mode I/O nexus. 


 4.3.14 D$BSZ - number of bytes per block. (On a disk device, this
would be the sector size).


 4.3.15 D$RATE - max. transfer rate, bits/second. Not used by DPS 1.1,
but maintained by device drivers, wherever applicable. Intended for use
by application programs to estimate time necessary for a transfer.
 

 4.3.16 D$TYPE - device type related flags. The following are defined:

 Bit   Name        

 7  reserved
 6  DD$PARS       Supports parameter setting/ reading
 5  DD$AIL        Alien data format (non-DPS file system)
 4  DD$REM        Remote device (direct device<> memory I/O done elsewhere
 3  DD$REW        Rewindable device
 2  DD$RAN        Random access device (any block at any time)
 1  DD$OUT        Device can be written to
 0  DD$IN         Device can be read from.


 4.3.16 D$MLUN - max. valid LUN. Used in conjunction with D$LUNS.


 4.3.17 D$EXT - device descriptor extension address. If the device allows
random-access (DD$RAN in D$TYPE =1) and it is to have a file system,
it must have an extension associated with the file system.
 At XO$ROOT, an IOCB is maintained which is used by DPS to access the 
root directory. It is up to the D$INIT and possibly D$ON, D$OFF to maintain
this IOCB open and up to date (in the cases of medium change etc.).
The other IOCB at XD$CAT is the IOCB of the device's CAT; it must only
be reserved to the device descriptor it belongs to, DPS takes care
of opening it using the root directory (UNITCAT.SYST).
 The root directory beginning & size are taken from block 0 at
B0$ROOT & B0$RSZ.


 4.4 The DPS 1.1 file system.
 A device allowing random access (DD$RAN in D$TYPE =1) can have a file
system. The minimum information necessary to DPS to begin some search
is the root directory; how it located and the root access IOCB is open
is device dependent. Generally, the beginning and size of the root
directory are taken from block 0 (B0$ROOT and B0$RSZ), but this is done
by code inherent to the device driver (the INIT, ON and OFF entries).
If the file system is going to be accesses in a way requiring device
space allocation changes, in the root directory a file named UNITCAT.SYST
must be present and it must contain the valid device CAT. Device lockout
clusters are not processed by DPS; the "lockout" utility can create
a lockout table and/or OR it to the device CAT if so commanded.
 

 4.4.1 Block 0 format

 Block 0 has the following format:

Offset (bytes, decimal)
| 
| Length (bytes)
|   |
|   |  Name        Function
|   |   |           |
|   |   |           |
 0  4 B0$SIZE      Block size (bytes)
 4  4 B0$LSBL      Last (highest) block number
 8  4 B0$BOOT      Starting block of boot code (0 means no boot code)
12  4 B0$ROOT      Root directory starting block
16  4 reserved
20  4 reserved
24  4 reserved
28  4 B0$RBKP      Backup root directory starting block (0 if none)
32  2 B0$VREV      Version/ revision e.g. 1.1
36 12 B0$DATE      Initialization date - YMMDDHHmmSS
48 16 reserved
74  4 B0$DESZ      Default directory size (number of entries)
68  4 B0$CFSZ      Default file creation size
72  4 B0$BLEN      Bootblock length (bytes)
76  4 B0$BASE      Bootblock memory load address
80  4 B0$EXEC      Bootblock execution address
84  4 B0$CLSZ      Cluster size (blocks per cluster)

 Typically, on a bootable device DPS.SYST would be contiguously allocated
and accessed for boot via B0$BOOT, B0$BLEN, B0$BASE and B0$EXEC. The SCSI
driver which comes with DPS 1.1 compares the block size as reported by the
device and compares it to what is found at B0$SIZE; if they do not match,
data format is assumed to be non-DPS.


 4.4.2 Directory format

 A directory is a file containing directory entries, which lead to
some file each. The directory entries are preceeded by a header which has
the following format:

Offset (bytes, decimal)
| 
| Length (bytes)
|   |
|   |  Name        Function
|   |   |           |
|   |   |           |
 0  4 DIR$SIZ     Directory size (number of entries)
 4  4 reserved
 8  4 reserved
12  2 DIR$RPR     Read priority allowing access (not used in DPS 1.1)
14  2 DIR$WPR     Write priority allowing access (not used in DPS 1.1)
16 48 reserved
64  0 DIR$ST      First directory entry (number 0)

 A directory entry has the following format:

Offset (bytes, decimal)
| 
| Length (bytes)
|   |
|   |  Name        Function
|   |   |           |
|   |   |           |
0   8 DE$NAME     File name
8   4 DE$SUFF     Name suffix
12  6 DE$DATE     Last modification time & date (BCD) - YYMMDDHHmmSS
18  2 DE$TYPE     File type + access restriction flags
20  4 DE$EOF      End Of File LBN (Logical Byte Number)
24  4 DE$SG0      Segment 0 starting block
28  4 DE$S0SZ     Segment 0 size (number of blocks). 0 if > 2 segments
32  4 DE$SG1      Segment 1 starting block (if 2 segments or less)
36  4 DE$S1SZ     Segment 1 size
40  0 DE$LEN      Directory entry length

 4.4.2.1 DE$NAME and DE$SUFF are compared as they are to the IO$NAME
by DIRSR$ and are written from IO$NAME to DE$NAME when creating a
new entry. An entry having its first byte 0 or with bit 7 set is
considered an empty entry. The file name processing calls map all
alphabetical characters to upper case before writing to de IOCB
standard name area.

 4.4.2.2 DE$TYPE has the following format:

 MSB:

 Bit   Name        

 7   FT$DELP     Delete protected
 6   FT$WRP      Write protected
 5   FT$SYS      System file (not shown by DIR unless ordered to)
 4   FT$USR      User defined (for future use by application programmers)
 Bits 0 to 3 are reserved for later versions.

 LSB:

 Bit   Name
 7   reserved
 6   reserved
 5   reserved
 4   reserved
 3 \
 2  | - file type (see dpsequ.txt)
 1  |
 0 /

 The reserved bits are intended for various access restrictions being
implemented on later versions.
 
 4.4.2.3 DE$SG0 - DE$S1SZ. These 4 long word locations define how the file
is to be found. If the file is not scattered in more than 2 pieces,
uhen its first segment starting PBN (Physical Block Number) is found
in DE$SG0. The block just before the first block (i.e. the number from
DE$SG0 minus 1) is also always allocated to the file; in the case of the
file being fragmented in more than 2 pieces, this block is used as
the RIB (Retrieve Information Block). In the case of 1 or 2 segments,
DE$SG0 and DE$S0SZ contain the beginning and size (number of contigouous
blocks) of segment 0 and DE$SG1 and DE$S1SZ contain the same data about
segment 1. In the RIB case, the RIB block contains a sequence of long
word pairs of the same kind as DE$SG0 and DE$S0SZ, being zero terminated.
(Termination is not necessary in DPS 1.1 - file size is always known from
IO$EOF).


 4.4.3 CAT format

 The device CAT (Cluster Allocation Table) follows the common DPS CAT
format (used also for the MCAT - Memory CAT). The clusters available for
allocation are described by a word aligned bitmap with the most significant 
bit of the first word corresponding to the cluster with the lowest address.
The bitmap is prefixed by a header of the following format:

Offset (bytes, decimal)
| 
| Length (bytes)
|   |
|   |
0   1     Bit 7 used as a lock flag for CAT modification, bit 6 - change flag,
1   1     reserved
2   2     Bitmap size (number of WORDS, does not include header & terminator)
4   4     Cluster size (number of blocks per bit)
8  ----- bitmap data

 The bitmap is terminated by a word containing $FFFF.



 5. The PSCT module

 In order to spawn a task under DPS, a program module (and other data) must
be specified. A program module (also called a PSCT module) is a contiguous
block of memory, containing (generally) program data, which corresponds
to one of the system maintained list of PSCT modules. A module, once
loaded into system memory, will be kept there as long as there is at least
one task running with this module being its spawn time PSCT, or until
there is at least one library call from any task using this module (the
latter assumes that the module supports library calls). Modules are loaded
from an I/O nexus, which should be a registered one.
 

 5.1 PSCT file format.

 A PSCT file, which can be loaded and executed as a PSCT module, has the
format described below. The same description applies to non-file mode
I/O, except that the PM$DIR will not contain a valid directory (which
can be seen from IO$DTT of the IOCB pointed to by PM$FILE).

 The PSCT header is transformed into an internal PSCT module header
(not stuck to the memory block it describes; DPS maintains/allocates the
list of PCT module descriptors).
 In the following paragraph, the entry function description applies to
the fields in the PSCT type file header, while the one in the square
brackets applies to the PSCT module descriptor created by DPS as a
result of the PSCT file having been successfully loaded.

Offset (bytes, decimal)
| 
| Length (bytes)
|   |
|   |  Name        Function
|   |   |           |
|   |   |           |
 0  1 PM$FLAG0   Flags - see 5.1.1 PM$FLAG0 - PM$FLAG3
 1  1 PM$FLAG1
 2  1 PM$FLAG2
 3  1 PM$FLAG3
 4  2 PM$USRS    Must be 0 [Number of tasks interested in this module]
 6  4 PM$BASE    0 or absolute load address if P0$ABSP in PM$FLAG0 1
                 [ Memory base address ]
10  4 PM$END     Module size [Address after module's end address (end+1)]
14  4 PM$EXEC    Offset to execution address [ Module execution address ]
18  4 PM$DSCT    Number of bytes necessary to allocate as user DSCT
22  2 PM$SR      Spawn time SR (processor Status Register)
24  4 PM$DIR     Not used [ IOCB address of directory from where loaded ]
28  4 PM$FILE    Not used [ IOCB address via which load was done ]
32  4 PM$DEV     Not used [ Device descriptor address (from which loaded) ]
36  2 PM$LUN     Not used [ Load device LUN ]
38 12 PM$NAME    [ File name (of file from PM$FILE) ]
50  4 PM$IDSZ    Initialized DSCT size (bytes)
54  4 reserved
58  0 PM$LEN      -- Module data starts at the next block beginning --

 5.1.1 PM$FLAG0 - PM$FLAG3 are module related flags with the following
meaning:

 PM$FLAG0:

 Bit   Name        

 7  P0$RSV        Not used [ Descriptor reserved ]
 6  P0$ABSP       Absolute PSCT address;
                  must be loaded at address from PM$BASE
 5  P0$ABSD       Absolute DSCT address - DSCT must be at the address found
                  in PM$DSCT, size passed (to SPAWN$) separately
 4  P0$LCK        Not used [ header locked for modification ]
 3  P0$WIN        Will use a window (not used by DPS 1.1)
 2  P0$NWI        Requires a new window (not used by DPS 1.1)
 1  P0$WPS        Supports external call offsets
 0  P0$IDSC       Initialized DSCT starts at PM$LEN, PSCT
                  at (PM$LEN+(PM$IDSZ)+$1ff)!.$FFFFFE00 (!. = & )
                  [ Initialized DSCT to module exists ]

 PM$FLAG0:

 Bit   Name        

 7  P1$BGD        Default task start is in background
 6  P1$NREE       Module code is non-reentrant
 5  P1$LIB        Module contains library functions 

 The remaining bits from all the flag bytes are reserved and must be 0.

 5.1.2 PM$USRS - in the system module descriptor only - number of tasks
depending on this module being present in memory. Incremented each time
a task is spawned with this module as task's PSCT and each library call
to this module, decremented each return from a library call and each
associated task kill; if found 0 after decrement or, upon killing,
if the PM$FILE is registered and no other task remains checked into
the module's file (meaning no task uses it), the module is removed
from memory.

 5.1.3 PM$BASE - in the file header, 0 or, if P0$ABSP=1, absolute load
address. In the module descriptor, PSCT data base address.

 5.1.4 PM$END - in the file header, PSCT (only; initialized DSCT not
included) size (bytes). In the module descriptor, PSCT end address +1, i.e.
start address of the memory cluster immediately following last PSCT
memory cluster.

 5.1.5 PM$EXEC - in the file header, offset from module beg. (the location
corresponding to PM$BEG) to execution entry point (location given control
to by SPAWN$). In the module descriptor, absolute execution addess.

 5.1.6 PM$DSCT - number of bytes to allocate (by SPAWN$) if no alternate
value passed as task's user DSCT. Includes the size of the initialized DSCT
(from PM$IDSC).

 5.1.7 PM$SR - value to set the processor SR to on spawn time. Applicable
to 68K processor types; typically 0. If $2000, the task will be initially
gien control to in supervisor mode (this must be the case if no user
DSCT is not allocated).

 5.1.8 PM$DIR - IOCB of directory where file was loaded from. Will be
preserved registered & open as long as the module exists in memory.

 5.1.9 PM$FILE - IOCB of file which was loaded. Preserved registered and
open as long as the module exists in memory.

 5.1.10 PM$DEV - DD of of file where the file was loaded from. Maintained
by DPS 1.1, though it can be found also from IO$DEV in PM$FILE (PM$DIR
may be invalid if PM$FILE is in non-file mode).

 5.1.11 PM$NAME - Module name. If IOCB from PM$FILE is in file mode,
this name duplicates the file name. If in non-file mode, header is
not altered.

 5.1.12 PM$IDSC - Initialized DSCT size. If P0$IDSC=1, this specifies
the number of bytes to read from the file starting from $200 at the
end of the allocated user DSCT before giving control to the task. The
SPAWN$ does this automatically; the spawned task stack pointer is placed
just below this section.


 5.2. Internal PSCT module defined offsets
 
 Certain offsets within the PSCT module are defined and used by DPS.


 5.2.1 Library PSCT modules.

 A PSCT module with the P1$LIB from PM$FLAG1=1 must support library
calls. In order to do that, the code at the address from the module
descriptor's PM$BASE must start with a list of variables (see DPS
variables). At least 1, possibly linking valid variable entry must
be there. Non-linking (function specifying) variables contain at
VA$ENT the offset to the function code.


 5.2.2 Standard external call entry points.

 If P0$WPS in PM$FLAG0 is 1, the following locations from the PSCT module
are used by DPS for the following purposes:

Offset (bytes, decimal, from module beg. (found in PM$BASE)
| 
|  Length (bytes)
|    |
|    |  Name        Function
|    |   |           |
|    |   |           |
 64  4 WM$CKSG    Offset to check for signal routine
 68  4 WM$GSIG    Offset to get signal routine
 72  4 WM$ACKS    Offset to acknowledge signal routine
 76  4 WM$REJS    Offset to reject signal routine
 80  4 WM$CLCK    Reserved
 84  4 WM$SIG     Offset to put signal entry
 88  8 WM$TOUT    Time for signalling task to wait for response
 96  8 WM$TMAX    Upper limit for WM$TOUT of other tasks when signalling them
104 60 reserved
164 -------- Code can start here ...

 All offsets above are from the module beginning to the address to call
as a subroutine when using the apropriate offset.
Refer to SIGN$, SIGNTO$, GETSIG$, CHKSIG$, ACKSIG$ and REJSIG$ for
details.
 The time limits are in seconds, fixed point between the two long 
words, unsigned.


 5.2.3 Object type descriptor files

 An object descriptor file is loaded when an object of a type corresponding
to the file name (the file name consists of the first 8 alphanumeric
characters of the object type name) is accessed via the DO$ or QACT$ calls
and the object is unknown at this point. An object file may contain
more than one type descriptor; in this case, however, only one of the 
contained types will be found after the object name.
 An object descriptor has the following format:

Offset (bytes, decimal)
| 
|  Length (bytes)
|    |
|    |  Name        Function
|    |   |           |
|    |   |           |
 0   1 O$FLAG0    Flags
 1   1 O$FLAG1    reserved
 2   1 O$FLAG2    reserved
 3   1 O$FLAG3    reserved
 4   4 O$NEXT     Offset to next from the list of object descriptors
 8   4 O$TYPE     Object type
24   4 O$CLASS    \                 [ Offset to parent object descriptor ] 
28   4 O$LREF      | Parent type    [ Last moment of reference ]
32   4 O$RNUM      |                [ number of references ]
36   4 O$BIRTH    /                 [ Moment of installation ]
40 --- O$ACT      Action location table begins here

 Function descriptions in square brackets apply to the object descriptor
as it is already installed in the system memory; lines without square
brackets have the same function in the file and in memory.
 All offsets are from the descriptor beginning (O$FLAG0).

 5.2.3.1  O$FLAG0 - O$FLAG3 are descriptor related flags. Only part of
O$FLAG0 is used by DPS 1.1; the remaining are reserved and must be 0.
 The following are defined:

 Bit   Name        

 7  O0$RSV        Reserved flag (must be 0 in file)
 6  O0$VAL        Valid flag (must be 1 in file)
 5  O0$NOA        No private actions (search directly parent)
 4  O0$LOCK       Descriptor locked (for modification)


 5.2.3.2  O$NEXT - offset to next descriptor. In the system memory, this
is how the next descriptor to check for type match. A daemon task, which
periodically checks how object descriptors are utilized, may exchange
these links in favour of those more frequently used (by placing them
closer to the list beginning). The last descriptor on the list points
to the first one ("something"), and the latter is never moved. (Such a
daemon task is not automatically started with DPS 1.1 and its functionality
is not subject of this specification).
 In the object descriptor file, if there is a single object descriptor
in this file, this field must be 0. If there are more than one descriptors
in the same file, the first (in the file) must point to some other and
so on until all descriptors contained in the file are linked, the
terminating one being 0. Upon installation, the whole chain (possibly a
single descriptor) is inserted into the linked list as it is.
last position.


 5.2.3.3  O$TYPE - object type. This is the value which is compared to the
object's XO$TYPE when searching the object descriptor. Though compare is
done by just comparing 4 long words, and any kind of data is allowed,
the descriptors written so far consist only of alphanumeric characters
(lower case only), hyphen (-, $2D) and underscore (_, $5F). If the type
name is shorter than 16 characters, it is filled with spaces ($20).


 5.2.3.4  O$CLASS to O$BIRTH - in the file, this 16 bytes contain
the parent object type in the same format as at O$TYPE. It is used
by DPS upon object installation to locate the object descriptor of
the parent object; if not found, DPS attempts to install it recorsively.
Once the parent descriptor is found, O$TYPE is overwritten by the
offset to the parent object descriptor; the moment of installation
(system slice, just from SY$TIME) is written to O$BIRTH.
 O$LREF is updated with the current moment every time the descriptor is 
accessed via the DO$ and QACT$ calls, O$RNUM is incremented every 
DO$ or QACT$ reference, thus, along with O$BIRTH maintaining reference 
frequency information.


 5.2.3.5 O$ACT - from here starts the action location table. It consists
of variables in the common DPS variable format; the field may contain
empty (zero-filled) entries for subsequent expansions, although variable
segments can also be inserted using the linking capability of the
variable field format.
 Here is a description of the variable format (including this particular
purpose specific details):

Offset (bytes, decimal)
| 
|  Length (bytes)
|    |
|    |  Name        Function
|    |   |           |
|    |   |           |
 0   8 VA$NAME     Variable name, 8 alphanumeric lower case characters,
 8   4 VA$ENT      Offset to action, calculated from VA$NAME,
12   1 VA$FLAG     Common variable flag bits,
13   1 reserved
14   1 VA$USFL     User defined flags (not used by our code), 
15   1 VA$FLAG3    Action code access related flags.
16 ----- VA$LEN   


 The following bits from VA$FLAG3 are used as action routine search
modifiers:

 Bit   Name        

 1  AC$DIR        Direct addressing - VA$ENT contains code absolute address,
 2  AC$OFS        Relative - VA$ENT contains offset to code from VA$NAME,
 3  AC$NAME       Named library function. VA$ENT contains offset from
                  VA$ENT to a text string, specifying the file & function
                  name, which are passed to PCALL$.













 


 6. System calls

 There are 2 general types of system calls: those which execute
at user level (wcall, acall) and during whiches execution the scheduler
can interrupt the task in order to give control to another, and those
which execute at supervisor level (scall), during which period a task
will not be forced out (but still may exit for arbitration at its own
will - a device driver, for example, will exit (executing a xtask$) 
while waiting for some event or for any reason).
 The following 68K processor traps are associated with the calls:

 trap #14 - SCALL functions (run at supervisor level),
 trapCC -   WCALL functions (run at user level),
 trap #11 - ACALL functions (run at user level).

 In addition, traps #10 and 12 are used for return from library calls
and wcall/acall functions, respectively.

 The WCALL and ACALL are identic (execute the same code for the same
function index); the difference between them is that the WCALL trap
handler replaces the caller's A3 with the pointer to the task window
descriptor (taken from the task descriptor), while the ACALL handler leaves
A3 unchanged. It is up to the calling program to make sure that it
passes an apropriate window descriptor address to those WCALL/ACALL
functions, which require a valid descriptor.

 In order to execute a system call, the program must execute a TRAP
instruction, followed by a word (16 bits) designating the function
code (in the case of the TRAPCC instruction (WCALL), this is part of the
opcode. The trap handler increments the return  PC to skip the call index,
whenever necessary.

 System calls, which return status (virtually all), return it in D0
in conjunction with the carry bit in the processor CCR (Condition
Code Register). If the carry upon return is clear, no error has occured
and D0 is impredictable unless otherwise stated in the decription of
this particular call; if the carry bit is set, D0 contains a valid
return status.

 6.1. System calls summary

 6.1.2. Supervisor level system calls (SCALL functions)

 6.1.2.1. Memory related functions

 allcm$: allocate memory (D2=requested length)
 allcma$: allocate mem. without swapping declared blocks
 allfx$: allocate at fixed address
 allfxt$: tolerant allocate at fixed address
 allmr$: recorded memory allocate
 all3pm$: reg.allocate memory to third party
 dallm$: deallocate memory
 dallmt$: tolerant memory deallocate
 keepmb$: declare memory block for swapping (a1=base,d2=size, cl. 
 rmbl$: retrieve mem. block (a2:d1)
 fchmm$: release a mem. block (unknown which)
 delmb$: delete memory block (a2)
 lckmb$: lock mem. block (a2)
 unlmb$: unlock mem. block (but leave entry alive)
 clln$: get memory cluster size (number of bytes)

 6.1.2.2. I/O related functions

 path$: process path (a5)
 fpath$: find path (no destination area written to)
 fetch$: gain access to an I/O nexus in registered mode
 xopen$: fetch but with a4-> 12 char. name taken unchanged
 leave$: leave registered nexus (close if last task to leave it)
 leav1$: leave file, but keep directory chain registered
 rd$: random file read (any size from any offset)
 wr$: random file write (any size at any offset)
 sfpos$: set file pos. (d3,d1,a1 - a3->iocb)
 sfposr$: set file pos. (fill the whole buffer)
 gfpos$: get current file position
 get1$: get 1 character from file (a3=iocb)
 put1$: put 1 character to file
 outch$: output a character to stdo
 inch$: input a character from stdi
 resrv$: reserve an iocb to a device
 open$: open an I/O nexus
 pdata$: output data string
 crlf$: cr,lf to stdo
 spac$: space to stdo
 ckbrk$: check for break/hold
 ckbkn$: check for break (no hold)
 out8h$: output d0 as 8 hex to stdo
 out8hs$: output d0 as hex,space
 out4h$: output d0.w as 4 hex to stdo
 out4hs$: same as out4h$, but followed by a space
 OUT2H$: output d0.b as 2 hex to stdo
 OUT2HS$: same as out2h$, but followed by a space
 OUT1H$: output d0 bits 0-3 as a hex digit to stdo
 OUT1HS$: same as out1h$, but followed by a space
 pfnam$: process file name
 afnam$: analyze file name
 attch$: attach a device descriptor
 echo$: echo a character
 get$: get data from file into io$bbs to io$bb
 put$: put data to file io$bbs to io$bbi
 lock$: lock IOCB
 close$: close an I/O nexus
 unlck$: unlock IOCB
 kill$: kill a task
 chk$: check if data from I/O nexus available for input
 look$: check if data from stdi available for input
 fload$: load a program module from file
 put1h$: put d0 bits 0-3 as hex to iocb (a3)
 put2h$: put d0.b as hex to iocb (a3)
 put4h$: put d0.w as hex to iocb (a3)
 put8h$: put d0.l as hex to iocb (a3)
 put1hs$: put d0 bits 0-3 as hex,followed by a space, to iocb (a3)
 put2hs$: put d0.b as hex,followed by a space, to iocb (a3)
 put4hs$: put d0.w as hex,followed by a space, to iocb (a3)
 put8hs$: put d0.l as hex,followed by a space, to iocb (a3)
 pcrlf$: output cr,lf (a3 -> iocb)
 pspac$: output a space ( a3 -> iocb)
 pdec1$: put d0 as decimal (no leading nulls)
 pdec2$: put d0 as decimal,no trailing nulls
 odec1$: putdc1 via std out
 odec2$: putdc2 via std out
 getln$: get line from I/O nexus (dialogue mode)
 keyin$: get line from stdi
 nderr$: display error message
 ddld$: load device driver
 reles$: release an i/o nexus
 put1l$: lock and put 1/unlock
 get1l$: lock and get 1/unlock
 unlckr$: unlock once and release if unlocked
 unlckp$: unlock once and release
 locku$: lock once only if unlocked
 read$: read from file (d3=first lbn to read)
 ckin$: check in reg.list for nexus access
 ckrg$: check if nexus with a3->iocb registered
 cka3r$: check if a3 is a valid registration addr.
 write$: write to reg. nexus (d3=first lbn to wr.)
 ckdir$: check directory iocb
 unlk$: unlock (as many times as it takes) iocb
 unlr$: unlock (use unlk$) and release device
 ptid$: output task id (module name and no.) to stdo
 ptnumb$: output task no. to stdo
 pmnam$: output task's module name to stdo
 rdnxt$: read from next lbn (reg. nexus)
 wrnxt$: append to reg. nexus
 fdev$: find device descriptor
 prep$: prepare name with * or ? into std area
 fname$: process file name including * and ?
 getb$: get (like get,but fills until io$bbe)
 putb$: put (like put,but writes the whole buffer
 pdec$: put decimal (right tabulated)
 phexr$: put hex (right tabulated)
 phex$: put hex (no leading zeroes)
 odec$: output decimal (right tabulated)
 ohexr$: output hex (right tabulated)
 ohex$: output hex (no leading zeroes)
 swapr$: recorded vector swap
 dirsr$: directory search
 ch3p$: check third party task in for I/O nexus access
 ptpth$: output path string to I/O nexus (a3)
 pass$: pass locked iocb (a3) to task descriptor (a0)
 srchd$: search device name (d1,z bit)
 ckmea5$: check current task for access to file (a5)
 outfn$: output file name (a1) (no spaces padded)
 outfnt$: output file name (a1) with pad spaces
 ptfnam$: put file name
 stdi$: get stdi (a3)
 stdo$: get stdo (a3)
 pmsg$: output message (a0 -> msg with length hdr.w)
 omsg$: pmsg$ to stdo
 setsti$: set stdi to A3
 setsto$: set stdo to A3
 ptid1$: output task id (id in d1)
 derr$: display third party's error msg
 bllen$: get device block length (a3 -> open iocb)
 serr$: set std error output iocb
 gerr$: get std error output iocb
 otid1$: output to IOCB (a3) task id (in d1)
 otnumb$: output task no. to (a3)
 omnam$: output task's module name to (a3)
 set$: set device's parameter
 pget$: get device's parameter
 putdt$: pdata,but a3 -> iocb to put to
 findd$: find device descriptor address (d1=name,a4->dd)
 setcd$: set task's current directory to (a5)
 chkd$: check iocb's **device** if accessible
 ecrlf$: CR,LF to stderr
 eutch$: outch to stderr
 putlin$: output line (like pdata,but cr terminated)
 outlin$: line to stdo
 fsize$: get file size (in d2.l;a3 ->iocb)
 chtkin$: check task in (d1=id) for access to I/O nexus

 6.1.2.3. Execution related functions

 spawnn$: spawn without starting
 start$: start a task (already spawned via spawnn)
 exit$: exit task (forever)
 fcall$: call program library file function (search directory in A5)
 pcall$: call function (start from task's spawn dir.)
 xload$: load a PSCT module from file (a3) (iocb open)
 load$: load PSCT module
 xtask$: exit task for re-scheduling
 xtwt$: exit and wait specified time
 xtws$: exit and wait a number of slices
 xtwm$: exit and wait for the moment in d1
 spawn$: spawn a task (start immediately)
 killp$: kill particular (0 does not kill current,but 0)
 eword$: set task error status word (d0=status)
 curd$: get current directory (a5)
 win$: get task's window descriptor (a3)
 dsct$: get task's user dsct (a1 - beg.,a2 - end+1)
 comm$: get common dsct address in a1
 pty$: get priority (d1 - base,d2 - current)
 flagm$: get flags (d1.l) and module descriptor (a2)
 phirc$: put a task history record
 rdy$: set t0$rdy (see sign$, signto$ wcalls)
 scomm$: set common dsct
 fpuon$: enable fpu save/restore upon task switch
 fpuoff$: disable fpu save/restore
 gettd$: return pointer to task descriptor in A0
 exec$: spawn and execute (wait for termination)
 bgnd$: switch task to background mode
 updlk$: update vector link data (at (vbr+1024+4),v#*8)
 spawnd$: get spawn directory in a5
 gtime$: get date & time
 tspmm$: get task (d2) spawn moment (in d1)
 gettd2$: point (a0) to td with id in d2.w
 myid$: get own id & spawn moment in d1:d2
 gspmd2$: get spawn moment (in d1) of task with id=d2
 geword$: get own error status word (in d1)
 setto$: set timeout value (d1:d2; ret. d2=slices)
 getto$: get timeout value (d1:d2)
 seword$: set error stat. word to d1.w
 stflag$: set flag # d2.w bit in own task descriptor

 6.1.2.4. Miscellaneous functions

 getvar$: search for variable (a0,a1)
 globvar$: search for global variable
 setvar$: set variable to value (a2)
 setgvar$: set global variable to a value
 vsgin$: initialize segment for variable storage
 strip$: skip string leading spaces (a0)
 hexd$: convert ascii to hex (default ascii hex.)
 decd$: convert ascii to hex (default ascii dec.
 bind$: convert ascii to hex (default ascii bin.)
 asbcd$: ascii string to bcd
 hxdec$: convert hex to bcd
 dechx$: bcd into hex
 swap$: swap a vector
 vrest$: restore vector
 usqv$: get next free user IRQ vector
 ckown$: check if owning memory range
 nxnsp$: find next non-space character
 pld8h$: put d0 as 8 hex at (a2)+
 pld4h$: put d0 as 4 hex at (a2)+
 pld2h$: put d0 as 2 hex at (a2)+
 pld0h$: put d0 as 1 hex at (a2)+
 setwd$: set window descriptor to a5
 pltid1$: place task id (name and no.) at (a2)+
 pldec1$: place d0 as decimal at (a2)+ (no ld.nulls)
 pldc1s$: place d0.l as signed decimal text @ (a2)+
 ckiol$: check if iocb locked & owned
 plhex$: place d0 at (a2)+ as hex (no leading 0s)
 lck02$: lock bit #d2 at (a0), d3:d4=tout



 6.1.3. User level system calls (WCALL and ACALL functions)

 neww$: create a new window
 scurw$: set current task window descr.
 clrhom$: clear screen,go home
 home$: text cursor home
 stlim$: set text window limits
 sglim$: set graphic window limits
 glimqtx$: set graphic limits equal to text limits
 settxta$: set window attributes
 setgrp$: set graphic page to pattern (d6)
 remcurs$: remove cursor
 remcurl$: lock & remove cursor
 dispd0$: display d0.b (8 bit)
 crcmd$: cursor at left display column
 currght$: cursor right
 cursup$: cursor up
 curleft$: cursor left
 lf$: cursor down (line feed)
 delch$: delete character under cursor
 delchat$: delete character with attributes
 insspcc$: insert space
 insspca$: insert space with attributes
 insline$: insert line
 delline$: delete line
 clreol$: clear to eol
 clreola$: clear to eol with attributes
 clreop$: clear to eop
 clreopa$: to eop with attributes
 settop$: set top display line (d1)
 setbot$: set bottom dipslay line
 setldc$: left display column
 setrdc$: right display column
 moveol$: move cursor to eol
 moveop$: move to eop
 ldcurs$: load cursor (d1.w,d2.w)
 setsca$: set screen attributes (d0)
 setrga$: set region attributes (d0)
 absrg$: check if region valid/make absolute
 schatt$: set character attributes
 hidetxt$: hide text screen
 hidetrg$: hide text region
 showtxt$: show text screen
 showtrg$: show text region
 cgscgpg$: change window graphic page
 cgrggpg$: change region graphic page
 ssgpage$: set screen graphic page (d5)
 srgpage$: set region graphic page
 drline$: general type line draw (xs,ys;xe,ye)
 lined0$: draw line with type in d0
 wrgd$: write region data
 wrg$: write region (text and attr.)
 wrgdt$: write region text data
 wrgt$: write region text
 wrgad$: write region attribute data
 wrga$: write region attributes
 wsave$: save window
 wrest$: restore window
 wleave$: leave widow (remove and forget)
 xwseq$: execute object sequence (mouse curs. removed) (show all until 0)
 knba5$: install a knob in window
 remknb$: remove a knob
 remalk$: remove all knobs from window
 clrtrgn$: clear text region
 strgr$: set region graphics to layer's colour
 streggr$: set region graphics to colour
 wdmode$: set window drawing mode
 xwsqa4$: execute (a4 -> frt)
 stlimr$: set setxt window limits relative to current
 rmous$: remove mouse cursor
 rmouslk$: remove mouse cursor;lock it off
 unlm$: unlock mouse cursor
 xwseqn$: execute sequence (mouse cursor left alone)
 swlimg$: set text limits after graphic coords
 wglims$: get window graphic limits
 wld1d2$: write text line at d1,d2 (text coords)
 wrlims$: get window reserved limits
 putobj$: put an object into window's buffer
 sglimr$: set graphic limits equal to reserved
 setgwp$: set grphic page to layer's colour
 drkna5$: draw a knob (a5 -> func. desc.)
 wrline$: write text line at cursor pos.
 sign$: send signal to task
 rdcurs$: read cursor
 cmod$: get current drawing mode (d6)
 curgp$: set current graphic page
 dialr$: display decimally right just. no l.n.
 wrlgrc$: write text line at graphic coords
 wld1d2$: write text line at d1,d2 (text coords)
 srgtcol$: set region text colour
 chsize$: get character size
 curgpg$: get current drawing page
 getcol$: get colour (d6 layer into d6 colour) curr. frt
 preal$: convert .x into ascii string
 asreal$: convert ascii string into .x
 dialrf$: fp right aligned dial (numeric display)
 signto$: signal (with time-out)
 scac$: set character attributes to current ones
 frame$: draw frame (rectangular)
 getsc$: get scale factor
 setsc$: set scale factor
 getang$: get drawing angle
 setang$: set drawing angle
 getsig$: get signal (no acknowledge)
 acksig$: acknowledge signal
 rejsig$: reject signal
 chksig$: check if signal received
 wdn$, get window descriptor number
 skipobj$: skip 1 object (increment a5 by object's size)
 alignx$: align x (in a pair of coords,d1-d4) to a character multiple
 aligny$: align y (in a pair of coords,d1-d4)
 remall$: remove all objects from window buffer
 leavnt$: leave window (without putting to top)
 sclims$: set clip limits
 gettlm$: get text limits (relative,text coords)
 topme$: put window to top
 topmein$: put window to top,connect to input
 tcgc$: rel.text (to leftdc,) pair (d1,d2) into gr. pair (to w$wdlx)
 do$: do action over obj. (a5); a0->action name
 erastx$: erase current text window (set to space with default attributes)
 qact$: same as do$,but action name in d1 & d2
 inctyp$: incorporate object type
 ldobj$: load object(s) file ***(a2 -> iocb)***
 ptyp$: point to type descriptor by a4 (a5->obj.)
 vsrch$: search for var (a1-> vars, a0->name)
 qvsrch$: quick v-search (a1 -> vars,d1&d2=name)
 rdobj$: read object (and load) from file
 ssize$: get screen size (in d3&d4)
 nwlims$:set new window limits (d1-d4)
 remwin$: remove window from screen (uncover others),keep existing
 unfrd2$: uncover & unfreeze task #d2's current window
 srgatl$: set region attributes after 2 layers (d6 ls-ms)
 twolatt$: two layers into attributes (d6 both)
 pix$: get bits per pixel (d1)
 sig73$: signal to wd (a3),d7=signal index
 lvnol$: leave window (no autolock;must be locked)
 unfra$: unfreeze all uncovered windows
 elia2$: choose one window to connect to input
 unfranl$: unfreeze all (no lock/unlock)
 xwsnf$: show objects (xwseq,but no freeze)
 wstat$: get window status
 rmsykn$: remove system knobs of current task
 rmsyd1$: remove system knobs of task with id in d1
 frzall$: freeze all windows
 freez$: freeze window (a3)
 unfr$: unfreeze window (a3)
 qa54$: do action d1:d2 at (a5), using obj. descr. (a4)
 qa54p$: do action d1:d2 at (a5), using parent of (a4)



 6.2. Detailed system call descriptions

 6.2.1 Supervisor level system calls (SCALL functions)

 ALLCM$: allocate a contiguous block of system memory.
 Input: D2 - number of bytes to allocate.
Output:
 If no error (carry clear):
        A1 - allocated block base address,
        D1 - number of bytes actually allocated (will be a multiple
             of memory clusters, while requested via D2 may be not.
 If and error has occured and the error is E$INSFM (insufficient memory):
       A1 - largest available at the moment contiguous block beg. address,
       D1 - block's size (bytes).
 If the requested amount of memory is not available at the first attempt
and memory blocks are enabled (BLOCKS statement found in setup.syst on
boot time), memory blocks (if some) are sequentially swapped to disk
until memory can be allocated or until no more blocks can be found, in
which case an insufficient memory error occurs.

 ALLCMA$: allocate a contiguous block of memory. Same as ALLCM$, but
does not attempt to swap memory blocks to disk.

 DALLM$: deallocate a contiguous block of memory.
 Input: D2 - number of bytes to deallocate (must be a multiple of the
             cluster size.
Output: If no error, none. If the error is E$CLSZ (cluster size error),
        D1 returns the system memory cluster size.

 ALLFX$: allocate memory at a fixed address.
 Input: D2 - number of bytes to allocate,
        A1 - address to allocate starting with (must be a multiple of
        the cluster size).
Output:
 If no error (carry clear):
        A1 - allocated block base address (i.e. unchanged),
        D1 - number of bytes actually allocated (will be a multiple
             of memory clusters, while requested via D2 may be not.
 If the requested number of bytes was not available at this position,
E$INSFM (insufficient memory) is returned, and in D1 is returned the
number of available bytes starting from the requested address.


KEEPMB$: declare memory block for swapping.
 Input:  a1 - base address of block (must be cluster aligned),
         d2 - block size in bytes, cluster aligned.
Output:  a2 - block ID for future references,
         d1 - creation moment (time slice no.).
 After this call, the declared memory block may ce taken over by another
task; in order to access this memory again, the task must first retrieve
the block, using the block ID. DPS keeps a list of declared blocks
which is checked every time memory requested for allocation was not
available; blocks from this list are written to disk and deallocated
until a sufficient amount of memory is available for allocation. 


RMBL$: retrieve mem. block.
 Input:  a2 - block ID,
         d1 - declaration moment (both as returned from the keepmb$).
Output:  a1 - block memory address,
         d1 - block size (bytes). If d1=0, the DPS could not allocate
enough memory in order to retrieve it from disk; in this case (not an
error), a1 returns the ID of the file, where the memory block is
saved. It is up to the calling task to process this case.
 If the block was never removed from memory, DPS just returns its
old address and size; if it was removed, memory of the same size
is allocated (most likely at a different address than originally),
then the data is read from the file, after which the file is deleted.


DELMB$: delete memory block.
 Input: a2 - block ID.
Output: none.
 The resources, occupied by the block (memory and/or file) are released
(memory is deallocated, the file is deleted) and the entry is removed
from the list of blocks.


LCKMB$: lock memory block.
 Input: a2 - block ID.
Output: none.
 After this call, the memory block indicated by a2 will no longer be
available for state modification (removed/retrieved etc.). Generally
used internally by DPS only.


UNLMB$: unlock memory block and leave entry alive.
 Input: a2 - block ID.
Output: none.
 The memory block entry can be accessed by other tasks after this (i.e.
it can be swapped etc.).



CLLN$: get memory clister size.
 Input: none.
Output: d1.l - clister size (number of bytes).


SPAWN$: spawn a task.
  Input: A2 - PSCT module to spawn descriptor address,
        A3 - a message packet of the following format:
 Offset (bytes, decimal)
 |
 | Length (bytes) 
 |  |
 |  |  Name        Function
 |  |   |           |
 |  |   |           |
 0  4 SP$DSCT    User DSCT size (bytes) to allocate for the task. If 0,
                the value from PM$DSCT of the module descriptor (A2) is taken.
 4  4 SP$INP     New task's STDI IOCB. If 0, parent's is assigned; if 1
                (valid IOCB addresses are even), no STDI IOCB is assigned
                (left as 1 in task descriptor).                         
 8  4 SP$OUT     New task's STDO IOCB. If 0, parent's is assigned; if 1
                (valid IOCB addresses are even), no STDO IOCB is assigned
                (left as 1 in task descriptor).                         
12  4 SP$WIN    Window descriptor address. If 0, the parent's WD is taken.
16  4 SP$PRCS   Common DSCT address. If 0, taken the parent's one.
20  2 SP$PRTY   Basic Priority. if 0, taken the parent's one.
22  1 SP$ERRLV  Script abort error level.
33  1 SP$ERRMS  Script abort error mask.
24  4 SP$EIOC   New task's STDERR IOCB. If 0, set same as STDO.
28  1 SP$FLAG0  Flags ored to flag 0 (TD$FLAG0) of new task descriptor
29  1 SP$FLAG1  Flags ored to flag 1 (TD$FLAG1) of new task descriptor
30  1 SP$RFL0   Flags anded to flag 0 (TD$FLAG0) of new task descriptor
31  1 SP$RFL1   Flags anded to flag 1 (TD$FLAG1) of new task descriptor
32  4 reserved
36    SP$LEN    Length of spawn message packet.


 LOAD$: load a PSCT module into memory.

  TO LOAD A FILE AS A PSCT MODULE, USE XLOAD$,  which calls internally the
 LOAD$.
 Input: A0 - Module header address (see 5.1 PSCT file format),
        A1 - load routine address. XLOAD$ passes its own I/O nexus based
        load routine address.

 Output: If no error (carry clear), then
         A1 - module memory base address,
         A2 - module descriptor address,
         D1 - number of bytes allocated for the module (cluster aligned
              module size),
         D2 - module actual length (requested for allocation).
     If an error has occured (carry set), then D0 returns the status,
     and the contents of D1,D2,A1 and A2 are impredictable.
 

 ALLFXT$: tolerant fixed address memory allocate. Same as ALLFX$,
 (see ALLFX$), except that A1 needs not be cluster aligned. The
custer, into which A1 points, will be the first allocated.
 Input:  A1 - allocated block start address,
         D2 - number of bytes to allocate.
 Output: A1 - unchanged,
         A2 - lowest allocated address (always <= A1),
         D1 - actual number of bytes allocated (cluster aligned).

 If an error has occured, carry is returned set and D0 contains the error
index.


 XTASK$: temporary task exit. The scheduler chooses to which task
to switch; next time the calling task is given control to, the function
returns. No registers are changed.
 This function is extensively used by device drivers and other software,
which would wait for an event; it saves system time, giving immediately
control to other tasks when having nothing to do instead of staying
in a loop and waiting to be forced out at the end of the time slice.

 XTWT$: suspend task execution for a specified period of time.
 The scheduler switches to another task; after the specified time has
elapsed and the scheduler assignes a time slice to the calling task,
the function returns.
 Input: D0:D1 - the time to wait in seconds (unsigned), fixed point
between D0 and D1, D0 being at the left of the point.
 Upon return, D0 and D1 are destroyed.

 XTWS$: suspend task execution for a specified number of time slices.
 After the number of slices has expired and the scheduler gives control to
the calling task, the function returns.
 Input: D1 - number of slices not to be given control to.
 Upon return, D1 is destoryed.

 XTWM$: suspend task execution until a specified moment. After the
moment arrives and the scheduler gives control to the calling task, the
function returns.
 Input: D1 - moment to wait for (in internal system slices).
 No registers are changed.

 FETCH$: fetch an I/O nexus for registered access.
 Input:  A0 -> nexus (file) name,
         A5 -  directory file ID,
         D4.W - desired IO$DTT (both bytes) (see 4.2.3 IO$DTT),
         D5  - desired IO$TYPE if creating a new file,
         D3  - initial file size if creating a new one; see OPEN$.
Output:  A2 - I/O nexus (file) ID. Strictly, this is the
address of the IOCB used to access the I/O nexus. Notice it is returned
in A2 while it must be passed in most cases in A3 to call the I/O
functions.
         A0 - incremented after the last successfully processed
character (after the terminator, if success).
 The function does the following: after checking the directory IOCB for
validity (it must be a registered IOCB with a directory type at IO$TYPE),
the passed name is processed into an intermediate IOCB, along with
directory, device and LUN. Then, the list of nexi is checked if this
particular one is already open (present on the list); if not,
a new entry is created with the backup IOCB copied to it; subsequently,
the OPEN$ is called with the new IOCB from the list; if the OPEN$
succeeds, a flag bit corresponding to the calling task number is set,
thus indicating this task has checked in for access to this nexus.
 If an IOCB for that particular nexus is found on the list, it is
locked by the calling task, after which the passed via D4 IO$DTT
bits (except the internal use ones) are written to the IOCB's IO$DTT,
and finally the calling task is checked in.
 If the non-file mode has been requested by having DT$NONF set in
D4 (bit 15), the passed directory in A5 is not checked wether it
is a directory.
 In all cases, the PATH$ or FPATH$ prepare the A5 to be passed to the FETCH$.

 FPATH$: find the path to an I/O nexus (file).
 Input:  A0 -> text describing the path. The full format is:
   #dev\lun:dir1\dir2\dir3\file.some 
    The device name may be up to 4 characters, the LUN must be a valid
   hexadecimal number (0..$ffff; DPS 1.1 processes only 0..$f, though).
         A5 - directory file ID to start the search from.
Output:  A5 - searched directory ID,
         A2 - file name (if one found after all the directories),
         D2 and D3 - same as from PFNAM$ after having the file name
 processed; additionally, the following bits of D3 are affected:
  bit 21 - set if path search was done (0 if only a file name),
  bit 20 - set if path search attempted (\ character was found as delimiter),
  bit 19 - set if no file name (last character was a "\"),
  bit 18 - set if A5 returning a non-file mode nexus ID instead of
           a directory ID. This will happen, if  a device and LUN name
           were specified only. 
         A0 - incremented after the last successfully processed character.


 PATH$: find the path to an I/O nexus (file); process the file name
into a standard name area.
 Input:  A0 -> text describing the path. The full format is:
   #dev\lun:dir1\dir2\dir3\file.some 
    The device name may be up to 4 characters, the LUN must be a valid
   hexadecimal number (0..$ffff; DPS 1.1 processes only 0..$f, though).
         A5 - directory file ID to start the search from,
         A1 -> standard name area to write the processed name into.
Output:  A5 - searched directory ID,
         A2 - file name (if one found after all the directories),
         D2 and D3 - same as from PFNAM$ after having the file name
 processed; additionally, the following bits of D3 are affected:
  bit 21 - set if path search was done (0 if only a file name),
  bit 20 - set if path search attempted (\ character was found as delimiter),
  bit 19 - set if no file name (last character was a "\"),
  bit 18 - set if A5 returning a non-file mode nexus ID instead of
           a directory ID. This will happen, if  a device and LUN name
           were specified only. 
         A0 - incremented after the last successfully processed character.
 The standard name area is updated with the found device name, LUN and file
name.

  

[Contact us] [Home]