view docs/os9sysprog/os9sysprog.docbook @ 897:16d7698f8929

os9copy does eol translation now
author boisy
date Fri, 17 Jan 2003 20:55:49 +0000
parents d0eff7f2c418
children 10fa04d30a71
line wrap: on
line source

<?xml version="1.0" ?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<!-- $Id$ -->
<book id="os9sysprog" lang="en">
<bookinfo>
 <title>OS-9 Operating System</title>
 <subtitle>System Programmer's Manual</subtitle>
 <titleabbrev>OS-9 System Programmer's Manual</titleabbrev>

<copyright>
<year>1980</year>
<year>1982</year>
<holder>Microware Systems Corporation</holder>
</copyright>

<legalnotice>

<para>All rights reserved.</para>

<para>This manual, the OS-9 Program, and any information  contained
herein is the copyrighted property of Microware Systems Corporation.
Reproduction of this manual in part or whole by any means, electrical
or otherwise, is prohibited, except by written permission from
Microware Systems Corporation.</para>

<para>The information contained herein is believed to be accurate as of
the date of publication. However, Microware will not be liable for
any damages, including indirect or consequential, related to use of
the OS-9 Operating System or of this documentation. The information
contained herein is subject to change without notice.</para>
</legalnotice>
<revhistory>
<revision>
<revnumber>F-1</revnumber>
<date>January 1983</date>
</revision>
</revhistory>
</bookinfo>

<chapter>
<title>Introduction</title>

<para>OS-9 Level One is a versatile multiprogramming/multitasking
operating system for computers utilizing the Motorola 6809
microprocessor,. It is well-suited for a wide range of applications
on 6809 computers of almost any size or complexity.
Its main features are:</para>

<itemizedlist mark="bullet">
	<listitem><para>Comprehensive management of all system resources: memory,
	input/output and CPU time.</para></listitem>
	<listitem><para>A powerful user interface that is easy to learn and use.</para></listitem>
	<listitem><para>True multiprogramming operation.</para></listitem>
	<listitem><para>Efficient operation in typical microcomputer configuratjons.</para></listitem>
	<listitem><para>Expandable, device-independent unified I/O system.</para></listitem>
	<listitem><para>Full support for modular ROMed software.</para></listitem>
	<listitem><para>Upward and downward compatibility with OS-9 Level Two.</para></listitem>
</itemizedlist>

<para>This manual is intended to provide the information necessary to
install, maintain, expand, or write assembly-language software for
OS-9 systems. It assumes that the reader is familiar with the 6809
architecture, instruction set, and assembly language.</para>

<sect1>
<title>History And Design Philosophy</title>

<para>OS-9 Level One is one of the products of the BASIC09 Advanced 6809
Programming Language development effort undertaken by Microware and
Motorola from 1978 to 1980. During the course of the project it
became evident that a fairly sophisticated operating system would be
required to support BASIC09 and similar high-performance 6809
software.</para>

<para>OS-9's design was modeled after Bell Telephone
Laboratories' &quot;UNIX&quot; operating system, which is becoming
widely recognized as a standard for mini and micro multiprogramming
operating systems because of its versatility and relatively simple,
yet elegant structure. Even though a &quot;clone&quot; of UNIX for
the 6809 is relatively easy to implement, there are a number of
problems with this approach. UNIX was designed for fairly large-scale
minicomputers (such as large PDP-11s) that have high CPU throughput,
large fast disk storage devices and a static I/O environment. Also,
UNIX is not particularly time or disk-storage efficient, especially
when used with low-cost disk drives.</para>

<para>For these reasons, OS-9 was designed to retain the overall concept
and user interface of UNIX, but its implementation is considerably
different. OS-9's design is tailored to typical microcomputer
performance ranges and operational environments. As an example, OS-9,
unlike UNIX, does not dynamically swap running programs on and off
disk This is because floppy disks and many lower-cost Winchester-type
hard disks are simply too slow to do this efficiently. Instead, OS-9
always keeps running programs in memory and emphasizes more efficient
use of available ROM or RAM.</para>

<para>OS-9 also introduces some important new features that are intended
to make the most of the capabilities of third-generation
microprocessors, such as support of reentrant, position-independent
software that can be shared by several users simultaneously to reduce
overall memory requirements.</para>

<para>Perhaps the most innovative part of OS-9 is its &quot;memory
module&quot; management system, which provides extensive support for
modular software, particularly ROMed software. This will play an
increasingly important role in the future as a method of reducing
software costs. The &quot;memory module&quot; and LINK capabilities of OS-9
permit modules to be automatically identified, linked together,
shared, updated or repaired. Individual modules in ROM which are
defective may be repaired (without reprogramming the ROM) by placing
a &quot;fixed&quot; module, with the same name, but a higher revision number
into memory. Memory modules have many other advantages, for example,
OS-9 can allow several programs to share a common math subroutine
module. The same module could automatically be replaced with a module
containing drivers for a hardware arithmetic processor without any
change to the programs which call the module.</para>

<para>Users experienced with UNIX should have little difficulty adapting
to OS-9. Here are some of the main differences between the two
systems: 
</para>
<orderedlist  numeration="arabic">
	<listitem><para>OS-9 is written in 6809 assembly language, not C. This
	improves program size and speed characteristics.</para></listitem>
	<listitem><para>OS-9 was designed for a mixed RAM/ROM microcomputer memory
	environment and more effectively supports reentrant,
	position-independent code.</para></listitem>
	<listitem><para>OS-9 introduces the &quot;memory module&quot; concept for
	organizing object code with built-in dynamic inter-module linkage.</para></listitem>
	<listitem><para>OS-9 supports multiple file managers, which are modules that
	interface a class of devices to the file system.</para></listitem>
	<listitem><para>&quot;Fork&quot; and &quot;Execute&quot; calls are faster and
	more memory efficient than the UNIX equivalents.</para></listitem>
</orderedlist>
</sect1>

<sect1>
<title>System Hardware Requirements</title>

<para>The OS-9 Operating system consists of building blocks called
memory modules, which are automatically located and linked together
when the system starts up. This makes it extremely easy to
reconfigure the system. For example, reconfiguring the system to
handle additional devices is simply a matter of placing the
corresponding modules into memory. Because OS-9 is so flexible, the
minimum hardware requirements are difficult to define. A bare-bones
LEVEL I system requires 4K of ROM and 2K of RAM, which may be
expanded to 56K RAM.</para>

<para>Shown below are the requirements for a typical OS-9 software
development system. Actual hardware requirements may vary depending
upon the particular application.</para>
<itemizedlist mark="bullet">
	<listitem><para>6809 MPU 
	</para></listitem>
	<listitem><para>24K Bytes RAM Memory for Assembly Language Development. 40K
	Bytes RAM Memory for High Level Languages such as BASIC09 (RAM Must
	Be Contiguous From Address Zero Upward) 
	</para></listitem>
	<listitem><para>4K Bytes of ROM: 2K must be addressed at $F800 - $FFFF, the
	other 2K is position-independent and self-locating. Some disk
	systems may require three 2K ROMs.</para></listitem>
	<listitem><para>Console terminal and interface using serial, parallel, or
	memory mapped video.</para></listitem>
	<listitem><para>Optional printer using serial or parallel interface.</para></listitem>
	<listitem><para>Optional real-time clock hardware.</para></listitem>
</itemizedlist>

<para>I/O device controller addresses can be located anywhere in the
memory space, however it is good practice to place them as high as
possible to maximize RAM expansion capability. Standard
Microware-supplied OS-9 packages for computers made by popular
manufacturers usually conform to the system's customary memory map.</para>
</sect1>
</chapter>


<chapter>
<title>Basic System Organization</title>

<para>OS-9 is composed of a group of modules, each of which provides
specific functions. When OS-9 is configured for a specific system
various modules are selected to provide a given level of
functionality. For example, a small control computer without a disk
does not need the disk-related OS-9 modules. Most examples in this
manual describe a fully-configured OS-9 system.</para>

<figure>
<title>OS-9 COMPONENT MODULE ORGANIZATION</title>
<screen>
                 +-----------------------+
+----------+     !                       !     +----------+
!          !     !                       !     !          !
!   INIT   ! - - !     OS-9 KERNEL       ! - - !  Clock   !
!          !     !        (ROM)          !     !          !
+----------+     !                       !     +----------+
                 +-----------------------+
                             !
                             !
                 +-----------------------+
                 !                       !
                 ! Input/Output Manager  !
                 !       (IOMAN)         !
                 !                       !
                 +-----------------------+
                    !                 !
                    !                 !
   +--------------------+       +--------------------+
   !                    !       !                    !
   ! Disk File Manager  !       ! Char. File Manager !    More
   !      (RBFMAN)      !       !      (SCFMAN)      ! -&gt; opt.
   !                    !       !                    !
   +--------------------+       +--------------------+
        !          !                !           !
        !          !                !           !
   +--------+  +--------+       +--------+  +--------+
   !        !  !        !       !        !  !        !
   !  Disk  !  !  Disk  !       !  ACIA  !  !  PIA   !    More
   ! Driver !  ! Driver !       ! Driver !  ! Driver ! -&gt; opt.
   !        !  !        !       !        !  !        !
   +--------+  +--------+       +--------+  +--------+
     !     !     !     !          !     !     !     !
     !     !     !     !          !     !     !     !
   +---+ +---+  +---+ +---+     +---+ +---+  +---+ +---+
   !D0 ! !D1 !  !D2 ! !D3 !     !T1 ! !T2 !  !P1 ! !P2 !-&gt; More
   +---+ +---+  +---+ +---+     +---+ +---+  +---+ +---+   opt.
    RBF Device Descriptors        SCF Device Descriptors
</screen>
</figure>


<para>Notice that the diagram on the previous page indicates a
multilevel organization.</para>

<para>The first level is the KERNEL and the CLOCK MODULE. The kernel
provide basic system services such as multitasking, memory
management, and links all other system modules. The CLOCK module is a
software handler for the specific real-time-clock hardware. INIT is
an initialization table used by the kernel during system startup. It
specifies initial table sizes, initial system device names, etc.</para>

<para>The second level is the Input/Output Manager. It provides common
processing all I/O operations. It is required if any OS-supported I/O
is to be performed.</para>

<para>The third level is the File Manager level. File managers perform
I/O request processing for similar classes of I/O devices. The Random
Block File Manager (RBFMAN) processes all disk-type device
functions, and the Sequential Character File Manager (SCFMAN) handles
all non-mass storage devices that basically operate a character at a
time, such as terminals and printers. The user can add additional
File Managers to handle classes of devices not covered by SCFMAN or
RBFMAN.</para>

<para>The fourth level is the Device Driver Level. Device drivers handle
basic physical I/O functions for specific I/O controller hardware.
Standard OS-9 systems are typically supplied with a disk driver, a
ACIA driver for terminals and serial printers, and a PIA driver for
parallel printers. Many users add customized drivers of their own
design or purchased from a hardware vendor.</para>

<para>The fifth level is the Device Descriptor Level. These modules are
small tables that are associate specific I/O ports with their logical
names, and the port's device driver and file manager. They also
contain the physical address of the port and initialization data. By
use of device descriptors, only one copy of each driver is required
for each specific type of I/O controller regardless of how many
controllers the system uses.</para>

<para>One important component not shown is the Shell., which is the
command interpreter. It is technically a program and not part of the
operating system itself, and is described fully in the OS-9 Users
Manual.</para>

<para>Even though all modules can be resident in ROM, generally only the
KERNEL and INIT modules are ROMed in disk-based systems. All other
modules are loaded into RAM during system startup by a disk bootstrap
module (not shown on diagram) which is also resident in ROM.</para>
</chapter>


<chapter>
<title>Basic Functions of the Kernel</title>

<para>The nucleus of OS-9 is the &quot;kernel&quot;, which serves as the
system administrator, supervisor, and resource manager. It is about
3K bytes long and normally resides in two 2K byte ROMs: &quot;P1&quot;
residing at addresses $F800 - $FFFF, and &quot;P2&quot;, which is
position-independent. P2 only occupies about half (1K) of the ROM,
the other space in the ROM is reserved for the disk bootstrap module.</para>

<para>The kernel's main functions are:</para>
<orderedlist  numeration="arabic">
        <listitem><para>System initialization after restart.</para></listitem>
	<listitem><para>Service request processing.</para></listitem>
	<listitem><para>Memory management.</para></listitem>
	<listitem><para>MPU management (multiprogramming).</para></listitem>
	<listitem><para>Basic interrupt processing.</para></listitem>
</orderedlist>

<para>Notice that input/output functions were not included in the list
above; this is because the kernel does not directly process them. The
kernel passes I/O service requests directly to another the
Input/Output Manager (IOMAN) module for processing.</para>

<para>After a hardware reset, the kernel will initialize the system
which involves: locating ROMs in memory, determining the amount of
RAM available, loading any required modules not already in ROM from
the bootstrap device, and running the system startup task (&quot;SYSGO&quot;).
The INIT module is a table used during startup to specify initial
table sizes and system device names.</para>

<sect1>
<title>Kernel Service Request Processing</title>

<para>Service requests (system calls) are used to communicate between
OS-9 and assembly-language-level programs for such things as
allocating memory, creating new processes, etc. System calls use the
SWI2 instruction followed by a constant byte representing the code.
Parameters for system calls are usually passed in MPU registers.
In addition to I/O and memory management functions, there are
other service request functions including interprocess control and
timekeeping.</para>

<para>A system-wide assembly languaqe equate file called &quot;OS9Defs&quot; defines
symbolic names for all service requests. This file is included when
assembling hand-written or compiler-generated code. The OS-9
Assembler has a built-in macro to generate system calls, for example:</para>

<informalexample>
<programlisting>
OS9 I$READ
</programlisting>
</informalexample>

<para>is recongnized and assembled as the equivalent to:</para>
<informalexample>
<programlisting>
SWI2
FCB  I$READ
</programlisting>
</informalexample>

<para>Service requests are divided into two categories:</para>

<para>I/O REQUESTS perform various input/output functions. Requests of
this type are passed by the kernel to IOMAN for processing. The
symbolic names for this category have a &quot;I$&quot; prefix, for example,
the &quot;read&quot; service request is called &quot;I$READ&quot;.</para>

<para>FUNCTION REQUESTS perform memory management, multiprogramming, and
miscellaneous functions. Most are processed by the kernel. The
symbolic names for this category begins with &quot;F$&quot;.
</para>
</sect1>

<sect1>
<title>Kernel Memory Management Functions</title>

<para>Memory management is an important operating system function. OS-9
manages both the physical assignment of memory to programs <emphasis>and</emphasis>
the logical contents of memory, by using entities called &quot;memory
modules&quot;. All programs are loaded in memory module format,
allowing OS-9 to maintain a directory which contains the name,
address, and other related information about each module in memory.
These structures are the foundation of OS-9's modular software
environment. Some of its advantages are: automatic run-time &quot;linking&quot;
of programs to libraries of utility modules; automatic &quot;sharing&quot;
of reentrant programs; replacement of small sections of large
programs for update or correction (even when in ROM); etc.</para>
</sect1>

<sect1>
<title>Memory Utilization</title>

<para>All usable RAM memory must be contiguous from address 0 upward.
During the OS-9 start-up sequence the upper bound of RAM is detemined
by an automatic search, or from the configuration module. Some RAM is
reserved by OS-9 for its own data structures at the top and bottom of
memory. The exact amount depends on the sizes of system tables that
are specified in the configuration module.</para>

<para>All other RAM memory is pooled into a &quot;free memory&quot;
space. Memory space is dynamically taken from and returned to this
pool as it is allocated or deallocated for various purposes. The
basic unit of memory allocation is the 256-byte page . Memory is
always allocated in whole numbers of pages.</para>

<para>The data structure used to keep track of memory allocation is a
32-byte bit-map located at addresses $0100 - $011F. Each bit in this
table is associated with a specific page of memory. Bits are cleared
to indicate that the page is free and available for assignment, or
set to indicate that the page is in use or that no RAM memory is
present at that address.</para>

<para>Automatic memory allocation occurs when:</para>
<orderedlist numeration="arabic">
<listitem><para>Program modules are loaded into RAM.</para></listitem>

<listitem><para>Processes are created.</para></listitem>

<listitem><para>Processes request additional RAM.</para></listitem>

<listitem><para>OS-9 needs I/O buffers, larger tables, etc.</para></listitem>
</orderedlist>
<para>All of the above usually have inverse functions that cause
previously allocated memory to be deallocated and returned to the
free memory pool.</para>

<para>In general, memory is allocated for program modules and buffers
from high addresses downward, and for process data areas from lower
addresses upward.</para>
<informalfigure>
<screen>
   TYPICAL MEMORY MAP


+-----------------------+  &lt;- $FFFF
|                       |
|     OS-9 ROMS (4K)    |
|                       |
+-----------------------+  &lt;- $F000
|                       | 
|  I/O DEVICE ADDRESSES |
|                       | 
+-----------------------+  &lt;- $E000
|                       | 
|    SPACE FOR MORE     |
|    OPTIONAL ROMS      |
|                       | 
+-----------------------+  &lt;- END OF RAM MEMORY
|                       | 
|    FILE MANAGERS      |
|  DEVICE DRIVERS, ETC. |
|   (APPROXIMATELY 6K)  |
|                       |
+-----------------------+
|                       |
|      SHELL (1K)       |
|                       |
+-----------------------+
|                       |
| OS-9 DATA STRUCTURES  |
|  (APPROXIMATELY 1K)   |
|                       |
+-----------------------+
|                       |
|    FREE MEMORY FOR    |
|     GENERAL USE       |
|                       |
+-----------------------+ &lt;- $0400
|                       |
| OS-9 DATA STRUCTURES  |
|   AND DIRECT PAGE     |
|                       |
+-----------------------+ &lt;- $0000 BEGINNING OF RAM MEMORY
</screen>
</informalfigure>

<para>
The map above is for a &quot;typical&quot; system. Actual memory
sizes and addresses may vary depending on the exact system
configuration.</para>
</sect1>

<sect1>
<title>Overview of Multiprogramming</title>

<para>OS-9 is a multiprogramming operating system, which allows several
independent programs called &quot;processes&quot; can be executed
simultaneously. Each process can have access to any system resource
by issuing appropriate service requests to OS-9. Multiprogramming
functions use a hardware real-time clock that generates interrupts at
a regular rate of about 10 times per second. MPU time is therefore
divided into periods typically 100 milliseconds in duration. This
basic time unit is called a tick . Processes that are &quot;active
(meaning not waiting for some event) are run for a specific
system-assigned period called a &quot;time slice&quot;. The duration of
the time slice depends on a process's priority value relative to the
priority of all other active processes. Many OS-9 service requests
are available to create, terminate, and control processes.</para>
</sect1>

<sect1>
<title>Process Creation</title>

<para>New processes are created when an existing process executes a "fork"
service request. Its main argument is the name of the program module
(called the &quot;primary module&quot;) that the new process is to
initially execute. OS-9 first attempts to find the module in the
&quot;module directory&quot;, which includes the names of all program
modules already present in memory. If the module cannot be found
there. OS-9 usually attempts to load into memory a mass-storage file
using the requested module name as a file name.</para>

<para>Once the module has been located, a data structure called a
&quot;process descriptor&quot; is assigned to the new process. The process
descriptor is a 64-byte package that contains information about the
process, its state, memory allocations, priority, queue pointers,
etc. The process descriptor is automatically initialized and
maintained by OS-9. The process itself has no need, and is not
permitted to access the descriptor.</para>

<para>The next step in the creation of a new process is allocation of
data storage (RAM) memory for the process. The primary module's
header contains a storage size value that is used unless the &quot;fork&quot;
system call requested an optionally larger size. OS-9 then attempts
to allocate a CONTIGUOUS memory area of this size from the free
memory space.</para>

<para>If any of the previous steps cannot be performed, creation of the
new process is aborted, and the process that originated the &quot;fork&quot;
is informed of the error. Otherwise, the new process is added to the
active process queue for execution scheduling.</para>

<para>The new process is also assigned a unique number called a &quot;process
ID&quot; which is used as its identifier. Other processes can
commnunciate with it by referring to its ID in various system
calls. The process also has associated with it a &quot;user ID&quot; which
is used to identify all processes and files belonging to a
particular user. The user ID is inherited from the parent process.</para>

<para>Processes terminate when they execute an &quot;EXIT&quot; system service
request, or when they receive fatal signals. The process termination
closes any open paths, deallocates its memory, and unlinks its
primary module.</para>
</sect1>

<sect1>
<title>Process States</title>

<para>At any instant, a process can be in one of three states:</para>

<para>ACTIVE - The process is active and ready for execution.
</para>

<para>WAITING - The process is suspended until a child process
terminates or a signal is received.
</para>

<para>SLEEPING - The process is suspended for a specific period of time
or until a signal is received.
</para>

<para>There is a queue for each process state. The queue is a linked
list of the &quot;process descriptors&quot; of processes in the
corresponding state. State changes are performed by moving a process
descriptor to another queue.</para>

<sect2>
<title>The Active State</title>

<para>This state includes all &quot;runnable&quot; processes, which are given
time slices for execution according to their relative priority with
respect to all other active processes. The scheduler uses a
pseudo-round-robin scheme that gives all active processes some CPU
time, even if they have a very low relative priority.</para>
</sect2>

<sect2>
<title>The Wait State</title>

<para>This state is entered when a process executes a WAIT system
service request. The process remains suspended until the death of any
of its descendant processes, or, until it receives a signal.</para>
</sect2>

<sect2>
<title>The Sleeping State</title>

<para>This state is entered when a process executes a SLEEP service
request, which specifies a time interval. (a specific number of
ticks) for which the process is to remain suspended. The process
remains asleep until the specified time has elapsed, or until a
signal is received.</para>
</sect2>
</sect1>

<sect1>
<title>Execution Scheduling</title>

<para>The kernel contains a scheduler that is responsible for allocation
of CPU time to active processes. OS-9 uses a scheduling algorithm
that ensures all processes get some execution time.</para>

<para>All active processes are members of the active process queue,
which is kept sorted by process &quot;age&quot;. Age is a count of
how many process switches have occurred since the process' last time
slice. When a process is moved to the active process queue from
another queue, its &quot;age&quot; is initialized by setting it to
the process' assigned priority, i.e., processes having relatively
higher priority are placed in the queue with an artificially higher
age. Also, whenever a new process is activated, the ages of all other
processes are incremented.</para>

<para>Upon conclusion of the currently executing process' time slice,
the scheduler selects the process having the highest age to be
executed next. Because the queue is kept sorted by age, this process
will be at the bead of the queue. At this time the ages of all other
active processes are incremented (ages are never incremented beyond
255).</para>

<para>An exception is newly-active processes that were previously
deactivated while they were in the system state. These processes are
noted and given higher priority than others because they are usually
executing critical routines that affect shared system resources and
therefore could be blocking other unrelated processes.</para>

<para>When there are no active processes, the kernel will set itself up
to handle the next interrupt and then execute a CWAI instruction,
which decreases interrupt latency time.</para>
</sect1>

<sect1>
<title>Signals</title>

<para>&quot;Signals&quot; are an asynchronous control mechanism used for
interprocess communication and control. A signal behaves like a
software interrupt in that it can cause a process to suspend a
program, execute a specific routine, and afterward return to the
interrupted program. Signals can be sent from one process to another
process (by means of the SEND service request), or they can be sent
from OS-9 system routines to a process.</para>

<para>Status information can be conveyed by the signal in the form of a
one-byte numeric value. Some of the signal &quot;codes&quot; (values)
have predefined meanings, but all the rest are user-defined. The
defined signal codes are: 
</para>

<informalexample>
<para>0 = KILL (non-interceptable process abort)</para>

<para>1 = WAKEUP - wake up sleeping process</para>

<para>2 = KEYBOARD ABORT</para>

<para>3 = KEYBOARD INTERRUPT</para>

<para>4 - 255 USER DEFINED</para>
</informalexample>

<para>When a signal is sent to a process, the signal is noted and saved
in the process descriptor. If the process is in the sleeping or
waiting state, it is changed to the active state. It then becomes
eligible for execution according to the usual MPU scheduler criteria.
When it gets its next time slice, the signal is processed.</para>

<para>What happens next depends on whether or not the process had
previously set up a &quot;signal trap&quot; (signal service routine) by
executing an INTERCEPT service request. If it had not, the process is
immediately aborted. It is also aborted if the signal code is zero.
The abort will be deferred if the process is in system mode: the
process dies upon its return to user state.</para>

<para>If a signal intercept trap has been set up, the process resumes
execution at the address given in the INTERCEPT service request. The
signal code is passed to this routine, which should terminate with an
RTI instruction to resume normal execution of the process.</para>

<para>NOTE: &quot;Wakeup&quot; signals activate a sleeping process: they DO
NOT vector through the intercept routine.</para>

<para>If a process has a signal pending (usually because it has not been
assigned a time slice since the signal was received), and some other
process attempts to send it another signal, the new signal is aborted
and the &quot;send&quot; service request will return an error status. The
sender should then execute a sleep service request for a few ticks
before attempting to resend the signal, so the destination process
has an opportunity to process the previously pending signal.</para>
</sect1>

<sect1>
<title>Interrupt Processing</title>

<para>Interrupt processing is another important function of the kernel.
All hardware interrupts are vectored to specific processing routines.
IRQ interrupts are handled by a prioritized polling system (actually
part of IOMAN) which automatically identifies the source of the
interrupt and dispatches to the associated user or system defined
service routine. The real-time clock will generate IRQ interrupts.
SWI, SWI2, and SWI3 interrupts are vectored to user-definable
addresses which are &quot;local&quot; to each procedure, except that SWI2
is normally used for OS-9 service requests calls. The NMI and FIRQ
interrupts are not normally used and are vectored through a RAM
address to an RTI instruction.</para>

<sect2>
<title>Physical Interrupt Processing</title>

<para>The OS-9 kernel. ROMs contain the hardware vectors required by the
6809 MPU at addresses $FFF0 through $FFFF. These vectors each
point to jump-extended-indirect instruction which vector the MPU to
the actual interrupt service routine. A RAM vector table in page zero
of memory contains the target addresses of the jump instructions as
follows:
</para>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.1in" colname="c1"/>
<colspec colwidth="1.1in" colname="c2"/>
   <thead>
	    <row>
			    <entry>INTERRUPT</entry>
			    <entry>ADDRESS</entry>
	    </row>
    </thead>
    <tbody>
	    <row>
			    <entry>SWI3</entry>
			    <entry>$002C</entry>
	    </row>
	    <row>
			    <entry>SWI2</entry>
			    <entry>$002E</entry>
	    </row>
	    <row>
			    <entry>FIRQ</entry>
			    <entry>$0030</entry>
	    </row>
	    <row>
			    <entry>IRQ</entry>
			    <entry>$0032</entry>
	    </row>
	    <row>
			    <entry>SWI</entry>
			    <entry>$0034</entry>
	    </row>
	    <row>
			    <entry>NMI</entry>
			    <entry>$0036</entry>
	    </row>
    </tbody>
</tgroup>
</informaltable>

<para>OS-9 initializes each of these locations after reset to point to a
specific service routine in the kernel. The SWI, SWI2, and SWI3
vectors point to specific routines which in turn read the
corresponding pseudo vector from the process' process descriptor and
dispatch to it. This is why the F$SSWI service request to be local to
a process since it only changes a pseudo vector in the process
descriptor. The IRQ routine points directly to the IRQ polling
system, or to it indirectly via the real-time clock device service
routine. The FIRQ and NMI vectors are not normally used by OS-9 and
point to RTI instructions.</para>

<para>A secondary vector table located at $FFE0 contains the addresses
of the routines that the RAM vectors are initialized to. They may be
used when it is necessary to restore the original service routines
after altering the RAM vectors. On the next page are the definitions
of both the actual hardware interrupt vector table, and the
secondary vector table:
</para>
<informaltable frame="none">
<tgroup cols="3">
<colspec colwidth="1.1in" colname="c1"/>
<colspec colwidth="1.1in" colname="c2"/>
<colspec colwidth="2.8in" colname="c3"/>
<spanspec spanname="two" namest="c1" nameend="c2"/>
    <thead>
	    <row>
			    <entry>VECTOR</entry>
			    <entry>ADDRESS</entry>
			    <entry></entry>
	    </row>
    </thead>
    <tbody>
	    <row>
			    <entry spanname="two">Secondary Vector Table</entry>
			    <entry></entry>
	    </row>
	    <row>
			    <entry>TICK</entry>
			    <entry>$FFE0</entry>
			    <entry>Clock Tick Service Routine</entry>
	    </row>
	    <row>
			    <entry>SWI3</entry>
			    <entry>$FFE2</entry>
			    <entry></entry>
	    </row>
	    <row>
			    <entry>SWI2</entry>
			    <entry>$FFE4</entry>
			    <entry></entry>
	    </row>
	    <row>
			    <entry>FIRQ</entry>
			    <entry>$FFE6</entry>
			    <entry></entry>
	    </row>
	    <row>
			    <entry>IRQ</entry>
			    <entry>$FFE8</entry>
			    <entry></entry>
	    </row>
	    <row>
			    <entry>SWI</entry>
			    <entry>$FFEA</entry>
			    <entry></entry>
	    </row>
	    <row>
			    <entry>NMI</entry>
			    <entry>$FFEC</entry>
			    <entry></entry>
	    </row>
	    <row>
			    <entry>WARM</entry>
			    <entry>$FFEE</entry>
			    <entry>Reserved for warm-start</entry>
	    </row>
	    <row>
			    <entry spanname="two">Hardware Vector Table</entry>
			    <entry></entry>
	    </row>
	    <row>
			    <entry>SWI3</entry>
			    <entry>$FFF2</entry>
			    <entry></entry>
	    </row>
	    <row>
			    <entry>SWI2</entry>
			    <entry>$FFF4</entry>
			    <entry></entry>
	    </row>
	    <row>
			    <entry>FIRQ</entry>
			    <entry>$FFF6</entry>
			    <entry></entry>
	    </row>
	    <row>
			    <entry>IRQ</entry>
			    <entry>$FFF8</entry>
			    <entry></entry>
	    </row>
	    <row>
			    <entry>SWI</entry>
			    <entry>$FFFA</entry>
			    <entry></entry>
	    </row>
	    <row>
			    <entry>NMI</entry>
			    <entry>$FFFC</entry>
			    <entry></entry>
	    </row>
	    <row>
			    <entry>RESTART</entry>
			    <entry>$FFFE</entry>
			    <entry></entry>
	    </row>
    </tbody>
</tgroup>
</informaltable>

<para>If it is necessary to alter the RAM vectors use the secondary
vector table to exit the substitute routine. The technique of
altering the IRQ pointer is usually used by the clock service
routines to reduce latency time of this frequent interrupt source.</para>
</sect2>

<sect2>
<title>Logical Interrupt Polling System</title>

<para>In OS-9 systems, most I/O devices use IRQ-type interrupts, so OS-9
includes a sophisticated polling system that automatically identifies
the source of the interrupt and dispatches to its associated
user-defined service routine. The information required for IRQ
polling is maintained in a data structure called the &quot;IRQ
polling table&quot;. The table has a 9-byte entry for each possible
IRQ-generatinq device. The table size is static and defined by an
initialization constant in the System Configuration Module.</para>

<para>The polling system is prioritized so devices having a relatively
greater importance (i.e., interrupt frequency) are polled before
those of lesser priority. This is accomplished by keeping the entries
sorted by priority, which is a number between 0 (lowest) and 255
(highest). Each entry in the table has 6 variables:
</para>
<orderedlist  numeration="arabic">
	<listitem><para>POLLING ADDRESS: The address of the device's status register,
	which must have a bit or bits that indicate it is the source of an
	interrupt.</para></listitem>
	<listitem><para>MASK BYTE; This byte selects one or more bits within the
	device status register that are interrupt request flag(s). A set bit
	identifies the active bit(s).</para></listitem>
	<listitem><para>FLIP BYTE: This byte selects whether the bits in the device
	status register are true when set or true when cleared. Cleared bits
	indicate active when set.</para></listitem>
	<listitem><para>SERVICE ROUTINE ADDRESS: The user-supplied address of the
	device's interrupt service routine.</para></listitem>
	<listitem><para>STATIC STORAGE ADDRESS: a user-supplied ter to the permanent
	storage required by the device service routine.</para></listitem>
	<listitem><para>PRIORITY; The device priority number: 0 to 255. This value
	determines the order in which the devices in the polling table will
	be polled. Note: this is not the same as a process priority which is
	used by the execution scheduler to decide which process gets the
	next time slice for MPU execution.</para></listitem>
</orderedlist>

<para>When an IRQ interrupt occurs, the polling system is entered via
the corresponding RAM interrupt vector. It starts polling the
devices, using the entries in the polling table in priority order.
For each entry, the status register address is loaded into
accumulator A using the device address from the table. An
exclusive-or operation using the flip-byte is executed, followed by a
logical-and operation using the mask byte. If the result is non-zero,
the device is assumed to be the cause of the interrupt.</para>

<para>The device's static storage address and service routine address is
read from the table and executed.</para>

<para>--&gt; NOTE: The interrupt service routine should terminate with
an an <emphasis>RTS</emphasis>, not an RTI instruction.</para>

<para>Entries can be made to the IRQ polling table by use of a special
OS-9 service request called &quot;F$IRQ&quot;. This is a priviledged
service request that can be executed only when OS-9 is in System Mode
(which is the case when device drivers are executed).</para>

<para>--&gt; NOTE: The actual code for the interrupt polling system is
located in the IOMAN module. The kernel P1 and P2 modules contain
the physical interrupt processing routines.</para>
</sect2>
</sect1>
</chapter>


<chapter>
<title>Memory Modules</title>

<para>Any object to be loaded into the memory of an OS-9 system must use
the memory module format and conventions. The memory module concept
allows OS-9 to manage the logical contents as well as the physical
contents of memory. The basic idea is that all programs are
individual, named objects.</para>

<para>The operating system keeps track of modules which are in memory at
all times by use of a &quot;module directory&quot; . It contains the addresses
and a count of how many processes are using each module. When modules
are loaded into memory, they are added to the directory. When they
are no longer needed, their memory is deallocated and their name
removed from the directory (except ROMs, which are discussed later).
In many respects, modules and memory in general, are managed just
like a disk. In fact, the disk and memory management sections of OS-9
share many subroutines.</para>

<para>Each module has three parts; a module header, module body and a
cyclic-redundancy-check (CRC) value. The header contains information
that describes the module and its use. This information includes: the
modules size, its type (machine language. BASIC09 compiled code,
etc); attributes (executable, reentrant, etc), data storage memory
requirements, execution starting address, etc. The CRC value is used
to verify the integrity of a module.</para>

<para>There are several different kinds of modules, each type having a
different usage and function. Modules do not have to be complete
programs, or even 6809 machine language. They may contain BASIC09
&quot;I-code&quot;, constants, single subroutines, subroutine packages, etc. The
main requirements are that modules do not modify themselves arid that
they be position-independent so OS-9 can load or relocate them
wherever memory space is available. In this respect, the module
format is the OS-9 equivalent of &quot;load records&quot; used in
older-style operating systems.</para>

<sect1>
<title>Memory Module Structure</title>

<para>At the beginning (lowest address) of the module is the module
header, which can have several forms depending on the module's
usage. OS-9 family software such as BASIC09, Pascal, C, the
assembler, and many utility programs automatically generate modules
and headers. Following the header is the program/constant section
which is usually pure code. The module name string is included
somewhere in this area. The last three bytes of the module are a
three-byte Cyclic Redundancy Check (CRC) value used to verify the
integrity of the module.</para>
<table>
<title>MODULE FORMAT</title>
<tgroup cols="1">
<colspec colwidth="1.5in"/>
    <tbody>
    <row rowsep="1">
	<entry align="center">MODULE HEADER</entry>
    </row>
    <row rowsep="1">
	<entry align="center">PROGRAM OR CONSTANTS</entry>
    </row>
    <row rowsep="1">
	<entry align="center">CRC</entry>
    </row>
</tbody>
</tgroup>
</table>

<para>The 24-bit CRC is performed over the entire module from the first
byte of the module header to the byte just before the CRC itself. The
CRC polynomial used is $800FE3.</para>

<para>Because most OS-9 family software (such as the assembler)
automatically generate the module header and CRC values, the
programner usually does not have to be concerned with writing
routines to generate them.</para>
</sect1>

<sect1>
<title>Module Header Definitions</title>

<para>The first nine bytes of all module headers are identical:
</para>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="0.9in" align="right"/>
<colspec colwidth="4in"/>
<thead>
<row>
	<entry>MODULE OFFSET</entry>
	<entry>DESCRIPTION</entry>
</row>
</thead>
<tbody>
<row>
	<entry>$0,$1 =</entry>
	<entry>Sync Bytes ($87,$CD). These two constant bytes are used to
	locate modules.</entry>
</row>

<row>
<entry>$2,$3 =</entry>
<entry>Module Size. The overall size of the module in bytes (includes
CRC).</entry>
</row>

<row>
<entry>$4,$5 =</entry>
<entry>Offset to Module Name. The address of the module name string
relative to the start (first sync byte) of the module. The name
string can be located anywhere in the module and consists of a string
of ASCII characters having the sign bit set on the last character.
</entry>
</row>

<row>
	<entry>$6 =</entry>
	<entry>Module Type/Language Type. See text.</entry>
</row>

<row>
	<entry>$7 =</entry>
	<entry>Attributes/Revision Level. See text.</entry>
</row>

<row>
	<entry>$8 =</entry>
	<entry>Header Check. The one's compliment of (the vertical parity
	(exclusive OR) of) the previous eight bytes</entry>
</row>

</tbody>
</tgroup>
</informaltable>

<sect2>
<title>Type/Language Byte</title>

<para>The module type is coded into the tour most significant bits of
byte 6 of the module header. Eight types are pre-defined by
convention, some of which are for OS-9's internal use only. The type
codes are:</para>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="0.9in" align="right"/>
<colspec colwidth="3in"/>
	<tbody>
		<row>
				<entry>$1</entry>
				<entry>Program module</entry>
		</row>
		<row>
				<entry>$2</entry>
				<entry>Subroutine module</entry>
		</row>
		<row>
				<entry>$3</entry>
				<entry>Multi-module (for future use)</entry>
		</row>
		<row>
				<entry>$4</entry>
				<entry>Data module</entry>
		</row>
		<row>
				<entry>$5-$B</entry>
				<entry>User-definable</entry>
		</row>
		<row>
				<entry>$C</entry>
				<entry>OS-9 System module</entry>
		</row>
		<row>
				<entry>$D</entry>
				<entry>OS-9 File Manager module</entry>
		</row>
		<row>
				<entry>$E</entry>
				<entry>OS-9 Device Driver module</entry>
		</row>
		<row>
				<entry>$F</entry>
				<entry>OS-9 Device Descriptor module</entry>
		</row>
	</tbody>
    </tgroup>
</informaltable>

<para>NOTE: 0 is not a legal type code.</para>

<para> &quot;user-defined types having type codes of 0 through 9. They
have six more bytes in their headers defined as follows:
</para>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="0.9in" align="right"/>
<colspec colwidth="4in"/>
	<thead>
		<row>
			<entry>MODULE OFFSET</entry>
			<entry>DESCRIPTION</entry>
		</row>
	</thead>
	<tbody>
		<row>
	<entry>$9,$A =</entry>
	<entry>Execution Offset. The program or subroutine's starting
	address, relative to the first byte of the sync code. Modules
	having multiple entry points (cold start, warm start, etc.) may
	have a branch table starting at this address.</entry>
		</row>
		<row>
    <entry>$B,$C =</entry>
    <entry><para>Permanent Storage Requirement. This is the minimum number of
    bytes of data storage required to run. This is the number used by
    FORK and CHAIN to allocate a process' data area.</para><para>
    If the module will not be directly executed by a CHAIN or FORK
    service request (for instance a subroutine package), this entry
    is not used by OS-9. It is commonly used to specify the maximum
    stack size required by reentrant subroutine modules. The calling
    program can check this value to determine if the subroutine has
    enough stack space.</para></entry>
		</row>
	</tbody>
    </tgroup>
</informaltable>
</sect2>
</sect1>

<sect1>
<title>Executable Memory Module Format</title>
<informalfigure>
<screen>
Relative            Usage                    Check Range
Address

        +------------------------------+  ---+--------+---
 $00    |                              |     |        |
        +--    Sync Bytes ($87CD)    --+     |        |
 $01    |                              |     |        |
        +------------------------------+     |        |
 $02    |                              |     |        |
        +--   Module Size (bytes)    --+     |        |
 $03    |                              |     |        |
        +------------------------------+     |        |
 $04    |                              |     |        |
        +--   Module Name Offset     --+   header     |
 $05    |                              |   parity     |
        +------------------------------+     |        |
 $06    |     Type     |   Language    |     |        |
        +------------------------------+     |        |
 $07    |  Attributes  |   Revision    |     |        |
        +------------------------------+  ---+--    module
 $08    |     Header Parity Check      |             CRC
        +------------------------------+              |
 $09    |                              |              |
        +--     Execution Offset     --+              |
 $0A    |                              |              |
        +------------------------------+              |
 $0B    |                              |              |
        +--  Permanent Storage Size  --+              |
 $0C    |                              |              |
        +------------------------------+              |
 $0D    |                              |              |
        |  (Add'l optional header      |              |
        |   extensions located here    |              |
        |                              |              |
        |  .  .  .  .  .  .  .  .  .   |              |
        |                              |              |
        |                              |              |
        |       Module Body            |              |
        | object code, constants, etc. |              |
        |                              |              |
        |                              |              |
        +------------------------------+              |
        |                              |              |
        +--                          --+              |
        |       CRC Check Value        |              |
        +--                          --+              |
        |                              |              |
        +------------------------------+  ------------+---
</screen>
</informalfigure>
</sect1>

<sect1>
<title>ROMed Memory Modules</title>

<para>When OS-9 starts after a system reset, it searches the entire
memory space for ROMed modules. It detects them by looking for the
module header sync code ($87,$CD) which are unused 6809 opcodes. When
this byte pattern is detected, the header check is performed to
verify a correct header. If this test succeeds, the module size is
obtained from the header and a 24-bit CRC is performed over the
entire module. If the CRC matches correctly, the module is considered
valid, and it is entered into the module directory. The chances of
detecting a &quot;false module&quot; are virtually nil.</para>

<para>In this manner all ROMed modules present in the system at startup
are automatically included in the system module directory. Some of
the modules found initially are various parts of OS-9: file managers,
device driver, the configuration module, etc.</para>

<para>After the module search OS-9 links to whichever of its component
modules that it found. This is the secret of OS-9's extraordinary
adaptability to almost any 6809 computer; it automatically locates
its required and optional component modules, wherever they are, and
rebuilds the system each time that it is started.</para>

<para>ROMs containing non-system modules are also searched so any
user-supplied software is located during the start-up process and
entered into the module directory.</para>
</sect1>
</chapter>


<chapter>
<title>The OS-9 Unified Input/Output System</title>

<para>OS-9 has a unified I/O system that provides system-wide
hardware-independent I/O services for user programs and OS-9 itself.
All I/O service requests (system call) are received by the kernel and
passed to the Input/Output Manager (IOMAN) module for processing
IOMAN performs some processing (such as allocating data structures
for the I/O path) and calls the file managers and device drivers to
do much of the actual work. File manager, device driver, and device
descriptor modules are standard memory modules that can be loaded
into memory from files and used while the system is running.</para>

<para>The structural organization of I/O-related modules in an OS-9
system is hierarchical, as illustrated below:</para>
<informalfigure>
<screen>
               +-----------------------+
               !                       !
               ! Input/Output Manager  !
               !       (IOMAN)         !
               !                       !
               +-----------------------+
                  !                 !
                  !                 !
 +--------------------+       +--------------------+
 !                    !       !                    !
 ! Disk File Manager  !       ! Char. File Manager !    More
 !      (RBFMAN)      !       !      (SCFMAN)      ! -&gt; opt.
 !                    !       !                    !
 +--------------------+       +--------------------+
      !          !                !           !
      !          !                !           !
 +--------+  +--------+       +--------+  +--------+
 !        !  !        !       !        !  !        !
 !  Disk  !  !  Disk  !       !  ACIA  !  !  PIA   !    More
 ! Driver !  ! Driver !       ! Driver !  ! Driver ! -&gt; opt.
 !        !  !        !       !        !  !        !
 +--------+  +--------+       +--------+  +--------+
   !     !     !     !          !     !     !     !
   !     !     !     !          !     !     !     !
+---+ +---+  +---+ +---+     +---+ +---+  +---+ +---+
!D0 ! !D1 !  !D2 ! !D3 !     !T1 ! !T2 !  !P1 ! !P2 !-&gt; More
+---+ +---+  +---+ +---+     +---+ +---+  +---+ +---+   opt.
 RBF Device Descriptors        SCF Device Descriptors
</screen>
</informalfigure>

<sect1>
<title>The Input/Output Manager (IOMAN)</title>

<para>The Input/output Manager (IOMAN) module provides the first level
of service for I/O system calls by routing data on I/O paths from
processes to/from the appropriate file managers and device drivers.
It maintains two important internal OS-9 data structures: the device
table and the path table. This module is used in all OS-9 Level One
systems and should never be modified.</para>

<para>When a path is opened, IOMAN attempts to link to a memory module
having the device name given (or implied) in the pathlist. This
module is the device's descriptor, which contains the names of the
device driver and file manager for the device. This information is
saved by IOMAN so subsequent system call can be routed to these
modules.</para>
</sect1>

<sect1>
<title>File Managers</title>

<para>OS-9 systems can have any number of File Manager modules. The
function of a file manager is to process the raw data stream to or
from device drivers for a similar class of devices to conform to the
OS-9 standard I/O and file structure, removing as many unique device
operational characteristics as possible from I/O operations. They are
also responsible for mass storage allocation and directory processing
if applicable to the class of devices they service.</para>

<para>File managers usually buffer the data stream and issue requests to
the kernel for dynamic allocation of buffer memory. They may also
monitor and process the data stream, for example, adding line feed
characters after carriage return cbaracters.
</para>

<para>The file managers are reentrant and one file manager may be used
for an entire class of devices having similar operational
ctiaracteristics. The two standard OS-9 file managers are:
</para>

<para>RBFMAN: The Random Block File Manager which operates random-access,
block-structured devices such as disk systems, bubble memories, etc.</para>

<para>SCFMAN: Sequential Character File Manager which is used with
single-character-oriented devices such as
CRT or hardcopy terminals, printers, modems etc.</para>
</sect1>

<sect1>
<title>Device Driver Modules</title>

<para>The device driver modules are subroutine packages that perform
basic, low-level I/O transfers to or from a specific type of I/O
device hardware controller. These modules are reentrant so one copy
of the module can simultaneously run several different devices which
use identical I/O ccntrollers. For example the device driver for 6850
serial interfaces is called &quot;ACIA&quot; and can communicate to
any number of serial terminals.</para>

<para>Device driver modules use a standard module header and are given a
module type of &quot;device driver&quot; (code $E).The
execution offset address in the module header points to a branch
table that has a minimum of six (three-byte) entries.Each
entry is typically a LBRA to the corresponding subroutine. The File
Managers call specific routines in the device driver through this
table, passing a pointer to a path decriptor and the hardware control
register address in the MPU registers. The branch table looks like:
</para>
<literallayout>
+0 = Device Initialization Routine
+3 = Read From Device
+6 = Write to Device
+9 = Get Device Status
+$C = Set Device Status
+$F = Device Termination Routine
</literallayout>

<para>For a complete description of the parameters passed to these
subroutines see the file manager descriptions. Also see
the appendicies on writing device drivers.</para>
</sect1>

<sect1>
<title>Device Descriptor Modules</title>

<para>Device descriptor modules are small, non-executable modules that
provide information that associates a specific I/O device with its
logical name, hardware controller address(es), device driver name,
file manager name, and initialization paramaters.</para>

<para>Recall that device drivers and file managers both operate on
general classes of devices, not specific I/O ports. The
device descriptor modules tailor their functions to a specific I/O
device. One device descriptor module must exist for each I/O device
in the system.</para>

<para>The name of the module is the name the device is known by to the
system and user (i.e. it is the device name given in pathlists}. Its
format consists of a standard module header that has a type &quot;device
descriptor&quot; (code $F). The rest of the device descriptor header
consists of:</para>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.2in" align="right"/>
<colspec colwidth="5in"/>
<tbody>
<row>
<entry>$9,$A =</entry>
<entry>File manager name string relative address.</entry>
</row>
<row>
<entry>$B,$C =</entry>
<entry>Device driver name string relative address</entry>
</row>
<row>
<entry>$D =</entry>
<entry>Mode/Capabilities. (D S PE PW PR E W R)</entry>
</row>
<row>
<entry>$E,$F,$10 =</entry>
<entry>Device controller absolute physical (24-bit) address</entry>
</row>
<row>
<entry>$11 =</entry>
<entry>Number of bytes ( &quot;n&quot; bytes in intialization
table)</entry>
</row>
<row>
<entry>$12,$12+n =</entry>
<entry>Initialization table</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>The initialization table is copied into the &quot;option section&quot;
of the path descriptor when a path to the device is opened. The
values in this table may be used to define the operating parameters
that are changeable by the OS9 I$GSTT and I$SSTT service requests.
For example, a terminal's initialization parameters define which
control characters are used for backspace, delete, etc. The maximum
size of initialization table which may be used is 32 bytes. If the
table is less than 32 bytes long, the remaining values in the path
descriptor will be set to zero.</para>

<para>You may wish to add additional devices to your system. If a
similar device controller already exists, all you need to do is add
the new hardware and load another device descriptor. Device
descriptors can be in ROM or loaded into RAM from mass-storage files
while the system is running.</para>

<para>The diagram on the next page illustrates the device descriptor
module format.</para>
<informalfigure>
<screen>
MODULE     DEVICE DESCRIPTOR MODULE FORMAT
OFFSET

           +-----------------------------+  ---+--------+---
  $0       |                             |     |        |
           +--   Sync Bytes ($87CD)    --+     |        |
  $1       |                             |     |        |
           +-----------------------------+     |        |
  $2       |                             |     |        |
           +--   Module Size (bytes)   --+     |        |
  $3       |                             |     |        |
           +-----------------------------+     |        |
  $4       |                             |     |        |
           +-- Offset to Module Name   --+   header     |
  $5       |                             |   parity     |
           +-----------------------------+     |        |
  $6       | $F (TYPE)   |  $1 (LANG)    |     |        |
           +-----------------------------+     |        |
  $7       | Attributes  |   Revision    |     |        |
           +-----------------------------+  ---+--    module
  $8       |  Header Parity Check        |             CRC
           +-----------------------------+              |
  $9       |                             |              |
           +--  Offset to File Manager --+              |
  $A       |         Name String         |              |
           +-----------------------------+              |
  $B       |                             |              |
           +-- Offset to Device Driver --+              |
  $C       |         Name String         |              |
           +-----------------------------+              |
  $D       |        Mode Byte            |              |
           +-----------------------------+              |
  $E       |                             |              |
           +--    Device Controller    --+              |
  $F       | Absolute Physical Address   |              |
           +--       (24 bit)          --+              |
 $10       |                             |              |
           +-----------------------------+              |
 $11       |  Initialization Table Size  |              |
           +-----------------------------+              |
$12,$12+N  |                             |              |
           |  (Initialization Table)     |              |
           |                             |              |
           +-----------------------------+              |
           |    (Name Strings etc)       |              |
           +-----------------------------+              |
           |      CRC Check Value        |              |
           +-----------------------------+  ------------+---
</screen>
</informalfigure>
</sect1>

<sect1>
<title>Path Descriptors</title>

<para>Every open path is represented by a data structure called a path
descriptor (&quot;PD&quot;). It contains the information required by
the file managers and device drivers to perform I/O functions. Path
descriptors are exactly 64 bytes long and are dynamically allocated
and deallocated by IOMAN as paths are opened and closed.</para>

<para>PDs are INTERNAL data structures that are not normally referenced
from user or applications programs. In fact, it is almost impossible
to locate a path's PD when OS-9 is in user mode. The description of
PDs is mostly of interest to, and presented here for those
programmers who need to write custom file managers, device drivers,
or other extensions to OS-9.</para>

<para>PDs have three sections: the first 10-byte section is defined
universally for all file managers and device drivers, as shown below.</para>

<table frame="none">
<title>Universal Path Descriptor Definitions</title>
<tgroup cols="4">
<colspec colwidth="0.8in"/>
<colspec colwidth="0.8in"/>
<colspec colwidth="0.8in" align="right"/>
<colspec colwidth="4in"/>
<thead>
<row rowsep="1">
<entry>Name</entry>
<entry>Addr</entry>
<entry>Size</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>PD.PD</entry><entry>$00</entry><entry>1</entry>
<entry>Path number</entry>
</row>
<row>
<entry>PD.MOD</entry><entry>$01</entry><entry>1</entry>
<entry>Access mode: 1=read 2=write 3=update</entry>
</row>
<row>
<entry>PD.CNT</entry><entry>$02</entry><entry>1</entry>
<entry>Number of paths using this PD</entry>
</row>
<row>
<entry>PD.DEV</entry><entry>$03</entry><entry>2</entry>
<entry>Address of associated device table entry</entry>
</row>
<row>
<entry>PD.CPR</entry><entry>$05</entry><entry>1</entry>
<entry>Requester's process ID</entry>
</row>
<row>
<entry>PD.RGS</entry><entry>$06</entry><entry>2</entry>
<entry>Caller's MPU register stack address</entry>
</row>
<row>
<entry>PD.BUF</entry><entry>$08</entry><entry>2</entry>
<entry>Address of 236-byte data buffer (if used)</entry>
</row>
<row>
<entry>PD.FST</entry><entry>$0A</entry><entry>22</entry>
<entry>Defined by file manager</entry>
</row>
<row>
<entry>PD.OPT</entry><entry>$20</entry><entry>32</entry>
<entry>Reserved for GETSTAT/SETSTAT options</entry>
</row>
</tbody>
</tgroup>
</table>

<para>The 22-byte section called &quot;PD.FST&quot; is reserved for and
defined by each type of file manager for file pointers, permanent
variables, etc.</para>

<para>The 32-byte section called &quot;PD.OPT&quot; is used as an
&quot;option&quot; area for dynamically-alterable operating
parameters for the file or device. These variables are initialized at
the time the path is opened by copying the initialization table
contained in the device descriptor module, and can be altered later
by user programs by means of the GETSTAT and SETSTAT system calls.</para>

<para>These two sections are defined each file manager's in the assembly
language equate file (SCFDefs for SCFMAN and RBFDefs for RBFMAN).</para>
</sect1>
</chapter>


<chapter>
<title>Random Block File Manager</title>

<para>The Random Block File Manager (RBFMAN) is a file manager module
that supports random access block-oriented mass storage devices such
as disk systems, bubble memory systems, and high-performance tape
systems. RBFMAN can handle any number or type of such systems
simultaneously. It is a reentrant subroutine package called by IOMAN
for I/O service requests to random-access devices. It is responsible
for maintaining the logical and physical file structures.
</para>

<para>In the course of normal operation, RBFMAN requests allocation and
deallocation of 256-byte data buffers; usually one is required for
each open file. When physical I/O functions are necessary, RBFMAN
directly calls the subroutines in the associated device drivers. All
data transfers are performed using 256-byte data blocks. RBFMAN does
not directly deal with physical addresses such as tracks, cylinders,
etc. Instead, it passes to device driver modules address parameters
using a standard address called a "logical sector number",
or "LSN". LSNs are integers in the range of 0 to n-1, where n is the
maximum number of sectors on the media. The driver is responsible for
translating the logical sector number to actual cylinder/track/sector
values.</para>

<para>Because RBFMAN is designed to support a wide range of devices
having different performance and storage capacity, it is highly
parameter-driven. The physical parameters it uses are stored on the
media itself. On disk systems, this information is written on the
first few sectors of track number zero. The device drivers also use
this information, particularly the physical parameters stored on
sector 0. These parameters are written by the "format" program that
initializes and tests the media.</para>

<sect1>
<title>Logical and Physical Disk Organization</title>

<para>All mass storage volumes (disk media) used by OS-9 utilize the
first few sectors of the volume to store basic identification
structure, and storage allocation information.</para>

<para>Logical sector zero (LSN 0) is called the
<emphasis>Identification Sector</emphasis> which contains description of the
physical and logical format of the volume.</para>

<para>Logical sector one (LSN 1) contains an allocation map which
indicates which disk sectors are free and available for use in new or
expanded files.</para>

<para>The volume's root directory usually starts at logical sector two.</para>

<sect2>
<title>Identification Sector</title>

<para>Logical sector number zero contains a description of the physical
and logical characteristics of the volume. These are established by
the &quot;format&quot; command program when the media is initialized, the
table below gives the OS-9 mnemonic name, byte address, size, and
description of each value stored in this sector.
</para>
<informaltable frame="none">
<tgroup cols="4">
<colspec colwidth="1.2in"/>
<colspec colwidth="0.6in"/>
<colspec colwidth="0.6in" align="right"/>
<colspec colwidth="2.6in"/>
<thead>
<row rowsep="1">
<entry>Name</entry>
<entry>Addr</entry>
<entry>Size</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
    <entry>DD.TOT</entry>
    <entry>$00</entry>
    <entry>3</entry>
    <entry>Total number of sectors on media</entry>
</row>
<row>
    <entry>DD.TKS</entry>
    <entry>$03</entry>
    <entry>1</entry>
    <entry>Number of sectors per track</entry>
</row>
<row>
    <entry>DD.MAP</entry>
    <entry>$04</entry>
    <entry>2</entry>
    <entry>Number of bytes in allocation map</entry>
</row>
<row>
    <entry>DD.BIT</entry>
    <entry>$06</entry>
    <entry>2</entry>
    <entry>Number of sectors per cluster</entry>
</row>
<row>
    <entry>DD.DIR</entry>
    <entry>$08</entry>
    <entry>3</entry>
    <entry>Starting sector of root directory</entry>
</row>
<row>
    <entry>DD.OWN</entry>
    <entry>$0B</entry>
    <entry>2</entry>
    <entry>Owner's user number</entry>
</row>
<row>
    <entry>DD.ATT</entry>
    <entry>$0D</entry>
    <entry>1</entry>
    <entry>Disk attributes</entry>
</row>
<row>
    <entry>DD.DSK</entry>
    <entry>$05</entry>
    <entry>2</entry>
    <entry>Disk identification (for internal use)</entry>
</row>
<row>
    <entry>DD.FMT</entry>
    <entry>$10</entry>
    <entry>1</entry>
    <entry>Disk format: density, number of sides</entry>
</row>
<row>
    <entry>DD.SPT</entry>
    <entry>$11</entry>
    <entry>2</entry>
    <entry>Number of sectors per track</entry>
</row>
<row>
    <entry>DD.RES</entry>
    <entry>$13</entry>
    <entry>2</entry>
    <entry>Reserved for future use</entry>
</row>
<row>
    <entry>DD.BT</entry>
    <entry>$15</entry>
    <entry>3</entry>
    <entry>Starting sector of bootstrap file</entry>
</row>
<row>
    <entry>DD.BSZ</entry>
    <entry>$18</entry>
    <entry>2</entry>
    <entry>Size of bootstrap file (in bytes)</entry>
</row>
<row>
    <entry>DD.DAT</entry>
    <entry>$1A</entry>
    <entry>5</entry>
    <entry>Time of creation: Y:M:D:H:M</entry>
</row>
<row>
    <entry>DD.NAM</entry>
    <entry>$1F</entry>
    <entry>32</entry>
    <entry>Volume name: last char has sign bit set</entry>
</row>
<row>
    <entry>DD.OPT</entry>
    <entry>$3F</entry>
    <entry>32</entry>
    <entry>Option area</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</sect2>

<sect2>
<title>Disk Allocation Map Sector</title>

<para>One sector (usually LSN 1) of the disk is used for the &quot;disk
allocation map&quot; that specifies which clusters on the disk are
available for allocation of file storage space The address of this
sector is always assigned logical sector 1 by the format program
DD.MAP specifies the number of bytes in this sector which are
actually used in the map.</para>

<para>Each bit in the map corresponds to a cluster of sectors on the
disk. The number of sectors per cluster is specified by the &quot;DD.BIT&quot;
variable in the identification sector, and is always an integral
power of two, i,e., 1, 2, 4, 8, 16, etc. There are a maximum of 4096
bits in the map, so media such as double-density double-sided floppy
disks and hard disks will use a cluster size of two or more sectors.
Each bit is cleared if the corresponding cluster is available for
allocation, or set if the sector is already allocated, non-existent,
or physically defective. The bitmap is initially created by the
&quot;format&quot; utility program.</para>
</sect2>

<sect2>
<title>File Descriptor Sectors</title>

<para>The first sector of every file is called a &quot;file descriptor&quot;,
which contains the logical and physical description of the file.. The
table below describes the contents of the descriptor.</para>
<informaltable frame="none">
<tgroup cols="4">
<colspec colwidth="0.8in"/>
<colspec colwidth="0.6in"/>
<colspec colwidth="0.6in" align="right"/>
<colspec colwidth="3in"/>
<thead>
<row rowsep="1">
<entry>Name</entry>
<entry>Addr</entry>
<entry>Size</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
    <entry>FD.ATT</entry><entry>$0</entry><entry>1</entry>
    <entry>File Attributes: D S PE PW PR E W R</entry>
</row>
<row>
    <entry>FD.OWN</entry><entry>$1</entry><entry>2</entry>
    <entry>Owner's User ID</entry>
</row>
<row>
    <entry>FD.DAT</entry><entry>$3</entry><entry>5</entry>
    <entry>Date Last Modified; Y M D H M</entry>
</row>
<row>
    <entry>FD.LNK</entry><entry>$8</entry><entry>1</entry>
    <entry>Link Count</entry>
</row>
<row>
    <entry>FD.SIZ</entry><entry>$9</entry><entry>4</entry>
    <entry>File Size (number of bytes)</entry>
</row>
<row>
    <entry>FD.DCR</entry><entry>$D</entry><entry>3</entry>
    <entry>Date Created: Y M D</entry>
</row>
<row>
    <entry>FD.SEG </entry><entry>$10</entry><entry>240</entry>
    <entry>Segment List: see below</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>The attribute byte contains the file permission bits. Bit 7 is set
to indicate a directory file, bit 6 indicates a &quot;sharable&quot;
file, bit 5 is public execute, bit 4 is public write, etc.</para>

<para>The segment list consists of up to 48 five-byte entries that have
the size and address of each block of storage that comprise the file
in logical order. Each entry has a three-byte logical sector number
of the block, and a two-byte block size (in sectors). The entry
following the last segment will be zero.</para>

<para>When a file is created, it initially has no data segments
allocated to it. Write operations past the current end-of-file (the
first write is always past the end-of-file) cause additional sectors
to be allocated to the file. If the file has no segments, it is given
an initial segment having the number of sectors specified by the
minimum allocation entry in the device descriptor, or the number of
sectors requested if greater than the minimum. Subsequent expansions
of the file are also generally made in minimum allocation increments.
An attempt is made to expand the last segment wherever possible
rather than adding a new segment. When the file is closed, unused
sectors in the last segment are truncated.</para>

<para>A note about disk allocation: OS-9 attempts to minimize the number
of storage segments used in a file. In fact, many files will only
have one segment in which case no extra read operations are needed to
randomly access any byte on the file. Files can have multiple
segments if the free space of the disk becomes very fragmented, or if
a file is repeatedly closed, then opened and expanded at some later
time. This can be avoided by writing a byte at the highest address to
be used on a file before writing any other data.</para>
</sect2>

<sect2>
<title>Directory Files</title>

<para>Disk directories are files that have the &quot;D&quot; attribute
set. Directory files contain an integral number of directory entries
each of which can bold the name and LSN of a single regular or
directory file.</para>

<para>Each directory entry is 32 b,ytes long, consisting of 29 bytes for
the file name followed by a three byte logical sector number of the
file's descriptor sector. The file name is left-justified in the
field with the sign bit of the last character set. Unused entries
have a zero byte in the first file name character position.</para>

<para>Every mass-storage media must have a master directory called the
&quot;root directory&quot;. The beginning logical sector number of
this directory is stored in the identification sector, as previously
described.</para>
</sect2>
</sect1>

<sect1>
<title>RBFMAN Definitions of the Path Descriptor.</title>

<para>The table below describes the usage of the file-manager-reserved
section of path descriptors used by RBFMAN.</para>

<informaltable frame="none">
<tgroup cols="4">
<colspec colwidth="1in" colname="c1"/>
<colspec colwidth="0.6in"/>
<colspec colwidth="0.6in" align="right"/>
<colspec colwidth="2.8in" colname="c4"/>
<spanspec spanname="all" namest="c1" nameend="c4"/>
<thead>
<row rowsep="1">
    <entry>Name</entry>
    <entry>Addr</entry>
    <entry>Size</entry>
    <entry>Description</entry>
</row>
</thead>
<tbody>
<row>
    <entry spanname="all">Universal Section (same for all file managers)</entry>
</row>
<row>
    <entry>PD.PD</entry>
    <entry>$00</entry>
    <entry>1</entry>
    <entry>Path number</entry>
</row>
<row>
    <entry>PD.MOD</entry>
    <entry>$01</entry>
    <entry>1</entry>
    <entry>Mode (read/write/update)</entry>
</row>
<row>
    <entry>PD.CNT</entry>
    <entry>$02</entry>
    <entry>1</entry>
    <entry>Number of open images</entry>
</row>
<row>
    <entry>PD.DEV</entry>
    <entry>$03</entry>
    <entry>2</entry>
    <entry>Address of device table entry</entry>
</row>
<row>
    <entry>PD.CPR</entry>
    <entry>$05</entry>
    <entry>1</entry>
    <entry>Current process ID</entry>
</row>
<row>
    <entry>PD.RGS</entry>
    <entry>$06</entry>
    <entry>2</entry>
    <entry>Address of callers register stack</entry>
</row>
<row>
    <entry>PD.BUF</entry>
    <entry>$08</entry>
    <entry>2</entry>
    <entry>Buffer address</entry>
</row>
<row>
    <entry spanname="all">RBFMAN Path Descriptor Definitions</entry>
</row>
<row>
    <entry>PD.SMF</entry>
    <entry>$0A</entry>
    <entry>1</entry>
    <entry>State flags (see next page)</entry>
</row>
<row>
    <entry>PD.CP</entry>
    <entry>$0B</entry>
    <entry>4</entry>
    <entry>Current logical file position (byte addr)</entry>
</row>
<row>
    <entry>PD.SIZ</entry>
    <entry>$0F</entry>
    <entry>4</entry>
    <entry>File size</entry>
</row>
<row>
    <entry>PD.SBL</entry>
    <entry>$13</entry>
    <entry>3</entry>
    <entry>Segment beginning logical sector number</entry>
</row>
<row>
    <entry>PD.SBP</entry>
    <entry>$16</entry>
    <entry>3</entry>
    <entry>Segment beginning physical sector number</entry>
</row>
<row>
    <entry>PD.SSZ</entry>
    <entry>$19</entry>
    <entry>2</entry>
    <entry>Segment size</entry>
</row>
<row>
    <entry>PD.DSK</entry>
    <entry>$15</entry>
    <entry>2</entry>
    <entry>Disk ID (for internal use only)</entry>
</row>
<row>
    <entry>PD.DTB</entry>
    <entry>$lD</entry>
    <entry>2</entry>
    <entry>Address of drive table</entry>
</row>
<row>
    <entry spanname="all">RBFMAN Option Section Definitions (Copied from dev descriptor)</entry>
</row>
<row>
    <entry></entry>
    <entry>$20</entry>
    <entry>1</entry>
    <entry>Device class 0= SCF 1=NSF 2=PIPE 3=SBF</entry>
</row>
<row>
    <entry>PD.DRV</entry>
    <entry>$21</entry>
    <entry>1</entry>
    <entry>Drive number (0..N)</entry>
</row>
<row>
    <entry>PD.STP</entry>
    <entry>$22</entry>
    <entry>1</entry>
    <entry>Step rate</entry>
</row>
<row>
    <entry>PD.TYV</entry>
    <entry>$23</entry>
    <entry>1</entry>
    <entry>Device type</entry>
</row>
<row>
    <entry>PD.UNS</entry>
    <entry>$24</entry>
    <entry>1</entry>
    <entry>Density capability</entry>
</row>
<row>
    <entry>PD.CYL</entry>
    <entry>$25</entry>
    <entry>2</entry>
    <entry>Number of cylinders (tracks)</entry>
</row>
<row>
    <entry>PD.SID</entry>
    <entry>$27</entry>
    <entry>1</entry>
    <entry>Number of sides (surfaces)</entry>
</row>
<row>
    <entry>PD.VFY</entry>
    <entry>$28</entry>
    <entry>1</entry>
    <entry>0 = verify disk writes</entry>
</row>
<row>
    <entry>PD.SCT</entry>
    <entry>$29</entry>
    <entry>2</entry>
    <entry>Default number of sectors/track</entry>
</row>
<row>
    <entry>PD.T0S</entry>
    <entry>$2B</entry>
    <entry>2</entry>
    <entry>Default number of sectors/track (track 0)</entry>
</row>
<row>
    <entry>PD.ILV</entry>
    <entry>$2D</entry>
    <entry>1</entry>
    <entry>Sector interleave factor</entry>
</row>
<row>
    <entry>PD.SAS</entry>
    <entry>$2E</entry>
    <entry>1</entry>
    <entry>Segment allocation size</entry>
</row>
<row>
    <entry spanname="all">(the following values are NOT copied from the device descriptor)</entry>
</row>
<row>
    <entry>PD.ATT</entry>
    <entry>$33</entry>
    <entry>1</entry>
    <entry>File attributes (D S PE PW PR E W R)</entry>
</row>
<row>
    <entry>PD.FD</entry>
    <entry>$34</entry>
    <entry>3</entry>
    <entry>File descriptor PSN (physical sector #)</entry>
</row>
<row>
    <entry>PD.DFD</entry>
    <entry>$37</entry>
    <entry>3</entry>
    <entry>Directory file descriptor PSN</entry>
</row>
<row>
    <entry>PD.DCP</entry>
    <entry>$3A</entry>
    <entry>4</entry>
    <entry>File's directory entry pointer</entry>
</row>
<row>
    <entry>PD.DVT</entry>
    <entry>$3E</entry>
    <entry>2</entry>
    <entry>Address of device table entry</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>
State Flag (PD.SMF): the bits of this byte are defined as: 
</para>
<literallayout>
bit 0 = set if current buffer has been altered
bit 1 = set if current sector is in buffer
bit 2 = set if descriptor sector in buffer
</literallayout>

<para>The first section of the path descriptor is universal for all file
managers, the second and third sections are defined by RBFMAN and
RBFMAN-type device drivers. The option section of the path descriptor
contains many device operating parameters which may be read and/or
written by the OS9 I$GSTT and I$SSTT service requests. This section
is initialized by IOMAN which copies the initialization table of the
device descriptor into the option section of the path descriptor when
a path to a device is opened. Any values not determined by this table
will default to zero.</para>
</sect1>

<sect1>
<title>RBF Device Descriptor Modules</title>

<para>This section describes the definitions and use of the
initialization table contained in device descriptor modules for
RBF-type devices.</para>

<informaltable frame="none">
<tgroup cols="4">
<colspec colwidth="1in"/>
<colspec colwidth="0.7in"/>
<colspec colwidth="0.7in"/>
<colspec colwidth="4in"/>
<thead>
<row>
    <entry>Module Offset</entry>
    <entry></entry>
    <entry></entry>
    <entry></entry>
</row>
</thead>
<tbody>
<row>
    <entry>0-$11</entry>
    <entry></entry>
    <entry></entry>
    <entry>Standard Device Descriptor Module Header</entry>
</row>
<row>
    <entry>$12</entry>
    <entry>IT.DTP</entry>
    <entry>RMB 1</entry>
    <entry>DEVICE TYPE (0=SCF 1=RBF 2=PIPE 3=SBF)</entry></row>
<row>
    <entry>$13</entry>
    <entry>IT.DRV</entry>
    <entry>RMB 1</entry>
    <entry>DRIVE NUMBER</entry></row>
<row>
    <entry>$14</entry>
    <entry>IT.STP</entry>
    <entry>RMB 1</entry>
    <entry>STEP RATE</entry></row>
<row>
    <entry>$15</entry>
    <entry>IT.TYP</entry>
    <entry>RMB 1</entry>
    <entry>DEVICE TYPE (See RBFMAN path descriptor)</entry></row>
<row>
    <entry>$16</entry>
    <entry>IT.DNS</entry>
    <entry>RMB 1</entry>
    <entry>MEDIA DENSITY (0 - SINGLE, 1-DOUBLE)</entry></row>
<row>
    <entry>$17</entry>
    <entry>IT.CYL</entry>
    <entry>RMB 2</entry>
    <entry>NUMBER OF CYLINDERS (TRACKS)</entry></row>
<row>
    <entry>$19</entry>
    <entry>IT.SID</entry>
    <entry>RMB 1</entry>
    <entry>NUMBER OF SURFACES (SIDES)</entry></row>
<row>
    <entry>$1A</entry>
    <entry>IT.VFY</entry>
    <entry>RMB 1</entry>
    <entry>0 = VERIFY DISK WRITES</entry></row>
<row>
    <entry>$1B</entry>
    <entry>IT.SCT</entry>
    <entry>RMB 2</entry>
    <entry>Default Sectors/Track</entry></row>
<row>
    <entry>$1D</entry>
    <entry>IT.T0S</entry>
    <entry>RMB 2</entry>
    <entry>Default Sectors/Track (Track 0)</entry></row>
<row>
    <entry>$1F</entry>
    <entry>IT.ILV</entry>
    <entry>RMB 1</entry>
    <entry>SECTOR INTERLEAVE FACTOR</entry>
</row>
<row>
    <entry>$20</entry>
    <entry>IT.SAS</entry>
    <entry>RMB 1</entry>
    <entry>SEGMENT ALLOCATION SIZE</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>
IT.DRV - This location is used to associate a one byte integer
with each drive that a controller will handle. The drives for each
controller should be numbered 0 to n-1, where n is the maximum number
of drives the controller can handle.</para>

<para>IT.STP - (Floppy disks) This location sets the head stepping rate
that will be used with a drive. The step rate should be set to the
fastest value that the drive is capable of to reduce access time. The
actual values stored depended on the specific disk controller and
disk driver module used. Below are the values which are used by the
popular Western Digital floppy disk controller IC:</para>

<informaltable frame="all">
<tgroup cols="5">
<colspec colwidth="1in" colname="q1" align="center"/>
<colspec colwidth="1.2in" colname="q2" align="right"/>
<colspec colwidth="1.2in" colname="q3" align="right"/>
<colspec colwidth="1.2in" colname="q4" align="right"/>
<colspec colwidth="1.2in" colname="q5" align="right"/>
<spanspec spanname="x1" namest="q2" nameend="q3"/>
<spanspec spanname="x2" namest="q4" nameend="q5"/>
<thead>
<row>
    <entry>Step Code</entry>
    <entry spanname="x1" align="center">FD1771</entry>
    <entry spanname="x2" align="center">FD179X Family</entry>
</row>
</thead>
<tbody>
<row>
    <entry></entry>
    <entry>5"</entry>
    <entry>8"</entry>
    <entry>5"</entry>
    <entry>8"</entry>
</row>
<row>
    <entry>0</entry>
    <entry>40ms</entry>
    <entry>20ms</entry>
    <entry>30ms</entry>
    <entry>15ms</entry>
</row>
<row>
    <entry>1</entry>
    <entry>20ms</entry>
    <entry>10ms</entry>
    <entry>20ms</entry>
    <entry>10ms</entry>
</row>
<row>
    <entry>2</entry>
    <entry>12ms</entry>
    <entry>6ms</entry>
    <entry>12ms</entry>
    <entry>6ms</entry>
</row>
<row>
    <entry>3</entry>
    <entry>12ms</entry>
    <entry>6ms</entry>
    <entry>6ms</entry>
    <entry>3ms</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<literallayout>
IT.TYP - Device type (All types)
    bit 0 -- 0 = 5&quot; floppy disk
             1 = 8&quot; floppy disk
    bit 6 -- 0 = Standard OS-9 format
             1 = Non-standard format
    bit 7 -- 0 = Floppy disk
             1 = Hard disk

IT.DNS - Density capabilities (Floppy disk only)
    bit 0 -- 0 = Single bit density (FM)
             1 = Double bit density (MFM)

    bit 1 -- 0 = Single track density (5&quot;, 48 TPI)
             1 = Double track density (5&quot;, 96 TPI)
</literallayout>

<para>IT.SAS - This value specifies the minimum number of sectors to
be allocated at any one time.</para>
</sect1>

<sect1>
<title>RBF-type Device Drivers</title>

<para>An RBF type device driver module contains a package of subroutines
that perform sector oriented I/O to or from a specific hardware
controller. These modules are usually reentrant so that one copy of
the module can simultaneously run several different devices that use
identical I/O controllers. IOMAN will allocate a static storage area
for each device (which may control several drives). The size of the
storage area is given in the device driver module header. Some of
this storage area will be used by IOMAN and RBFMAN, the device driver
is free to use the remainder in any manner. This static storage is
used as follows: 
</para>
<table frame="none">
<title>Static Storage Definitions</title>
<tgroup cols="4">
<colspec colwidth="0.6in" colname="c1"/>
<colspec colwidth="0.7in" colname="c2"/>
<colspec colwidth="1.2in" colname="c3"/>
<colspec colwidth="2.5in" colname="c4"/>
<spanspec spanname="x1" namest="c1" nameend="c2"/>
<spanspec spanname="x2" namest="c3" nameend="c4"/>
<thead>
<row>
    <entry spanname="x1">Offset</entry>
    <entry spanname="x2">ORG 0</entry>
</row>
</thead>
<tbody>
<row><entry>0</entry><entry>V.PAGE</entry><entry>RMB 1</entry>
<entry>PORT EXTENDED ADDRESS (A20 - A16)</entry></row>
<row><entry>1</entry><entry>V.PORT </entry><entry>RMB 2</entry>
<entry>DEVICE BASE ADDRESS</entry></row>
<row><entry>3</entry><entry>V.LPRC</entry><entry>RMB 1</entry>
<entry>LAST ACTIVE PROCESS ID</entry></row>
<row><entry>4</entry><entry>V.BUSY</entry><entry>RMB 1</entry>
<entry>ACTIVE PROCESS ID (0 = NOT BUSY)</entry></row>
<row><entry>5</entry><entry>V.WAKE</entry><entry>RMB 1</entry>
<entry>PROCESS ID TO REAWAKEN</entry></row>
<row><entry></entry><entry>V.USER</entry><entry>EQU .</entry>
<entry>END OF OS9 DEFINITIONS</entry></row>
<row><entry>6</entry><entry>V.NDRV</entry><entry>RMB 1</entry>
<entry>NUMBER OF DRIVES</entry></row>
<row><entry></entry><entry>DRVBEG</entry><entry>EQU .</entry>
<entry>BEGINNING OF DRIVE TABLES</entry></row>
<row><entry>7</entry><entry>TABLES</entry><entry>RMB DRVMEM*N</entry>
<entry>RESERVE N DRIVE TABLES</entry></row>
<row><entry></entry><entry></entry><entry>RMB 1</entry>
<entry></entry></row>
<row><entry></entry><entry>FREE</entry><entry>EQU </entry>
<entry>FREE FOR DRIVER TO USE</entry></row>
</tbody>
</tgroup>
</table>

<para>NOTE: V.PAGE through V.USER are predefined in the OS9DEFS file.
V.NDRV, DRVBEG, DRVMEM are predefined in the RBFDEFS file.</para>

<para>V.PAGE, V.PORT These three bytes are defined by IOMAN as the 24-bit
device address.</para>

<para>V.LPRC This location contains the process ID of the last process
to use the device. Not used by RBF-type device drivers.</para>

<para>V.BUSY This location contains the process ID of the process
currently using the device. Defined by RBFMAN.</para>

<para>V.WAKE This location contains the process-ID of any process that
is waiting for the device to complete I/O (0 = NO PROCESS WAITING).
Defined by device driver.</para>

<para>V.NDRV This location contains the number of drives that the
controller can use. Defined by the device driver as the maximum
number of drives that the controller can work with. RBFMAN will
assume that there is a drive table for each drive. Also see the
driver INIT routine in this section.</para>

<para>TABLES This area contains one table for each drive that the
controller will handle (RBFMAN will assume that there are as many
tables as indicated by V.NDRV). Some time after the driver INIT
routine has been called, RBFMAN will issue a request for the driver
to read the identification sector (logical sector zero) from a drive.
At this time the driver will initialize the corresponding drive table
by copying the first part of the identification sector (up to
DD.SIZ) into it, Also see the &quot;Identification Sector&quot; section of
this manual. The format of each drive table is as given below:</para>
<informaltable frame="none">
<tgroup cols="4">
<colspec colwidth="0.6in" colname="c1"/>
<colspec colwidth="0.7in" colname="c2"/>
<colspec colwidth="1.2in" colname="c3"/>
<colspec colwidth="2.5in" colname="c4"/>
<spanspec spanname="x1" namest="c1" nameend="c2"/>
<spanspec spanname="x2" namest="c3" nameend="c4"/>
<thead>
<row>
    <entry spanname="x1">Offset</entry>
    <entry spanname="x2">ORG 0</entry>
</row>
</thead>
<tbody>
<row>
    <entry>$00</entry>
    <entry>DD.TOT</entry>
    <entry>RMB 3</entry>
    <entry>Total number of sectors on media</entry>
</row>
<row>
    <entry>$03</entry>
    <entry>DD.TKS</entry>
    <entry>RMB 1</entry>
    <entry>Number of sectors per track</entry>
</row>
<row>
    <entry>$04</entry>
    <entry>DD.MAP</entry>
    <entry>RMB 2</entry>
    <entry>Number of bytes in allocation map</entry>
</row>
<row>
    <entry>$06</entry>
    <entry>DD.BIT</entry>
    <entry>RMB 2</entry>
    <entry>Number of sectors per cluster</entry>
</row>
<row>
    <entry>$08</entry>
    <entry>DD.DIR</entry>
    <entry>RMB 3</entry>
    <entry>Starting sector of root directory</entry>
</row>
<row>
    <entry>$0B</entry>
    <entry>DD.OWN</entry>
    <entry>RMB 2</entry>
    <entry>Owner's user number</entry>
</row>
<row>
    <entry>$0D</entry>
    <entry>DD.ATT</entry>
    <entry>RMB 1</entry>
    <entry>Disk attributes</entry>
</row>
<row>
    <entry>$05</entry>
    <entry>DD.DSK</entry>
    <entry>RMB 2</entry>
    <entry>Disk identification</entry>
</row>
<row>
    <entry>$10</entry>
    <entry>DD.FMT</entry>
    <entry>RMB 1</entry>
    <entry>Disk format: density, number of sides</entry>
</row>
<row>
    <entry>$11</entry>
    <entry>DD.SPT</entry>
    <entry>RMB 2</entry>
    <entry>Number of sectors per track</entry>
</row>
<row>
    <entry>$13</entry>
    <entry>DD.RES</entry>
    <entry>RMB 2</entry>
    <entry>Reserved for future use</entry>
</row>
<row>
    <entry></entry>
    <entry>DD.SIZ</entry>
    <entry>EQU .</entry>
    <entry></entry>
</row>
<row>
    <entry>$15</entry>
    <entry>V.TRAK</entry>
    <entry>RMB 2</entry>
    <entry>Current Track Number</entry>
</row>
<row>
    <entry>$17</entry>
    <entry>V.BMB</entry>
    <entry>RMB 1</entry>
    <entry>Bit-map Use Flag</entry>
</row>
<row>
    <entry>$18</entry>
    <entry>DRVMEM</entry>
    <entry>EQU .</entry>
    <entry>Size of Each Drive Table</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>DD.TOT This location contains the total number of
sectors contained on the disk.</para>

<para>DD.TKS This location contains the track size (in sectors).</para>

<para>DD.MAP This location contains the
number of bytes in the disk allocation bit map.</para>

<para>DD.BIT This location contains the number of sectors that each bit
represents in the disk allocation bit map.</para>

<para>DD.DIR This location contains the logical sector number of the disk root directory.</para>

<para>DD.OWN This location contains the disk owner's user number.</para>

<para>DD.APT This location contains the disk access permission attributes as defined
below:</para>

<literallayout>
BIT 7 - D (DIRECTORY IF SET)
BIT 6 - S (SHARABLE IF SET)
BIT 5 - PX (PUBLIC EXECUTE IF SET)
BIT 4 - PW (PUBLIC WRITE IF SET)
BIT 3 - PR (PUBLIC READ IF SET)
BIT 2 - X (EXECUTE IF SET)
BIT 1 - W (WRITE IF SET).
BIT 0 - R (READ IF SET)
</literallayout>

<para>
DD.DSK This location contains a pseudo random number which is
used to identify a disk so that OS-9 may detect when a disk is
removed from the drive and another inserted in its place.</para>

<para>DD.FMT DISK FORMAT:</para>
<literallayout>
BIT B0 - SIDE
    0 = SINGLE SIDED
    1 = DOUBLE SIDED

BIT B1 - DENSITY
    0 = SINGLE DENSITY
    1 = DOUBLE DENSITY

BIT B2 - TRACK DENSITY
    0 = SINGLE (48 TPI)
    1= DOUBLE (96 TPI)
</literallayout>

<para>DD.SPT Number of sectors per track (track zero may use a different
value, specified by IT.T0S in the device descriptor).</para>

<para>DD.RES RESERVED FOR FUTURE USE</para>

<para>V.TRAK This location contains the current track which the head is
on and is updated by the driver.</para>

<para>V.BMB This location is used by RBFMAN to indicate whether or not
the disk allocation bit map is currently in use (0 = not in use). The
disk driver routines must not alter this location.</para>
</sect1>

<sect1>
<title>RBFMAN Device Drivers</title>

<para>As with all device drivers, RBFMAN-type device drivers use a
standard executable memory module format with a module type of
&quot;device driver&quot; (CODE $E). The execution offset address in
the module header points to a branch table that has six three byte
entries. Each entry is typically a LBRA to the corresponding
subroutine. The branch table is defined as follows:
</para>
<informaltable frame="none">
<tgroup cols="4">
<colspec colwidth="0.8in"/>
<colspec colwidth="0.8in"/>
<colspec colwidth="0.8in"/>
<colspec colwidth="1.6in"/>
<tbody>
<row>
	<entry morerows="5">ENTRY</entry>
	<entry>LBRA</entry>
	<entry>INIT</entry>
	<entry>INITIALIZE DRIVE</entry>
</row>
<row>
	<entry>LBRA</entry>
	<entry>READ</entry>
	<entry>READ SECTOR</entry>
</row>
<row>
	<entry>LBRA</entry>
	<entry>WRITE</entry>
	<entry>WRITE SECTOR</entry>
</row>
<row>
	<entry>LBRA</entry>
	<entry>GETSTA</entry>
	<entry>GET STATUS</entry>
</row>
<row>
	<entry>LBRA</entry>
	<entry>SETSTA</entry>
	<entry>SET STATUS</entry>
</row>
<row>
	<entry>LBRA</entry>
	<entry>TERM</entry>
	<entry>TERMINATE DEVICE</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Each subroutine should exit with the condition code register C bit
cleared if no error occurred. Otherwise the C bit should be set and
an appropriate error code returned in the B register. Below is a
description of each subroutine, its input parameters, and its output
parameters.</para>

<sect2>
<title>NAME: INIT</title>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.0in"/>
<tbody>
<row>
	<entry>NAME:</entry>
	<entry>INIT</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(U) = ADDRESS OF DEVICE STATIC STORAGE
(Y) = ADDRESS OF THE DEVICE DESCRIPTOR MODULE</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>NONE</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
<row>
	<entry>FUNCTION:</entry>
	<entry>INITIALIZE DEVICE AND ITS STATIC STORAGE AREA</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<orderedlist  numeration="arabic">
	<listitem><para>If disk writes are verified, use the F$SRQM service, request
	to allocate a 256 byte buffer area where a sector may be read back
	and verified after a write.</para></listitem>
	<listitem><para>Initialize the device permanent storage. For floppy disk
	controller typically this consists of initializing V.NDRV to the
	number of drives that the controller will work with, initializing
	DD.TOT in the drive table to a non-zero value so that sector zero
	may be read or written to, and initializing V.TRAK to $FF so that
	the first seek will find track zero.</para></listitem>
	<listitem><para>Place the IRQ service routine on the IRQ polling list by
	using the OS9 F$IRQ service request.</para></listitem>
	<listitem><para>Initialize the device control registers (enable interrupts if
	necessary).</para></listitem>
</orderedlist>

<para>NOTE: Prior to being called, the device permanent storage will be
cleared (set to zero) except for V.PAGE and V.PORT which will contain
the 24 bit device address. The driver should initialize each drive
table appropriately for the type of disk the driver expects to be
used on the corresponding drive.</para>
</sect2>

<sect2>
<title>NAME: READ</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.0in"/>
<tbody>
<row>
	<entry>NAME:</entry>
	<entry>READ</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(U) = ADDRESS OF THE DEVICE STATIC STORAGE
(Y) = ADDRESS OF THE PATH DESCRIPTOR
(B) = NSB OF DISK LOGICAL SECTOR NUMBER
(X) = LSB's OF DISK LOGICAL SECTOR NUMBER</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>SECTOR IS RETURNED IN THE SECTOR BUFFER</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
<row>
	<entry>FUNCTION:</entry>
	<entry>READ A 256 BYTE SECTOR</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>
Read a sector from the disk and place it in the sector buffer
(256 byte). Below are the things that the disk driver must do:</para>

<para>1. Get the sector buffer address from PD.BUF in the path
descriptor.</para>

<para>2. Get the drive number from PD.,DRV in the path descriptor.</para>

<para>3. Compute the physical disk address from the logical sector.</para>

<para>number.</para>

<para>4. Initiate the read operation.</para>

<para>5. Copy V.BUSY to V.WAKE, then go to sleep and wait for the I/O to
complete (the IRQ service routine is responsible for sending a wake
up signal). After awakening, test V.WAKE to see if it is clear, if
not, go back to sleep.</para>

<para>If the disk controller can not be interrupt driven it will be
necessary to perform programmed I/O.</para>

<para>NOTE 1: Whenever logical sector zero is read, the first part
of this sector must be copied into the proper drive table (get the
drive number from PD.DRV in the path descriptor). The number of bytes
to copy is DD.SIZ.</para>

<para>NOTE 2: The drive number (PD.DRv) should be used to compute
the offset to the corresponding drive table as follows:</para>

<programlisting>
LDA PD.DRV.Y Get drive number
LDB #DRVMEM Get size of a drive table
MUL
LEAX DRVBEG,U Get address of first table
LEAX D,X           Compute address of table N
</programlisting>
</sect2>

<sect2>
<title>NAME: WRITE</title>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.0in"/>
<tbody>
<row>
	<entry>NAME:</entry>
	<entry>WRITE</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(U) = ADDRESS OF THE DEVICE STATIC STORAGE
(Y) = ADDRESS OF THE PATH DESCRIPTOR
(B) = MSB OF DISK LOGICAL SECTOR NUMBER
(X) = LSB's OF DISK LOGICAL SECTOR NUMBER</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>THE SECTOR BUFFER IS WRITTEN OUT TO DISK</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
<row>
	<entry>FUNCTION:</entry>
	<entry>WRITE A SECTOR</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Write the sector buffer (256 bytes) to the disk. Below are the
things that a disk driver must do:</para>

<para>1. Get the sector buffer address from PD.BUF in the path
descriptor.</para>

<para>2. Get the drive number from PD.DRV in the path descriptor.</para>

<para>3. Compute the physical disk address from the logical sector number.</para>

<para>4. Initiate the write operation.</para>

<para>5. Copy V.BUSY to V.WAKE, then go to sleep and wait for the I/O
to complete (the IRQ service routine is responsible for sending the
wakeup signal). After awakening, test V.WAKE to see if it is clear,
if it is not, then go back to sleep. If the disk controller can not
be interrupt-driven, it will be necessary to perform a programmed I/O
transfer.</para>

<para>6. If PD.VFY in the path descriptor is equal to zero, read the
sector back in and verify that it was written correctly. This usually
does not involve a compare of the data.</para>

<para>NOTE 1: If disk writes are to be verified, the INIT routine must
request the buffer where the sector may be placed when it is read
back in. Do not copy sector zero into the drive table when it is read
back to be verified.</para>

<para>NOTE 2: Use the drive number (PD.DRV) to compute the offset to the
corresponding drive table as shown for the READ routine.</para>
</sect2>

<sect2>
<title>NAME: GETSTA PUTSTA</title>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.0in"/>
<tbody>
<row>
	<entry>NAME:</entry>
	<entry>GETSTA/PUTSTA</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(U) = ADDRESS OF THE DEVICE STATIC STORAGE AREA
(Y) = ADDRESS OF THE PATH DESCRIPTOR
(A) = STATUS CODE</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(DEPENDS UPON THE FUNCTION CODE)</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
<row>
	<entry>FUNCTION:</entry>
	<entry>GET/SET DEVICE STATUS</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>These routines are wild card calls used to get (set) the device's
operating parameters as specified for the OS9 I$GSTT and I$SSTT
service requests.</para>

<para>It may be necessary to examine or change the register stack which
contains the values of MPU registers at the time of the I$GSTT or
I$SSTT service request. The address of the register stack may be
found in PD.RGS, which is located in the path descriptor, . The
following offsets may be used to access any particular value in the
register stack:</para>
<informaltable frame="none">
<tgroup cols="5">
<colspec colwidth="0.6in"/>
<colspec colwidth="0.8in"/>
<colspec colwidth="0.5in"/>
<colspec colwidth="0.3in" colname="c4"/>
<colspec colwidth="2.5in" colname="c5"/>
<thead>
    <row>
	<entry>OFFSET</entry>
	<entry align="left" nameend="c4">MNEMONIC</entry>
	<entry namest="c5">MPU REGISTER</entry>
    </row>
</thead>
<tbody>
<row>
    <entry>$0</entry>
    <entry>R$CC</entry>
    <entry>RMB</entry>
    <entry>1</entry>
    <entry>CONDITIONS CODE REGISTER</entry>
</row>
<row>
    <entry>$1</entry>
    <entry>R$D</entry>
    <entry>EQU</entry>
    <entry>.</entry>
    <entry>D REGISTER</entry>
</row>
<row>
    <entry>$1</entry>
    <entry>R$A</entry>
    <entry>RMB</entry>
    <entry>1</entry>
    <entry>A REGISTER</entry>
</row>
<row>
    <entry>$2</entry>
    <entry>R$B</entry>
    <entry>RMB</entry>
    <entry>1</entry>
    <entry>B REGISTER</entry>
</row>
<row>
    <entry>$3</entry>
    <entry>R$DP</entry>
    <entry>RMB</entry>
    <entry>1</entry>
    <entry>DP REGISTER</entry>
</row>
<row>
    <entry>$4</entry>
    <entry>R$X</entry>
    <entry>RMB</entry>
    <entry>2</entry>
    <entry>X REGISTER</entry>
</row>
<row>
    <entry>$6</entry>
    <entry>R$Y</entry>
    <entry>RMB</entry>
    <entry>2</entry>
    <entry>Y REGISTER</entry>
</row>
<row>
    <entry>$8</entry>
    <entry>R$U</entry>
    <entry>RMB</entry>
    <entry>2</entry>
    <entry>U REGISTER</entry>
</row>
<row>
    <entry>$A</entry>
    <entry>R$PC</entry>
    <entry>RMB</entry>
    <entry>2</entry>
    <entry>PROGRAM COUNTER</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</sect2>

<sect2>
<title>NAME:TERM</title>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.0in"/>
<tbody>
<row>
	<entry>NAME:</entry>
	<entry>TERM</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(U) = ADDRESS OF DEVICE STATIC STORAGE AREA</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>NONE</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
<row>
	<entry>FUNCTION:</entry>
	<entry>TERMINATE DEVICE</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This routine is called when a device is no longer in use in the
system, which is defined to be when the link count of its device
descriptor module becomes zero). The TERM routine must:</para>

<para>1. Wait until any pending I/O has completed.</para>

<para>2. Disable the device interrupts.</para>

<para>3. Remove the device from the IRQ polling list.</para>

<para>4. If the INIT routine reserved a 256 byte buffer for verifying
disk writes, return the memory with the F$MEM service request.</para>
</sect2>

<sect2>
<title>NAME: IRQ SERVICE ROUTINE</title>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.0in"/>
<tbody>
<row>
	<entry>NAME:</entry>
	<entry>IRQ SERVICE ROUTINE</entry>
</row>
<row>
	<entry>FUNCTION:</entry>
	<entry>SERVICE DEVICE INTERRUPTS</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>
Although this routine is not included in the device driver
module branch table and is not called directly by RBFMAN, it is an
key routine in interrupt-driven device drivers. Its function is to:</para>

<para>1. Service device interrupts.</para>

<para>2. When the I/O is complete, the IRQ service routine should send
a wake up signal to the process whose process ID is in V.WAKE</para>

<para>Also clear V.WAKE as a flag to the mainline program that the IRQ
has indeed occurred.</para>

<para>NOTE: When the IRQ service routine finishes servicing an interrupt
it must clear the array and exit with an RTS instruction.</para>
</sect2>

<sect2>
<title>NAME: BOOT (Bootstrap Module)</title>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.0in"/>
<tbody>
<row>
	<entry>NAME:</entry>
	<entry>TERM</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry><literallayout>(U) = SIZE OF THE BOOT FILE (in bytes)
(X) = ADDRESS OF WHERE THE BOOT FILE WAS LOADED IN MEMORY</literallayout></entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
<row>
	<entry>FUNCTION:</entry>
	<entry>LOAD THE BOOT FILE INTO MEMORY FROM MASS-STORAGE</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>NOTE: The BOOT module is <emphasis>not</emphasis> part of the disk driver. It is a
separate module which is normally co-resident with the "OS9P2" module
in the system firmware.</para>

<para>
The bootstrap module contains one subroutine that loads the
bootstrap file and some related information into memory, it uses the
standard executable module format with a module type of &quot;system&quot;
(code $C). The execution offset in the module header contains the
offset to the entry point of this subroutine.</para>

<para>It obtains the starting sector number and size of the &quot;OS9Boot&quot;
file from the identification sector (LSN 0). OS-9 is called to
allocate a memory area large enough for the boot file, and then it
loads the boot file into this memory area.</para>

<para>1. Read the identification sector (sector zero) from the disk.
BOOT must pick its own buffer area. The identification sector
contains the values for DD.BT (the 24 bit logical sector number of
the bootstrap file), and DD.BSZ (the size of the bootstrap file in
bytes). For a full description of the identification sector.
See 6.1.1.</para>

<para>2. After reading the identification sector into the buffer, get
the 24 bit logical sector number of the bootstrap file from DD.BT.</para>

<para>3. Get the size (in bytes) of the bootstrap file from DD.BSZ. The
boot is contained in one logically contiguous block beginning at the
logical sector specified in DD.BT and extending for (DD.BSZ/256+1)
sectors.</para>

<para>4. Use the OS9 F$SRQM service request to request the memory area
where the boot file will be loaded into.</para>

<para>5. Read the boot file into this memory area.</para>

<para>6. Return the size of the boot file and its location.</para>
</sect2>
</sect1>
</chapter>


<chapter>
<title>Sequential Character File Manager</title>

<para>The Sequential Character File Manager (SCFMAN) is the OS-9 file
manager module that supports devices that operate on a
character-by-character basis, such as terminals, printers, modems, etc. SCFMAN
can handle any number or type of such devices. It is a reentrant
subroutine package called by IOMAN for I/O service requests to
sequential character-oriented devices. It includes the extensive
input and output editing functions typical of line-oriented
operation such as: backspace, line delete, repeat line, auto line
feed. Screen pause, return delay padding, etc.</para>

<para>Standard OS-9 systems are supplied with SCFMAN and two SCF-type
device driver modules: ACIA, which run 6850 serial interfaces, and
PIA, which drives a 6821-type parallel interface for printers.</para>

<sect1>
<title>SCFMAN Line Editing Functions</title>

<para>I$READ and I$WRITE service requests (which correspond to Basic09
GET and PUT statements) to SCFMAN-type devices pass data to/from the
device without any modification, except that keyboard interrupt,
keyboard abort, and pause character are filtered out of the input
(editing is disabled if the corresponding character in the path
descriptor contains a zero). In particular, carriage returns are not
automatically followed by line feeds or nulls, and the high order
bits are passed as sent/received.</para>

<para>I$RDLN and I$WRLN service requests (which correspond to Basic09
INPUT, PRINT, READ and WRITE statements) to SCFMAN-type devices
perform full line editing of all functions enabled for the particular
device. These functions are initialized when the device is first used
by copying the option table from the device descriptor table
associated with the specific device. They may be altered anytime
afterwards from assembly language programs using the I$SSTT and
I$GSST service requests, or from the keyboard using the TMODE
command. Also, all bytes transfered in this mode will have the high
order bit cleared.</para>

<para>The following path descriptor values control the line editing
functions:
</para>

<para>If PD.UPC &lt;&gt; 0 bytes input or output in the range "a..z" are made
"A..Z"</para>

<para>If PD.EKO &lt;&gt; 0, input bytes are echoed, except that
undefined control characters in the range $0..$1F print as "."
</para>

<para>If PD.ALF &lt;&gt; 0, carriage returns are automatically followed
by line feeds.</para>

<para>If PD.NUL &lt;&gt; 0, After each CR/LF a PD.NUL "nulls" (always
$00) are sent.</para>

<para>If PD.PAU &lt;&gt; 0, Auto page pause will occur after every
PD.PAU lines since the last input.</para>

<para>If PD.BSP &lt;&gt; 0, SCF will recognize PD.BSP as the "input"
backspace character, and will echo PD.BSE (the backspace echo
character) if PD.BSO = 0, or PD.BSE, space, PD.BSE if PD.BSO &lt;&gt; 0.</para>

<para>If PD.DEL &lt;&gt; 0, SCF will recognize PD.DEL the delete line
character (on input), and echo the backspace sequence over the entire
line if PD.DLO = 0, or echo CR/LF if PD.DLO &lt;&gt; 0.</para>

<para>PD.EOR defines the end of record character. This is the last
character an each line entered (I$RDLN), and terminates the output
(I$WRLN) when this character is sent. Normally PD.EOR will be set
to $0D. If it is set to zero, SCF's READLN will NEVER terminate,
unless an EOF occurs.</para>

<para>If PD.EOF &lt;&gt; 0, it defines the end of file character. SCFMAN
will return an end-of-file error on I$READ or I$RDLN if this is the
first (and only) character input. It can be disabled by setting its
value to zero.</para>

<para>If PD.RPR &lt;&gt; 0, SCF (I$RDLN) will, upon receipt of this
character, echo a carriage return [optional line feed], and then
reprint the current line.</para>

<para>If PD.DUP &lt;&gt; 0, SCF (I$RDLN) will duplicate whatever is in
the input buffer through the first "PD.EOR" character.</para>

<para>If PD.PSC &lt;&gt; 0, output is suspended before the next &quot;PD.EOR&quot;
character when this character is input. This will also delete any
"type ahead" input for I$RDLN.</para>

<para>If PD.INT &lt;&gt; 0, and is received on input, a keyboard
interrupt signal is sent to the last user of this path. Also it will
terminate the current I/O request (it any) with an error identical to
the keyboard interrupt signal code. This location normally is set to
a control-C character.</para>

<para>If PD.QUT &lt;&gt; 0, and is received on input, a keyboard abort
signal is sent to the last user of this path. Also it will terminate
the current I/O request (if any) with an error code identical to the
keyboard interrrupt signal code. This location is normally set to a
control-Q character.</para>

<para>If PD.OVF &lt;&gt; 0, It is echoed when I$RDLN has satisfied its
input byte count without finding a "PD.EOR" character.</para>

<para>NOTE: It is possible to disable most of these special editing
functions by setting the corresponding control character in the path
descriptor to zero by using the I$SSTT service request, or by running
the TMODE utility. A more permanent solution may be had by setting
the corresponding control character value in the device descriptor
module to zero.</para>

<para>
Device descriptors may be inspected to determine the default
settings for these values for specific devices.</para>
</sect1>

<sect1>
<title>SCFMAN Definitions of The Path Descriptor</title>

<para>The table below describes the path descriptors used by SCFMAN and
SCFMAN-type device drivers.</para>

<informaltable frame="none">
<tgroup cols="4">
<colspec colwidth="1in" colname="c1"/>
<colspec colwidth="0.6in"/>
<colspec colwidth="0.6in" align="right"/>
<colspec colwidth="4in" colname="c4"/>
<spanspec spanname="all" namest="c1" nameend="c4"/>
<thead>
<row rowsep="1">
    <entry>Name</entry>
    <entry>Offset</entry>
    <entry>Size</entry>
    <entry>Description</entry>
</row>
</thead>
<tbody>
<row>
    <entry spanname="all">Universal Section (same for all file managers)</entry>
</row>
<row>
    <entry>PD.PD</entry>
    <entry>$00</entry>
    <entry>1</entry>
    <entry>Path number</entry>
</row>
<row>
    <entry>PD.MOD</entry>
    <entry>$01</entry>
    <entry>1</entry>
    <entry>Mode (read/write/update)</entry>
</row>
<row>
    <entry>PD.CNT</entry>
    <entry>$02</entry>
    <entry>1</entry>
    <entry>Number of open images</entry>
</row>
<row>
    <entry>PD.DEV</entry>
    <entry>$03</entry>
    <entry>2</entry>
    <entry>Address of device table entry</entry>
</row>
<row>
    <entry>PD.CPR</entry>
    <entry>$05</entry>
    <entry>1</entry>
    <entry>Current process ID</entry>
</row>
<row>
    <entry>PD.RGS</entry>
    <entry>$06</entry>
    <entry>2</entry>
    <entry>Address of callers register stack</entry>
</row>
<row>
    <entry>PD.BUF</entry>
    <entry>$08</entry>
    <entry>2</entry>
    <entry>Buffer address</entry>
</row>
<row>
    <entry spanname="all">SCFMAN Path Descriptor Definitions</entry>
</row>

<row><entry>PD.DV2</entry><entry>$0A</entry><entry>2</entry><entry>Device table addr of 2nd (echo) device</entry></row>
<row><entry>PD.RAW</entry><entry>$0C</entry><entry>1</entry><entry>Edit flag: 0=raw mode, 1=edit mode</entry></row>
<row><entry>PD.MAX</entry><entry>$0D</entry><entry>2</entry><entry>Headline maximum character count</entry></row>
<row><entry>PD.MIN</entry><entry>$0F</entry><entry>1</entry><entry>Devices are "mine" if cleared</entry></row>
<row><entry>PD.STS</entry><entry>$10</entry><entry>2</entry><entry>Status routine module address</entry></row>
<row><entry>PD.STM</entry><entry>$12</entry><entry>2</entry><entry>Reserved for status routine </entry></row>

<row><entry spanname="all">SCFMAN Option Section Definition</entry></row>

<row><entry></entry><entry>$20</entry><entry>1</entry><entry>Device class 0=SCF 1=RBF 2=PIPE 3=SBF</entry></row>
<row><entry>PD.UPC</entry><entry>$21</entry><entry>1</entry><entry>Case (0=BOTH, 1=UPPER ONLY)</entry></row>
<row><entry>PD.BSO</entry><entry>$22</entry><entry>1</entry><entry>Backsp (0=BSE, 1=BSE SP BSE)</entry></row>
<row><entry>PD.DLO</entry><entry>$23</entry><entry>1</entry><entry>Delete (0 = BSE over line, 1=CR LF)</entry></row>
<row><entry>PD.EKO</entry><entry>$24</entry><entry>1</entry><entry>Echo (0=no echo)</entry></row>
<row><entry>PD.ALF</entry><entry>$25</entry><entry>1</entry><entry>Auto LF (0=no auto LF)</entry></row>
<row><entry>PD.NUL</entry><entry>$26</entry><entry>1</entry><entry>End of line null count</entry></row>
<row><entry>PD.PAU</entry><entry>$27</entry><entry>1</entry><entry>Pause (0= no end of page pause)</entry></row>
<row><entry>PD.PAG</entry><entry>$28</entry><entry>1</entry><entry>Lines per page</entry></row>
<row><entry>PD.BSP</entry><entry>$29</entry><entry>1</entry><entry>Backspace character</entry></row>
<row><entry>PD.DEL</entry><entry>$2A</entry><entry>1</entry><entry>Delete line character</entry></row>
<row><entry>PD.EOR</entry><entry>$25</entry><entry>1</entry><entry>End of record character (read only)</entry></row>
<row><entry>PD.EOF</entry><entry>$2C</entry><entry>1</entry><entry>End of file character (read only)</entry></row>
<row><entry>PD.RPR</entry><entry>$2D</entry><entry>1</entry><entry>Reprint line character</entry></row>
<row><entry>PD.DUP</entry><entry>$25</entry><entry>1</entry><entry>Duplicate last line character</entry></row>
<row><entry>PD.PSC</entry><entry>$2F</entry><entry>1</entry><entry>Pause character</entry></row>
<row><entry>PD.INT</entry><entry>$30</entry><entry>1</entry><entry>Keyboard interrupt character (CTL C)</entry></row>
<row><entry>PD.QUT</entry><entry>$31</entry><entry>1</entry><entry>Keyboard abort character (CTL Q)</entry></row>
<row><entry>PD.BSE</entry><entry>$32</entry><entry>1</entry><entry>Backspace echo character (BSE)</entry></row>
<row><entry>PD.OVF</entry><entry>$33</entry><entry>1</entry><entry>Line overflow character (bell)</entry></row>
<row><entry>PD.PAR</entry><entry>$34</entry><entry>1</entry><entry>Device initialization value (parity)</entry></row>
<row><entry>PD.BAU</entry><entry>$35</entry><entry>1</entry><entry>Software settable baud rate</entry></row>
<row><entry>PD.D2P</entry><entry>$36</entry><entry>2</entry><entry>Offset to 2nd device name string</entry></row>
<row><entry>PD.STN</entry><entry>$38</entry><entry>2</entry><entry>Offset of status routine name</entry></row>
<row><entry>PD.ERR</entry><entry>$3A</entry><entry>1</entry><entry>Most recent I/O error status</entry></row>
</tbody>
</tgroup>
</informaltable>

<para>The first section is universal for all file managers, the second
and third section are specific for SCFMAN and SCFMAN-type device
drivers. The option section of the path descriptor contains many
device operating parameters whicb may be read or written by the OS9
I$GSTT or I$SSTT service requests. IOMAN initializes this section
when a path is opened to a device by copying the corresponding device
descriptor initialization table. Any values not determined by this
table will default to zero.</para>

<para>Special editing functions may be disabled by setting the
corresponding control character value to zero.</para>
</sect1>

<sect1>
<title>SCF Device Descriptor Modules</title>

<para>Device descriptor modules for SCF-type devices contain the device
address and an initialization table which defines inital values for
the I/O editing features, as listed below.</para>

<informaltable frame="none">
<tgroup cols="4">
<colspec colwidth="0.9in"/>
<colspec colwidth="1.1in"/>
<colspec colwidth="0.7in"/>
<colspec colwidth="5in"/>
<thead>
<row>
<entry>MODULE OFFSET</entry>
<entry></entry>
<entry>ORG $12</entry>
<entry></entry>
</row>
</thead>
<tbody>
<row><entry></entry><entry>TABLE</entry><entry>EQU .</entry>
<entry>BEGINING OF OPTION TABLE</entry></row>
<row><entry>$12</entry><entry>IT.DVC</entry><entry>RMB 1</entry>
<entry>DEVICE CLASS (0=SCF 1=RBF 2=PIPE 3=SBF)</entry></row>
<row><entry>$13</entry><entry>IT.UPC</entry><entry>RMB 1</entry>
<entry>CASE (0=BOTH, 1=UPPER ONLY)</entry></row>
<row><entry>$14</entry><entry>IT.BSO</entry><entry>RMB 1</entry>
<entry>BACK SPACE (0=BSE, 1=BSE,SP,BSE)</entry></row>
<row><entry>$15</entry><entry>IT.DLO</entry><entry>RMB 1</entry>
<entry>DELETE (0=BSE OVER LINE, 1=CR)</entry></row>
<row><entry>$16</entry><entry>IT.EKO</entry><entry>RMB 1</entry>
<entry>ECHO (0=NO ECHO)</entry></row>
<row><entry>$17</entry><entry>IT.ALF</entry><entry>RMB 1</entry>
<entry>AUTO LINE FEED (0= NO AUTO LF)</entry></row>
<row><entry>$18</entry><entry>IT.NUL</entry><entry>RMB 1</entry>
<entry>END OF LINE NULL COUNT</entry></row>
<row><entry>$19</entry><entry>IT.PAU</entry><entry>RMB 1</entry>
<entry>PAUSE (0= NO END OF PAGE PAUSE)</entry></row>
<row><entry>$1A</entry><entry>IT.PAG</entry><entry>RMB 1</entry>
<entry>LINES PER PAGE</entry></row>
<row><entry>$1B</entry><entry>IT.BSP</entry><entry>RMB 1</entry>
<entry>BACKSPACE CHARACTER</entry></row>
<row><entry>$1C</entry><entry>IT.DEL</entry><entry>RMB 1</entry>
<entry>DELETE LINE CHARACTER</entry></row>
<row><entry>$1D</entry><entry>IT.EOR</entry><entry>RMB 1</entry>
<entry>END OF RECORD CHARACTER</entry></row>
<row><entry>$1E</entry><entry>IT.EOF</entry><entry>RMB 1</entry>
<entry>END OF FILE CHARACTER</entry></row>
<row><entry>$1F</entry><entry>IT.RPR</entry><entry>RMB 1</entry>
<entry>REPRINT LINE CHARACTER</entry></row>
<row><entry>$20</entry><entry>IT.DUP</entry><entry>RMB 1</entry>
<entry>DUP LAST LINE CHARACTER</entry></row>
<row><entry>$21</entry><entry>IT.PSC</entry><entry>RMB 1</entry>
<entry>PAUSE CHARACTER</entry></row>
<row><entry>$22</entry><entry>IT.INT</entry><entry>RMB 1</entry>
<entry>INTERRUPT CHARACTER</entry></row>
<row><entry>$23</entry><entry>IT.QUT</entry><entry>RMB 1</entry>
<entry>QUIT CHARACTER</entry></row>
<row><entry>$24</entry><entry>IT.BSE</entry><entry>RMB 1</entry>
<entry>BACKSPACE ECHO CHARACTER</entry></row>
<row><entry>$25</entry><entry>IT.OVF</entry><entry>RMB 1</entry>
<entry>LINE OVERFLOW CHARACTER (BELL)</entry></row>
<row><entry>$26</entry><entry>IT.PAR</entry><entry>RMB 1</entry>
<entry>INITIALIZATION VALUE (PARITY)</entry></row>
<row><entry>$27</entry><entry>IT.BAU</entry><entry>RMB 1</entry>
<entry>BAUD RATE</entry></row>
<row><entry>$28</entry><entry>IT.D2P</entry><entry>RMB 2</entry>
<entry>ATTACHED DEVICE NAME STRING OFFSET</entry></row>
<row><entry>$2A</entry><entry>IT.STN</entry><entry>RMB 2</entry>
<entry>OFFSET TO STATUS ROUTINE</entry></row>
<row><entry>$2C</entry><entry>IT.ERR</entry><entry>RMB 1</entry>
<entry>INITIAL ERROR STATUS</entry></row>
</tbody></tgroup></informaltable>

<para>NOTES:</para>

<para>SCF editing functions will be "turned off" if the corresponding
special character is a zero. For example, it IT.EOF was a zero, there
would be no end of file character.</para>

<para>IT.PAR is typically used to intitialize the device s control
register when a path is opened to it.</para>
</sect1>

<sect1>
<title>SCF Device Driver Storage Definitions</title>

<para>An SCFMAN-type device driver module contains a package of
subroutines that perform raw I/O transfers to or from a specific
hardware controller. These modules are usually reentrant so that one
copy of the module can simultaneously run several different devices
that use identical I/O controllers. For each
"incarnation" of the driver, IOMAN will allocate a static storage
area for that device. The size of the storage area is given in
the device driver module header. Some
of this storage area will be used by IOMAN and SCFMAN, the device
driver is free to use the remainder in any way (typically as
variables and butters). This static storage is defined as:
</para>
<informaltable frame="none">
<tgroup cols="4">
<colspec colwidth="0.6in"/>
<colspec colwidth="0.9in"/>
<colspec colwidth="0.7in"/>
<colspec colwidth="2.8in"/>
<thead>
<row>
<entry>OFFSET</entry>
<entry></entry>
<entry>ORG 0</entry>
<entry></entry>
</row>
</thead>
<tbody>
<row><entry>$0</entry><entry>V.PAGE</entry><entry>RMB 1</entry>
<entry>PORT EXTENDED ADDRESS</entry></row>
<row><entry>$1</entry><entry>V.PORT</entry><entry>RMB 2</entry>
<entry>DEVICE BASE ADDRESS</entry></row>
<row><entry>$3</entry><entry>V.LPRC</entry><entry>RMB 1</entry>
<entry>LAST ACTIVE PROCESS ID</entry></row>
<row><entry>$4</entry><entry>V.BUSY</entry><entry>RMB 1</entry>
<entry>ACTIVE PROCESS ID (0 NOT BUSY)</entry></row>
<row><entry>$5</entry><entry>V. WAKE</entry><entry>RMB 1</entry>
<entry>PROCESS ID TO REAWAKEN</entry></row>
<row><entry></entry><entry>V. USER</entry><entry>EQU .</entry>
<entry>END OF OS9 DEFINITIONS</entry></row>
<row><entry>$6</entry><entry>V.TYPE</entry><entry>RMB 1</entry>
<entry>DEVICE TYPE OR PARITY</entry></row>
<row><entry>$7</entry><entry>V.LINE</entry><entry>RMB 1</entry>
<entry>LINES LEFT TILL END OF PAGE</entry></row>
<row><entry>$8</entry><entry>V.PAUS </entry><entry>RMB 1</entry>
<entry>PAUSE REQUEST (0 = NO PAUSE)</entry></row>
<row><entry>$9</entry><entry>V.DEV2</entry><entry>RMB 2</entry>
<entry>ATTACHED DEVICE STATIC STORAGE</entry></row>
<row><entry>$B</entry><entry>V. INTR</entry><entry>RMB 1</entry>
<entry>INTERRUPT CHARACTER</entry></row>
<row><entry>$C</entry><entry>V.QUIT</entry><entry>RMB 1</entry>
<entry>QUIT CHARACTER</entry></row>
<row><entry>$D</entry><entry>V.PCHR</entry><entry>RMB 1</entry>
<entry>PAUSE CHARACTER</entry></row>
<row><entry>$E</entry><entry>V. ERR</entry><entry>RMB 1</entry>
<entry>ERROR ACCUMULATOR</entry></row>
<row><entry>$F</entry><entry>V.SCF</entry><entry>EQU .</entry>
<entry>END OF SCFMAN DEFINITIONS</entry></row>
<row><entry></entry><entry>FREE</entry><entry>EQU .</entry>
<entry>FREE FOR DEVICE DRIVER TO USE</entry></row>
</tbody></tgroup></informaltable>

<para>V.PAGE, V.PORT These three bytes are defined by IOMAN to be the 24
bit device address.</para>

<para>V.LPRC This location contains the process ID of the last process
to use the device. The IRQ service routine is responsible for sending
this process the proper signal in case a &quot;QUIT&quot; character
or an &quot;INTERRUPT&quot; character is recieved. Defined by SCFMAN.</para>

<para>V. BUSY This location contains the process ID of the process
currently using the device (zero if it is not being used). This is
used by SCFMAN to prevent more than one process from using the
device at the same moment. Defined by SCFMAN.</para>

<para>V.WAKE This location contains the process ID of any process that
is waiting for the device to complete I/O (or zero if there is none
waiting). The interrupt service routine should check this location to
see if a process is waiting and if so, send it a wake up signal.
Defined by the device driver.</para>

<para>V.TYPE This location contains any special characteristics of a
device. It is typically used as a value to initialize the device
control register, for parity etc. It is defined by SCFMAN which
copies its value from PD.PAR in the path descriptor.</para>

<para>V.LINE This location contains the number of lines left till end of
page. Paging is handled by SCFMAN and not by the device driver.</para>

<para>V.PAUS This location is a flag used by SCFMAN to indicate that a
pause character has been recieved. Setting its value to anything
other than zero will cause SCFMAN to stop transmitting characters at
the end of the next line. Device driver input routines must set
V.PAUS in the ECHO device's static storage area. SCFMAN will check
this value in the ECHO device's static storage when output is sent.</para>

<para>V.DEV2 This location contains the address of the ECHO (attached)
device's static storage area. Typically the device and the attached
device are one and the same. However they may be different as in the
case of a keyboard and a memory mapped video display. Defined by
SCFMAN.</para>

<para>V.INTR Keyboard interrupt character. It is defined by SCFMAN,
which copies its value from PD.INT in the path descriptor.</para>

<para>V.QUIT Keyboard abort character. It is defined by SCFMAN which
copies its value from PD.QUT in the path descriptor.</para>

<para>V.PCHR Pause character. It is defined by SCFMAN which copies its
value from PD.PSC in the path descriptor.</para>

<para>V.ERR This location is used to accumulate I/O errors. Typically it
is used by the IRQ service routine to record errors so that they may
be reported later when SCFMAN calls one of the device driver routines.</para>
</sect1>

<sect1>
<title>SCFMAN Device Driver Subroutines</title>

<para>As with all device drivers. SCFMAN device drivers use a standard
executable memory module format with a module type of
edevice
drivers (CODE $5). The execution offset address in the
module
header points to a branch table that has six three byte entries. Each
entry is typically a LBRA to the corresponding subroutine. The branch
table is as follows:</para>
<informaltable frame="none">
<tgroup cols="4">
<colspec colwidth="0.8in"/>
<colspec colwidth="0.8in"/>
<colspec colwidth="0.8in"/>
<colspec colwidth="1.6in"/>
<tbody>
<row>
	<entry morerows="5">ENTRY</entry>
	<entry>LBRA</entry>
	<entry>INIT</entry>
	<entry>INITIALIZE DEVICE</entry>
</row>
<row>
	<entry>LBRA</entry>
	<entry>READ</entry>
	<entry>READ CHARACTER</entry>
</row>
<row>
	<entry>LBRA</entry>
	<entry>WRITE</entry>
	<entry>WRITE CHARACTER</entry>
</row>
<row>
	<entry>LBRA</entry>
	<entry>GETSTA</entry>
	<entry>GET DEVICE STATUS</entry>
</row>
<row>
	<entry>LBRA</entry>
	<entry>SETSTA</entry>
	<entry>SET DEVICE STATUS</entry>
</row>
<row>
	<entry>LBRA</entry>
	<entry>TERM</entry>
	<entry>TERMINATE DEVICE</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>
Each subroutine should exit with the condition code register C
bit cleared it no error occured. Otherwise the C bit should be set
and an appropriate error code returned in the B register. Below is a
description of each subroutine, its input parameters and its output
parameters.</para>

<sect2>
<title>NAME: INIT</title>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.0in"/>
<tbody>
<row>
	<entry>NAME:</entry>
	<entry>INIT</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(U) = ADDRESS OF DEVICE STATIC STORAGE
(Y) = ADDRESS OF DEVICE DESCRIPTOR MODULE</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>NONE</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
<row>
	<entry>FUNCTION:</entry>
	<entry>INITIALIZE DEVICE AND ITS STATIC STORAGE</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>1. Initialize the device static storage.</para>

<para>2. Place the IRQ service routine on the IRQ polling list by using
the OS9 F$IRQ service request.</para>

<para>3. Initialize the device control registers (enable interrupts if
necessary).</para>

<para>NOTE: Prior to being called, the device static storage will be
cleared (set to zero) except for V.PAGE and V.PORT which will contain
the 24 bit device address. There is no need to initialize the portion
of static storage used by IOMAN and SCFMAN.</para>
</sect2>

<sect2>
<title>NAME: READ</title>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.0in"/>
<tbody>
<row>
	<entry>NAME:</entry>
	<entry>READ</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(U) = ADDRESS OF DEVICE STATIC STORAGE
(Y) = ADDRESS OF PATH DESCRIPTOR</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(A) = CHARACTER READ</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
<row>
	<entry>FUNCTION:</entry>
	<entry>GET NEXT CHARACTER</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This routine should get the next character from the input
buffer. If there is no data ready, this routine should copy its
process ID from V.BUSY into V.WAKE and then use the F$SLEP service
request to put itself to sleep.</para>

<para>Later when data is recieved, the IRQ service routine will leave
the data in a buffer, then check V.WAKE to see if any process is
waiting for the device to complete I/O. If so, the IRQ service
routine should send a wakeup signal to it.</para>

<para>NOTE: Data buffers are NOT automatically allocated. It any are
used, they should be defined in the device's static storage area.</para>
</sect2>

<sect2>
<title>NAME: WRITE</title>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.0in"/>
<tbody>
<row>
	<entry>NAME:</entry>
	<entry>WRITE</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(U) = ADDRESS OF DEVICE STATIC STORAGE
(Y) = ADDRESS OF THE PATH DESCRIPTOR
(A) = CHAR TO WRITE</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>NONE</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
<row>
	<entry>FUNCTION:</entry>
	<entry>OUTPUT A CHARACTER</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This routine places a data byte into an output buffer and enables
the device output interrupts. It the data buffer is already full,
this routine should copy its process ID from V.BUSY into V.WAKE and
then put itself to sleep.</para>

<para>Later when the IRQ service routine transmits a character and makes
room for more data in the buffer, it will check V.WAKE to see if
there is a process waiting for the device to complete I/O. It there
is, it will send a wake up signal to that process.</para>

<para>NOTE: This routine must ensure that the IRQ service routine will
start up when data is placed into the buffer. After an interrupt is
generated the IRQ service routine will continue to transmit data
until the data butter is empty, and then it will disable the device's
&quot;ready to transmit&quot; interrupts.</para>

<para>NOTE: Data buffers are NOT automatically allocated. If any are
used, they should be defined in the device's static storage.</para>
</sect2>

<sect2>
<title>NAME: GETSTA/SETSTA</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.0in"/>
<tbody>
<row>
	<entry>NAME:</entry>
	<entry>GETSTA/SETSTA</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(U) = ADDRESS OF DEVICE STATIC STORAGE
(Y) = ADDRESS OF PATH DESCRIPTOR
(A) = STATUS CODE</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>DEPENDS UPON FUNCTION CODE</entry>
</row>
<row>
	<entry>FUNCTION:</entry>
	<entry>GET/SET DEVICE STATUS</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>
This routine is a wild card call used to get (set) the device
parameters specified in the I$GSTT and I$SSTT service requests.
Currently all of the function codes defined by Microware for SCF-type
devices are handled by IOMAN or SCFMAN. Any codes not defined
by Microware will be passed to the device driver.</para>

<para>It may be necessary to examine or change the register packet which
contains the values of the 6809 registers at the time the OS9 service
request was issued. The address of the register packet may be found
in PD.RGS, which is located in the path descriptor. The following
offsets may be used to access any particular value in the register
packet:</para>
<informaltable frame="none">
<tgroup cols="5">
<colspec colwidth="0.6in"/>
<colspec colwidth="0.6in"/>
<colspec colwidth="0.5in"/>
<colspec colwidth="0.3in" colname="c4"/>
<colspec colwidth="2.5in" colname="c5"/>
<thead>
    <row>
	<entry>OFFSET</entry>
	<entry align="left" nameend="c4">MNEMONIC</entry>
	<entry namest="c5">MPU REGISTER</entry>
    </row>
</thead>
<tbody>
<row>
    <entry>$0</entry>
    <entry>R$CC</entry>
    <entry>RMB</entry>
    <entry>1</entry>
    <entry>CONDITIONS CODE REGISTER</entry>
</row>
<row>
    <entry>$1</entry>
    <entry>R$D</entry>
    <entry>EQU</entry>
    <entry>.</entry>
    <entry>D REGISTER</entry>
</row>
<row>
    <entry>$1</entry>
    <entry>R$A</entry>
    <entry>RMB</entry>
    <entry>1</entry>
    <entry>A REGISTER</entry>
</row>
<row>
    <entry>$2</entry>
    <entry>R$B</entry>
    <entry>RMB</entry>
    <entry>1</entry>
    <entry>B REGISTER</entry>
</row>
<row>
    <entry>$3</entry>
    <entry>R$DP</entry>
    <entry>RMB</entry>
    <entry>1</entry>
    <entry>DP REGISTER</entry>
</row>
<row>
    <entry>$4</entry>
    <entry>R$X</entry>
    <entry>RMB</entry>
    <entry>2</entry>
    <entry>X REGISTER</entry>
</row>
<row>
    <entry>$6</entry>
    <entry>R$Y</entry>
    <entry>RMB</entry>
    <entry>2</entry>
    <entry>Y REGISTER</entry>
</row>
<row>
    <entry>$8</entry>
    <entry>R$U</entry>
    <entry>RMB</entry>
    <entry>2</entry>
    <entry>U REGISTER</entry>
</row>
<row>
    <entry>$A</entry>
    <entry>R$PC</entry>
    <entry>RMB</entry>
    <entry>2</entry>
    <entry>PROGRAM COUNTER</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</sect2>

<sect2>
<title>NAME. TERM</title>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.0in"/>
<tbody>
<row>
	<entry>NAME:</entry>
	<entry>TERM</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(U) = PTR TO DEVICE STATIC STORAGE</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>NONE</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
<row>
	<entry>FUNCTION:</entry>
	<entry>TERMINATE DEVICE</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This routine is called when a device is no longer in use, defined
as when its device descriptor module's link count becomes zero). It
must perform the following:</para>

<para>1. Wait until the output buffer has been emptied (by the IRQ
service routine)</para>

<para>2. Disable device interrupts.</para>

<para>3. Remove device from the IRQ polling list.</para>

<para>
NOTE: Static storage used by device drivers is never returned
to the free memory pool. Therefore, it is desirable to NEVER
terminate any device that might be used again. Modules contained in
the BOOT tile will NEVER be terminated.</para>
</sect2>

<sect2>
<title>NAME: IRQ SERVICE ROUTINE</title>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.0in"/>
<tbody>
<row>
	<entry>NAME:</entry>
	<entry>IRQ SERVICE ROUTINE</entry>
</row>
<row>
	<entry>FUNCTION:</entry>
	<entry>SERVICE DEVICE INTERRUPTS</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>
Although this routine is not included in the device drivers
branch table and not called directly from SCFMAN, it is an important
routine in device drivers. The main things that it does are:</para>

<para>1. Service the device interrupts (recieve data from device or send
data to it). This routine should put its data into and get its data
from buffers which are defined in the device static storage.</para>

<para>2. Wake up any process waiting for I/O to complete by checking
to see if there is a process ID in V.WAKE (non-zero) and it so
send a wakeup signal to that process.</para>

<para>3. If the device is ready to send more data and the output buffer
is emoty, disable the device's &quot;ready to transmit&quot;
interrupts.</para>

<para>4. If a pause character is recieved, set V.PAUS in the attached
device static storage to a non-zero value. The address of the
attached device static storage is in V.DEV2.</para>

<para>
When the IRQ service routine finishes servicing an interrupt,
it must clear the carry and exit with an RTS instruction.</para>
</sect2>
</sect1>
</chapter>


<chapter>
<title>Assembly Language Programming Techniques</title>

<para>There are four key rules for programmers writing OS-9 assembly
language programs:</para>
<orderedlist  numeration="arabic">
	<listitem><para>All programs MUST use position-independent-code (PIC). OS9
	selects load addresses based on available memory at run-time. There
	is no way to force a program to be loaded at a specific address.</para></listitem>
	<listitem><para>All programs must use the standard OS-9 memory module formats
	or they cannot be loaded and run. Programs must not use
	self-modifying code. Programs must not change anything in a memory
	module or use any part of it for variables.</para></listitem>
	<listitem><para>Storage for all variables and data structures must be within a
	data area which is assigned by OS-9 at run-time, and is separate
	from the program memory module.</para></listitem>
	<listitem><para>All input and output operations should be made using OS-9
	service request calls.</para></listitem>
</orderedlist>

<para>Fortunately, the 6809's versatile addressing modes make the rules
above easy to follow,. The OS-9 Assembler also helps because it has
special capabilities to assist the programmer in creating programs
and memory modules for the OS-9 execution environment.</para>

<sect1>
<title>How to Write Position-Independent Code</title>

<para>The 6809 instruction set was optimized to allow efficient use of
Position Independent Code (PIC). The basic technique is to always use
PC-relative addressing; for example BRA, LBRA, BSR and LBSR. Get
addresses of constants and tables using LEA instructions instead of
load immediate instructions. If you use dispatch tables, use tables
of RELATIVE, not absolute, addresses.</para>
<informaltable frame="none">
<tgroup cols="2">
<thead>
<row rowsep="1">
<entry>INCORRECT</entry>
<entry>CORRECT</entry>
</row>
</thead>
<tbody>
<row>
<entry>LDX #CONSTANT</entry>
<entry>LEAX CONSTANT,PCR</entry>
</row>
<row>
<entry>JSR SUBR</entry>
<entry>BSR SUBR or LBSR SUBR</entry>
</row>
<row>
<entry>JMP LABEL</entry>
<entry>BRA LABEL or LBRA LABEL</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</sect1>

<sect1>
<title>Addressing Variables and Data Structures</title>

<para>Programs executed as processes (by FORK and CHAIN system calls or
by the Shell) are assigned a RAM memory area for variables, stacks,
and data structures at execution-time. The addresses cannot be
determined or specified ahead of time. However, a minimum size for
this area is specified in the program's module header. Again, thanks
to the 6809's full compliment of addressing modes this presents no
problem to the OS-9 programmer.</para>

<para>When the program is first entered, the Y register will have the
address of the top of the process' data memory area. If the creating
process passed a parameter area, it will be located from the value of
the SP to the top of memory (Y), and the D register will contain the
parameter area size in bytes. If the new process was called by the
shell, the parameter area will contain the part of the shell command
line that includes the argument (parameter) text. The U register will
have the lower bound of the data memory area, and the DP register
will contain its page number.</para>

<para>The most important rule is to NOT USE EXTENDED ADDRESSING!
Indexed and direct page addressing should be used exclusively to access data
area values and structures. Do not use program-counter relative
addressing to find addresses in the data area, but do use it to refer
to addresses within the program area.</para>

<para>The most efficient way to handle tables, buffers, stacks, etc., is
to have the program's initialization routine compute their absolute
addresses using the data area bounds passed by OS-9 in the registers.
These addresses can then be saved in the direct page where they can
be loaded into registers quickly, using short instructions. This
technique has advantages: it is faster than extended addressing, and
the program is inherently reentrant.</para>
</sect1>

<sect1>
<title>Stack Requirements</title>

<para>Because OS-9 uses interrupts extensively, and also because many
reentrant 6809 programs use the MPU stack for local variable storage,
a generous stack should be maintained at all times. The recommended
minimum is approximately 200 bytes.</para>
</sect1>

<sect1>
<title>Interrupt Masks</title>

<para>User programs should keep the condition codes register F (FIRQ
mask) and I (IRQ mask) bits off. They can be set during critical
program sequences to avoid task-switching or interrupts, but this
time should be kept to a minimum. If they are set for longer than a
tick period, system timekeeping accuracy may be affected. Also, some
Level Two systems will abort programs having a set IRQ mask.</para>
</sect1>

<sect1>
<title>Writing Interrupt-driven Device Drivers</title>

<para>OS-9 programs do not use interrupts directly. Any interrupt-driven
function should be implemented as a device driver module
which should handle all interrupt-related functions. When it is
necessary for a program to be synchronized to an interrupt-causing
event, a driver can send a semaphore to a program (or the reverse)
using OS-9's <emphasis>signal</emphasis> facilities.</para>

<para>It is important to understand that interrupt service routines are
asynchronous and somewhat nebulous in that they are not distinct
processes. They are in effect subroutines called by OS-9 when an
interrupt occurs.</para>

<para>Therefore, all interrupt-driven device drivers have two basic
parts: the "mainline" subroutines that execute as part of the calling
process, and a separate interrupt service routine.</para>

<para>THE TWO ROUTINES ARE ASYNCHRONOUS AND THEREFORE MUST USE SIGNALS
FOR COMMUNICATIONS AND COORDINATION.</para>

<para>The INIT initialization subroutine within the driver package
should allocate static storage for the service routine, get the
service routine address, and execute the F$IRQ system call to add it
to the IRQ polling table.</para>

<para>When a device driver routine does something that will result in an
interrupt, it should immediately execute a F$SLEP service request.
This results in the process' deactivation. When the interrupt in
question occurs, its service routine is executed after some random
interval. It should then do the minimal amount of processing
required, and send a "wakeup" signal to its associated process using
the F$SEND service request. It may also put some data in its static
storage (I/O data and status) which is shared with its associated
"sleeping" process.</para>

<para>Some time later, the device driver "mainline" routine is awakened
by the signal, and can process the data or status returned by the
interrupt service routine.</para>
</sect1>

<sect1>
<title>Using Standard I/O Paths</title>

<para>Programs should be written to use standard I/O paths wherever
practical. Usually, this involves I/O calls that are intended to
communicate to the user's terminal, or any other case where the OS-9
redirected I/O capability is desirable.</para>

<para>All three standard I/O paths will already be open when the program
is entered (they are inherited from the parent process). Programs
should <emphasis>not</emphasis> close these paths except under very special
circumstances.</para>

<para>Standard I/O paths are always assigned path numbers zero, one, and
two, as down below:</para>

<para>Path 0 - Standard Input. Analogous to the keyboard or other main
data input source.</para>

<para>Path 1 - Standard Output. Analogous to the terminal display or other
main data output destination.</para>

<para>Path 2 - Standard Error/Status. This path is provided so output
messages which are not part of the actual program output can be kept
separate. Many times paths 1 and 2 will be directed to the same
device.</para>
</sect1>

<sect1>
<title>A Sample Program</title>

<para>The OS-9 &quot;list&quot; utility command program is shown on this
and the next page as an example of assembly language programming.</para>

<programlisting>
Microware OS-9 Assembler 2.1    01/04/82 23:39:37         Page 001
LIST - File List Utility


     *****
     *  LIST UTILITY COMMAND
     *  Syntax: list &lt;pathname&gt; 
     *  COPIES INPUT FROM SPECIFIED FILE TO STANDARD OUTPUT 
0000 87CD0048           mod LSTEND,LSTNAM,PRGRM+OBJCT,
                            REENT+1,LSTENT,LSTMEM
000D 4C6973F4   LSTNAM   fcs   "List"

     * STATIC STORAGE OFFSETS 
     *
00C8            BUFSIZ   equ   200        size of input buffer
0000                     ORG   0
0000            IPATH    rmb   1          input path number
0001            PRMPTR   rmb   2          parameter pointer
0003            BUFFER   rmb   BUFSIZ     allocate line buffer
00CB                     rmb   200        allocate stack
0193                     rmb   200        room for parameter list
025B            LSTMEM   EQU   .

0011 9F01       LSTENT   stx   PRMPTR     save parameter ptr
0013 8601                lda   #READ.     select read access mode
0015 103F84              os9   I$OPEN     open input file
0018 252E                bcs   LIST50     exit if error
001A 9700                sta   IPATH      save input path number
001C 9F01                stx   PRMPTR     save updated param ptr

001E 9600       LIST20   lda   IPATH      load input path number
0020 3043                leax  BUFFER,U   load buffer pointer
0022 10BE0C88            ldy   #BUFSIZ    maximum bytes to read
0026 103F8B              os9   I$RDLN     read line of input
0029 2509                bcs   LIST30     exit if error
002B 8601                lda   #1         load std. out. path #
002D 103F8C              os9   I$WRLN     output line
0030 24EC                bcc   LIST20     Repeat if no error
0032 2014                bra   LIST50     exit if error

0034 C1D3       LIST30   cmpb  #E$EOF     at end of file?
0036 2610                bne   LIST50     branch if not
0038 9600                lda   IPATH      load input path number
003A 103F8F              os9   I$CLOS     close input path
003D 2509                bcs   LIST50     ..exit if error
003F 9E01                ldx   PRMPTR     restore parameter ptr
0041 A684                lda   0,X
0043 810D                cmpa  #$0D       End of parameter line?
0045 26CA                bne   LSTENT     ..no; list next file
0047 5F                  clrb
0048 103F06     LIST50   os9   F$EXIT     ... terminate

004B 95BB58              emod             Module CRC

004E            LSTEND   EQU   *
</programlisting>
</sect1>
</chapter>


<chapter>
<title>Adapting OS-9 to a New System</title>

<para>Thanks to OS-9's modular structure, it is easily portable to
almost any 6809-based computer, and in fact it has been installed on
an incredible variety of hardware. Usually only device driver and
device descriptor modules need by rewritten or modified for the
target system's specific hardware devices. The larger and more
complex kernel and file manager modules almost never need adaptation.</para>

<para>One essential point is that you will need a functional OS-9
development system to use during installation of OS-9 on a new target
system. Although it is possible to use a non-OS-9 system, or if you
are truly masochistic, the target system itself, lack of facilities
to generate and test memory modules and create system disks can make
an otherwise straightforward job a time-consuming headache that is
seldom less costly than a commercial OS-9-equipped computer. Over a
dozen manufacturers offer OS-9 based development systems in all price
ranges with an excellent selection of time-saving options such as
hard disks, line printers. PROM programmers, etc.</para>

<para>Microware sells source code for standard I/O drivers, and a &quot;User
Source Code Package&quot; (On OS-9 format disk only) which contains
source code to the Kernel. Shell, INIT, SYSGO, device driver and
descriptor modules, and a selection of utility commands which can
be useful when moving OS-9 to a new target system.</para>

<para>WARNING: Standard OS-9 software packages are licensed for use on a
single system. OS-9 cannot be resold or otherwise distributed (even
if modified) without a license,. Contact Microware for information
regarding software licenses.</para>

<sect1>
<title>Adapting OS-9 to Disk-based Systems</title>

<para>Usually, most of the work in moving OS-9 to a disk-based target
system is writing a device driver module for the target system's disk
controller. Part of this task involves producing a subset of the
driver (mostly disk read functions) for use as a bootstrap module.</para>

<para>If terminal and/or parallel I/O for terminals, printers, etc.,
will use ACIA and/or PIA-type devices, the standard ACIA and PIA
device driver modules may be used, or device drivers of your own
design may be used in place of or in addition to these standard
modules Device descriptor modules may also require adaptation to
match device addresses and initialization required by the target
system.</para>

<para>A CLOCK module may be adapted from a standard version, or a new
one may be created. All other component modules, such as IOMAN,
RBFMAN, SCFMAN, SHELL, and utilities seldom require modification.</para>
</sect1>

<sect1>
<title>Using OS-9 in ROM-based Systems</title>

<para>One of OS-9's major features is its ability to reside in ROM
memory and work effectively with ROMed applications programs written
in assembler or high-level languages such as Basic09, Pascal, and C.</para>

<para>All the component modules of OS-9 (including all commands and
utilities) are directly ROMable without modification. In some cases,
particularly when the target system is to automatically execute an
application program upon system start-up, it may be necessary to
reassemble the two modules used during system startup, INIT and SYSGO.</para>

<para>The first step in designing a ROM-based system is to select which
OS-9 modules to include in ROM. The following checklist is designed
to help you do so:</para>
<orderedlist  numeration="loweralpha">
    <listitem><para>Include OS9P1, OS9P2, SYSGO, and INIT. These modules are
    required in any OS-9 system.</para></listitem>

    <listitem><para>If the target system is perform any I/O or interrupt
    functions include IOMAN.</para></listitem>

    <listitem><para>If the target system is to perform I/O to character-oriented
    I/O devices using ACIAs, PIAs, etc., include SCFMAN, required
    device drivers (such as ACIA and PIA, and/or your own), and device
    descriptors as needed (such as TERM, T1, P, and/or your own). If
    device addresses and/or initialization functions need to be changed,
    the device descriptor modules must be modified before being ROMed.</para></listitem>

    <listitem><para>If the target system is to perform disk I/O, include RBFMAN,
    and appropriate disk driver and device descriptor modules. As in (c)
    above, change device addresses and initialization if needed. If
    RBFMAN <emphasis>will not</emphasis> be included, the INIT and SYSGO modules
    <emphasis>must</emphasis> be
    altered to remove references to disk files.</para></listitem>

    <listitem><para>If the target system requires multiprogramming, time-of-day,
    or other time-related functions, include a CLOCK module for the
    target system's real-time clock. Also consider how the clock is to
    be started,. You may want to ROM the &quot;Setime&quot; command, or
    have SYSGO start the clock.</para></listitem>

    <listitem><para>It the target system will receive commands manually, or if
    any application program uses Shell functions, include the SHELL and
    SYSGO modules, otherwise include a modified SYSGO module which calls
    your application program instead of Shell.</para></listitem>
</orderedlist>
</sect1>

<sect1>
<title>Adapting the Initialization Module</title>

<para>INIT is a module that contains system startup parameters.
It <emphasis>must</emphasis> be
in ROM in any OS-9 system (it usually resides in the same ROM as the
kernel). It is a non-executable module named "INIT" and has type
"system" (code $C). It is scanned once during the system startup. It
begins with the standard header followed by:</para>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.1in"/>
<colspec colwidth="3.9in"/>
<thead>
<row>
<entry>MODULE OFFSET</entry>
<entry></entry>
</row>
</thead>
<tbody>
<row>
<entry>$9,$A,$B</entry>
<entry>This location contains an upper limit RAM memory address
used to override OS-9's automatic end-of-RAM search so that memory
may be reserved for I/O device addresses or other special purposes.</entry>
</row>
<row>
<entry>$C</entry>
<entry>Number of entries to create in the IRQ polling table. One entry is
required for each interrupt- generating device control register.</entry>
</row>
<row>
<entry>$D</entry>
<entry>Number of entries to create in the system device table. One entry
is required for each device in the system.</entry>
</row>
<row>
<entry>$E,$F</entry>
<entry>Offset to a string which is the name of the first module to
be executed after startup, usually &quot;SYSG0&quot;. There must
always be a startup module.</entry>
</row>
<row>
<entry>$10,$11</entry>
<entry>Offset to the default
directory name string (normally /D0). This device is assumed when
device names are omitted from pathlists. If the system will not use
disks (e.g., RBFMAN will not be used) this offset <emphasis>must</emphasis>be
zero.</entry>
</row>
<row>
<entry>$12,$13</entry>
<entry>Offset to the initial standard path string
(typically /TERM). This path is opened as the standard paths for the
initial startup module. This offset <emphasis>must</emphasis> contain zero if there
is none.</entry>
</row>
<row>
<entry>$14,$15</entry>
<entry>Offset to bootstrap module name string. If OS-9 does not
find IOMAN in ROM during the start-up module search, it will execute
the bootstrap module named to load additional modules from a file on
a mass-storage device.</entry>
</row>
<row>
<entry>$16 to N</entry>
<entry>All name strings referred to above go here. Each must
have the sign bit (bit 7) of the last character set.</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</sect1>

<sect1>
<title>Adapting the SYSGO Module</title>

<para>SYSGO is a program which is the first process started after the
system start-up sequence. Its function is threefold:</para>

<itemizedlist mark="bullet">
<listitem><para>It does additional high-level system initialization, for
example, disk system SYSGO call the shell to process the &quot;Startup&quot;
shell procedure file.</para></listitem>

<listitem><para>It starts the first "user" process.</para></listitem>

<listitem><para>It thereafter remains in a "wait" state as insurance against all
user processes terminating, thus leaving the system halted. If this
happens. SYSGO can restart the first user program.</para></listitem>
</itemizedlist>

<para>The standard SYSGO module for disk systems cannot be used on
non-disk based systems unless it is modified to:</para>

<orderedlist  numeration="arabic">
<listitem><para>Remove initialization of the working execution directory.</para></listitem>

<listitem><para>Remove processing of the "Startup" procedure file.</para></listitem>

<listitem><para>Possibly change the name of the first user program from Shell
to the name of a applications program. Here are some example name strings:</para>

    <informaltable frame="none">
    <tgroup cols="2">
    <tbody>
    <row>
	<entry>fcs /userpqm/</entry>
	<entry>(object code module &quot;userpgm&quot;)</entry>
    </row>
    <row>
	<entry>fcs /RunB userpgm/</entry>
	<entry>(compiled Basie09 program using RunB run-time-only system)</entry>
    </row>
    <row>
	<entry>fcs /Basic09 userpgm/</entry>
	<entry>(compiled Basic09 program using Basic09)</entry>
    </row>
    </tbody>
    </tgroup>
    </informaltable>
</listitem>
</orderedlist>
</sect1>
</chapter>


<chapter>
<title>OS-9 Service Request Descriptions</title>

<para>System calls are used to communicate between the OS-9 operating
system and assembly-language-level programs. There are three general
categories:</para>

<para><literallayout>
1. User mode function requests
2. System mode function requests
3. I/O requests
</literallayout></para>

<para>System mode function requests are privileged and may be executed
only while OS-9 is in the system state (when it is processinq another
service request, executing a file manager, device drivers, etc.).
They are included in this manual primarily for the benefit of those
programmers who will be writing device drivers and other system-level
applications.</para>

<para>The system calls are performed by loading the MPU registers with
the appropriate parameters (if any), and executing a SWI2
instruction immediately followed by a constant byte which is the
request code. Parameters (if any) will be returned in the MPU
registers after OS-9 has processed the service request. A standard
convention for reporting errors is used in all system calls; if an
error occurred, the "C bit" of the condition code register will be
set and accumulator B will contain the appropriate error code. This
permits a BCS or BCC instruction immediately following the system
call to branch on error/no error.</para>

<para>Here is an example system call for the "CLOSE" service request:</para>

<programlisting>
LDA PATHNUM 
SWI2 
FCB $8B 
BCS ERROR 
</programlisting>

<para>Using the assembler's "OS9" directive simplifies the call:</para>

<programlisting>
LDA PATHNUM 
OS9 I$CLOS 
BCS ERROR 
</programlisting>

<para>The I/O service requests are simpler to use than in many other
operating systems because the calling program does not have to
allocate and set up &quot;file control blocks&quot;, &quot;sector
buffers&quot;, etc. Instead OS-9 will return a one byte path number
when a path to a file/device is opened or created; then this path
number may be used in subsequent I/O requests to identify the
file/device until the path is closed. OS-9 internally allocates and
maintains its
own data structures and users never have to deal
with them: in fact attempts to do so are memory violations.</para>

<para>All system calls have a mnemonic name that starts with &quot;F$&quot;
for system functions, or &quot;I$&quot; for I/O related requests.
These are defined in the assembler-input equate file
called &quot;OS9DEFS&quot;.</para>

<para>In the service request descriptions which follow, registers not
explicitly specified as input or output parameters are not altered.
Strings passed as parameters are normally terminated by having bit
seven of the last character set, a space character, or an end of line
character.</para>


<sect1>
<title>ABIT Set bits in an allocation bit map F$ABIT</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$ABIT</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 13</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(X) = Base address of allocation bit map.
(D) = Bit number of first bit to set.
(Y) = Bit count (number of bits to set)</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This system mode service request sets bits in the allocation bit
map specified by the X register.</para>

<para>Bit numbers range from 0..N-1, where N is the number of bits in
the allocation bit map.</para>
</sect1>

<sect1>
<title>CHAIN Load and execute a new primary module F$CHAN</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$CHAN</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 05</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(X) = Address of module name or file name
(Y) = Parameter area size (256 byte pages)
(U) = Beginning address of parameter area
(A) = Lanquage / type code
(B) = Optional data area size (256 byte pages)</literallayout></entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This system call is similar to FORK, but it does not create a new
process. It effectively "resets" the calling process' program and
data memory areas and begins execution of a new primary module. Open
paths are not closed or otherwise affected.</para>

<para>This system call is used when it is necessary to execute an
entirely new program, but without the overhead of creating a new
process. It is functionally similar to a FORK followed by an EXIT.
but with less processing overhead.</para>

<para>The sequence of operations taken by CHAIN is as follows:
</para>

<para>1. The system parses the name string ot the new proces'
"primary module" - the program that will initially be executed. Then
the system module directory is searched to see if a module with the
same name and type / language is already in memory. If so it is
linked to. If not, the name string is used as the pathlist of a file
which is to be loaded into memory. Then the first module in this file
is linked to (several modules may have been loaded from a single
file).</para>

<para>2. The process' old primary module is UNLINKED.</para>

<para>3. The data memory area is reconfigured to the size specified in
the new primary module's header.</para>

<para>The diagram below shows how CHAIN sets up the data memory area and
registers for the new module.</para>
<informalfigure>
<screen>
   +-----------------+  &lt;--  Y          (highest address)
   !                 !
   !   Parameter     !
   !     Area        !
   !                 !
   +-----------------+  &lt;-- X, SP
   !                 !
   !                 !
   !   Data Area     !
   !                 !
   !                 !
   +-----------------+
   !   Direct Page   !
   +-----------------+  &lt;-- U, DP       (lowest address)

   D = parameter area size
  PC = module entry point abs. address
  CC = F=0, I=0, others undefined
</screen>
</informalfigure>

<para>Y (top of memory pointer) and U (bottom of memory pointer) will
always have a values at 256-byte page boundaries. If the parent does
not specify a parameter area, Y, X, and SP will be the same, and D
will equal zero. The minimum overall data area size is one page (256
bytes).</para>

<para>
WARNING: The hardware stack pointer (SP) should be located
somewhere in the direct page before the F$CHAN service request is
executed to prevent a "suicide attempt" error or an actual suicide
(system crash). This will prevent a suicide from occurring in case
the new module requires a smaller data area than what is currently
being used. You should allow approximately 200 bytes of stack space
for execution of the F$CHAN service request and other system
"overhead".</para>

<para>
For more information, please see the F$FORK service request
description.</para>
</sect1>

<sect1>
<title>COMPARE NAMES Compare two names F$CNAM</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$CNAM</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 11</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(X) = Address of first name.
(B) = Length of first name.
(Y) = Address of second name.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(CC) = C bit clear if the strings match.</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>
Given the address and length of a string, and the address of a
second string, compares them and indicates whether they match.
Typically used in conjunction with "parsename".</para>

<para>The second name must bave the sign bit (bit 7) of the last
character set.</para>
</sect1>

<sect1>
<title>CRC Compute CRC F$CRC</title>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$CRC</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 17</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(X) = Starting byte address.
(Y) = Byte count.
(U) = Address of 3 byte CRC accumulator.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>CRC accumulator is updated.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry>None.</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This service request calculates the CRC (cyclic redundancy count)
for use by compilers, assemblers, or other module generators. The CRC
is calculated starting at the source address over "byte count" bytes,
it is not necessary to cover an entire module in one call, since the
CRC may be "accumulated" over several calls. The CRC accumulator can
be any three byte memory location and must be initialized to $FFFFFF
before the first F$CRC call.</para>

<para>The last three bytes in the module (where the three CRC bytes will
be stored) are not included in the CRC generation.</para>
</sect1>

<sect1>
<title>DBIT Deallocate in a bit map F$DBIT</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$DBIT</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 14</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(X) = Base address of an allocation bit map.
(D) = Bit number of first bit to clear.
(Y) = Bit count (number of bits to clear).</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This system mode service request is used to clear bits in the
allocation bit map pointed to by X.</para>

<para>Bit numbers range from 0..N-1, where N is the number of bits in
the allocation bit map.</para>
</sect1>

<sect1>
<title>EXIT Terminate the calling process. F$EXIT</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$EXIT</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 06</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(B) = Status code to be returned to the parent process</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>Process is terminated.</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This call kills the calling process and is the only means by which
a process can terminate itself. Its data memory area is deallocated,
and its primary module is UNLINKed. All open paths are automatically
closed.</para>

<para>The death of the process can be detected by the parent executing a
WAIT call, which returns to the parent the status byte passed by the
child in its EXIT call. The status byte can be an OS-9 error code the
terminating process wishes to pass back to its parent process (the
shell assumes this), or can be used to pass a user-defined status
value. Processes to be called directly by the shell should only
return an OS-9 error code or zero if no error occurred.</para>
</sect1>

<sect1>
<title>FORK Create a new process. F$FORK</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$FORK</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 03</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(X) = Address of module name or file name.
(Y) = Parameter area size.
(U) = Beginning address of the parameter area.
(A) = Language / Type code.
(B) = Optional data area size (pages).</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry><literallayout>(X) = Updated past the name string.
(A) = New process ID number.</literallayout></entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This system call creates a new process which becomes a "child" of
the caller, and sets up the new process' memory and MPU registers.</para>

<para>The system parses the name string of the new process' &quot;primary
module&quot; - the program that will initially be executed. Then the
system module directory is searched to see if the program is already
in memory. If so, the module is linked to and executed. If not, the
name string is used as the pathlist of the file which is to loaded
into memory. Then the first module in this file is linked to and
executed (several modules may have been loaded from a single file).</para>

<para>The primary module's module header is used to determine the
process' initial data area size. OS-9 then attempts to allocate a
contiguous RAM area equal to the required data storage size,
(includes the parameter passing area, which is copied from the parent
process' data area). The new process' registers are set up as shown
in the diagram on the next page. The execution offset given in the
module header is used to set the PC to the module's entry point.</para>

<para>When the shell processes a command line it passes a string in the
parameter area which is a copy of the parameter part (if any) of the
command line. It also inserts an end-of-line character at the end of
the parameter string to simplify string-oriented processing. The X
register will point to the beginning of the parameter string. If the
command line included the optional memory size specification (#n or
#nK), the shell will pass that size as the requested memory size when
executing the FORK.</para>

<para>If any of the above operations are unsuccessful, the FORK is
aborted and the caller is returned an error.</para>

<para>The diagram below
shows how FORK sets up the data memory area and registers for a
newly-created process.</para>

<informalfigure>
<screen>
   +-----------------+  &lt;--  Y          (highest address)
   !                 !
   !   Parameter     !
   !     Area        !
   !                 !
   +-----------------+  &lt;-- X, SP
   !                 !
   !                 !
   !   Data Area     !
   !                 !
   !                 !
   +-----------------+
   !   Direct Page   !
   +-----------------+  &lt;-- U, DP       (lowest address)

   D = parameter area size
  PC = module entry point abs. address
  CC = F=0, I=0, others undefined
</screen>
</informalfigure>

<para>Y (top of memory pointer) and U (bottom of memory pointer) will
always have a values at 256-byte page boundaries. If the parent does
not specify a parameter area, Y, X, and SP will be the same, and D
will equal zero. The minimum overall data area size is one page (256
bytes). Shell will always pass at least an end of line character in
the parameter area.</para>

<para>NOTE: Both the child and parent process will execute
concurrently. If the parent executes a F$WAIT call
immediately after the fork, it will wait until the child dies before
it resumes execution. Caution should be exercised when recursively
calling a program that uses the F$FORK service request since another
child may be created with each &quot;incarnation&quot;. This will
continue until the process table becomes full.</para>
</sect1>

<sect1>
<title>INTERCEPT Set up a signal intercept trap. F$ICFT</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$ICFT</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 09</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(X) = Address of the intercept routine.
(U) = Address of the intercept routine local storage.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This system call tells OS-9 to set a signal intercept trap, where
X contains the address of the signal handler routine, and U contains
the base address of the routine's storage area. After a signal trap
has been set, whenever the process receives a signal, its intercept
routine will be executed. A signal will abort any process which has
not used the F$ICPT service request to set a signal trap, and its
termination status (B register) will be the signal code. Many
interactive programs will set up an intercept routine to handle
keyboard abort (control Q), and keyboard interrupt (control C).</para>

<para>The intercept routine is entered asynchronously because a signal
may be sent at any time (it is like an interrupt) and is passed the
following: 
</para>

<para>U = Address of intercept routine local storage.</para>

<para>B = Signal code.</para>

<para>NOTE: The value of DP may not be the same as it was when the
F$ICFT call was made.</para>

<para>Whenever a signal is received. OS-9 will pass the signal code and
the base address of its data area (which was defined by a F$ICPT
service request) to the signal intercept routine. The base address of
the data area is selected by the user and is typically a pointer to
the process' data area.</para>

<para>The intercept routine is activated when a signal is received, then
it takes some action based upon the value of the signal code such as
setting a flag in the process' data area. After the signal has been
processed, the handler routine should terminate with an RTI
instruction.</para>
</sect1>

<sect1>
<title>GET ID Get process ID / user ID F$ID</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$ID</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 0C</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>None</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry><literallayout>(A) = Process ID.
(Y) = User ID.</literallayout></entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Returns the caller's process ID number, which is a byte value in
the range of 1 to 255, and the user ID which is a integer in the
range 0 to 65535. The process ID is assigned by OS-9 and is unique to
the process. The user ID is defined in the system password file, and
is used by the file security system and a few other functions.
Several processes can have the same user ID.</para>
</sect1>

<sect1>
<title>LINK Link to memory module. F$LINK</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$LINK</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 00</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(X) = Address of the module name string.
(A) = Module type / language byte.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry><literallayout>(X) = Advanced past the module name.
(Y) = Module entry point absolute address.
(U) = Module header absolute address.
(A) = Module type / language.
(B) = Module attributes / revision level.</literallayout></entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This system call causes OS-9 to search the module directory for a
module having a name, language and type as given in the parameters.
If found, the address of the module's header is returned in U, and
the absolute address of the module's execution entry point is
returned in Y (as a convenience: this and other information can be
obtained from the module header). The module's link count' is
incremented whenever a LINK references its name, thus keeping track
of how many processes are using the module. If the module requested
has an attribute byte indicating it is not sharable (meaning it is
not reentrant) only one process may link to it at a time.</para>

<para>Possible errors:</para>

<para>(A) Module not found.</para>

<para>(B) Module busy (not sharable and in use).</para>

<para>(C) Incorrect or defective module header.</para>
</sect1>

<sect1>
<title>LOAD Load module(s) from a file, F$LOAD</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$LOAD</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 01</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(X) = Address of pathlist (file name)
(A) = Language / type (0 = any language / type)</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry><literallayout>(X) = Advanced past pathlist
(Y) = Primary module entry point address
(U) = Address of module header
(A; - Language / type
(B) = Attributes / revision level</literallayout></entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Opens a file specified by the pathlist, reads one or more memory
modules from the file into memory, then closes the file. All modules
loaded are added to the system module directory, and the first
module read is LINKed. The parameters returned are the same as the
LINK call and apply only to the first module loaded.</para>

<para>In order to be loaded, the file must have the &quot;execute&quot;
permission and contain a module or modules that have a proper module
header. The file will be loaded from the working execution directory
unless a complete pathlist is given.</para>

<para>Possible errors: module directory full; memory full; plus errors
that occur on OPEN, READ, CLOSE and LINK system calls.</para>
</sect1>

<sect1>
<title>MEM Resize data memory area, F$MEM</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$MEM</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 07</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(D) = Desired new memory area size in bytes</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry><literallayout>(Y) = Address of new memory area upper bound
(D) = Actual new memory area size in bytes</literallayout></entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Used to expand or contract the process' data memory area. The new
size requested is rounded up to the next 256-byte page boundary.
Additional memory is allocated contiguously upward (towards higher
addresses), or deallocated downward from the old highest address. If
D = 0, then the current upper bound and size will be returned.</para>

<para>This request can never return all of a process' memory, or the
page in which its SP register points to.</para>

<para>In Level One systems, the request may return an error upon an
expansion request even though adequate free memory exists. This is
because the data area is always made contiguous, and memory requests
by other processes may fragment free memory into smaller, scattered
blocks that are not adjacent to the caller's present data area. Level
Two systems do not have this restriction because of the availability
of hardware for memory relocation, and because each process has its
own &quot;address space&quot;.</para>
</sect1>

<sect1>
<title>PRERR Print error message. F$PERR</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$PERR</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 0F</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(A) = Output path number.
(B) = Error code.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This is the system's error reporting utility. It writes an error
message to the output path specified. Most OS-9 systems will display:</para>

<para>ERROR #&lt;decimal number&gt;
</para>

<para>by default. The error reporting routine is vectored and can be
replaced with a more elaborate reporting module. To replace this
routine use the F$SSVC service request.</para>
</sect1>

<sect1>
<title>PARSENAME Parse a path name, F$PNAM</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$PNAM</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 10</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(X) = Address of the pathlist</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry><literallayout>(X) = Updated past the optional "/"
(Y) = Address of the last character of the name + 1.
(B) = Length of the name
</literallayout></entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.
(X) = Updated past space characters.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Parses the input text string for a legal OS-9 name. The name is
terminated by any character that is not a legal component character.
This system call is useful for processing pathlist arguments passed
to new processes. Also if X was at the end of a pathlist, a bad name
error will be returned and X will be moved past any space characters
so that the next pathlist in a command line may be parsed.</para>

<para>Note that this system call processes only one name, so several
calls may be needed to process a pathlist that has more than one name.</para>

<para>BEFORE F$PNAM CALL:</para>
<screen>
+---+---+---+---+---+---+---+---+---+---+---+---+---
! / ! D ! 0 ! / ! F ! I ! L ! E !   !   !   !   !
+---+---+---+---+---+---+---+---+---+---+---+---+---
  ^
  X
</screen>
<para>AFTER THE F$PNAM CALL:</para>
<screen>
+---+---+---+---+---+---+---+---+---+---+---+---+---
! / ! D ! 0 ! / ! F ! I ! L ! E !   !   !   !   !
+---+---+---+---+---+---+---+---+---+---+---+---+---
      ^       ^
      X       Y       (B) = 2
</screen>
</sect1>

<sect1>
<title>SBMAP Search bit map for a free area F$SBIT</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$SBIT</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 12</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(X) = Beginning address of a bit map.
(D) = Beginning bit number.
(Y) = Bit count (free bit block size).
(U) = End of bit map address.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry><literallayout>(D) = Beginning bit number.
(Y) = Bit count.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This system mode service request searches the specified allocation
bit map starting at the &quot;beginning bit number&quot; for a free
block (cleared bits) of the required length.</para>

<para>If no block of the specified size exists, it returns with the
carry set, beginning bit number and size of the largest block.</para>
</sect1>

<sect1>
<title>SEND Send a signal to another process, F$SEND</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$SEND</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 08</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(A) = Receiver's process ID number.
 (B) = Signal code.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This system call sends a &quot;signal&quot; to the process
specified. The signal code is a single byte value of 1 - 255.</para>

<para>If the signal's destination process is sleeping or waiting, it
will be activated so that it may process the signal. The signal
processing routine (intercept) will be executed if a signal trap was
set up (see F$ICPT), otherwise the signal will abort the destination
process, and the signal code becomes the exit status (see WAIT). An
exception is the WAKEUP signal, which activates a sleeping process
but does not cause the signal intercept routine to be executed.</para>

<para>Some of the signal codes have meanings defined by convention: 
</para>

<literallayout>
0 = System Abort (cannot be intercepted)
1 = Wake Up Process
2 = Keyboard Abort
3 = Keyboard Interrupt
4-255 = user defined
</literallayout>

<para>If an attempt is made to send a signal to a process that has an
unprocessed, previous signal pending, the current &quot;send&quot;
request will be cancelled and an error will be returned. An attempt
can be made to re-send the signal later. It is good practice to issue
a &quot;sleep&quot; call for a few ticks before a retry to avoid
wasting MPU time.</para>

<para>For related information see the F$ICPT, F$WAIT and F$SLEP service
request descriptions.</para>
</sect1>

<sect1>
<title>SLEEP Put calling process to sleep. F$SLEP</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$SLEP</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 0A</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(X) = Sleep time in ticks (0 = indefinitely)</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(X) = Decremented by the number of ticks that the process was asleep.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This call deactivates the calling process for a specified time, or
indefinitely if X = 0. If X = 1, the effect is to have the caller
give up its current time slice. The process will be activated before
the full time interval if a signal is received, therefore sleeping
indefinitely is a good way to wait for a signal or interrupt without
wasting CPU time.</para>

<para>The duration of a "tick" is system dependent but is most commonly
100 milliseconds.</para>

<para>Due to the fact that it is not known when the F$SLEP request was
made during the current tick, F$SLEP can not be used for precise
timing. A sleep of one tick is effectively a &quot;give up remaining
time slice&quot; request; the process is immediately inserted into
the active process queue and will resume execution when it reaches
the front of the queue. A sleep of two or more ticks causes the
process to be inserted into the active process queue after N-1 ticks
occur and will resume execution when it reaches the front of the
queue.</para>
</sect1>

<sect1>
<title>SETPR Set process priority. F$SPRI</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$SPRI</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 0D</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(A) = Process ID number.
(B) = Priority:
       0 = lowest
       255 - highest</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Changes the process' priority to the new value given. $FF is the
highest possible priority, $00 is the lowest. A process can change
another process' priority only if it has the same user ID.</para>
</sect1>

<sect1>
<title>SSVC Install function request F$SSVC</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$SSVC</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 32</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(Y) = Address of service request initialization table.</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This system mode service request is used to add a new function
request to OS-9's user and privileged system service request tables,
or to replace an old one. The Y register passes the address of a
table which contains the function codes and offsets to the
corresponding service request handler routines. This table has the
following format:</para>

<screen>
OFFSET

          +----------------------+
 $00      !     Function Code    !  &lt;--- First entry
          +----------------------+
 $01      ! Offset From Byte 3   !
          +--                  --+
 $02      !  To Function Handler !
          +----------------------+
 $03      !     Function Code    !  &lt;--- Second entry
          +----------------------+
 $04      ! Offset From Byte 6   !
          +--                  --+
 $05      !  To Function Handler !
          +----------------------+
          !                      !   &lt;--- Third entry etc.
          !     MORE ENTRIES     !
          !                      !
          !                      !
          +----------------------+
          !         $80          !   &lt;--- End of table mark
          +----------------------+
</screen>

<para>NOTE: If the sign bit of the function code is set, only the system
table will be updated. Otherwise both the system and user tables will
be updated. Privileged system service requests may be called only
while executing a system routine.</para>

<para>The service request handler
routine should process the service request and return from subroutine
with an RTS instruction. They may alter all MPU registers (except for
SP). The U register will pass the address of the register stack to
the service request handler as shown in the following diagram:
</para>
<informalfigure>
<screen>
                         OFFSET   OS9DEFS
                                  MNEMONIC
        +------+
U ---&gt;  !  CC  !            $0      R$CC
        +------+            $1      R$D
        !  A   !            $1      R$A
        +------+
        !  B   !            $2      R$B
        +------+
        !  DP  !            $3      R$DP
        +------+------+
        !      X      !     $4      R$X
        +-------------+
        !      Y      !     $6      R$Y
        +-------------+
        !      U      !     $8      R$U
        +-------------+
        !      PC     !     $A      R$PC
        +-------------+
</screen>
</informalfigure>

<para>Function request codes are broken into the two categories
as shown below:</para>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.5in"/>
<colspec colwidth="3.5in"/>
<tbody>
<row>
<entry>$00 - $27</entry>
<entry>User mode service request codes.</entry>
</row>
<row>
<entry>$29 - $34</entry>
<entry>Privileged system mode service request codes.
When installing these service
request, the sign bit should be set if it is to be placed
into the system table only.</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>
NOTE: These categories are defined by convention and not
enforced by OS9.</para>

<para>
Codes $25..$27, and $70..$7F will not be used by MICROWARE and
are free for user definition.</para>
</sect1>

<sect1>
<title>SETSWI Set SWI vector. F$SSWI</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$SSWI</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 0E</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(A) = SWI type code.
(X) = Address of user SWI service routine.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Sets up the interrupt vectors for SWI, SWI2 and SWI3 instructions.
Each process has its own local vectors. Each SETSWI call sets up one
type of vector according to the code number passed in A.</para>

<literallayout>
1 = SWI 
2 = SWI2 
3 = SWI3 
</literallayout>

<para>When a process is created, all three vectors are initialized with
the address of the OS-9 service call processor.</para>

<para>WARNING: Microware-supplied software uses SWI2 to call OS-9. If
you reset this vector these programs will not work. If you change all
three vectors, you will not be able to call OS-9 at all.</para>
</sect1>

<sect1>
<title>SETIME Set system date and time. F$STIM</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$STIM</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 16</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(X) = Address of time packet (see below)</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>Time/date is set.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This service request is used to set the current system date/time
and start the system real-time clock. The date and time are passed in
a time packet as follows:</para>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1in"/>
<colspec colwidth="1.5in"/>
<thead>
<row rowsep="1">
  <entry>OFFSET</entry>
  <entry>VALUE</entry>
</row>
</thead>

<tbody>
<row>
  <entry colsep="1">0</entry> <entry>year</entry>
</row>
<row>
  <entry colsep="1">1</entry> <entry>month</entry>
</row>
<row>
  <entry colsep="1">2</entry> <entry>day</entry>
</row>
<row>
  <entry colsep="1">3</entry> <entry>hours</entry>
</row>
<row>
  <entry colsep="1">4</entry> <entry>minutes</entry>
</row>
<row>
  <entry colsep="1">5</entry> <entry>seconds</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</sect1>

<sect1>
<title>TIME Get system date and time. F$TIME</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$TIME</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 15</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(X) = Address of place to store the time packet.</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>Time packet (see below).</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This returns the current system date and time in the form of a six
byte packet (in binary). The packet is copied to the address passed
in X. The packet looks like:</para>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1in"/>
<colspec colwidth="1.5in"/>
<thead>
<row rowsep="1">
  <entry>OFFSET</entry>
  <entry>VALUE</entry>
</row>
</thead>

<tbody>
<row>
  <entry colsep="1">0</entry> <entry>year</entry>
</row>
<row>
  <entry colsep="1">1</entry> <entry>month</entry>
</row>
<row>
  <entry colsep="1">2</entry> <entry>day</entry>
</row>
<row>
  <entry colsep="1">3</entry> <entry>hours</entry>
</row>
<row>
  <entry colsep="1">4</entry> <entry>minutes</entry>
</row>
<row>
  <entry colsep="1">5</entry> <entry>seconds</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</sect1>

<sect1>
<title>UNLINK Unlink a module. F$UNLK</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$UNLK</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 02</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(U) = Address of the module header.</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Tells OS-9 that the module is no longer needed by the calling
process. The module's link count is decremented, and the module is
destroyed and its memory deallocated when the link count equals zero.
The module will not be destroyed if in use by any other process(es)
because its link count will be non-zero. In Level Two systems, the
module is usually switched out of the process' address space.</para>

<para>Device driver modules in use or certain system modules cannot he
unlinked. ROMed modules can be unlinked but cannot be deleted from
the module directory.</para>
</sect1>

<sect1>
<title>WAIT Wait for child process to die. F$WAIT</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$WAIT</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 04</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>None</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry><literallayout>(A) = Deceased child process' process ID
(B) = Child process' exit status code</literallayout></entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>The calling process is deactivated until a child process
terminates by executing an EXIT system call, or by receiving a
signal. The child's ID number and exit status is returned to the
parent. If the child died due to a signal, the exit status byte (B
register) is the signal code.</para>

<para>If the caller has several children, the caller is activated when
the first one dies, so one WAIT system call is required to detect
termination of each child.</para>

<para>If a child died before the WAIT call, the caller is reactivated
almost immediately. WAIT will return an error if the caller has no
children.</para>

<para>See the EXIT description for more related information.</para>
</sect1>


<sect1>
<title>A64 Allocate a 64 byte memory block F$A64</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$A64</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 30</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(X) = Base address of page table (zero if the page table
has not yet been allocated).</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry><literallayout>(A) = Block number
(X) = Base address of page table
(Y) = Address of block.</literallayout></entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This system mode service request is used to dynamically allocate
64 byte blocks of memory by splitting whole pages (256 byte) into
tour sections. The first 64 bytes of the base page are used as a
&quot;page table&quot;, which contains the MSB of all pages in the
memory structure. Passing a value of zero in the X register will
cause the F$A64 service request to allocate a new base page and the
first 64 byte memory block. Whenever a new page is needed, an F$SRQM
service request will automatically be executed. The first byte of
each block contains the block number; routines using this service
request should not alter it. Below is a diagram to show how 7 blocks
might be allocated:</para>
<informalfigure>
<screen>
                   ANY 256 BYTE            ANY 256 BYTE
                   MEMORY PAGE             MEMORY PAGE
BASE PAGE  ---&gt;   +-------------+         +-------------+
                  !             !         !X            !
                  !  PAGE TABLE !         !   BLOCK 4   !
                  !  (64 bytes) !         !  (64 bytes) !
                  +-------------+         +-------------+
                  !X            !         !X            !
                  !   BLOCK 1   !         !   BLOCK 5   !
                  !  (64 bytes) !         !  (64 bytes) !
                  +-------------+         +-------------+
                  !X            !         !X            !
                  !   BLOCK 2   !         !   BLOCK 6   !
                  !  (64 bytes) !         !  (64 bytes) !
                  +-------------+         +-------------+
                  !X            !         !X            !
                  !   BLOCK 3   !         !   BLOCK 7   !
                  !  (64 bytes) !         !  (64 bytes) !
                  +-------------+         +-------------+
</screen>
</informalfigure>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>APRC Insert process in active process queue F$APRC</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$APRC</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 2C</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(X) = Address of process descriptor.</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This system mode service request inserts a process into the active
process queue so that it may be scheduled for execution.</para>

<para>All processes already in the active process queue are aged, and
the age of the specified process is set to its priority. If the
process is in system state, it is inserted after any other process's
also in system state, but before any process in user state. If the
process is in user state, it is inserted according to its age.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>FIND-64 Find a 64 byte memory block F$F64</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$F64</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 2F</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(X) = Address of base page.
(A) = Block number.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(Y) = Address of block.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This system mode service request will return the address of a 64
byte memory block as described in the F$A64 service request. OS-9
used this service request to find process descriptors and path
descriptors when given their number.</para>

<para>Block numbers range from 1..N</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>IODEL Delete I/O device from system F$IODL</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$IODL</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 33</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(X) = Address of an I/O module, (see description).</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This system mode service request is used to determine whether or
not an I/O module is being used. The X register passes the address of
a device descriptor module, device driver module, or file manager
module. The address is used to search the device table, and if found
the use count is checked to see if it is zero. If it is not zero, an
error condition is returned.</para>

<para>This service request is used primarily by IOMAN and may be of
limited or no use for other applications.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>IOQUEUE Enter I/O queue F$IOQU</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$IOQU</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 2B</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(A) = Process Number.</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This system mode service request links the calling process into
the I/O queue of the specified process and performs an untimed sleep.
It is assumed that routines associated with the specified process
will send a wakeup signal to the calling process.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>SETIRQ Add or remove device from IRQ table. F$IRQ</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$IRQ</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 2A</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(X) = Zero to remove device from table, or the address of a
packet as defined below to add a device to the IRQ polling table:

        [x] = flip byte
        [X+1] = mask byte
        [X+2] = priority
(U) = Address of service routine's static storage area.
(Y) = Device IRQ service routine address.
(D) = Address of the device status register.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This service request is used to add a device to or remove a device
from the IRQ polling table. To remove a device from the table the
input should be (X)=0, (U)= Addr of service routine's static storage.
This service request is primarily used by device driver routines. See
the text of this manual for a complete discussion of the interrupt
polling system.</para>

<para>PACKET DEFINITIONS:</para>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.5in"/>
<colspec colwidth="3.5in"/>
<tbody>
<row>
<entry>Flip Byte</entry>
<entry>This byte selects whether the bits in the device status
register are active when set or active when
cleared. A set bit(s) identifies the active bit(s).</entry>
</row>

<row>
<entry>Mask Byte</entry>
<entry>This byte selects one or more bits within the device
status register that are interrupt request flag(s). A set bit
identifies an active bit(s)</entry>
</row>

<row>
<entry>Priority</entry>
<entry><literallayout>The device priority number:
          0 = lowest
        255 = highest</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>NXTPRCS Start next process F$NPRC</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$NPRC</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 2D</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>Control does not return to caller.</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This system mode service request takes the next process out of the
Active Process Queue and initiates its execution. If there is no
process in the queue, OS-9 waits for an interrupt, and then checks the
active process queue again.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>R64 Deallocate a 64 byte memory block F$R64</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$R64</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 31</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(X) = Address of the base page.
(A) = Block number.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This system mode service request deallocates a 64 byte block of
memory as described in the F$A64 service request.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>SRQMEM System memory request F$SRQM</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$SRQM</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 28</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(D) = Byte count.</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(U) = Beginning address of memory area.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This system mode service request allocates a block of memory from
the top of available RAM of the specified size. The size requested is
rounded to the next 256 byte page boundary.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>SRTMEM Return System Memory F$SRTM</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$SRTM</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 29</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(U) = Beginning address of memory to return.
(D) = Number of bytes to return.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>
This system mode service request is used to deallocate a block of contigous 256 byte pages.
The U register must point to an even page boundary.
</para>
<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>VMOD Verify module F$VMOD</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  F$VMOD</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 2E</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(X) = Address of module to verify</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(U) = Address of module directory entry</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>This system mode service request checks the module header parity
and CRC bytes of an OS-9 module. If these values are valid, then
the module directory is searched for a module with the same name.
If a module with the same name exists, the one with the highest
revision level is retained in the module directory. Ties are
broken in favor of the established module.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>


<sect1>
<title>ATTACH Attach a new device to the system. I$ATCH</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  I$ATCH</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 80</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(X) = Address of device name string
(A) = Access mode.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(U) = Address of device table entry</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This service request is used to attach a new device to the system,
or verify that it is already attached. The device's name string is
used to search the system module directory to see if a device
descriptor module with the same name is in memory (this is the name
the device will be known by). The descriptor module will contain the
name of the device's file manager, device driver and other related
information. It it is found and the device is not already attached,
OS-9 will link to its file manager and device driver, and then place
their address' in a new device table entry. Any permanent storage
needed by the device driver is allocated, and the driver's
initialization routine is called (which usually initializes the
hardware).</para>

<para>If the device has already been attached, it will not be
reinitialized.</para>

<para>An ATTACH system call is not required to perform routine I/O. It
does NOT "reserve" the device in question - it just prepares it for
subsequent use by any process. Most devices are automatically
installed, so it is used mostly when devices are dynamically
installed or to verify the existence of a device.</para>

<para>The access mode parameter specifies which subsequent read and/or
write operations will be permitted as follows:
</para>

<para>0 = Use device capabilities.</para>

<para>1 = Read only.</para>

<para>2 = Write only.</para>

<para>3 = Both read and write.</para>
</sect1>

<sect1>
<title>CHDIR Change working directory. I$CDIR</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  I$CDIR</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 86</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(X) = Address of the pathlist.
(A) = Access mode.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Changes a process' working directory to another directory file
specified by the pathlist. Depending on the access mode given, the
current execution or the current data directory may be changed (but
only one may be changed per call). The file specified must be a
directory file, and the caller must have read permission for it
(public read if not owned by the calling process).</para>

<para>ACCESS MODES
</para>

<para>1 = Read</para>

<para>2 = Write</para>

<para>3 = Update (read or write)</para>

<para>4 = Execute</para>

<para>If the access mode is read, write, or update the current data
directory is changed. If the access mode is execute, the current
execution directory is changed.</para>
</sect1>

<sect1>
<title>CLOSE Close a path to a file/device. I$CLOS</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  I$CLOS</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 8F</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(A) = Path number.</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Terminates the I/O path specified by the path number. I/O can no
longer be performed to the file/device, unless another OPEN or CREATE
call is used. Devices that are non-sharable become available to other
requesting processes. All OS-9 internally managed buffers and
descriptors are deallocated.</para>

<para>Note: Because the OS9 F$EXIT service request automatically closes
all open paths (except the standard I/O paths), it may not he
necessary to close them individually with the OS9 I$CLOS service request.</para>

<para>Standard I/O paths are not typically closed except when it is
desired to change the files/devices they correspond to.</para>
</sect1>

<sect1>
<title>CREATE Create a path to a new file. I$CREA</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  I$CREA</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 83</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(X) = Address of the pathlist.
(A) = Access mode.
(B) = File attributes.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry><literallayout>(X) = Updated past the pathlist (trailing blanks skipped)
(A) = Path number.</literallayout></entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Used to create a new file on a multifile mass storage device.
The pathlist is parsed, and the new file name is entered in the
specified (or default working) directory. The file is given the
attributes passed in the B register, which has individual bits
defined as follows:</para>
<literallayout>
bit 0 = read permit
bit 1 = write permit
bit 2 = execute permit
bit 3 = public read permit
bit 4 = public write permit
bit 5 - public execute permit
bit 6 = sharable file
</literallayout>

<para>The access mode parameter passed in register A must be either
&quot;WRITE&quot; or &quot;UPDATE&quot;. This only affects the file
until it is closed; it can be reopened later in any access mode
allowed by the file attributes (see OPEN). Files open for &quot;WRITE&quot;
may allow faster data transfer than &quot;UPDATE&quot;, which
sometimes needs to preread setors. These access codes are defined
as given below:
</para>
<literallayout>
2 = Write only
3 = Update (read and write)
</literallayout>

<para>NOTE: If the execute bit (bit 2) is set, the file will be created
in the working execution directory instead of the working data
directory.</para>

<para>The path number returned by OS-9 is used to identify the file in
subsequent I/O service requests until the file is closed.</para>

<para>No data storage is initially allocated for the file at the time it
is created; this is done automatically by WRITE or explicitly by the
PUTSTAT call.</para>

<para>An error will occur if the file name already exists in the
directory. CREATE calls that specify non-multiple file devices (such
as printers, terminals, etc.) work correctly: the CREATE behaves the
same as OPEN. Create cannot be used to make directory files (see
MAKDIR).</para>
</sect1>

<sect1>
<title>DELETE Delete a file. I$DLET</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  I$DLET</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 87</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(X) = Address of pathlist.</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(X) = Updated past pathlist (trailing spaces skipped).</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This service request deletes the file specified by the pathlist.
The file must have write permission attributes (public write if not
the owner), and reside on a multifile mass storage device. Attempts
to delete devices will result in an error.</para>
</sect1>

<sect1>
<title>DETACH Remove a device from the system. I$DTCH</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9   I$DTCH</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 81</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(U) = Address of the device table entry.</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Removes a device from the system device table if not in use by any
other process. The device driver's termination routine is called,
then any permanent storage assigned to the driver is deallocated. The
device driver and file manager modules associated with the device are
unlinked (and may be destroyed if not in use by another process.</para>

<para>The I$DTCH service request must be used to un-attach devices that
were attached with the I$ATCH service request. Both of these are used
mainly by IOMAN and are of limited (or no use) to the typical user.
SCFMAN also uses ATTACH/DETACH to setup its second (echo) device.</para>
</sect1>

<sect1>
<title>DUP Duplicate a path. I$DUP</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  I$DUP</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 82</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(A) = Path number of path to duplicate.</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(A) = New path number.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Given the number of an existing path, returns another synonymous
path number for the same file or device. SHELL uses this service
request when it redirects I/O. Service requests using either the old
or new path numbers operate on the same file or device.</para>

<para>
NOTE: This only increments the &quot;use count&quot; of a path
descriptor and returns the synonymous path number. The path
descriptor is not copied.</para>
</sect1>

<sect1>
<title>GETSTAT Get file device status. I$GSTT</title>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  I$GSTT</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 8D</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(A) = Path number.
(B) Status code.
(Other registers depend upon status code)</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(depends upon status code)</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This system is a &quot;wild card&quot; call used to handle individual
device parameters that:</para>
<orderedlist numeration="loweralpha">
<listitem><para>are not uniform on all devices</para></listitem>
<listitem><para>are highly hardware dependent</para></listitem>
<listitem><para>need to be user-changable</para></listitem>
</orderedlist>

<para>The exact operation of this call depends on the device driver an
file manager associated with the path. A typical use is to
determine a terminal's parameters for backspace character, delete
character, echo on/off, null padding, paging, etc. It is commonly
used in conjunction with the SETSTAT service request which is
used to set the device operating parameters. Below are presently
defined function codes for GETSTAT:</para>

<informaltable frame="none">
<tgroup cols="3">
<colspec colwidth="1.2in"/>
<colspec colwidth="1in"/>
<colspec colwidth="3.5in"/>
<thead>
<row rowsep="1">
<entry>MNEMONIC</entry>
<entry>CODE</entry>
<entry>FUNCTION</entry>
</row>
</thead>
<tbody>
<row>
<entry>SS.OPT</entry>
<entry>0</entry>
<entry>Read the 32 byte option section of the path descriptor.</entry>
</row>
<row>
<entry>SS.RDY</entry>
<entry>1</entry>
<entry>Test for data ready on SCFMAN-type device.</entry>
</row>
<row>
<entry>SS.SIZ</entry>
<entry>2</entry>
<entry>Return current file size (on RBFMAN-type devices).</entry>
</row>
<row>
<entry>SS.POS</entry>
<entry>5</entry>
<entry>Get current file position.</entry>
</row>
<row>
<entry>SS.EOF</entry>
<entry>6</entry>
<entry>Test for end of file.</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>CODES 7-127 Reserved for future use.</para>

<para>CODES 128-255 These getstat codes and their parameter passing
conventions are user definable (see the sections of this manual on
writing device drivers). The function code and register stack are
passed to the device driver.</para>

<para>Parameter Passing Conventions</para>

<para>The parameter passing conventions for each of these function codes
are given below:</para>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.5in"/>
<colspec colwidth="3.5in"/>
<tbody>
<row>
	<entry>SS.OPT (code 0):</entry>
	<entry>Read option section of the path descriptor.</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(A) = Path number
(B) = Function code 0
(X) = Address of place to put a 32 byte status packet.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>Status packet.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This getstat function reads the option section of the path
descriptor and copies it into the 32 byte area pointed to by the X
register. It is typically used to determine the current settings for
echo, auto line feed, etc. For a complete description of the
status packet, please see the section of this manual on path
descriptors.</para>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.5in"/>
<colspec colwidth="3.5in"/>
<tbody>
<row>
	<entry>SS.RDY (code 1):</entry>
	<entry>Test for data available on SCFMAN supported devices.</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(A) = Path number
(B) = Function code 1</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entrytbl cols="4">
	<thead>
	<row><entry rowsep="1"></entry>
	<entry rowsep="1">Ready</entry>
	<entry rowsep="1">Not Ready</entry>
	<entry rowsep="1">Error</entry></row>
	</thead>
	<tbody>
	<row><entry rowsep="1">(CC)</entry>
	<entry rowsep="1">C bit clear</entry>
	<entry rowsep="1">C bit set</entry>
	<entry rowsep="1">C bit set</entry></row>
	<row><entry rowsep="1">(B)</entry>
	<entry rowsep="1">zero</entry>
	<entry rowsep="1">$F6 (<errorcode>E$NRDY</errorcode>)</entry>
	<entry rowsep="1">ERROR Code</entry></row>
	</tbody>
	</entrytbl>
</row>
</tbody>
</tgroup>
</informaltable>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.5in"/>
<colspec colwidth="3.5in"/>
<tbody>
<row>
	<entry>SS.SIZ (code 2):</entry>
	<entry>Get current file size (RBFMAN supported devices only)</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(A) = Path number
(B) = Function code 2</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry><literallayout>(X) = M.S. 16 bits of current file size.
(U) = L.S. 16 bits of current file size.</literallayout></entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.5in"/>
<colspec colwidth="3.5in"/>
<tbody>
<row>
	<entry>SS.POS (code 5):</entry>
	<entry>Get current file position (RBFMAN supported devices only)</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(A) = Path number
(B) = Function code 5</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry><literallayout>(X) = M.S. 16 bits of current file position.
(U) = L.S. 16 bits of current file position.</literallayout></entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.5in"/>
<colspec colwidth="3.5in"/>
<tbody>
<row>
	<entry>SS.EOF (code 6):</entry>
	<entry>Test for end of file.</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(A) = Path number
(B) = Function code 6</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entrytbl cols="4">
	<thead>
	<row><entry rowsep="1"></entry>
	<entry rowsep="1">Not EOF</entry>
	<entry rowsep="1">EOF</entry>
	<entry rowsep="1">Error</entry></row>
	</thead>
	<tbody>
	<row><entry rowsep="1">(CC)</entry>
	<entry rowsep="1">C bit clear</entry>
	<entry rowsep="1">C bit set</entry>
	<entry rowsep="1">C bit set</entry></row>
	<row><entry rowsep="1">(B)</entry>
	<entry rowsep="1">zero</entry>
	<entry rowsep="1">$D3 (<errorcode>E$EOF</errorcode>)</entry>
	<entry rowsep="1">ERROR Code</entry></row>
	</tbody>
	</entrytbl>
</row>
</tbody>
</tgroup>
</informaltable>
</sect1>

<sect1>
<title>MAKDIR Make a new directory I$MDIR</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 I$MDIR</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 85</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(X) = Address of pathlist.
(B) = Directory attributes.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(X) = Updated path pathlist (trailing spaces skipped).</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>MAKDIR is the only way a new directory file can be created. It
will create and initialize a new directory as specified by the
pathlist. The new directory file contains no entries, except for
an entry for itself (".") and its parent directory ("..")</para>

<para>The caller is made the owner of the directory. MAKDIR dies not
return a path number because directory files are not "opened" by
this request (use OPEN to do so). The new directory will
automatically have its "directory" bit set in the access
permission attributes. The remaining attributes are specified by
the byte passed in the B register, which has individual bits
defined as follows:</para>

<literallayout>
bit 0 = read permit
bit 1 = write permit
bit 2 = execute permit
bit 3 = public read permit
bit 4 = public write permit
bit 5 - public execute permit
bit 6 = sharable file
bit 7 = (don't care)
</literallayout>
</sect1>

<sect1>
<title>OPEN Open a path to a file or device I$OPEN</title>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  I$OPEN</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 84</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(X) = Address of pathlist.
(A) = Access mode (D S PE PW PR E W R)</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry><literallayout>(X) = Updated past pathlist (trailing spaces skipped).
(A) = Path number.</literallayout></entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Opens a path to an existing file or device as specified by the
pathlist. A path number is returned which is used in subsequent
service requests to identify the file.</para>

<para>The access mode parameter specifies which subsequent read and/or
write operation are permitted as follows:</para>

<literallayout>
1 = read mode
2 = write mode
3 = update mode (both read and write)
</literallayout>

<para>Update mode can be slightly slower because pre-reading of sectors
may be required for random access of bytes within sectors. The
access mode must conform to the access permission attributes
associated with the file or device (see CREATE). Only the owner
may access a file unless the appropiate "public permit" bits are
set.</para>

<para>Files can be opened by several processes (users) simultaneously.
Devices have an attribute that specifies whether or not they are
sharable on an individual basis.</para>

<para>NOTES:</para>

<para>If the execution bit is set in the access mode, OS-9 will begin
searching for the file in the working execution directory (unless
the pathlist begins with a slash).</para>

<para>The sharable bit (bit 6) in the access mode can not lock other
users out of  file in OS-9 Level I. It is present only for
upward compatibility with OS-9 Level II.</para>

<para>Directory files may be read or written if the D bit (bit 7) is set
in the access mode.</para>
</sect1>

<sect1>
<title>READ Read data from a file or device I$READ</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  I$READ</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 89</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(X) = Address to store data.
(Y) = Number of bytes to read.
(A) = Path number.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(Y) = Number of bytes actually read.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Reads a specified number of bytes from the path number given. The
path must previously have been opened in READ or UPDATE mode. The
data is returned exactly as read from the file/device without
additional processing or editing such as backspace, line delete,
end-of-file, etc.</para>

<para>After all data in a file has been read, the next I$READ service
request will return an end of file error.</para>

<para>NOTES:</para>

<para>The keyboard abort, keyboard interrupt, and end-of-file characters
may be filtered out of the input data on SCFMAN-type devices
unless the coresponding entries in the path descriptor have been
set to zero. It may be desirable to modify the device descriptor
so that these values in the path descriptor are initialized to
zero when the path is opened.</para>

<para>The number of bytes requested will be read unless:</para>
<literallayout>
A. An end-of-file occurs
B. An end-of-record occurs (SCFMAN only)
C. An error condition occurs.
</literallayout>
</sect1>

<sect1>
<title>READLN Read a text line with editing. I$RDLN</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  I$RDLN</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 8B</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(X) = Address to store data.
(Y) = Number of bytes to read.
(A) = Path number.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(Y) = Actual number of bytes read.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This system call is the same as "READ" except it reads data from
the input file or device until a carriage return character is
encountered or until the maximum byte count specified is reached,
and that line editing will occur on SCFMAN-type devices. Line
editing refers to backspace, line delete, echo automatic line
feed, etc.</para>

<para>SCFMAN requires that the last byte entered be an end-of-record
character (normally carriage return). If more data is entered
than the maximum specified, it will not be accepted and a PD.OVF
character (normally bell) will be echoed.</para>

<para>After all data in the file has been read, the next I$RDLN service
request will return an end of file error.</para>

<para>NOTE: For more information on line editing, see 7.1.</para>
</sect1>

<sect1>
<title>SEEK Reposition the logical file pointer I$SEEK</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  I$SEEK</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 88</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(A) = Path number.
(X) = M.S. 16 bits of desired file position.
(U) = L.S. 16 bits of desired file position.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This system call repositions the path's "file pointer"; which is
the 32-bit addres of the next byte in the file to be read
from or written to.</para>

<para>A seek may be performed to any value even if the file is not large
enough. Subsequent WRITEs will automatically expand the file to
the required size (if possible), but READs will return an end-of-file
condition. Note that a SEEK to address zero is the same as a
"rewind" operation.</para>

<para>Seeks to non-random access devices are usually ignored and return
without error.</para>
</sect1>

<sect1>
<title>SETSTAT Set file/device status I$SSTT</title>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  I$SSTT</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 8E</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(A) = Path number.
(B) Function code.
(Other registers depend upon function code)</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(depends upon function code)</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>This system is a &quot;wild card&quot; call used to handle individual
device parameters that:</para>
<orderedlist numeration="loweralpha">
<listitem><para>are not uniform on all devices</para></listitem>
<listitem><para>are highly hardware dependent</para></listitem>
<listitem><para>need to be user-changeable</para></listitem>
</orderedlist>

<para>The exact operation of this call depends on the device driver and
file manager associated with the path. A typical use is to
set a terminal's parameters for backspace character, delete
character, echo on/off, null padding, paging, etc. It is commonly
used in conjunction with the GETSTAT service request which is
used to read the device operating parameters. Below are presently
defined function codes:</para>

<informaltable frame="none">
<tgroup cols="3">
<colspec colwidth="1.2in"/>
<colspec colwidth="0.8in"/>
<colspec colwidth="3.5in"/>
<thead>
<row rowsep="1">
<entry>MNEMONIC</entry>
<entry>CODE</entry>
<entry>FUNCTION</entry>
</row>
</thead>
<tbody>
<row>
<entry>SS.OPT</entry>
<entry>$0</entry>
<entry>Write the 32 byte option section of the path descriptor</entry>
</row>
<row>
<entry>SS.SIZ</entry>
<entry>$2</entry>
<entry>Set the file size (RBF)</entry>
</row>
<row>
<entry>SS.RST</entry>
<entry>$3</entry>
<entry>Restore head to track zero (RBF)</entry>
</row>
<row>
<entry>SS.WRT</entry>
<entry>$4</entry>
<entry>Write (format) track (RBF)</entry>
</row>
<row>
<entry>SS.FEE</entry>
<entry>$9</entry>
<entry>Issue Form Feed (SCF)</entry>
</row>
<row>
<entry>SS.FRZ</entry>
<entry>$A</entry>
<entry>Freeze DD. Information (RBF)</entry>
</row>
<row>
<entry>SS.SPT</entry>
<entry>$B</entry>
<entry>Set Sectors per track (RBF)</entry>
</row>
<row>
<entry>SS.SQD</entry>
<entry>$C</entry>
<entry>Sequence down disk drive (RBF)</entry>
</row>
<row>
<entry>SS.DCM</entry>
<entry>$D</entry>
<entry>Direct command to hard disk controller (RBF)</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Codes 128 through 255  their parameter passing
conventions are user definable (see the sections of this manual on
writing device drivers). The function code and register stack are
passed to the device driver.</para>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.5in"/>
<colspec colwidth="3.5in"/>
<tbody>
<row>
	<entry>SS.OPT (code 0):</entry>
	<entry>Write option section of the path descriptor.</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(A) = Path number
(B) = Function code 0
(X) = Address of a 32 byte status packet.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This setstat function writes the option section of the path
descriptor from the 32 byte status packet pointed to by the X
register. It is typically used to set the device operating
parameters, such as echo, auto line feed, etc.</para>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.5in"/>
<colspec colwidth="3.5in"/>
<tbody>
<row>
	<entry>SS.SIZ (code 2):</entry>
	<entry>Set the file size (RBFMAN-type devices)</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(A) = Path number
(B) = Function code 2
(X) = M.S. 16 bits of desired file size.
(U) = L.S. 16 bits of desired file size.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This setstat function is used to change the file's size.</para>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.5in"/>
<colspec colwidth="3.5in"/>
<tbody>
<row>
	<entry>SS.RST (code 3):</entry>
	<entry>Restore head to track zero.</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(A) = Path number
(B) = Function code 3</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Home disk head to track zero. Used for formatting and
for error recovery.</para>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.5in"/>
<colspec colwidth="3.5in"/>
<tbody>
<row>
	<entry>SS.WTK (code 4):</entry>
	<entry>Write track</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(A) = Path number
(B) = Function code 4
(X) = Address of track buffer.
(U) = Track number (L.S. 8 bits)
(Y) = Side/density
         Bit B0 = SIDE (0 = side zero, 1 = side one)
	 Bit B1 = DENSITY (0 = single, 1 = double)</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This code causes a format track (most floppy disks)
operation to occur. For hard disks or floppy disks with a "format
entire disk" command, this command should format the entire media
only when the track number equals zero.</para>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.5in"/>
<colspec colwidth="3.5in"/>
<tbody>
<row>
	<entry>SS.FRZ (code $A):</entry>
	<entry>Freeze DD. Information</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>none</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>none</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Inhibits the reading of identification sector (LSN 0) to
DD.xxx variables (that define disk formats) so non-standard disks
may be read.</para>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.5in"/>
<colspec colwidth="3.5in"/>
<tbody>
<row>
	<entry>SS.SPT (code $B):</entry>
	<entry>Set Sectors Per Track</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>X = new sectors per track</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</sect1>

<sect1>
<title>WRITE Write data to file or device I$WRITE</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9  I$WRITE</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 8A</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(X) = Address of data to write.
(Y) = Number of bytes to write.
(A) = Path number.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(Y) = Number of bytes actually written.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>WRITE outputs one or more bytes to a file or device associated
with the path
number specified. The path must have been OPENed or CREATEd in the
WRITE or UPDATE access modes.</para>

<para>Data is written to the file or device without processing or
editing. If data is written past the present end-of-file, the file is
automatically expanded.</para>
</sect1>

<sect1>
<title>WRITELN Write line of text with editing I$WRLN</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 I$WRLN</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 8C</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(X) = Address of data to write.
(Y) = Maximum number of bytes to write.
(A) = Path number.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(Y) = Actual number of bytes written.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This system call is similar to WRITE except it writes data until a
carriage return character is encountered. Line editing
is also activated for character-oriented devices such as terminals,
printers, etc. The line editing refers to auto line feed, null
padding at end of line, etc.</para>

<para>For more information about line editing, see section 7.1.</para>

</sect1>
</chapter>


<appendix>
<title>Memory Module Diagrams</title>

<informalfigure>
<screen>
MODULE          EXECUTABLE MEMORY MODULE FORMAT
OFFSET

        +------------------------------+  ---+--------+---
 $00    |                              |     |        |
        +--    Sync Bytes ($87CD)    --+     |        |
 $01    |                              |     |        |
        +------------------------------+     |        |
 $02    |                              |     |        |
        +--   Module Size (bytes)    --+     |        |
 $03    |                              |     |        |
        +------------------------------+     |        |
 $04    |                              |     |        |
        +--   Module Name Offset     --+   header     |
 $05    |                              |   parity     |
        +------------------------------+     |        |
 $06    |     Type     |   Language    |     |        |
        +------------------------------+     |        |
 $07    |  Attributes  |   Revision    |     |        |
        +------------------------------+  ---+--    module
 $08    |     Header Parity Check      |             CRC
        +------------------------------+              |
 $09    |                              |              |
        +--     Execution Offset     --+              |
 $0A    |                              |              |
        +------------------------------+              |
 $0B    |                              |              |
        +--  Permanent Storage Size  --+              |
 $0C    |                              |              |
        +------------------------------+              |
 $0D    |                              |              |
        |  (Add'l optional header      |              |
        |   extensions located here    |              |
        |                              |              |
        |  .  .  .  .  .  .  .  .  .   |              |
        |                              |              |
        |                              |              |
        |       Module Body            |              |
        | object code, constants, etc. |              |
        |                              |              |
        |                              |              |
        +------------------------------+              |
        |                              |              |
        +--                          --+              |
        |       CRC Check Value        |              |
        +--                          --+              |
        |                              |              |
        +------------------------------+  ------------+---
</screen>
</informalfigure>
<informalfigure>
<screen>
MODULE     DEVICE DESCRIPTOR MODULE FORMAT
OFFSET
           +-----------------------------+  ---+--------+---
  $0       |                             |     |        |
           +--   Sync Bytes ($87CD)    --+     |        |
  $1       |                             |     |        |
           +-----------------------------+     |        |
  $2       |                             |     |        |
           +--   Module Size (bytes)   --+     |        |
  $3       |                             |     |        |
           +-----------------------------+     |        |
  $4       |                             |     |        |
           +-- Offset to Module Name   --+   header     |
  $5       |                             |   parity     |
           +-----------------------------+     |        |
  $6       | $F (TYPE)   |  $1 (LANG)    |     |        |
           +-----------------------------+     |        |
  $7       | Attributes  |   Revision    |     |        |
           +-----------------------------+  ---+--    module
  $8       |  Header Parity Check        |             CRC
           +-----------------------------+              |
  $9       |                             |              |
           +--  Offset to File Manager --+              |
  $A       |         Name String         |              |
           +-----------------------------+              |
  $B       |                             |              |
           +-- Offset to Device Driver --+              |
  $C       |         Name String         |              |
           +-----------------------------+              |
  $D       |        Mode Byte            |              |
           +-----------------------------+              |
  $E       |                             |              |
           +--    Device Controller    --+              |
  $F       | Absolute Physical Address   |              |
           +--     (24 bit)            --+              |
 $10       |                             |              |
           +-----------------------------+              |
 $11       |   Option Table Size         |              |
           +-----------------------------+              |
$12,$12+N  |    (Option Table)           |              |
           |                             |              |
           | . . . . . . . . . . . . . . |              |
           |                             |              |
           |    (Name Strings etc)       |              |
           +-----------------------------+              |
           |                             |              |
           +--                         --+              |
           |    CRC Check Value          |              |
           +--                         --+              |
           |                             |              |
           +-----------------------------+  ------------+---
</screen>
</informalfigure>
<informalfigure>
<screen>
MODULE      CONFIGURATION MODULE FORMAT
OFFSET
        +------------------------------+  ---+--------+---
 $00    |                              |     |        |
        +--    Sync Bytes ($87CD)    --+     |        |
 $01    |                              |     |        |
        +------------------------------+     |        |
 $02    |                              |     |        |
        +--   Module Size (bytes)    --+     |        |
 $03    |                              |     |        |
        +------------------------------+     |        |
 $04    |                              |     |        |
        +--   Module Name Offset     --+   header     |
 $05    |                              |   parity     |
        +------------------------------+     |        |
 $06    |  $C (TYPE)   |  0  (LANG)    |     |        |
        +------------------------------+     |        |
 $07    |  Attributes  |   Revision    |     |        |
        +------------------------------+  ---+--    module
 $08    |     Header Parity Check      |             CRC
        +------------------------------+              |
 $09    |                              |              |
        +--     Forced Limit of Top  --+              |
 $0A    |         of Free RAM          |              |
        +--                          --+              |
 $0B    |                              |              |
        +------------------------------+              |
 $0C    | # IRQ Polling Table Entries  |              |
        +------------------------------+              |
 $0D    |    # Device Table Entries    |              |
        +------------------------------+              |
 $0E    |                              |              |
        +--    Offset to Startup     --+              |
 $0F    |      Module Name String      |              |
        +------------------------------+              |
 $10    |                              |              |
        +-- Offset to Default Mass-  --+              |
 $11    |  Storage Device Name String  |              |
        +------------------------------+              |
 $12    |                              |              |
        +--    Offset to Initial     --+              |
 $13    |        Standard Path         |              |
        +------------------------------+              |
 $14    |                              |              |
        +--   Offset to Bootstrap    --+              |
 $15    |     Module Name String       |              |
        +------------------------------+              |
 $16-n  |        Name Strings          |              |
        +------------------------------+              |
        |                              |              |
        +--                          --+              |
        |      CRC Check Value         |              |
        +--                          --+              |
        |                              |              |
        +------------------------------+  ------------+---
</screen>
</informalfigure>
</appendix>


<appendix>
<title>Standard Floppy Disk Formats</title>
<table frame="none">
<title>Single Density Floppy Disk Format</title>
<tgroup cols="3">
<colspec colwidth="2in" colname="c1"/>
<colspec colwidth="1.8in" colname="c2"/>
<colspec colwidth="1.8in" colname="c3"/>
<tbody>
    <row>
	<entry>SIZE</entry>
	<entry>5"</entry>
	<entry>8"</entry>
    </row>
    <row>
	<entry>DENSITY</entry>
	<entry>SINGLE</entry>
	<entry>SINGLE</entry>
    </row>
    <row>
	<entry>#TRACKS</entry>
	<entry>35</entry>
	<entry>77</entry>
    </row>
    <row>
	<entry>#SECTORS/TRACK</entry>
	<entry>10</entry>
	<entry>16</entry>
    </row>
    <row>
	<entry>BYTES/TRACK (UNFORMATTED)</entry>
	<entry>3125</entry>
	<entry>5208</entry>
    </row>
</tbody>
</tgroup>
<tgroup cols="5">
<colspec colwidth="2in" colname="c1"/>
<colspec colwidth="0.8in" colname="c2"/>
<colspec colwidth="1in" colname="c3"/>
<colspec colwidth="0.8in" colname="c4"/>
<colspec colwidth="1in" colname="c5"/>
<thead>
    <row>
	<entry>FORMAT FIELD</entry>
	<entry>#BYTES (DEC)</entry>
	<entry>VALUE (HEX)</entry>
	<entry>#BYTES (DEC)</entry>
	<entry>VALUE (HEX)</entry>
    </row>
</thead>
<tbody>
    <row>
	<entry morerows="3">HEADER (ONCE PER TRACK)</entry>
	<entry>30</entry>
	<entry>FF</entry>
	<entry>30</entry>
	<entry>FF</entry>
    </row>
    <row>
	<entry>6</entry>
	<entry>00</entry>
	<entry>6</entry>
	<entry>00</entry>
    </row>
    <row>
	<entry>1</entry>
	<entry>FC</entry>
	<entry>1</entry>
	<entry>FC</entry>
    </row>
    <row>
	<entry>12</entry>
	<entry>FF</entry>
	<entry>12</entry>
	<entry>FF</entry>
    </row>
    <row>
	<entry morerows="12">SECTOR (REPEATED N TIMES)</entry>
	<entry>6</entry>
	<entry>00</entry>
	<entry>6</entry>
	<entry>00</entry>
    </row>
    <row>
	<entry>1</entry>
	<entry>FE</entry>
	<entry>1</entry>
	<entry>FE</entry>
    </row>
    <row>
	<entry>1</entry>
	<entry>(TRK #)</entry>
	<entry>1</entry>
	<entry>(TRK #)</entry>
    </row>
    <row>
	<entry>1</entry>
	<entry>(SIDE #)</entry>
	<entry>1</entry>
	<entry>(SIDE #)</entry>
    </row>
    <row>
	<entry>1</entry>
	<entry>(SECT #)</entry>
	<entry>1</entry>
	<entry>(SECT #)</entry>
    </row>
    <row>
	<entry>1</entry>
	<entry>(BYTCNT)</entry>
	<entry>1</entry>
	<entry>(BYTCNT)</entry>
    </row>
    <row>
	<entry>2</entry>
	<entry>(CRC)</entry>
	<entry>2</entry>
	<entry>(CRC)</entry>
    </row>
    <row>
	<entry>10</entry>
	<entry>FF</entry>
	<entry>10</entry>
	<entry>FF</entry>
    </row>
    <row>
	<entry>6</entry>
	<entry>00</entry>
	<entry>6</entry>
	<entry>00</entry>
    </row>
    <row>
	<entry>1</entry>
	<entry>FB</entry>
	<entry>1</entry>
	<entry>FB</entry>
    </row>
    <row>
	<entry>256</entry>
	<entry>(DATA)</entry>
	<entry>256</entry>
	<entry>(DATA)</entry>
    </row>
    <row>
	<entry>2</entry>
	<entry>(CRC)</entry>
	<entry>2</entry>
	<entry>(CRC)</entry>
    </row>
    <row>
	<entry>10</entry>
	<entry>FF</entry>
	<entry>10</entry>
	<entry>FF</entry>
    </row>
    <row>
	<entry>TRAILER (ONCE PER TRACK)</entry>
	<entry>96</entry>
	<entry>FF</entry>
	<entry>391</entry>
	<entry>FF</entry>
    </row>
</tbody>
</tgroup>
<tgroup cols="3">
<colspec colwidth="2in" colname="c1"/>
<colspec colwidth="1.8in" colname="c2"/>
<colspec colwidth="1.8in" colname="c3"/>
<tbody>
    <row>
	<entry>BYTES/SECTOR (FORMATTED)</entry>
	<entry>256</entry>
	<entry>256</entry>
    </row>
    <row>
	<entry>BYTES/TRACK (FORMATTED)</entry>
	<entry>2560</entry>
	<entry>4096</entry>
    </row>
    <row>
	<entry>BYTES/DISK (FORMATTED)</entry>
	<entry>89,600</entry>
	<entry>315,392</entry>
    </row>
</tbody>
</tgroup>
</table>
<table frame="none">
<title>Double Density Floppy Disk Format</title>
<tgroup cols="3">
<colspec colwidth="2in" colname="c1"/>
<colspec colwidth="1.8in" colname="c2"/>
<colspec colwidth="1.8in" colname="c3"/>
<tbody>
    <row>
	<entry>SIZE</entry>
	<entry>5"</entry>
	<entry>8"</entry>
    </row>
    <row>
	<entry>DENSITY</entry>
	<entry>DOUBLE</entry>
	<entry>DOUBLE</entry>
    </row>
    <row>
	<entry>#TRACKS</entry>
	<entry>35</entry>
	<entry>77</entry>
    </row>
    <row>
	<entry>#SECTORS/TRACK</entry>
	<entry>16</entry>
	<entry>28</entry>
    </row>
    <row>
	<entry>BYTES/TRACK (UNFORMATTED)</entry>
	<entry>6250</entry>
	<entry>10,416</entry>
    </row>
</tbody>
</tgroup>
<tgroup cols="5">
<colspec colwidth="2in" colname="c1"/>
<colspec colwidth="0.8in" colname="c2"/>
<colspec colwidth="1in" colname="c3"/>
<colspec colwidth="0.8in" colname="c4"/>
<colspec colwidth="1in" colname="c5"/>
<thead>
    <row>
	<entry>FORMAT FIELD</entry>
	<entry>#BYTES (DEC)</entry>
	<entry>VALUE (HEX)</entry>
	<entry>#BYTES (DEC)</entry>
	<entry>VALUE (HEX)</entry>
    </row>
</thead>
<tbody>
    <row>
	<entry morerows="4">HEADER (ONCE PER TRACK)</entry>
	<entry>80</entry>
	<entry>4E</entry>
	<entry>80</entry>
	<entry>4E</entry>
    </row>
    <row>
	<entry>12</entry>
	<entry>00</entry>
	<entry>12</entry>
	<entry>00</entry>
    </row>
    <row>
	<entry>3</entry>
	<entry>F5 (A1)</entry>
	<entry>3</entry>
	<entry>F5</entry>
    </row>
    <row>
	<entry>1</entry>
	<entry>FC</entry>
	<entry>1</entry>
	<entry>FC</entry>
    </row>
    <row>
	<entry>32</entry>
	<entry>4E</entry>
	<entry>32</entry>
	<entry>4E</entry>
    </row>
    <row>
	<entry morerows="14">SECTOR (REPEATED N TIMES)</entry>
	<entry>12</entry>
	<entry>00</entry>
	<entry>12</entry>
	<entry>00</entry>
    </row>
    <row>
	<entry>3</entry>
	<entry>F5 (A1)</entry>
	<entry>3</entry>
	<entry>F5</entry>
    </row>
    <row>
	<entry>1</entry>
	<entry>FE</entry>
	<entry>1</entry>
	<entry>FE</entry>
    </row>
    <row>
	<entry>1</entry>
	<entry>(TRK #)</entry>
	<entry>1</entry>
	<entry>(TRK #)</entry>
    </row>
    <row>
	<entry>1</entry>
	<entry>(SIDE #)</entry>
	<entry>1</entry>
	<entry>(SIDE #)</entry>
    </row>
    <row>
	<entry>1</entry>
	<entry>(SECT #)</entry>
	<entry>1</entry>
	<entry>(SECT #)</entry>
    </row>
    <row>
	<entry>1</entry>
	<entry>(BYTCNT)</entry>
	<entry>1</entry>
	<entry>(BYTCNT)</entry>
    </row>
    <row>
	<entry>2</entry>
	<entry>(CRC)</entry>
	<entry>2</entry>
	<entry>(CRC)</entry>
    </row>
    <row>
	<entry>22</entry>
	<entry>4E</entry>
	<entry>22</entry>
	<entry>4E</entry>
    </row>
    <row>
	<entry>12</entry>
	<entry>00</entry>
	<entry>12</entry>
	<entry>00</entry>
    </row>
    <row>
	<entry>3</entry>
	<entry>F5 (A1)</entry>
	<entry>3</entry>
	<entry>F5 (A1)</entry>
    </row>
    <row>
	<entry>1</entry>
	<entry>FB</entry>
	<entry>1</entry>
	<entry>FB</entry>
    </row>
    <row>
	<entry>256</entry>
	<entry>(DATA)</entry>
	<entry>256</entry>
	<entry>(DATA)</entry>
    </row>
    <row>
	<entry>2</entry>
	<entry>(CRC)</entry>
	<entry>2</entry>
	<entry>(CRC)</entry>
    </row>
    <row>
	<entry>22</entry>
	<entry>4E</entry>
	<entry>22</entry>
	<entry>4E</entry>
    </row>
    <row>
	<entry>TRAILER (ONCE PER TRACK)</entry>
	<entry>682</entry>
	<entry>4E</entry>
	<entry>768</entry>
	<entry>4E</entry>
    </row>
</tbody>
</tgroup>
<tgroup cols="3">
<colspec colwidth="2in" colname="c1"/>
<colspec colwidth="1.8in" colname="c2"/>
<colspec colwidth="1.8in" colname="c3"/>
<tbody>
    <row>
	<entry>BYTES/SECTOR (FORMATTED)</entry>
	<entry>256</entry>
	<entry>256</entry>
    </row>
    <row>
	<entry>BYTES/TRACK (FORMATTED)</entry>
	<entry>4096</entry>
	<entry>7168</entry>
    </row>
    <row>
	<entry>BYTES/DISK (FORMATTED)</entry>
	<entry>141,824</entry>
	<entry>548,864</entry>
    </row>
</tbody>
</tgroup>
</table>
</appendix>


<appendix>
<title>Service Request Summary</title>

<table frame="none">
<title>User Mode Service Requests</title>
<tgroup cols="4">
<colspec colwidth="1.2in" colname="c1"/>
<colspec colwidth="1.0in" colname="c2"/>
<colspec colwidth="3.6in" colname="c3"/>
<colspec colwidth="0.6in" colname="c4"/>
<thead>
<row>
  <entry>Code</entry>
  <entry>Mnemonic</entry>
  <entry>Function</entry>
  <entry>Page</entry>
</row>
</thead>
<tbody>
<row>
  <entry>103F 00</entry>
  <entry>F$LINK</entry>
  <entry>Link to memory module.</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 01</entry>
  <entry>F$LOAD</entry>
  <entry>Load module(s) from a file.</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 02</entry>
  <entry>F$UNLK</entry>
  <entry>Unlink a module.</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 03</entry>
  <entry>F$FORK</entry>
  <entry>Create a new process.</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 04</entry>
  <entry>F$WAIT</entry>
  <entry>Wait for child process to die.</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 05</entry>
  <entry>F$CHAN</entry>
  <entry>Load and execute a new primary module</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 06</entry>
  <entry>F$EXIT</entry>
  <entry>Terminate the calling process.</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 07</entry>
  <entry>F$MEM</entry>
  <entry>Resize data memory area,</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 08</entry>
  <entry>F$SEND</entry>
  <entry>Send a signal to another process,</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 09</entry>
  <entry>F$ICFT</entry>
  <entry>Set up a signal intercept trap.</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 0A</entry>
  <entry>F$SLEP</entry>
  <entry>Put calling process to sleep.</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 0C</entry>
  <entry>F$ID</entry>
  <entry>Get process ID / user ID</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 0D</entry>
  <entry>F$SPRI</entry>
  <entry>Set process priority.</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 0E</entry>
  <entry>F$SSWI</entry>
  <entry>Set SWI vector.</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 0F</entry>
  <entry>F$PERR</entry>
  <entry>Print error message.</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 10</entry>
  <entry>F$PNAM</entry>
  <entry>Parse a path name,</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 11</entry>
  <entry>F$CNAM</entry>
  <entry>Compare two names</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 12</entry>
  <entry>F$SBIT</entry>
  <entry>Search bit map for a free area</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 13</entry>
  <entry>F$ABIT</entry>
  <entry>Set bits in an allocation bit map</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 14</entry>
  <entry>F$DBIT</entry>
  <entry>Deallocate in a bit map</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 15</entry>
  <entry>F$TIME</entry>
  <entry>Get system date and time.</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 16</entry>
  <entry>F$STIM</entry>
  <entry>Set system date and time.</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 17</entry>
  <entry>F$CRC</entry>
  <entry>Compute CRC</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 18</entry>
  <entry>F$GPrDsc</entry>
  <entry>Get Process Descriptor copy </entry>
  <entry></entry>
</row>
<row>
  <entry>103F 19</entry>
  <entry>F$GBlkMp</entry>
  <entry>Get system Block Map copy</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 1A</entry>
  <entry>F$GModDr</entry>
  <entry>Get Module Directory copy</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 1B</entry>
  <entry>F$CpyMem</entry>
  <entry>Copy external Memory</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 1C</entry>
  <entry>F$SUser</entry>
  <entry>Set User ID number</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 1D</entry>
  <entry>F$UnLoad</entry>
  <entry>Unlink module by name</entry>
  <entry></entry>
</row>
</tbody>
</tgroup>
</table>





<table frame="none">
<title>System Mode Privileged Service Requests</title>
<tgroup cols="4">
<colspec colwidth="1.2in" colname="c1"/>
<colspec colwidth="1.0in" colname="c2"/>
<colspec colwidth="3.6in" colname="c3"/>
<colspec colwidth="0.6in" colname="c4"/>
<thead>
<row>
  <entry>Code</entry>
  <entry>Mnemonic</entry>
  <entry>Function</entry>
  <entry>Page</entry>
</row>
</thead>
<tbody>
<row>
  <entry>103F 28</entry>
  <entry>F$SRQM</entry>
  <entry>System memory request</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 28</entry>
  <entry>F$SRqMem</entry>
  <entry>System Memory Request </entry>
  <entry></entry>
</row>
<row>
  <entry>103F 29</entry>
  <entry>F$SRTMEM</entry>
  <entry>System memory request</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 29</entry>
  <entry>F$SRtMem</entry>
  <entry>System Memory Return </entry>
  <entry></entry>
</row>
<row>
  <entry>103F 2A</entry>
  <entry>F$IRQ</entry>
  <entry>Add or remove device from IRQ table.</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 2B</entry>
  <entry>F$IOQU</entry>
  <entry>Enter I/O queue</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 2C</entry>
  <entry>F$APRC</entry>
  <entry>Insert process in active process queue</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 2D</entry>
  <entry>F$NPRC</entry>
  <entry>Start next process</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 2E</entry>
  <entry>F$VMODUL</entry>
  <entry>Validate module</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 2F</entry>
  <entry>F$F64</entry>
  <entry>Find a 64 byte memory block</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 30</entry>
  <entry>F$A64</entry>
  <entry>Allocate a 64 byte memory block</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 31</entry>
  <entry>F$R64</entry>
  <entry>Deallocate a 64 byte memory block</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 32</entry>
  <entry>F$SSVC</entry>
  <entry>Install function request</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 33</entry>
  <entry>F$IODL</entry>
  <entry>Delete I/O device from system</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 34</entry>
  <entry>F$SLink</entry>
  <entry>System Link </entry>
  <entry></entry>
</row>
<row>
  <entry>103F 35</entry>
  <entry>F$Boot</entry>
  <entry>Bootstrap system</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 36</entry>
  <entry>F$BtMem</entry>
  <entry>Bootstrap Memory request</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 37</entry>
  <entry>F$GProcP</entry>
  <entry>Get Process Pointer </entry>
  <entry></entry>
</row>
<row>
  <entry>103F 38</entry>
  <entry>F$Move</entry>
  <entry>Move data (low bound first)</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 39</entry>
  <entry>F$AllRAM</entry>
  <entry>Allocate RAM blocks</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 3A</entry>
  <entry>F$AllImg</entry>
  <entry>Allocate Image RAM blocks</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 3B</entry>
  <entry>F$DelImg</entry>
  <entry>Deallocate Image RAM blocks</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 3C</entry>
  <entry>F$SetImg</entry>
  <entry>Set process DAT Image</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 3D</entry>
  <entry>F$FreeLB</entry>
  <entry>get Free Low block </entry>
  <entry></entry>
</row>
<row>
  <entry>103F 3E</entry>
  <entry>F$FreeHB</entry>
  <entry>get Free High block </entry>
  <entry></entry>
</row>
<row>
  <entry>103F 3F</entry>
  <entry>F$AllTsk</entry>
  <entry>Allocate process Task number</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 40</entry>
  <entry>F$DelTsk</entry>
  <entry>Deallocate process Task number</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 41</entry>
  <entry>F$SetTsk</entry>
  <entry>Set process Task DAT registers </entry>
  <entry></entry>
</row>
<row>
  <entry>103F 42</entry>
  <entry>F$ResTsk</entry>
  <entry>Reserve Task number</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 43</entry>
  <entry>F$RelTsk</entry>
  <entry>Release Task number</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 44</entry>
  <entry>F$DATLog</entry>
  <entry>Convert DAT block/offset to Logical Addr</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 45</entry>
  <entry>F$DATTmp</entry>
  <entry>Make Temporary DAT image</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 46</entry>
  <entry>F$LDAXY</entry>
  <entry>Load A [X, [Y] ] </entry>
  <entry></entry>
</row>
<row>
  <entry>103F 47</entry>
  <entry>F$LDAXYP</entry>
  <entry>Load A [X+, [Y] ]</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 48</entry>
  <entry>F$LDDDXY</entry>
  <entry>Load D [D+X, [Y] ] </entry>
  <entry></entry>
</row>
<row>
  <entry>103F 49</entry>
  <entry>F$LDABX</entry>
  <entry>Load A from 0,1 in task B </entry>
  <entry></entry>
</row>
<row>
  <entry>103F 4A</entry>
  <entry>F$STABX</entry>
  <entry>Store A at 0,X in task B</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 4B</entry>
  <entry>F$AllPrc</entry>
  <entry>Allocate Process descriptor</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 4C</entry>
  <entry>F$DelPrc</entry>
  <entry>Deallocate Process descriptor</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 4D</entry>
  <entry>F$ELink</entry>
  <entry>Link using module directory Entry</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 4E</entry>
  <entry>F$FModul</entry>
  <entry>Find Module directory entry</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 4F</entry>
  <entry>F$MapBlk</entry>
  <entry>Map specific Block</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 50</entry>
  <entry>F$ClrBlk</entry>
  <entry>Clear specific Block</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 51</entry>
  <entry>F$DelRam</entry>
  <entry>Deallocate RAM blocks</entry>
  <entry></entry>
</row>
</tbody>
</tgroup>
</table>



<table frame="none">
<title>Input/Output Service Requests</title>
<tgroup cols="4">
<colspec colwidth="1.2in" colname="c1"/>
<colspec colwidth="1.0in" colname="c2"/>
<colspec colwidth="3.6in" colname="c3"/>
<colspec colwidth="0.6in" colname="c4"/>
<thead>
<row>
  <entry>Code</entry>
  <entry>Mnemonic</entry>
  <entry>Function</entry>
  <entry>Page</entry>
</row>
</thead>
<tbody>
<row>
  <entry>103F 80</entry>
  <entry>I$ATCH</entry>
  <entry>Attach a new device to the system.</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 81</entry>
  <entry>I$DTCH</entry>
  <entry>Remove a device from the system.</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 82</entry>
  <entry>I$DUP</entry>
  <entry>Duplicate a path.</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 83</entry>
  <entry>I$CREA</entry>
  <entry>Create a path to a new file.</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 84</entry>
  <entry>I$Open</entry>
  <entry>Open a path to a file or device</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 85</entry>
  <entry>I$MakDir</entry>
  <entry>Make a new directory</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 86</entry>
  <entry>I$CDIR</entry>
  <entry>Change working directory.</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 87</entry>
  <entry>I$DLET</entry>
  <entry>Delete a file.</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 88</entry>
  <entry>I$SEEK</entry>
  <entry>Reposition the logical file pointer</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 89</entry>
  <entry>I$READ</entry>
  <entry>Read data from a file or device</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 8A</entry>
  <entry>I$WRITE</entry>
  <entry>Write Data to File or Device</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 8B</entry>
  <entry>I$RDLN</entry>
  <entry>Read a text line with editing.</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 8C</entry>
  <entry>I$WRLN</entry>
  <entry>Write Line of Text with Editing</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 8D</entry>
  <entry>I$GSTT</entry>
  <entry>Get file device status.</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 8E</entry>
  <entry>I$SSTT</entry>
  <entry>Set file/device status</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 8F</entry>
  <entry>I$CLOS</entry>
  <entry>Close a path to a file/device.</entry>
  <entry></entry>
</row>
<row>
  <entry>103F 90</entry>
  <entry>I$DeletX</entry>
  <entry>Delete a file</entry>
  <entry></entry>
</row>
</tbody>
</tgroup>
</table>

<table frame="none">
<title>Standard I/O Paths</title>
<tgroup cols="1">
    <tbody>
    <row>
	<entry>0 = Standard Input</entry>
    </row>
    <row>
	<entry>1 = Standard Output</entry>
    </row>
    <row>
	<entry>2 = Standard Error Output</entry>
    </row>
    </tbody>
</tgroup>
</table>

<table frame="none">
<title>Module Types</title>
<tgroup cols="2">
<colspec colwidth="0.3in"/>
<colspec colwidth="1.5in"/>
	<tbody>
		<row>
				<entry>$1</entry>
				<entry>Program</entry>
		</row>
		<row>
				<entry>$2</entry>
				<entry>Subroutine module</entry>
		</row>
		<row>
				<entry>$3</entry>
				<entry>Multi-module</entry>
		</row>
		<row>
				<entry>$4</entry>
				<entry>Data module</entry>
		</row>
		<row>
				<entry>$C</entry>
				<entry>System Module</entry>
		</row>
		<row>
				<entry>$D</entry>
				<entry>File Manager</entry>
		</row>
		<row>
				<entry>$E</entry>
				<entry>Device Driver</entry>
		</row>
		<row>
				<entry>$F</entry>
				<entry>Device Descriptor</entry>
		</row>
	</tbody>
    </tgroup>
</table>


<table frame="none">
<title>File Access Codes</title>
<tgroup cols="2">
<colspec colwidth="1.0in"/>
<colspec colwidth="1.4in"/>
    <tbody>
	<row>
	    <entry>READ</entry>
	    <entry>$01</entry>
	</row>
	<row>
	    <entry>WRITE</entry>
	    <entry>$02</entry>
	</row>
	<row>
	    <entry>UPDATE</entry>
	    <entry>READ + WRITE</entry>
	</row>
	<row>
	    <entry>EXEC</entry>
	    <entry>$04</entry>
	</row>
	<row>
	    <entry>PREAD</entry>
	    <entry>$08</entry>
	</row>
	<row>
	    <entry>PWRIT</entry>
	    <entry>$10</entry>
	</row>
	<row>
	    <entry>PEXEC</entry>
	    <entry>$20</entry>
	</row>
	<row>
	    <entry>SHARE</entry>
	    <entry>$40</entry>
	</row>
	<row>
	    <entry>DIR</entry>
	    <entry>$80</entry>
	</row>
    </tbody>
</tgroup>
</table>


<table frame="none">
<title>Module Languages</title>
<tgroup cols="2">
<colspec colwidth="0.3in"/>
<colspec colwidth="1.5in"/>
	<tbody>
		<row>
				<entry>$0</entry>
				<entry>Data</entry>
		</row>
		<row>
				<entry>$1</entry>
				<entry>6809 Object code</entry>
		</row>
		<row>
				<entry>$2</entry>
				<entry>BASIC09 I-code</entry>
		</row>
		<row>
				<entry>$3</entry>
				<entry>Pascal P-Code</entry>
		</row>
		<row>
				<entry>$4</entry>
				<entry>Cobol I-code</entry>
		</row>
	</tbody>
    </tgroup>
</table>

<table frame="none">
<title>Module Attributes</title>
<tgroup cols="2">
<colspec colwidth="0.3in"/>
<colspec colwidth="1.5in"/>
	<tbody>
		<row>
				<entry>$8</entry>
				<entry>Reentrant</entry>
		</row>
	</tbody>
    </tgroup>
</table>



</appendix>


<appendix>
<title>Error Codes</title>
<sect1>
<title>OS-9 Error Codes</title>

<para>The error codes are shown both in hexadecimal (first column) and
decimal (second column). Error codes other than those listed are
generated by programming languages or user programs.</para>

<informaltable frame="none">
<tgroup cols="3">
<colspec colwidth="0.6in"/>
<colspec colwidth="0.6in"/>
<colspec colwidth="3.8in"/>
<thead>
<row>
<entry rowsep="1">HEX</entry>
<entry rowsep="1">DEC</entry>
<entry rowsep="0"></entry>
</row>
</thead>
<tbody>
<row>
 <entry>$C8</entry>
 <entry>200</entry>
 <entry>PATH TABLE FULL - The file cannot be opened because
 the system path table is currently full.</entry></row>
<row>
 <entry>$C9</entry>
 <entry>201</entry>
 <entry>ILLEGAL PATH NUMBER - Number too large or for non-existant path.</entry></row>
<row>
 <entry>$CA</entry>
 <entry>202</entry>
 <entry>INTERRUPT POLLING TABLE FULL</entry></row>
<row>
 <entry>$CB</entry>
 <entry>203</entry>
 <entry>ILLEGAL MODE - attempt to perform I/O function of which the device or file is incapable.</entry></row>
<row>
 <entry>$CC</entry>
 <entry>204</entry>
 <entry>DEVICE TABLE FULL - Can't add another device</entry></row>
<row>
 <entry>$CD</entry>
 <entry>205</entry>
 <entry>ILLEGAL MODULE HEADER - module not loaded because its
 sync code, header parity, or CRC is incorrect.</entry></row>
<row>
 <entry>$CE</entry>
 <entry>206</entry>
 <entry>MODULE DIRECTORY FULL - Can't add another module</entry></row>
<row>
 <entry>$CF</entry>
 <entry>207</entry>
 <entry>MEMORY FULL - Level One: not enough contiquous RAM free.
 Level Two: process address space full</entry></row>
<row>
 <entry>$D0</entry>
 <entry>208</entry>
 <entry>ILLEGAL SERVICE REQUEST - System call had an illegal code number</entry></row>
<row>
 <entry>$D1</entry>
 <entry>209</entry>
 <entry>MODULE BUSY - non-sharable module is in use by another process.</entry></row>
<row>
 <entry>$D2</entry>
 <entry>210</entry>
 <entry>BOUNDARY ERROR - Memory allocation or deallocation request not on a page boundary.</entry></row>
<row>
 <entry>$D3</entry>
 <entry>211</entry>
 <entry>END OF FILE - End of file encountered on read.</entry></row>
<row>
 <entry>$D4</entry>
 <entry>212</entry>
 <entry>RETURNING NON-ALLOCATED MEMORY - (NOT YOUR MEMORY)
 attempted to deallocate memory not previously assigned.</entry></row>
<row>
 <entry>$D5</entry>
 <entry>213</entry>
 <entry>NON-EXISTING SEGMENT - device has damaged file structure.</entry></row>
<row>
 <entry>$D6</entry>
 <entry>214</entry>
 <entry>NO PERMISSION - file attributes do not permit access requested.</entry></row>
<row>
 <entry>$D7</entry>
 <entry>215</entry>
 <entry>BAD PATH NAME - syntax error in pathlist (illegal character, etc.).</entry></row>
<row>
 <entry>$D8</entry>
 <entry>216</entry>
 <entry>PATH NAME NOT FOUND - can't find pathlist specified.</entry></row>
<row>
 <entry>$D9</entry>
 <entry>217</entry>
 <entry>SEGMENT LIST FULL - file is too fragmented to be expanded further.</entry></row>
<row>
 <entry>$DA</entry>
 <entry>218</entry>
 <entry>FILE ALREADY EXISTS - file name already appears in current directory.</entry></row>
<row>
 <entry>$DB</entry>
 <entry>219</entry>
 <entry>ILLEGAL BLOCK ADDRESS - device's file structure has been damaged.</entry></row>
<row>
 <entry>$DC</entry>
 <entry>220</entry>
 <entry>ILLEGAL BLOCK SIZE - device's file structure has been damaged.</entry></row>
<row>
 <entry>$DD</entry>
 <entry>221</entry>
 <entry>MODULE NOT FOUND - request for link to module not found in directory.</entry></row>
 <row>
 <entry>$DE</entry>
 <entry>222</entry>
 <entry>SECTOR OUT OF RANGE - device file structure damaged or
incorrectly formatted.</entry></row>
<row>
 <entry>$DF</entry>
 <entry>223</entry>
 <entry>SUICIDE ATTEMPT - request to return memory where your stack is located.</entry></row>
<row>
 <entry>$E0</entry>
 <entry>224</entry>
 <entry>ILLEGAL PROCESS NUMBER - no such process exists.</entry></row>
<row>
 <entry>$E2</entry>
 <entry>226</entry>
 <entry>NO CHILDREN - can't wait because process has no children.</entry></row>
<row>
 <entry>$E3</entry>
 <entry>227</entry>
 <entry>ILLEGAL SWI CODE - must be 1 to 3.</entry></row>
<row>
 <entry>$E4</entry>
 <entry>228</entry>
 <entry>PROCESS ABORTED - process aborted by signal code 2.</entry></row>
<row>
 <entry>$E5</entry>
 <entry>229</entry>
 <entry>PROCESS TABLE FULL - can't fork now.</entry></row>
<row>
 <entry>$E6</entry>
 <entry>230</entry>
 <entry>ILLEGAL PARAMETER AREA - high and low bounds passed in fork call are incorrect.</entry></row>
<row>
 <entry>$E7</entry>
 <entry>231</entry>
 <entry>KNOWN MODULE - for internal use only.</entry></row>
<row>
 <entry>$E8</entry>
 <entry>232</entry>
 <entry>INCORRECT MODULE CRC - module has bad CRC value.</entry></row>
<row>
 <entry>$E9</entry>
 <entry>233</entry>
 <entry>SIGNAL ERROR - receiving process has previous
 unprocessed signal pending.</entry></row>
<row>
 <entry>$EA</entry>
 <entry>234</entry>
 <entry>NON-EXISTENT MODULE - unable to locate module.</entry></row>
<row>
 <entry>$EB</entry>
 <entry>235</entry>
 <entry>BAD NAME - illegal name syntax.</entry></row>
<row>
 <entry>$EC</entry>
 <entry>236</entry>
 <entry>BAD HEADER - module header parity incorrect</entry></row>
<row>
 <entry>$ED</entry>
 <entry>237</entry>
 <entry>RAM FULL - no free system RAM available at this time</entry></row>
<row>
 <entry>$EE</entry>
 <entry>238</entry>
 <entry>UNKNOWN PROCESS ID - incorrect process ID number</entry></row>
<row>
 <entry>$EF</entry>
 <entry>239</entry>
 <entry>NO TASK NUMBER AVAILABLE - all task numbers in use</entry></row>
</tbody>
</tgroup>
</informaltable>
</sect1>

<sect1>
<title>Device Driver/Hardware Errors</title>

<para>The following error codes are generated by I/O device drivers, and
are somewhat hardware dependent. Consult manufacturer's hardware
manual for more details.</para>

<informaltable frame="none">
<tgroup cols="3">
<colspec colwidth="0.6in"/>
<colspec colwidth="0.6in"/>
<colspec colwidth="3.8in"/>
<thead>
<row>
<entry rowsep="1">HEX</entry>
<entry rowsep="1">DEC</entry>
<entry rowsep="0"></entry>
</row>
</thead>
<tbody>
<row>
 <entry>$F0</entry>
 <entry>240</entry>
 <entry>UNIT ERROR - device unit does not exist</entry></row>
<row>
 <entry>$F1</entry>
 <entry>241</entry>
 <entry>SECTOR ERROR - sector number is out of range.</entry></row>
<row>
 <entry>$F2</entry>
 <entry>242</entry>
 <entry>WRITE PROTECT - device is write protected.</entry></row>
<row>
 <entry>$F3</entry>
 <entry>243</entry>
 <entry>CRC ERROR - CRC error on read or write verify</entry></row>
<row>
 <entry>$F4</entry>
 <entry>244</entry>
 <entry>READ ERROR - Data transfer error during disk read
 operation, or SCF (terminal) input buffer overrun.</entry></row>
<row>
 <entry>$F5</entry>
 <entry>245</entry>
 <entry>WRITE ERROR - hardware error during disk write operation.</entry></row>
<row>
 <entry>$F6</entry>
 <entry>246</entry>
 <entry>NOT READY - device has "not ready" status.</entry></row>
<row>
 <entry>$F7</entry>
 <entry>247</entry>
 <entry>SEEK ERROR - physical seek to non-existant sector.</entry></row>
<row>
 <entry>$F8</entry>
 <entry>248</entry>
 <entry>MEDIA FULL - insufficient free space on media.</entry></row>
<row>
 <entry>$F9</entry>
 <entry>249</entry>
 <entry>WRONG TYPE - attempt to read incompatible media (i.e.
 attempt to read double-side disk on single-side drive)</entry></row>
<row>
 <entry>$FA</entry>
 <entry>250</entry>
 <entry>DEVICE BUSY - non-sharable device is in use</entry></row>
<row>
 <entry>$FB</entry>
 <entry>251</entry>
 <entry>DISK ID CHANGE - Media was changed with files open</entry></row>
<row>
 <entry>$FC</entry>
 <entry>252</entry>
 <entry>RECORD IS LOCKED-OUT - Another process is accessing the
requested record.</entry></row>
<row>
 <entry>$FD</entry>
 <entry>253</entry>
 <entry>NON-SHARABLE FILE BUSY - Another process is accessing the
requested file.</entry></row>
</tbody>
</tgroup>
</informaltable>
</sect1>
</appendix>





<appendix>
<title>Level Two System Service Requests</title>

<sect1>
<title>$3A* F$AllImg Allocate Image RAM blocks F$AllImg</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$AllImg</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 3A</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(A) = Beginning block number
(B) = Number of blocks
(X) = Process Descriptor pointer</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Allocates RAM blocks for process DAT image. The blocks do not
need to be contiguous.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>$4B* F$AllPrc Allocate Process descriptor F$AllPrc</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$AllPrc</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 4B</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>none</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(U) = Process Descriptor pointer</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Allocates and initializes a 512-byte process descriptor.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>$39* F$AllRAMAllocate RAM blocks F$AllRAM</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$AllRAM</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 39</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(B) = Desired block count</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(D) = Beginning RAM block number</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Searches the Memory Block map for the desired number of contuguous
free RAM blocks.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST
</para>
</sect1>

<sect1>
<title>$3F* F$AllTsk Allocate process Task number F$AllTsk</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$AllTsk</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 3F</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(X) = Process Descriptor pointer </entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Allocates a Task number for the given process.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST 
</para>
</sect1>

<sect1>
<title>$35* F$Boot Bootstrap system F$Boot</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$Boot</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 35</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>none</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>none</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Links to the module named "Boot" or as specified in the INIT module;
calls linked module; and expects the return of a pointer and size of
an area which is then searched for new modules.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>$36* F$BtMem Bootstrap Memory request F$BtMem</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$BtMem</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 36</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(D) = Byte count requested.</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry><literallayout>(D) = Byte count granted.
(U) = Pointer to memory allocated.</literallayout></entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Allocates requested memory (rounded up to nearest block) as
contigous memory in the system's address space.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST
</para>
</sect1>

<sect1>
<title>$50* F$ClrBlk Clear specific Block F$ClrBlk</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$ClrBlk</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 50</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(B) = Number of blocks
(U) = Address of first block</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry>None.</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Marks blocks in process DAT image as unallocated.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST
</para>
</sect1>

<sect1>
<title>$1B F$CpyMem Copy external Memory F$CpyMem</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$CpyMem</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 1B</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(D) = Starting Memory Block number
(X) = Offset in block to begin copy
(Y) = Byte count
(U) = Caller's destination buffer</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Reads external memory into the user's buffer for inspection. Any
memory in the system may be viewed in this way.</para>
</sect1>

<sect1>
<title>$44* F$DATLog Convert DAT block/offset to Logical Addr F$DATLog</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$DATLog</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 44</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(B) = DAT image offset
(X) = Block offset</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(X) = Logical address.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Converts a DAT imaqe block number and block offset to its
equivalent logical address.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>$45* F$DATTmp Make Temporary DAT image F$DATTmp</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$DATTmp</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 45</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(D) = Block number</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(Y) = DAT image pointer</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Builds a temporary DAT image to access the given memory block.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST
</para>
</sect1>

<sect1>
<title>$3B* F$DelImg Deallocate Image RAM blocks F$DelImg</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$DelImg</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 3B</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(A) = Beginning block number
(B) = Block count
(X) = Process Descriptor pointer</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Deallocated memory from the process' address space.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>$4C* Deallocate Process descriptor F$DelPrc</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$DelPrc</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 4C</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(A) = Process ID.</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Returns process descriptor memory to system free memory pool.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>$51* F$DelRam Deallocate RAM blocks F$DelRam</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$DelRam</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 51</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(B) = Number of blocks
(X) = Beginning block number.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry>None.</entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Marks blocks in system memory block map as unallocated.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>$40* F$DelTsk Deallocate process Task number F$DelTsk</title>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$DelTsk</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 40</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(X) = Process Descriptor pointer</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Releases the Task number in use by the process.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>

</sect1>

<sect1>
<title>$4D* F$ELink Link using module directory Entry F$ELink</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$ELink</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 4D</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(B) = Module type.
(X) = Pointer to module directory entry.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Performs a "Link" given a pointer to a module directory entry. Note
that this call differs from F$Link in that a pointer to the module
directory entry is supplied rather than a pointer to a module name.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>

</sect1>

<sect1>
<title>$4E* F$FModul Find Module directory entry F$FModul</title>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$FModul</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 4E</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(A) = Module type.
(X) = Module Name string pointer.
(Y) = Name string DAT image pointer.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry><literallayout>(A) = Module Type.
(B) = Module Revision.
(X) = Updated past name string.
(U) = Module directory entry pointer.</literallayout></entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>This call returns a pointer to the module directory entry given the
module name.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>$3E* F$FreeHB get Free High block  F$FreeHB</title>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$FreeHB</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 3E</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(B) = Block count
(Y) = DAT image pointer</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(A) High block number</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Searches the DAT image for the highest free block of given size.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>

</sect1>

<sect1>
<title>$3D* F$FreeLB get Free Low block  F$FreeLB</title>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$FreeLB</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 3D</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(B) = Block count
(Y) = DAT image pointer</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(A) = Low block number</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Searches the DAT image for the lowest free block of given size.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>$19 F$GBlkMp Get system Block Map copy F$GBlkMp</title>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$GBlkMp</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 19</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(X) = 1024 byte buffer pointer</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry><literallayout>(D) = Number of bytes per block (MMU block size dependent).
(Y) = Size of system's memory block map.</literallayout></entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Copies the system's memory block map into the user's buffer for inspection.</para>
</sect1>

<sect1>
<title>$1A F$GModDr Get Module Directory copy F$GModDr</title>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$GModDr</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 1A</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(X) = 2048 byte buffer pointer</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Copies the system's module directory into the user's buffer for inspection.</para>
</sect1>

<sect1>
<title>$18 F$GPrDsc  Get Process Descriptor copy  F$GPrDsc</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$GPrDsc</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 18</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(A) = Requested process ID.
(X) = 512 byte buffer pointer.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Copies a process descriptor into the calling process' buffer for
inspection There is no way to change data in a process
descriptor.</para>
</sect1>

<sect1>
<title>$37* F$GProcP Get Process Pointer  F$GProcP</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$GProcP</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 37</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(A) = Process ID</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(Y) = Pointer to Process Descriptor</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Translates a process ID number to the address of its process
descriptor in the system address space.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>$49* F$LDABX Load A from 0,1 in task B  F$LDABX</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$LDABX</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 49</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(B) = Task number
(X) = Data pointer</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(A) = Data byte at 0,X in task's address space</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>One byte is returned from the logical address in (X) in the
given task's address space. This is typically used to get one
byte from the current process's memory in a system state
routine.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>$46* F$LDAXY Load A [X, [Y] ]  F$LDAXY</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$LDAXY</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 46</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(X) = Block offset
(Y) = DAT image pointer</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(A) = data byte at (X) offset of (Y)</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Returns one data byte in the memory block specified by the DAT image in
(Y), offset by (X).</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>$47* F$LDAXYP  Load A [X+, [Y] ] F$LDAXYP</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$LDAXYP</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 47</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(X) = Block offset
(Y) = DAT image pointer</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry><literallayout>(A) = Data byte at (X) offset of (Y)
(X) = incremented by one</literallayout></entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Similar to the assembly instruction "LDA ,X+", except that (X) refers
to an offset in the memory block described by the DAT
image at (Y).</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>$48* F$LDDDXY Load D [D+X, [Y] ]  F$LDDDXY</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$LDDDXY</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 48</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(D) = Offset to offset
(X) = Offset
(Y) = DAT image pointer</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(D) = bytes address by [D+X,Y]</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Loads two bytes from the memory block described by the DAT image
pointed to by (Y). The bytes loaded are at the offset (D+X) in
the memory block.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>$4F* F$MapBlk Map specific Block F$MapBlk</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$MapBlk</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 4F</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(B) = Number of blocks.
(X) = Beginning block number.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(U) = Address of first block.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Maps specified block(s) into unallocated blocks of process address space.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>$38* F$Move Move data (low bound first) F$Move</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$Move</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 38</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(A) = Source Task number
(B) = Destination Task number
(X) = Source pointer
(Y) = Byte count
(U) = Destination pointer</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Moves data bytes from one address space to anotber, usually from
System's to User's, or vice-versa.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>$43* F$RelTsk Release Task number F$RelTsk</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
        <entry>ASSEMBLER CALL:</entry>
        <entry>OS9 F$RelTsk</entry>
</row>
<row>
        <entry>MACHINE CODE:</entry>
        <entry>103F 43</entry>
</row>
<row>
        <entry>INPUT:</entry>
        <entry>(B) = Task number</entry>
</row>
<row>
        <entry>OUTPUT:</entry>
        <entry>None.</entry>
</row>
<row>
        <entry>ERROR OUTPUT:</entry>
        <entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Releases the specified DAT Task number.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>$42* F$ResTsk Reserve Task number F$ResTsk</title>

<para> DAT task number.
</para>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
        <entry>ASSEMBLER CALL:</entry>
        <entry>OS9 F$ResTsk</entry>
</row>
<row>
        <entry>MACHINE CODE:</entry>
        <entry>103F 42</entry>
</row>
<row>
        <entry>INPUT:</entry>
        <entry>none</entry>
</row>
<row>
        <entry>OUTPUT:</entry>
        <entry>(B) = Task number</entry>
</row>
<row>
        <entry>ERROR OUTPUT:</entry>
        <entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Finds a free DAT task number.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>$3C* F$SetImg Set process DAT Image F$SetImg</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$SetImg</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 3C</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(A) = Beginning image block number
(B) = Block count
(X) = Process Descriptor pointer
(U) New image pointer</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Copies a DAT image into the process descriptor.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST
</para>
</sect1>

<sect1>
<title>$41* F$SetTsk Set process Task DAT registers  F$SetTsk</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$SetTsk</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 41</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(X) = Process Descriptor pointer</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Sets the process Task DAT registers.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>$34* F$SLink  System Link  F$SLink</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$SLink</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 34</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(A) = Module Type.
(X) = Module Name string pointer.
(Y) = Name string DAT image pointer.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry><literallayout>(A) = Module Type.
(B) = Module Revision.
(X) = Updated Name string pointer.
(Y) = Module Entry point.
(U) = Module pointer.</literallayout></entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Links a module whose name is outside the current (system) process'
adress space into the Address space that contains its name.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>$28* F$SRqMem System Memory Request  F$SRqMem</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$SRqMem</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 28</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(D) = byte count of requested memory</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry><literallayout>(D) = byte count of memory granted
(U) = pointer to memory block allocated</literallayout></entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>Allocates the requested memory (rounded up to the nearest
page) in the system's address space. Useful for allocating I/O buffers and
other semi-permanent system memory.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>$29* F$SRtMem System Memory Return  F$SRtMem</title>

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$SRtMem</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 29</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(D) = Byte count of memory being returned
(U) = Address of memory block being returned</literallayout></entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>
Returns system memory (e.g., memory in the system address space)
after it is no longer needed.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>$4A* F$STABX Store A at 0,X in task B F$STABX</title>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$STABX</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 4A</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(A) = Data byte to store in Task's address space
(B) = Task number
(X) = Logical address in task's address space to store</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None.</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>

</tbody>
</tgroup>
</informaltable>

<para>This is similar to the assembly instruction "STA 0,X", except
that (X) refers to an address in the given task's address space
rather than the current address space.</para>

<para>NOTE: THIS IS A PRIVILEGED SYSTEM MODE SERVICE REQUEST</para>
</sect1>

<sect1>
<title>$1C F$SUser Set User ID number F$SUser</title>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$SUser</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 1C</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry>(Y) = desired User ID number</entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>

</tbody>
</tgroup>
</informaltable>

<para>Alters the current user ID to that specified, without error checking.</para>
</sect1>

<sect1>
<title>$1D F$UnLoad Unlink module by name F$UnLoad</title>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 F$UnLoad</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 1D</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(A) = Module Type
(X) = Module Name pointer</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>None</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>

</tbody>
</tgroup>
</informaltable>
<para>Locates the module to the module directory, decrements its link
count and removes it from the directory if the count reaches zero.
Note that this call differs from F$UnLink in that the a pointer to module
name is supplied rather than the address of the module header.</para>
</sect1>

<sect1>
<title>DELETE Delete a file I$DeletX</title>
<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.4in"/>
<colspec colwidth="3.6in"/>
<tbody>
<row>
	<entry>ASSEMBLER CALL:</entry>
	<entry>OS9 I$Deletx</entry>
</row>
<row>
	<entry>MACHINE CODE:</entry>
	<entry>103F 90</entry>
</row>
<row>
	<entry>INPUT:</entry>
	<entry><literallayout>(X) = Address of pathlist
(A) = Access mode.</literallayout></entry>
</row>
<row>
	<entry>OUTPUT:</entry>
	<entry>(X) = Updated past pathlist (trailing spaces skipped).</entry>
</row>
<row>
	<entry>ERROR OUTPUT:</entry>
	<entry><literallayout>(CC) = C bit set.
(B) = Appropriate error code.</literallayout></entry>
</row>

</tbody>
</tgroup>
</informaltable>

<para>This service request deletes the file specified by the pathlist.
The file must have write permission attributes (public write if
not the owner), and reside on a multi-file mass storage device.
Attempts to delete devices will result in error.</para>

<para>The access mode is used to specify the current working directory
or me current execution directory (but not both) in the absence of
a full pathlist. If the access mode is read, write, or update, the
current data directory is assumed. If the access mode is
execute, the current execution directory is assumed. Note that
if a full pathlist (a pathlist beginning witt a "/") appears, the
access mode is ignored.</para>

<para>ACCESS MODES:</para>
<literallayout>
1 = Read
2 = Write
3 = Update (read or write)
4 = Execute
</literallayout>
</sect1>
</appendix>
</book>