3DO System Programmer's Guide Programmers

User Manual:

Open the PDF directly: View PDF PDF.
Page Count: 855

Download3DO System Programmer's Guide Programmers
Open PDF In BrowserView PDF
3DO System Programmer's Guide

3DO System Programmer's Guide
This book contains descriptions of the system level components that make up Portfolio: kernel, I/O,
tasks, filesystem, events, and so on. It is written for title developers who create programs that run on a
3DO system. To use this document, the you should have a working knowledge of the C programming
language and object-oriented concepts.
This book contains the following chapters:
●
●

●

●

●

●
●
●

●

●
●

●
●

●

●
●

Understanding the Kernel - Introduces the role of the kernel in the operation of Portfolio.
Tasks and Threads - Gives the background and necessary programming details to create and run
tasks and threads. Tasks and threads, although similar, operate differently in certain key respects.
Using Tags and TagArgs - Provides background on tags and Tag- Args and explains how to use
them.
Managing Linked Lists - Provides background on Portfolio linked lists and explains how to
manage them.
Managing Memory - Explains how to allocate memory, how to share it among tasks, how to get
information about it, and how to free it.
Managing Items -Explains what items are and how to use them.
Sharing System Resources -Explains techniques for sharing system resources.
Communicating Among Tasks - Provides background and necessary programming details for
doing intertask communication.
The Portfolio I/O Model- Provides an overview of 3DO hardware devices and explains how to
handle input/output operations using the standard Portfolio's I/O calls.
Portfolio Devices- Lists the device drivers and their associated commands and options.
The Filesystem and the File Folio-Describes the 3DO file system. It includes sample code that
illustrates how to use file system calls.
The Event Broker-Shows how a task uses the event broker to work with interactive devices.
The International Folio- Provides information on how an application can use the International
folio to determine the current language and country, and how to display dates, currency, and
numeric values in a manner consistent with the current language and country codes.
The Compression Folio- Describes the Compression folio that provides general-purpose
compression and decompression services.
The Math Folio- Introduces the different kinds of math calls available in the Math folio.
Access: A Simple User Interface-Explains how to use the Portfolio system task access to display
information to a user and accept user input.

file:///C|/%23%23DDOC/spg/00spg1.html [4/16/2002 11:12:19 PM]

Understanding the Kernel

Understanding the Kernel
This chapter introduces you to the role of the kernel in the 3DO operating system. It contains the
following topics:
●
●
●
●
●
●
●
●

Description of the Kernel
Multitasking
Managing Memory
Working With Folios
Managing Items
Semaphores
Intertask Communication
Portfolio Error Codes

file:///C|/%23%23DDOC/spg/01spg.html [4/16/2002 11:12:20 PM]

Description of the Kernel

Description of the Kernel
The kernel is a folio of function calls that is the heart of the Portfolio operating system. It controls 3DO
hardware and any software running on the system. It manages resources and provides communication
between running tasks and hardware devices. In particular, the kernel handles these responsibilities:
●

●

●

●

●

●

●

●

Multitasking. The kernel handles the execution of all programs (tasks) running on the system and
provides multitasking so that many tasks can run simultaneously.
Memory management. The kernel allocates memory to all running tasks and makes sure that one
task doesn't indiscriminately write to the memory allocated to another task. The kernel also
consolidates free memory, manages the system's own memory, and performs other memory
management duties.
Folio management. Folios are the mechanism used by the kernel to bundle related functionality.
Portfolio is composed of many folios, which together provide the system API. The kernel
manages the creation, disposal, loading, and unloading of folios.
Intertask communication. The kernel enables multiple tasks running simultaneously to
communicate with one another. The two primary methods of intertask communication are by
sending high-performance Boolean signals, or by sending messages.
Resource sharing. The kernel provides a check-in/check-out system for critical resources that
tasks share so that only one task at a time works with those resources.
Linked lists. The kernel creates and manages linked lists. Each linked list is an ordered group of
data structures that can grow, shrink, or change order as necessary.
Error codes and messages. The kernel provides a consistent way to handle error returns
throughout the system. It helps convert error codes into descriptive strings to make application
development easier.
I/O. The kernel provides synchronous and asynchronous communication with I/O devices, and
includes device and driver definitions for those devices.

file:///C|/%23%23DDOC/spg/01spg001.html [4/16/2002 11:12:20 PM]

Multitasking

Multitasking
One of the most important jobs of the kernel is managing the tasks that run on a 3DO system. Because
Portfolio supports preemptive multitasking, the kernel must provide conventions for deciding which
tasks get CPU time, and for saving a task's state when execution switches from one task to another.

Privileged and Non-Privileged Tasks
The kernel makes an important distinction between tasks running on a 3DO system, and divides them
into two categories: privileged tasks and non-privileged tasks. Privileged tasks have special rights that
non-privileged tasks do not have. Tasks that you create are always non-privileged. Only special tasks
created by a 3DO system can be privileged.

Multitasking
The kernel supports preemptive context switching for multitasking. It normally devotes one time
quantum (normally 15 milliseconds) of CPU time to a task and then switches execution to another task,
where it devotes another time quantum before switching to yet another task. To make the switch without
destroying the current state of the executing task, the kernel saves the context of the current task in the
task's TCB (task control block, a data structure that contains the parameters of each task), and reads the
context of the next task from its control block before executing that task. (A task's context includes states
such as its allocated address spaces and its register set.)
At any point during a time quantum, the kernel can preempt the current task, and immediately switch
execution to a more important task if necessary. To determine how and when to switch from one task to
another, the kernel reads task states and priorities.

Task States
A task can be in one of three states:
●

●

●

Running: The task is currently executing in the current time quantum.
Ready to run: The task is stored in the ready queue, awaiting execution by the kernel in a future
time quantum.
Waiting: The task is stored in the waiting queue, waiting for an external event (such as a vertical
blank or an I/O request) to occur. Once the task is notified of the event's occurrence, the task

file:///C|/%23%23DDOC/spg/01spg002.html (1 of 3) [4/16/2002 11:12:21 PM]

Multitasking

moves to the ready queue for execution.
The kernel executes tasks in the ready queue only, switching from task to task as required. It does not
execute tasks in the waiting queue, so waiting tasks don't require any CPU cycles-a courtesy to the other
tasks running on the system.
To determine how the ready-to-run tasks are executed, the kernel considers each task's priority.

Task Priorities
Each task has a priority that is associated with it. The priority is a value from 10 to 199: 10 is the lowest
priority, 199 is the highest priority. This priority can be changed at any time to give the task a higher or
lower priority than others in the ready queue-or to give the task an equal priority with other tasks.
Priority determines the order in which tasks in the ready queue are executed. The kernel executes only
the highest-priority task (or tasks) in the ready queue and doesn't devote any CPU time to lower-priority
tasks. If several tasks all share the same highest priority, the kernel rotates among those tasks, devoting
one time quantum to each. Lower-priority tasks in the ready queue don't receive any CPU time at all until
there are no higher-priority tasks in the ready queue: the higher-priority tasks either finish execution and
exit the system, move to the wait queue, or change to a lower priority.
Whenever a new task with a higher priority than the one running enters the ready queue, or whenever an
existing task is given a higher priority than the one running, the kernel preempts the running task. It
immediately switches execution to the higher-priority task, even if the switch occurs in the middle of a
time quantum. The higher-priority task then starts at the beginning of its own time quantum.
Note that round-robin scheduling takes place only when tasks of equal priority have the highest priority
in the ready queue. If only one task has the highest priority, only that task runs, and all others languish
until it finishes or is kicked out of the CPU limelight by another task with a higher priority. Note also that
if a task executes a Yield() call, it forgoes the rest of its quantum, and yields the CPU immediately to
other tasks of equal priority.

Waiting Tasks
To get into the wait queue, a task must execute a wait function call (such as WaitSignal(),
WaitIO(), or WaitPort()) to define what it's waiting for. It then becomes a waiting task and
receives no CPU time. When its wait conditions are satisfied, a task moves to the ready queue, where it
can compete for CPU time.
The wait queue is an important feature for keeping running tasks working at top speed without, wasting
CPU cycles on tasks waiting for external events. For the wait queue to work, each task must not use a
file:///C|/%23%23DDOC/spg/01spg002.html (2 of 3) [4/16/2002 11:12:21 PM]

Multitasking

loop that constantly checks for an event. Repeatedly checking for an event, known as "busy-waiting," is
greatly scorned in the Portfolio world-it eats up unnecessary CPU cycles and makes your task unpopular
with other developers and users around the world.

Task Termination
As each task runs, it accumulates its own memory and set of resources. The kernel keeps track of the
memory and resources allocated to each task and when that task quits or dies, the kernel automatically
closes those resources and returns the memory to the free memory pool. This means that the task doesn't
have to close resources and free memory on its own before it quits, a convenient feature. Good
programming practice, however, is to close and release resources and free memory within a task
whenever they are no longer in use. If a thread exits, it must free its memory so that the parent task can
allocate it for its own use.

Parent Tasks, Child Tasks, and Threads
Any task can launch another task. The launched task then becomes the child of the launching task and the
child task is a resource of the parent task. This means that when the parent task quits, all of its children
quit too.
To sever the parent/child relationship between two tasks so that the child task doesn't quit with the parent
task, the parent can use the SetItemOwner() function call to transfer ownership of the child task to
the child task itself. When the parent task quits, the child task continues to run.
A parent task spawns child tasks to take care of real-time processing and other operations. A child task
has one big disadvantage, it doesn't share memory with the parent. Because it must allocate its own
memory in pages, it can waste memory if its memory requirements are small. And because parent and
child don't share memory, they can't share values stored in shared data structures. To overcome these
disadvantages, a parent task can spawn a thread.
A thread is a child task that shares the parent task's memory. The owner of the thread can transfer
ownership of a thread to any thread in the parent's task family except to the thread itself. A task family is
a task and all of its threads.

file:///C|/%23%23DDOC/spg/01spg002.html (3 of 3) [4/16/2002 11:12:21 PM]

Managing Memory

Managing Memory
A multitasking system must manage memory carefully so that one task won't write to another's memory.
To do so, the kernel allocates exclusive memory to each task and restricts each task to writing to its own
memory unless given specific permission to do otherwise.

Types of Memory
When allocating memory, the kernel must consider the two main types of memory available in a 3DO:
DRAM (Dynamic Random Access Memory) and VRAM (Video Random Access Memory). DRAM is
memory with a standard data bus for read/write operations. VRAM has the standard data bus, but also
provides an additional bus named SPORT (short for Serial PORT), which can take streams of bits from
the VRAM arrays and generate video signals.
VRAM is premium memory because it can be used for everything, including special video operations.
Because the SPORT bus allows for very quick block memory transfers, VRAM is useful for
manipulating graphics and other complex data. VRAM can also be used for any other standard memory
operations. DRAM isn't as versatile as VRAM because it can't be used for all video operations, but works
fine for standard operations. DRAM can keep data for the cel engine (described in the Programming
3DO Graphics), which projects graphic images into VRAM.

Memory Size
A minimum 3DO system includes 2 MB of DRAM and 1 MB of VRAM for a total of 3 MB of RAM.
Optional memory configurations can, for this version of the hardware, go up to a maximum of 16 MB of
RAM: 1 MB of VRAM and 15 MB of DRAM, or 2 MB of VRAM and 14 MB of DRAM.
Note: Although the current hardware implementation doesn't address more than 16 MB total, future
implementations will go beyond that limit, so you must use full 32-bit addressing to ensure future
compatibility.
When the kernel allocates memory to tasks, it keeps track of each page of memory it allocates. The size
of a memory page is determined by the total amount of DRAM in the system divided by 64, the constant
number of DRAM pages available, regardless of the amount of memory in the system. In a standard 3
MB system, each page of DRAM is 32 KB large (2 MB of DRAM divided by 64). In a system with 16
MB of DRAM, the page size is 256 KB.
VRAM page size is similar to DRAM page size. If available VRAM is 1 MB, VRAM page size is 16
file:///C|/%23%23DDOC/spg/01spg003.html (1 of 5) [4/16/2002 11:12:22 PM]

Managing Memory

KB. If available VRAM is 2 MB, VRAM page size is 32 KB.
Note: The size of memory pages and the number of memory pages is subject to change at any time,
based on the current hardware design. Do not rely on these numbers within your titles.
To find out the page size of either type of memory, a task executes GetPageSize().
Warning: VRAM is also divided into banks. Each bank of VRAM is 1 MB large. The SPORT bus can't
transfer blocks of memory from one VRAM bank to another, so allocating VRAM within a single bank is
important for anything involving SPORT transfers. When bank location is important, a task should
always specify a bank, even though in a system with only 1 MB of VRAM, only one bank is available.
The task can never be sure that it's not running in a 2 MB VRAM system with two banks of VRAM.
To find out in which bank of VRAM an address is located, a task executes the GetBankBits() call.

Allocating Memory
Whenever a task starts from a file, the file includes the task's memory requirements: how much code
space and how much data space the task requires to run. Those memory requirements are determined
when the task's source code is compiled-set by the size of arrays dimensioned and other factors. The
kernel automatically allocates that much memory to the task before the task loads and runs. If the task
requires extra memory once it's running, it must use the kernel memory-allocation function calls
AllocMem(), AllocMemFromMemLists(), AllocMemBlocks(), or malloc() to request
that memory.
In a memory request, the task specifies the type of RAM it requires:
●
●
●
●
●

Any kind of RAM
VRAM only
Cel RAM (any RAM accessible to the cel engine)
Memory that doesn't cross a page boundary
Memory that starts on a page boundary

The task also specifies the amount, in bytes, of the memory it wants.
The kernel dedicates memory to a task a page at a time, and then allocates memory to the task from
within those dedicated pages. Consider an example: a 3 MB 3DO system has a 32- KB page size; a task
starts that requires 8 KB of memory. The kernel dedicates a single 32- KB page to the task by putting a
fence (discussed later in this chapter) around it. The kernel allocates the first 8 KB of the page to the task.
The task then requests another 20 KB of memory; the kernel allocates the next 20 KB of the page to the
task. 4 KB of free RAM remain in the page for future allocation, as shown in Figure 1.
file:///C|/%23%23DDOC/spg/01spg003.html (2 of 5) [4/16/2002 11:12:22 PM]

Managing Memory

Figure 1: Kernel page allocation.
When a task requests a block of memory that is larger than any contiguous stretch of free RAM left in a
task's RAM pages, the kernel dedicates a new page (or pages) of RAM to the task. It joins the new pages
with the memory already in the task's free list. It then allocates RAM from the new page(s). The kernel
will dedicate as many pages of RAM to the task as necessary to supply contiguous RAM; if it can't find
that much contiguous free RAM, it notifies the task that it failed to allocate the memory.
To see how that works, consider the last example where a task started with one page of dedicated RAM,
used 8 KB of the page for startup, and then requested and received 20 KB more. The task now requests 6
KB more RAM, but there are only 4 KB free in its dedicated pages. The kernel dedicates another page of
RAM to the task, a page that can't be guaranteed contiguous, to the first page of RAM. In this example,
consider the new page not to be contiguous. The kernel then allocates the first 6 KB of the new page to
the task. If it had tried to allocate the last 4 KB free in the first page along with the first 2 KB of the next
page, the block of memory would have been noncontiguous when it crossed the page boundary, so the
kernel allocates all of the memory block from the second page as shown in Figure 2.

file:///C|/%23%23DDOC/spg/01spg003.html (3 of 5) [4/16/2002 11:12:22 PM]

Managing Memory

Figure 2: Continuous allocation of memory block.

Memory Fences
When the kernel dedicates full pages of memory to a task, it sets up a memory fence around the dedicated
memory. The task can write to any address within its own memory, but normally it can't write outside of
its dedicated memory. The only exception is when one user task writes to the memory of another user
task with the second user task's permission. The first task can write there only with permission from the
second task; if it doesn't have permission, it can't write there. A user task can never write directly to
system memory (memory allocated to system tasks) because system tasks never grant write permission to
user tasks.
When a task writes (or tries to write) to RAM addresses beyond its allocated memory, it can have one of
two effects:
●

●

If the task tries to write outside its fence, the kernel aborts the task.
If the task writes inside its fence, the task isn't aborted, but it can write over its own data, causing
unforeseen problems.

Although fences restrict tasks from writing outside of their allocated memory, they don't restrict tasks
from reading memory elsewhere in the system. A user task can read memory allocated to other user tasks
as well as to system tasks.

Returning Memory
The kernel keeps track of free RAM in two ways: it keeps a list of all RAM pages allocated to tasks (and
so it knows which pages are free) and it lists free blocks of RAM within the dedicated pages. Whenever a
task is finished with a block of allocated RAM, it can free the block for further allocation by using a
function call that specifies the beginning address and size of the block. (The Kernel folio includes a
number of memory-freeing calls, such as FreeMem() and free().) If all the allocated blocks within a
dedicated page of RAM are freed, the kernel knows that the page is free but keeps the page dedicated to
the task for future allocation calls.
When a task wishes to release free RAM pages back to the kernel so the kernel can dedicate them to
other tasks, the task issues a ScavengeMem() call. This call causes the kernel to reclaim free pages
and to list them once again in the system free page pool.
Whenever a task quits or dies, all of its memory returns to the free RAM pool-unless it's a thread. When a
thread dies, its memory remains the property of the parent task, because a thread shares the memory of its
file:///C|/%23%23DDOC/spg/01spg003.html (4 of 5) [4/16/2002 11:12:22 PM]

Managing Memory

parent task.

Sharing Memory
The kernel gives every page of memory dedicated to a task a status that tells which task owns the page
and whether other tasks can write to that page or not. The status is set so that only the owning task can
write to the page. If the owning task wants to share write privileges with another task (or with several
other tasks), it can change the status with the call ControlMem(), which can take three actions:
●
●
●

Specify another task and give it write privileges to the page.
Specify another task and retract its write privileges to the page.
Specify another task and give it ownership of the page.

As long as a task owns a page, it can change the page status to any state it specifies-it can turn write
privileges on and off for other tasks or even for itself. However, once a task transfers ownership of a
page to another task, the original task can no longer set that page's status, which is under the sole control
of the new owner task. If the original task tries to write to the page, it will abort. Any I/O operation using
that page as a write buffer will also abort.

file:///C|/%23%23DDOC/spg/01spg003.html (5 of 5) [4/16/2002 11:12:22 PM]

Working With Folios

Working With Folios
Portfolio's folios, each a collection of function calls dealing with a different aspect of 3DO operation,
come in two types:
●

●

Permanent, where the folio is constantly in RAM and ready to handle function calls.
Demand-loaded, where the folio is stored on disk and must be loaded first before tasks can make
function calls to the folio.

The Kernel folio is a permanent folio by necessity; it includes the function calls that open other folios.
Other permanent folios are the Graphics, Audio, Math, and File folios. Examples of demand-loaded
folios include the International and Compression folios.
Demand-loaded folios are automatically fetched from disk when they are needed by a task. When a task
tries to open the folio, the kernel first looks in memory for the folio. If the folio isn't found in memory,
the kernel then tries to load it from disk. Once the folio has been loaded from disk, it can be used by
other tasks in the system without having to reload it.
When demand-loaded folios are no longer in use by any task, the kernel can remove them from memory
to make the memory available to other uses in the system.

file:///C|/%23%23DDOC/spg/01spg004.html [4/16/2002 11:12:22 PM]

Managing Items

Managing Items
In a multitasking system, tasks often share resources such as RAM, I/O devices, and data structures. If
the system doesn't manage those resources carefully, a task that depends on a shared resource can be
brutally disappointed. For example, one task creates a data structure for a second task to read and act
upon. If the first task dies and its data structure is no longer maintained or ceases to exist, the second task
can find itself reading erroneous data that can crash it. In another example, a task creates a data structure
and then use an invalid pointer to that structure (typically a NULL or uninitialized pointer). Because the
pointer doesn't point where it should, the task can read totally erroneous data or, even worse, try to write
to the data structure and crash itself, another task, or the 3DO system.
Note: Using a NULL pointer to read is illegal and causes an abort to occur on 3DO development
systems.

Items
To insure the integrity of shared resources, the kernel provides items. An item is a system-maintained
handle for a shared resource. The handle contains a globally unique item number and a pointer to the
resource. When a task needs access to a shared resource, the task simply asks for the resource by item
number instead of using a pointer to point directly at the resource. The kernel checks its list of items and,
if it finds the requested item, performs any requested actions on the item. If the kernel finds that the item
no longer exists, it informs the requesting task that access failed, and the task can go on without crashing
itself or the system.
An item can refer to any one of many system components: a data structure used to create graphics, an I/O
device, a folio, or even a task itself. In fact, almost all system-standard structures must be created as
items. You'll find one of the most commonly used kernel calls is CreateItem(), which, appropriately
enough, creates items. You use it to start a task, to lay out a graphics environment, to create messages to
send between tasks, and to handle many other Portfolio functions.

Creating an Item
To create an item, a task typically creates a list of parameters (tag arguments) for the item. The
parameters can include a name for the item, its dimensions and contents, and other important
information. The task then uses CreateItem() to ask the kernel to create the item. The task supplies
an item-type number that specifies the type of item to create, and a pointer to the list of parameters for
the item. The kernel has a predefined set of item types (which you can find in the 3DO Portfolio
Reference Manual). Each item requires different parameters to define it.

file:///C|/%23%23DDOC/spg/01spg005.html (1 of 3) [4/16/2002 11:12:23 PM]

Managing Items

The kernel receives the item parameters, and-if they're correct for the specified item type-creates the
item. The item contains a globally unique ID number, the item type, a pointer to the resource handled by
the item, and other parameters passed to it. The kernel returns the item number to the task that created the
item. The kernel records the fact that the item belongs to that task.
Portfolio contains a large number of convenience calls that let you easily create items; for example,
CreateMsgPort() and CreateThread(). It is generally simpler to use these higher-level routines
instead of calling CreateItem() directly.

Opening Items
Many system items are predefined and stored on the system boot disk. They don't need to be created
from scratch, only opened. To open a system item, a task uses the FindAndOpenItem() call to
specify the type of the item to open, provides an array of the arguments required to open the item, and
passes that information along to the kernel to open the item. The kernel finds the item on the disk, brings
necessary data structures into system memory, assigns the item a number, and returns the item number to
the task that asked for the item to be opened. When the task is finished with the opened item, it uses the
CloseItem() call to close the item.

Using Items
Once an item is opened or created, tasks can use it by specifying its item number. If a task doesn't have
the number for an item it wants to use, or knows the item number but doesn't know what type of item it
is, the kernel provides item-handling function calls such as FindItem(), FindNamedItem(), and
LookupItem(). These calls help find items by name, number, or other criteria, and then return item
type, item number, or other information about the item.
Note: Some types of items, such as folios and devices, must be opened with OpenItem() or
FindAndOpenItem() before a task can use the item.
The kernel provides the SetItemPri() call to change the priority of an item within a list of items. It
also provides the SetItemOwner() call to change ownership of an item.

Deleting Items
Whenever a task finishes using an item that it created, it can delete the item with DeleteItem(),
which removes the item and frees any resources committed to it, such as RAM devoted to the item's data
structure. The deleted item's number is not recycled when new items are created, so the kernel can inform
tasks trying to use that item number that the item no longer exists.

file:///C|/%23%23DDOC/spg/01spg005.html (2 of 3) [4/16/2002 11:12:23 PM]

Managing Items

There is one important rule about item deletion: a task can't delete any item it doesn't own. This means
that if a task creates an item and then passes ownership to another task, the first task can't delete the itemonly the new owner can delete the item.
Whenever a task or thread quits or dies, the kernel automatically deletes all items that it created, and
closes any items that it opened.

file:///C|/%23%23DDOC/spg/01spg005.html (3 of 3) [4/16/2002 11:12:23 PM]

Semaphores

Semaphores
Many tasks running on a 3DO system can share data structures, storing a structure in one task's memory
and allowing one or more outside tasks to read and write to that structure. Because one task using the
data structure can never be sure what another task may be doing to the same structure, dangers arise. For
example, one task writes to a data structure at the same time that another task writes to it. One task
overwrites the data of another, and neither is aware of what happened. To avoid conflicts like this, a task
must be able to lock down a shared data structure while it is working on it, and then release the structure
when it's done.
To provide a lock, the kernel offers an item called a semaphore, which is defined as an element of a data
structure. You can think of the semaphore as an "occupied" sign for a data structure. A polite task checks
the semaphore of a data structure before it uses the structure. If the semaphore says that the structure is
currently unused, the task can go to work on the structure. If the semaphore says that the structure is in
use, the task must either wait until the semaphore says the structure is free or return to execution without
using the structure.
To use a data structure with a semaphore, a task makes the function call LockSemaphore() to lock
the structure's semaphore. If the semaphore is unlocked, the kernel locks it and the task can proceed with
its business, using the semaphored data structure as it sees fit without interference from other polite tasks.
When the task is done, it makes another function call, UnlockSemaphore(), to unlock the
semaphore, releasing the semaphored data structure for use by other tasks.
When a task calls LockSemaphore(), it specifies what it will do if the semaphore is already locked:
wait for the semaphore to be unlocked (putting itself in the wait queue); or return to execution without
using the semaphored structure. If the semaphore is locked, the task acts accordingly.
The semaphore is a completely voluntary mechanism; it is what its name implies, only a flag that tells
whether a data structure is in use or not. It does not deny write permission to tasks that want to use the
data structure without checking the semaphore. If you want to share a data structure with another task, be
sure that the other task is written to check for the semaphore before it goes about its business.

file:///C|/%23%23DDOC/spg/01spg006.html [4/16/2002 11:12:23 PM]

Intertask Communication

Intertask Communication
When one task needs to communicate with another task, it can be a simple matter of notification ("Hey!
I'm finished doing what you asked me to do") or a more involved passing of detailed information
("Here's the table of values you asked me to calculate"). Portfolio provides mechanisms to handle both:
signals for simple notification and messages for passing detailed information.

Signals
A signal is a kernel mechanism that allows one task to send a flag to another task. The kernel dedicates
one 32-bit word in a task's TCB (task control block) for receiving signals. The kernel writes to that word
each time it carries a signal to the task.
The 31 least-significant bits of the 32-bit signal word each specify a different signal; the most-significant
bit is used for errors. Eight of the signal bits (0 to 7) are reserved by the kernel for system signals; the
other 23 bits (8 to 30) are left for custom user-task signals.

Allocating Signals
A task can't receive signals from another user task unless it has allocated a signal bit on which to receive.
To do so, it uses the AllocSignal() call, which returns a 32-bit value containing the next unused
user signal bit (the 32-bit value is called a signal mask). The task can send its signal mask to other tasks;
they can then send a signal back to the task, using the user signal bit set in its signal mask.
All tasks can receive system signals at any time. The lower-8 signal bits are reserved for this purpose.
For example, the system sends a task a signal (SIGF_DEADTASK) whenever one of its child threads or
task dies.

Sending a Signal
To send a signal to another task, a task prepares a 32-bit signal mask. It sets the appropriate bit (or bits, if
it's sending more than one signal) in the mask to 1 and sets the rest of the bits to 0. For example, if the
task wants to send a signal using bit 14, it creates the signal mask "00000000 00000000 01000000
00000000" (in binary). The task then uses the SendSignal() call to specify the item number of the
task it wants to signal and passes along the signal mask. The kernel logically ORs the signal mask into
the receiving task's TCB. Bits set in the t_SigBits field of the TCB indicate signals that the task has
received, but not yet acknowledged.

file:///C|/%23%23DDOC/spg/01spg007.html (1 of 3) [4/16/2002 11:12:24 PM]

Intertask Communication

Receiving a Signal
A task waits for one or more signals by using the WaitSignal() call. The kernel checks to see if any
of the bits in the task's signal mask match the bit mask passed WaitSignal(), indicating that a signal
has been received on that bit. If so, WaitSignal() clears the bits that match and immediately returns,
letting the task act on any signals it has received. If there are no received signals in the signal mask, the
task is put in the wait queue until it receives a signal it wants.

Freeing Signal Bits
To free up signal bits that a task has allocated, the task uses the FreeSignal() call to pass along a
free signal mask. The free signal mask should have a 1 in each bit where the signal bit is to be freed (that
is, set to 0 in the signal mask) and a 0 where the signal bit remains as it is.

Messages
A message is an item that combines three elements: a variable number of bytes of message data, 4 bytes
available for an optional reply to the message, and a specified place (a reply port, explained later) where
a reply to the message can be sent.
A message won't work without two message ports: one created by the task receiving the message and
another created by the task sending the message. The message port is an item that sets a user signal bit
for incoming message notification. It includes a message queue that receives and stores incoming
messages.

Creating a Message
To create a message, a task can use a number of calls including CreateMsg(),
CreateSmallMsg(), and CreateBufferedMsg(). These functions accept a string of text as the
message's name, a priority for the message, and the item number of the reply port for replies to the
message. It returns the item number of the newly created message for working with the message later.

Creating a Message Port
To create a message port, a task uses the CreateMsgPort() call, which it provides with a string of
text as a message port name. The kernel creates a message queue in system RAM for the message port,
automatically assigns a user-task signal bit for the message port, and gives the message port an item
number. The task is now ready to receive messages at the port.

Sending a Message
file:///C|/%23%23DDOC/spg/01spg007.html (2 of 3) [4/16/2002 11:12:24 PM]

Intertask Communication

If a task wants to send a message to another task, it must first know the item number of a message port of
the receiving task. (If it knows the name of the message port, it can use the FindMsgPort() call to
find the item number.) The sending task then uses either SendMsg() or SendSmallMsg() to fill out
a message, providing a destination message port item number and some message data to pass. The kernel
inserts the message, according to priority, into the destination port message queue, then signals the
receiving task that a message has arrived at its message port.

Receiving a Message
To receive a message, a task has two options:
●

●

It can use the GetMsg() call to check the message port and retrieve the top message in the list if
there are any messages. If there are no messages, the task resumes execution.
It can use the WaitPort() call to wait for a message. This puts the task into wait state until it
receives a message at its message port. The task then retrieves the message and resumes
execution.

Replying to a Message
A task that sends a message usually needs a reply from the task that receives the message, so the sending
task must specify a message port of its own as the reply port. (If the sending task doesn't have its own
message port, it must create one before creating a message.) When the receiving task receives the
message, it uses either ReplyMsg() or ReplySmallMsg() to return the same message to the reply
port with a 4-byte reply written into the message (stored in the 4-byte msg_Result field of the
Message structure). The sending task receives the reply and reads the 4-byte reply.

Interpreting a Message
When one task sends a message to another task, the meaning of the message data is completely arbitrary
and is determined by the two tasks sharing the message. In many cases, the message data is composed of
a pointer to a data structure created in the sending task's memory along with the data structure's size. The
receiving task then uses the pointer and size to read the data at that address.

file:///C|/%23%23DDOC/spg/01spg007.html (3 of 3) [4/16/2002 11:12:24 PM]

Portfolio Error Codes

Portfolio Error Codes
Portfolio has a uniform definition for the format of error codes. Whenever system components must
return an error, they always use the standard error code format explained here.
All Portfolio error codes are negative 32-bit numbers that are subdivided into multiple subcomponents.
Using these components, you can identify which subsystem generated the error, and get a modulespecific error number. Table 1 lists the various components of an error code:
Table 1: Error code components.
------------------------------------------------------Bit(s)|Purpose
------------------------------------------------------31
|This bit is always set. It makes all error codes
|negative numbers.
------------------------------------------------------25-30 |Object type that generated the error. This field
|identifies what generated the error: a folio, a
|device, a task, or another object type,
|generated the error. Possible values for this
|field include ER_FOLI, ER_DEVC, ER_TASK, or
|ER_LINKLIB.
------------------------------------------------------13-24 |Object ID. This is a code that uniquely
|identifies the component that generated the
|error. The value for this field is created with
|MakeErrID() and is basically two 6-bit
|characters identifying the module that caused
|the error. For example, kernel errors have an
|object ID of Kr.
------------------------------------------------------11-12 |A severity code. Possible values for this field
|include: ER_INFO, ER_WARN, ER_SEVERE, or
|ER_FATAL.
------------------------------------------------------9-10 |An environment code. This code defines who
|created the module that generated the error.
|Possible error values for this field include:
|ER_E_SSTM for system modules, ER_E_APPL for
|application modules, and ER_E_USER for user-code
|modules.
file:///C|/%23%23DDOC/spg/01spg008.html (1 of 2) [4/16/2002 11:12:24 PM]

Portfolio Error Codes

------------------------------------------------------8
|Error class. Possible error values for this
|field are: either ER_C_STND for a standard error
|code or ER_C_NSTND for a nonstandard error code.
|Standard error codes are errors that are well
|known in the system and have a default string to
|describe them. Nonstandard errors are
|module-specific and the module must provide a
|string to the system to describe the error.
------------------------------------------------------0-7
|The actual error code. The meaning of this code
|depends on the module that generated the error,
|and whether it is a standard or nonstandard
|error.
------------------------------------------------------The PrintfSysErr() kernel call accepts any error code, and prints an error string describing the
error to the debugging terminal. When developing code, it is extremely useful to know why a system call
is failing.
Note: Besides handling multitasking, memory management, folios, items, intertask communication, and
linked lists, the kernel also handles I/O and hardware control-both topics for another section. You'll find
them described in The Portfolio I/O Model."

file:///C|/%23%23DDOC/spg/01spg008.html (2 of 2) [4/16/2002 11:12:24 PM]

The Portfolio I/O Model

The Portfolio I/O Model
This chapter provides an overview of the 3DO system's hardware devices and the system software that
controls them. This chapter contains the following topics:
●
●
●
●
●
●

Introduction
Hardware Devices and Connections
I/O Architecture
Performing I/O
Examples
Function Calls

file:///C|/%23%23DDOC/spg/09spg.html [4/16/2002 11:12:25 PM]

Introduction

Introduction
The 3DO environment is rich in device possibilities: any 3DO unit may be set up with few or many
devices. Manufacturers can make 3DO units with a bare-bones configuration, or they can add extra
devices such as a second CD-ROM drive or a digital television tuner. Once the 3DO unit is out of the
box, users can add more devices by plugging in any of a large variety of controls, from simple controller
pads to keyboards, or by adding peripherals such as modems or RAM mass storage.
Because a task can run on a multiplayer with any number of devices attached to it, a task can't assume
that it knows what devices are available to it. Consider for example if a task knew the low-level details of
a particular CD-ROM drive. If the drive hardware were to change between 3DO manufacturers, the task
would suddenly fail to operate correctly.
To help a task traverse a world of devices that may change from minute to minute, Portfolio provides
device drivers and I/O calls that can sense attached devices and know how to communicate with them, all
without specific hardware knowledge on the part of client tasks.

file:///C|/%23%23DDOC/spg/09spg001.html [4/16/2002 11:12:25 PM]

Hardware Devices and Connections

Hardware Devices and Connections
The 3DO standard defines a set of buses and ports for connecting hardware devices. These bus and port
definitions make the best use of existing hardware technologies. Keep in mind a very important warning
as you read about the hardware described in this chapter: the bus and port definitions may change. As
hardware prices fall, better performance will be possible using advanced hardware that costs less than the
currently specified hardware; the 3DO standard will change to take advantage of better hardware as it
becomes available. In other words, the hardware descriptions in this chapter are a snapshot of the current
3DO standards. Don't write software that assumes 3DO hardware is always going to be manufactured as
it is now. Fortunately, you don't have to write hardware-specific code, because Portfolio takes care of the
specifics for you, as you'll read later in this chapter.

Internal Buses
The 3DO system currently offers a set of three internal buses that provide connections for devices
mounted within the 3DO box. They include the following:
●

●

●

The main data bus that connects the CPU to RAM. It can also connect to a full motion video
(FMV) cartridge.
The SlipStream bus that currently has a video-out signal and, in the future, may support video-in
as well.
The Slow bus that is a simple, slow, and low-cost 8-bit bus for devices mounted on the
motherboard. Those devices can include ROM, NVRAM, and a digital tuner.

The Expansion Port
The expansion port, which is a parallel port, provides external connections for plug-in modules that a
user may want to add to a 3DO unit. Those modules include devices such as an auxiliary CD-ROM drive,
a modem, RAM mass storage, and, in the future, read/write mass storage such as a hard disk drive.
To support high-power expansion devices, the expansion port uses a custom protocol that provides a fast
data rate. The port can support up to 15 devices, all of which are auto-configuring, so users don't have to
set DIP switches or set confusing software parameters to use a device; they just plug the device in and let
the software do the rest.

The Control Port
file:///C|/%23%23DDOC/spg/09spg002.html (1 of 2) [4/16/2002 11:12:25 PM]

Hardware Devices and Connections

The control port, which is a serial port, is used mainly to connect user-interface devices that control the
3DO unit. These devices include:
●

The controller pad a standard control that includes a joypad and buttons, and may include a
headphone jack. This device is used to point, select, and control on-screen action. It can also
provide stereo sound accompaniment through the headphone jack.

●

The photo-optic gun is used to shoot at targets on the video screen.

●

Stereoscopic glasses are used to view stereoscopic displays.

●

An interlink unit connects one 3DO unit to one or more other units.

●

A mouse or trackball is used to point to and select objects on the screen.

●

A keyboard is used to type in text.

●

A robot control device is used to remotely control a mechanical robot.

●

Any number of custom devices created and sold by 3DO-licensed manufacturers.

The control port supports a daisy chain of devices. Because a new device can always be plugged in to the
last device in the chain, the control port doesn't have a fixed maximum number of devices, but instead is
limited by the data bandwidth of the port. In other words, you can keep plugging in more control devices
until the control port is overwhelmed with data and starts to choke up. If this happens, the control port
fails to recognize the newly plugged in control devices that go beyond the port's capacities.
The control port is designed to be simple, robust, and convenient to users, who may plug and unplug
controllers while software is running. All 3DO control devices are autoconfiguring. Portfolio polls the
control port to see what's plugged in, and provides the appropriate drivers to work with each device. The
control port is not fast when compared to the expansion port and internal buses; it reads and writes data
once every video field (which occurs 60 times per second on NTSC systems, and 50 times per second on
PAL systems), and currently handles up to 2048 bits of information per field. In addition to data, the
control port carries an analog stereo audio output, which can be heard over earphones plugged into a
controller stereo jack.
Tasks interface to the control port using the event broker. To learn about interfacing to external control
port hardware, see The Event Broker.

file:///C|/%23%23DDOC/spg/09spg002.html (2 of 2) [4/16/2002 11:12:25 PM]

The Event Broker

The Event Broker
This chapter shows how a task uses the event broker to work with interactive devices. This chapter
contains the following topics:
●
●
●
●
●
●
●
●
●
●

About the Event Broker
Sending Messages Between Tasks and the Event Broker
The Process of Event Monitoring
Connecting a Task to the Event Broker
Monitoring Events Through the Event Broker
High-Performance Event Broker Use
Reconfiguring or Disconnecting a Task
Other Event Broker Activities
Event Broker Convenience Calls
Function Calls

file:///C|/%23%23DDOC/spg/12spg.html [4/16/2002 11:12:26 PM]

About the Event Broker

About the Event Broker
Working with an interactive device such as a controller pad poses a challenge to traditional I/O
architectures; a user can change the device's state at any time, so a task working with a device must
monitor it constantly. Successful device monitoring requires a task to run a loop that continually polls the
interactive device, or requires the interactive device driver to accept an I/O request but does not respond
until it detects a change in the device. In the first case, the polling task uses a lot of processor time. In the
second case, a task has to have several IOReqs pending to avoid losing any device changes while the
driver returns an IOReq. Portfolio provides the event broker, a solution to interactive device I/O that
requires neither polling nor multiple IOReqs.
The event broker is a task that constantly monitors activity on attached interactive devices. Currently,
interactive devices are attached only to the control port on the 3DO system. The event broker monitors
the control port to see what the devices are doing.
Activities on interactive devices are called events. Events include joypad presses and releases, key
strokes, mouse rolling, plugging a new control device into the control port, unplugging a device from the
control port, and many others. Events can occur on any hardware device attached to the control port. A
hardware device is called a pod. The event broker always identifies the pod in which an event occurs.
The event broker starts when the system starts up, and stands between user tasks and the interactive pods
on the control port. To work with interactive devices, a user task connects to the event broker and
registers itself as a listener. A listener is a task that connects to the event broker to receive event
notification and to pass data to pods. To become a listener, a task creates a message port for
communication with the event broker. Then the task communicates its requests to the event broker with
messages; the event broker responds to these messages with its own messages. I/O operations through the
event broker are carried out through messages instead of IOReqs.

Specifying and Monitoring Events
The first message a listener task sends to the event broker contains two event masks. A listener task uses
the first event mask to specify which of the 256 different event types it is interested in hearing about.
This mask is the trigger mask; it lists all event types that can trigger an event message to the listener. The
second event mask is the capture mask; it lists all event types for which the event broker must check
status whenever it sends an event message.
In each video field the event broker checks pods for events, 60 times per second on NTSC systems, and
50 times per second on PAL systems. If any of the events it senses match an event in a listener task
trigger mask, the event broker composes an event message to send to the listener. That event message

file:///C|/%23%23DDOC/spg/12spg001.html (1 of 3) [4/16/2002 11:12:26 PM]

About the Event Broker

contains a pointer to an accompanying data block that contains information about all event types that are
specified in either the trigger mask or the capture mask.
The event broker takes a "snapshot" of the pods' states whenever a triggering event occurs. For example,
a listener can specify "controller pad button down" as a trigger event and then specify "gunlike-device
button pressed" and "keyboard key pressed" as capture events. Whenever a controller pad button is
pressed down in a pod, the event broker is triggered to send an event message to the listener. The event
message's data block contains the status of "controller pad button down" (true because it was the
triggering event), the status of "gunlike-device button pressed" (true or false, depending on whether or
not the button was pressed on any attached gunlike devices during the field), and the status of "keyboard
key pressed" (true or false, depending on whether or not any keys were pressed on any attached
keyboards). The listener task now knows that the controller pad button was pressed, and knows whether
or not any keyboard keys or buttons on gunlike devices were pressed during the same video field. The
listener can then take appropriate action.
Because the event broker notifies listeners of events via messages, a listener task can enter the wait state
for an event broker message, just as a task waits for any other message. This allows synchronous I/O
with interactive pods. A listener can also continue execution after sending an event broker message,
which allows asynchronous I/O. In either case, whenever a listener task receives a message from the
event broker, it must reply to the event broker and say the message is processed and can be reused. If the
listener task does not reply, the event message queue can fill up, and it can lose events in which it was
interested.

Working With Input Focus
Input focus is an important concept to both 3DO users and 3DO tasks. When several tasks occupy the
display at the same time, input focus determines which task should respond to the user's actions. For
example, a pinball game occupies one part of the display, while a CD-ROM encyclopedia occupies
another part. When the user presses the "left" direction of the controller pad's joypad, does the left pinball
flipper flip, or does the reader for the encyclopedia move back a page? It depends on which program has
the input focus. If the user chose the reader earlier (via menu selection, for example) so that the reader is
now the active task, the reader holds the input focus and responds to the controller pad.
The event broker sends events to the appropriate focus holder-if connected tasks are set up to pay
attention to focus. Whenever a task connects to the event broker, it can request to be one of three listener
types:
●

●

A focus-dependent listener, which only receives its specified events from the event broker when
the event broker knows that the task has the input focus.
A focus-independent listener, which receives all of its specified events from the event broker at all

file:///C|/%23%23DDOC/spg/12spg001.html (2 of 3) [4/16/2002 11:12:26 PM]

About the Event Broker

times.
●

A focus-interested listener, which receives all of its specified events when it has the focus, and
only non-user interface type events when it does not have the focus.

Tasks such as the encyclopedia reader and the pinball game mentioned above are usually focusdependent listeners because they only respond when the user selects the task. Tasks that offer a programselection menu to the user are usually focus-independent because they must respond at any time to user
requests, even if they do not hold the focus.

Reconfiguring or Disconnecting an Event Broker
Connection
As a listener task works with the event broker, it can send a message requesting a new configuration at
any time. The new configuration can reset the task's focus dependence, specify new capture and trigger
events, set a new message port, or change other connection parameters. A listener task can also request to
be disconnected from the event broker so that it will no longer be notified of interactive events.

Other Event Broker Activities
Although the event broker's main activity is monitoring and reporting on interactive device events, it can
also:
●
●
●
●

Provide lists of connected devices and listener tasks
Send and receive I/O data from interactive devices
Send generic commands to interactive devices
Notify a listener task of events occurring in other listener tasks

file:///C|/%23%23DDOC/spg/12spg001.html (3 of 3) [4/16/2002 11:12:26 PM]

Sending Messages Between Tasks and the Event Broker

Sending Messages Between Tasks and
the Event Broker
All communication between the event broker and connected listener tasks is through messages (a process
discussed in earlier kernel chapters). These messages, which pass from listener to event broker or from
event broker to listener, are called event broker messages. Before programming with the event broker,
you should understand how these messages work.

Message Flavors
Each event broker message comes in a flavor that identifies the purpose of the message. The flavor of the
message determines the type (or types) of data structures contained in the data block, and specifies how
the message recipient should handle the message. The data structure EventBrokerHeader is always the
first field of the first data structure within a message data block. Its definition is shown below:
typedef struct EventBrokerHeader
{
enum EventBrokerFlavor ebh_Flavor;
} EventBrokerHeader;
EventBrokerHeader indicates the flavor of the message. Table 1 shows the available flavors.
Table 1: Event broker message flavors.
-------------------------------------------------------Event Broker Flavor
|Operation Requested
-------------------------------------------------------EB_NoOp
|No operation requested.
-------------------------------------------------------EB_Configure
|(Task to EB) Connect this task to
|the event broker and register its
|configuration.
-------------------------------------------------------EB_ConfigureReply
|Event broker reply to
|EB_Configure.
-------------------------------------------------------EB_EventRecord
|(EB to task) The events listed in
|the data block occurred in this
|field and are events in which the

file:///C|/%23%23DDOC/spg/12spg002.html (1 of 5) [4/16/2002 11:12:27 PM]

Sending Messages Between Tasks and the Event Broker

|task is interested.
-------------------------------------------------------EB_EventReply
|A listener's reply to
|EB_EventRecord.
-------------------------------------------------------EB_SendEvent
|(Task to EB) An event has
|happened within a task. This
|command is not currently
|implemented.
-------------------------------------------------------EB_SendEventReply
|Event broker reply to
|EB_SendEvent.
-------------------------------------------------------EB_Command
|This operation is not currently
|determined.
-------------------------------------------------------EB_CommandReply
|Event broker reply to EB_Command.
-------------------------------------------------------EB_RegisterEvent
|(Task to EB) Register this custom
|event name and assign an event
|number to that name. This command
|is not currently implemented.
-------------------------------------------------------EB_RegisterEventReply |Event broker reply to
|EB_RegisterEvent.
-------------------------------------------------------EB_GetListeners
|(Task to EB) Tell the requesting
|task which tasks are connected to
|the EB.
-------------------------------------------------------EB_GetListenersReply |Event broker reply to
|EB_GetListeners.
-------------------------------------------------------EB_SetFocus
|(Task to EB) Assign the input
|focus to a specified task.
-------------------------------------------------------EB_SetFocusReply
|Event broker reply to
|EB_SetFocus.
-------------------------------------------------------EB_GetFocus
|(Task to EB) Tell the requesting
|task which task has the current
|input focus.
-------------------------------------------------------file:///C|/%23%23DDOC/spg/12spg002.html (2 of 5) [4/16/2002 11:12:27 PM]

Sending Messages Between Tasks and the Event Broker

EB_GetFocusReply

|Event broker reply to
|EB_GetFocus.
-------------------------------------------------------EB_ReadPodData
|(Task to EB) Send requesting task
|data from the specified pod. This
|command is not currently
|implemented.
-------------------------------------------------------EB_ReadPodDataReply
|Event broker reply to
|EB_ReadPodData.
-------------------------------------------------------EB_WritePodData
|(Task to EB) Write the enclosed
|data to the specified pod. This
|command is not currently
|implemented.
-------------------------------------------------------EB_WritePodDataReply |Event broker reply to
|EB_WritePodData.
-------------------------------------------------------EB_LockPod
|(Task to EB) Lock the specified
|pod so only the requesting task
|can issue commands or write data
|to it. This command is not
|currently implemented.
-------------------------------------------------------EB_LockPodReply
|Event broker reply to EB_LockPod.
-------------------------------------------------------EB_UnlockPod
|(Task to EB) Unlock the specified
|pod so that other tasks can issue
|commands or write data to it.
|This command is not currently
|implemented.
-------------------------------------------------------EB_UnlockPodReply
|Event broker reply to
|EB_UnlockPod.
-------------------------------------------------------EB_IssuePodCmd
|(Task to EB) Issue this generic
|command to the specified pod.
-------------------------------------------------------EB_IssuePodCmdReply
|Event broker reply to
|EB_IssuePodCmd.
-------------------------------------------------------EB_DescribePods
|(Task to EB) Describe pods
file:///C|/%23%23DDOC/spg/12spg002.html (3 of 5) [4/16/2002 11:12:27 PM]

Sending Messages Between Tasks and the Event Broker

|attached to the control port.
-------------------------------------------------------EB_DescribePodsReply |Event broker reply to
|EB_DescribePods.
-------------------------------------------------------EB_MakeTable
|(Task to EB) Create a pod table
|and return a pointer to it.
-------------------------------------------------------EB_MakeTableReply
|Event broker reply to
|EB_MakeTable
-------------------------------------------------------With the exception of EB_NoOp, event broker messages come in pairs; every event broker operation
request is answered with a reply from either the event broker or the receiving task. The reply confirms an
operation's execution (or failure to execute). A reply message can carry information requested in the
operation request.
All operation requests are sent from a listener task to the event broker with one exception:
EB_EventRecord, which the event broker sends to a listener to tell it what specified events happened
during a field.

Message Types
Portfolio supports three types of messages:
●
●
●

Standard
Small
Buffered

To communicate with the event broker, a listener task can use either standard or buffered messages;
small messages do not work.
Whenever a listener task asks the event broker for information, it uses a buffered message. For example,
if the EB_DescribePods command is sent, the event broker puts the pod information in the buffer
associated with the message and returns the message to the listener task.
If the listener task is giving information to the event broker, for example using an EB_WritePodData
command, the task can use either a standard (pass by reference) or buffered (pass by value) message. The
event broker reads the data from the data block, but does not modify it.
When a task replies to event broker messages, such as returning an EB_EventRecord message, it
file:///C|/%23%23DDOC/spg/12spg002.html (4 of 5) [4/16/2002 11:12:27 PM]

Sending Messages Between Tasks and the Event Broker

should use the ReplyMsg() function. Always provide NULL for the data pointer, and 0 for the data
size arguments to ReplyMsg().

Flavor-Specific Message Requirements
Each message flavor requires a specific data structure (or set of data structures) to accompany it. The
data structures are defined in the include file event.h (see Reading Event Data). The data structures are
also discussed in the sections of this chapter that describe different event broker operations.
Operation requests and replies are sent with the same message. The event broker or receiving task fills in
the appropriate reply data, and returns the message.
When requesting data from the event broker, a listener task must use a buffered message to hold the
response. Because the reply data from an operation can be extensive, the message should have a large
enough data block for the event broker to fill in data. If the data block is not large enough, the event
broker puts no data in the buffer and returns an error.
Note that a reply message cannot copy useful data to the data blocks if the reply does not require large
amounts of data. For example, a listener task can use an EB_GetFocus message to ask the event broker
to report which task has the input focus . The event broker only needs to store the item number of the
task with focus in the error field of the EB_GetFocus message and return the message without copying
any data to the data block. In such a case, a task can use a standard message to request information
instead of a buffered message because the buffer is not used.

file:///C|/%23%23DDOC/spg/12spg002.html (5 of 5) [4/16/2002 11:12:27 PM]

Monitoring Events Through the Event Broker

Monitoring Events Through the Event Broker
Waiting for Event Messages on the Reply Port
After a task is connected as a listener, it can choose either of the following methods for event notification:
●

●

The task can enter the wait state until it receives an event broker message on the reply port (synchronous I/O).
The task can continue to execute, and pay attention to the event broker only when the task receives notification of a
message received on the reply port (asynchronous I/O).

The Event Broker Trigger Mechanism
While listeners wait for event notification, the event broker checks the pods once per field for events. The event broker checks
occurring events against the trigger mask of each connected listener. If an event matches a set bit in a listener's trigger mask
and the listener has the input focus (if required), the event broker sends an event notification to the listener.
When the event broker sends an event notification, it uses its own event messages, which it creates as necessary. After the
event broker creates an event message, it copies the information into the message's data block. The information contains a
report of the status of each event type that matches a set bit in either the listener of the trigger or capture masks. You can think
of the event message data block as a snapshot of the status of all listener-specified events during the field. Only events
specified in the trigger mask can trigger the snapshot, but the status of all events specified in either mask is reported in the
message.
For example, consider a listener that specifies the "Gun Button Pressed" event type in its trigger mask, and the "Control Button
Update" and "Keyboard Update" event types in its capture mask. When any gun attached to the control port is pressed during a
field, the event broker prepares an event message for the listener. The event message's data field reports a gun button press and
the status of the Control Button Update and Keyboard Update events (indicating whether or not either of those events occurred
during the field). If the "gun button pressed" event had not occurred, the event broker would not have sent an event message to
the listener, even if keyboard or controller pad button updates occurred, because those event types were in the capture mask but
not in the trigger mask.

Retrieving and Replying to Event Messages
After a listener has been notified of an incoming event message from the event broker, it must retrieve the message to read the
reported events. To do so, it uses the GetMsg() call. The listener can then read the message's data block (described in
Reading an Event Message Data Block below), and either act on the data or store it for later use.
After a listener has processed the event data in an event message, the listener must reply to the event broker. Its reply tells the
event broker that the event message is once again free for use. If the listener does not reply to an event message, the event
broker assumes that the message was not processed. Each unprocessed event message is one element in the listener's event
queue. When the number of unprocessed event messages exceeds the maximum event queue depth, the event broker stops
reporting events to the listener. Consequently, the listener loses events until it can process and free up messages in its queue. If
the listener asks to be notified of an event queue overflow, the event broker reports it as soon as an event message is free. The
update event types (EB_ControlButtonUpdate, EB_MouseUpdate, and so on) are all reported as occurring, because
an event queue overflow is considered an update.
file:///C|/%23%23DDOC/spg/12spg005.html (1 of 7) [4/16/2002 11:12:29 PM]

Monitoring Events Through the Event Broker

To reply to an event message and return it to the event broker, a listener uses the ReplyMsg() call. Always pass NULL as
the data pointer, and 0 as the data size parameter to ReplyMsg().

Reading an Event Message Data Block
When a listener receives an event message from the event broker, a pointer to the event data block is in the msg_DataPtr
field of the message structure, and the size in bytes of the data block in the msg_DataSize field. To interpret the event data
stored in the event message, the listener task must be able to read the data structures used in the data block.

Event Data Block Structure
When the event broker reports events in an event data block, it can report one or more events. Therefore, it must have a
flexible data arrangement within the data block to report any number of events. An event data block starts with an
EventBrokerHeader structure that specifies the message flavor as EB_EventRecord and follows with one or more
EventFrame structures, each containing the report of a single event. (Each event report is called an event frame.) The final
structure in the data block is a degenerate EventFrame data structure, which indicates the end of the event frames.

The EventFrame Data Structure
The EventFrame data structure is defined in event.h as follows:
typedef struct EventFrame
{
uint32
ef_ByteCount;
EventFrame */
uint32
ef_SystemID;
0=local */
uint32
ef_SystemTimeStamp;
timestamp */
int32
ef_Submitter;
0 */
uint8
ef_EventNumber;
uint8
ef_PodNumber;
uint8
ef_PodPosition;
daisychain, or 0 */
uint8
ef_GenericPosition;
of type, or 0 */
uint8
ef_Trigger;
capture */
uint8
rfu1[3];
uint32
rfu2;
uint32
ef_EventData[1];
data */
} EventFrame;
●

●

/* total size of
/* 3DO machine ID, or
/* event-count
/* Item of event sender, or
/* event code, [0,255] */
/* CP pod number, or 0 */
/* CP position on
/* Nth generic device
/* 1 for trigger, 0 for

/* first word of event

ef_ByteCount gives the total size of the EventFrame in bytes. Because the event data at the end of the frame
varies in size depending on the event, this value changes from frame to frame.
ef_SystemID reports the ID number of the 3DO unit where this event occurred. This value is useful if two or more

file:///C|/%23%23DDOC/spg/12spg005.html (2 of 7) [4/16/2002 11:12:29 PM]

Monitoring Events Through the Event Broker

3DO units are linked together (as they might be for networked games). If the event occurred on the local 3DO unit, this
value is set to 0.
●

●

●

●

●

●

ef_SystemTimeStamp is the exact system time the event broker recorded this event. This time value corresponds to
the current vblank count value as provided by the timer device's TIMER_UNIT_VBLANK unit.
ef_Submitter gives the item number of the event sender. This value is important when multiple listener tasks tied
into the event broker send events to each other. This item number is the item number of the sending task. If the event
comes from a pod and not a task, this field is set to 0.
ef_EventNumber is an event code from 0 to 255 that identifies the generic type of event. These event types are the
same as the event types identified within a configuration event mask. The include file event.h defines a constant for
each type as shown in Table 2.
ef_PodNumber gives the unique pod number of the pod where an event originated. This number is constant and is
assigned when a pod is first plugged into the 3DO unit. It does not change if the pod changes its position in the control
port daisy chain. This value is set to 0 if the event did not originate in a pod (for example, an event generated by another
task or the CD-ROM drive).
ef_PodPosition gives the position of the event-reporting pod in the control port daisy chain. Numbering starts with
1 for the first pod, and continues consecutively the further the chain extends from the 3DO unit. If the event did not
originate in a pod, this value is set to 0.
ef_GenericPosition, gives the daisy-chain position of the event-reporting pod among identical generic device
types in the daisy chain. A generic device type is a functional description of the pod or part of the pod, and currently
includes the following defined types:
❍
❍
❍
❍
❍
❍
❍
❍
❍

●

●

●

●

POD_IsControlPad
POD_IsMouse
POD_IsGun
POD_IsGlassesCtlr
POD_IsAudioCtlr
POD_IsKeyboard
POD_IsLightGun
POD_IsStick
POD_IsIRController

For example, an event occurs in the second controller pad in the daisy chain, in
which case this value is 2, or in the fourth photo-optic gun in the daisy chain,
in which case this value is 4. This value is set to 0 if the event did not occur
in a generic device.
A single pod attached to the 3DO unit can have more than one generic device type. For example, a single pod can be a
combination control pad and audio controller. In that case, when an event occurs on its control pad buttons, the generic
position listed in the event frame is that of a control pad among other control pads connected to the 3DO unit.
ef_Trigger identifies an event as one that triggered the event notification or as a captured event that did not trigger
the notification. If the value is 1, the event was a triggering event; if the value is 0, the event is a captured event.
ef_EventData is the first word of a data structure that contains data about an event. The rest of the data structure
follows this field in memory. The definition of the data structure depends entirely on the generic device where the event

file:///C|/%23%23DDOC/spg/12spg005.html (3 of 7) [4/16/2002 11:12:29 PM]

Monitoring Events Through the Event Broker

occurred. The data structures are described in Reading Event Data.

The Final (Degenerate) Event Frame
The final event frame within an event data block must be a degenerate event frame, which contains the value 0 for the
ef_ByteCount field. The rest of the EventFrame data structure cannot be present.

Reading Event Data
The event data array at the end of each full event frame is a data structure that determines the type of device reporting the
event. For example, an event occurring on a controller pad uses a structure designed to report control pad data. An event
occurring on a mouse uses a structure designed to report mouse data.

Control Pad Data Structure
The data structure that reports control pad data is ControlPadEventData, defined in event.h as follows:
typedef struct ControlPadEventData
{
uint32 cped_ButtonBits; /* left justified, zero fill */
} ControlPadEventData;
●

cped_ButtonBits contains a value whose bits tell the status of each controller pad button during the field. The
constants defining these flag bits are as follows:
❍
❍
❍
❍
❍
❍
❍
❍
❍
❍
❍

●

ControlDown - the down arm of the joypad cross.
ControlUp - the up arm of the joypad cross.
ControlRight - the right arm of the joypad cross.
ControlLeft -the left arm of the joypad cross.
ControlA -the A button.
ControlB - the B button.
ControlC - the C button.
ControlStart - the P (play/pause) button.
ControlX -the X (stop) button.
ControlLeftShift - the left shift button.
ControlRightShift - the right shift button.

The meaning of these bits varies for each type of control pad event:
❍

❍

For the EVENTNUM_ControlButtonPressed event, 1 means the button was pressed since the last field, 0
means the button was not pressed.
For the EVENTNUM_ControlButtonReleased event, 1 means the button was released since the last field,
0 means the button was not released.

❍

For the EVENTNUM_ControlButtonUpdat event, 1 means the button is down; 0 means the button is up.

❍

For the EVENTNUM_ControlButtonArrived event, 1 means the button is down; 0 means the button is up.

file:///C|/%23%23DDOC/spg/12spg005.html (4 of 7) [4/16/2002 11:12:29 PM]

Monitoring Events Through the Event Broker

Mouse and Trackball Data
The data structure used to report mouse and trackball data is MouseEventData, defined in event.h as follows:
typedef struct MouseEventData
{
uint32
med_ButtonBits;
/* left justified, zero fill */
int32
med_HorizPosition;
int32
med_VertPosition;
} MouseEventData;
●

●

●

med_ButtonBits contains a value whose bits tell which mouse button (or buttons) generated the event. The
constants defining these flag bits are as follows:
❍

MouseLeft - the left mouse button.

❍

MouseMiddle - the middle mouse button.

❍

MouseRight - the right mouse button.

❍

MouseShift - the mouse's shift button.

3DO mice currently have three buttons: left, middle, and right. The fourth constant provides for an extra shift button if
one ever appears on 3DO mice.
The meaning of the above bits varies for each type of mouse event:
❍

❍

●

For the EVENTNUM_MouseButtonPressed event, 1 means the button was pressed since the last field; 0
means the button was not pressed.
For the EVENTNUM_MouseButtonReleased event; 1 means the button was released since the last field, 0
means the button was not released.

❍

For the EVENTNUM_MouseUpdate evenly; 1 means the button is down, a 0 means the button is up.

❍

For the EVENTNUM_MouseDataArrived event; 1 means the button is down, a 0 means the button is up.

❍

For the EVENTNUM_MouseMoved event; 1 means the button is down, 0 means the button is up.

med_HorizPosition and med_VertPosition report the mouse's current position in absolute space. That
position is reckoned from an origin (0,0) that is set when the mouse is first plugged in, and uses units that will typically
(depending on the mouse) measure 100, 200, or 400 increments per inch. It is up to the task to interpret the absolute
position of the mouse to a pointer position on the display.

Light Gun Data Structure
file:///C|/%23%23DDOC/spg/12spg005.html (5 of 7) [4/16/2002 11:12:29 PM]

Monitoring Events Through the Event Broker

The data structure that reports light gun data is LightGunData, defined in event.h as follows:
typedef struct LightGunEventData
{
uint32 lged_ButtonBits;
/* left justified, zero fill */
uint32 lged_Counter;
/*cunter at top-center of hit */
uint32 lged_LinePulseCount;
/* # of scan lines which were hit */
} LightGunEventData;
●

lged_ButtonBits contains a value whose bits tell the state of the various triggers, buttons, and other pushable or
flippable controls on a light gun. Most light guns have one trigger and one auxiliary button. The only flag bit currently
defined for this field is:
❍

●

●

LightGunTrigger - the main light gun trigger.

lged_Counter contains a value which specifies the number of times that the light gun's internal clock (nominally 20
MHz) counted up, between the time it was reset (during vertical blanking) and the time that the light gun's optical
sensor "saw" a flash of light from the display as the display's electron beam passed through its field of view. The beam
travels left to right along each line, and downwards from line to line.
lged_LinePulseCount contains the value 0 if the light gun sensor did not detect a sufficiently strong pulse of light
while scanning the video field. In this case, the lged_Counter value may or may not be valid. If the light gun sensor
detected a sufficiently strong pulse of light, lged_LinePulseCount contains a nonzero value. Some light guns can
actually count the number of successive horizontal scan lines during a pulse and return that value in this field. For light
guns of this sort, the lged_LinePulseCount is considered a "quality of signal" indicator. Other light guns simply
return a constant value (typically 15) to indicate that their sensor detected at least one pulse that was strong enough to
trip the sensor.

Joystick Data
The data structure used to report joystick data is StickEventData, defined in event.h as follows:
typedef struct StickEventData
{
uint32
stk_ButtonBits;
int32
stk_HorizPosition;
int32
stk_VertPosition;
int32
stk_DepthPosition;
} StickEventData;
●

/* left justified, zero fill */

stk_ButtonBits contains a value that identifies which joystick button (or buttons) generated the event. The
constants defining these flag bits are as follows:
❍
❍
❍
❍
❍
❍
❍

StickCapability - the AND of Stick4Way and StickTurbulence.
Stick4Way - determines how many buttons the stick has.
StickTurbulence - indicates whether or not the stick understands output commands.
StickButtons - the stick buttons.
StickFire - the joystick was fired.
StickA - the A button.
StickB - the B button.

file:///C|/%23%23DDOC/spg/12spg005.html (6 of 7) [4/16/2002 11:12:29 PM]

Monitoring Events Through the Event Broker
❍
❍
❍
❍
❍
❍
❍
❍
❍

●

StickC - the C button.
StickUp - the up button of the stick.
StickDown - the down button of the stick.
StickRight - the right button of the stick.
StickLeft - the left button of the stick.
StickPlay - the play button of the stick.
StickStop - the stop button of the stick.
StickLeftShift - the left-shift button of the stick.
StickRightShift - the right-shift button of the stick.

stk_HorizPosition, stk_VertPosition, and stk_DepthPosition contain binary numbers and return a
value between 0 through 1023. A value of 0 means the joystick is pushed left or all of the way down. A value of 1023
means the joystick is pushed right or all the way up. Keep in mind that some joysticks cannot go all the way to 0 or
1023.

Device State Data Structure
When media is inserted or removed from a device, EVENTNUM_DeviceOnline or EVENTNUM_DeviceOffline
respectively, the DeviceStateEventData structure contains the Item number of the device, and the unit number within the
device that has gone on-line or off-line. The DeviceStateEventData structure is defined as follows:
typedef struct DeviceStateEventData
{
Item
dsed_DeviceItem;
uint32 dsed_DeviceUnit;
} DeviceStateEventData;

Filesystem State Data Structure
When a filesystem is mounted, dismounted, or placed off-line, EVENTNUM_FilesystemMounted,
EVENTNUM_FilesystemDismounted, or EVENTNUM_FilesystemOffline, the FileSystemEventData structure
contains the Item number of the Filesystem node, and the name of the filesystem which is changing state. The
FileSystemEventData structure is defined as follows:
typedef struct FilesystemEventData
{
Item fsed_FilesystemItem;
char fsed_Name[FILESYSTEM_MAX_NAME_LEN];
} FilesystemEventData;

file:///C|/%23%23DDOC/spg/12spg005.html (7 of 7) [4/16/2002 11:12:29 PM]

The Process of Event Monitoring

The Process of Event Monitoring
Although event broker messages come in enough flavors to allow a task to carry out a variety of I/O
operations through the event broker, the event broker's main function is to monitor events in userinterface devices and report the events to listening tasks. From a listener task's point of view, the process
of event monitoring has the following steps:
1. Connecting to the event broker
❍
❍
❍
❍
❍

Create a message port
Create a configuration message
Create a configuration block
Send the configuration message to the event broker
Receive the event broker's connection reply message

2. Monitoring events through the event broker
❍
❍
❍
❍

Wait for event messages on the allocated message port
Read an event message data block
Process event data block information (if desired)
Reply to the event broker for event message receipt

3. Changing configuration (if desired) or disconnecting from the event broker
❍

Send a new configuration data structure to the event broker

Each of these steps use event broker data structures and message flavors.

file:///C|/%23%23DDOC/spg/12spg003.html [4/16/2002 11:12:30 PM]

Connecting a Task to the Event Broker

Connecting a Task to the Event Broker
Before a task can work with the event broker, it must connect to the event broker by sending a message that requests
connection as a listener. To do so, the task sends a message of the flavor EB_Configure, using Portfolio's standard messagesending procedure. The message also specifies input focus, and indicates the event types in which the task is interested.

Creating a Message Port
Before creating a configuration message, a listener task must create its own message port to use as a reply port where the event
broker will send messages. To do so, the listener uses the CreateMsgPort()call, which returns the item number of the new
message port.

Creating a Configuration Message
After a listener task creates a message port, it must create a message using CreateMsg() or CreateBufferedMsg().
Both calls accept a string that names the message, supplies an optional priority number for the message, and provides the item
number of the listener message port. CreateBufferedMsg() also takes the size of the buffer to allocate with the message.
Both calls return the item number of the newly created message.

Creating a Configuration Block
To turn the newly created message into a configuration request, the listener task must create a configuration data block, which
consists of the ConfigurationRequest structure, shown in Example 1.
Example 1: ConfigurationRequest structure.
typedef struct ConfigurationRequest
{
EventBrokerHeader
EB_Configure } */
enum ListenerCategory
/* focus, monitor, or
uint32
uint32
int32

cr_Header;

/* {

cr_Category;
/* hybrid */
cr_TriggerMask[8]; /* events to trigger on */
cr_CaptureMask[8]; /* events to capture */
cr_QueueMax;
/* max # events

in
/* transit */
uint32
for now */
} ConfigurationRequest;

rfu[8];

/* must be 0

The listener task must fill in the following fields to set the parameters of its configuration request:
●
●

cr_Header is an EventBrokerHeader data structure in which the event flavor EB_Configure must be set.
cr_Category defines the listener type of input focus. It has four possible values:

file:///C|/%23%23DDOC/spg/12spg004.html (1 of 6) [4/16/2002 11:12:31 PM]

Connecting a Task to the Event Broker

❍

❍

●

●

●

LC_FocusListener sets the task to be a focus-dependent listener. It must have the focus to receive any
events.
LC_FocusUI sets the task to be a focus-interested listener. It must have the focus to receive user interface
events, but gets all other event types regardless of focus.

❍

LC_Observer sets the task to be a focus-independent listener. It gets all event types regardless of focus.

❍

LC_NoSeeUm sets the task to ignore all events completely, the equivalent of not connecting to the event broker.

cr_TriggerMask and cr_CaptureMask contain the event masks that specify events in which the task is
interested. The trigger mask specifies each event type that will trigger the event broker to notify the task; the capture
mask specifies each event type that the event broker reports on whenever it notifies the task of an event triggering.
These masks are discussed in The Event Broker Trigger Mechanism.
cr_QueueMax specifies the maximum number of event reports that the event broker posts at any one moment in the
task's event queue. This value can be set to the constant EVENT_QUEUE_MAX_PERMITTED, which sets the currently
defined maximum number of events in the queue (20 in this release), or the constant EVENT_QUEUE_DEFAULT,
which sets the currently defined default number of events (three in this release). The queue must have a minimum depth
of at least two events.
The rfu field is reserved for future use, and currently must be set to 0.

Event Types
The 256 different event types available through the event broker are divided into two main bodies:
●

●

System events. 128 system-defined generic events.
Custom events. 128 task-defined events primarily used for communicating events in one event broker listener to other
listeners. Custom events are not currently implemented.

Both system events and custom events are divided into two types that are defined by the way the event broker reports them to
focus-interested tasks:
●

●

UI events, which are not reported to a focus-interested task if a task does not hold the focus. The event broker provides
64 system and 64 custom UI events.
Non-UI events, which are reported to a focus-interested task even if the task does not hold the focus. The event broker
provides 64 system and 64 custom non-UI events.

Table 1 shows how the 256 different bit values in a bit mask are divided into system and custom events, and then UI and nonUI events. Custom event types are not supported in this release of Portfolio.
Table 1:
Flag Bit constants defined in event.h.
----------------------------------------------------------------System UI Event Type Constants |Event Definition
----------------------------------------------------------------file:///C|/%23%23DDOC/spg/12spg004.html (2 of 6) [4/16/2002 11:12:31 PM]

Connecting a Task to the Event Broker

EVENTBIT0_ControlButtonPressed

|A controller pad button was
|pressed.
----------------------------------------------------------------EVENTBIT0_ControlButtonReleased |A controller pad button was
|released.
----------------------------------------------------------------EVENTBIT0_ControlButtonUpdate
|A controller pad button was
|pressed or released, or control
|button information may be lost
|in an event queue overflow.
----------------------------------------------------------------EVENTBIT0_ControlButtonArrived |Data from a controller pad
|button has arrived (it arrives
|every field).
----------------------------------------------------------------EVENTBIT0_MouseButtonPressed
|A mouse button was pressed.
----------------------------------------------------------------EVENTBIT0_MouseButtonReleased
|A mouse button was released.
----------------------------------------------------------------EVENTBIT0_MouseUpdate
|A mouse button was pressed or
|released, the mouse has moved,
|or mouse info may be lost in an
|event queue overflow.
----------------------------------------------------------------EVENTBIT0_MouseMoved
|A mouse has moved.
----------------------------------------------------------------EVENTBIT0_MouseDataArrived
|Data from a mouse has arrived
|(it arrives every field).
----------------------------------------------------------------EVENTBIT0_GunButtonPressed
|A gun button was pressed. This
|is not currently implemented.
----------------------------------------------------------------EVENTBIT0_GunButtonReleased
|A gun button was released. This
|is not currently implemented.
----------------------------------------------------------------EVENTBIT0_GunUpdate
|A gun button was pressed or
|released, or gun button
|information may be lost in an
|event queue overflow. This is
|not currently implemented.
----------------------------------------------------------------EVENTBIT0_GunDataArrived
|Data from a gun has arrived (it
|arrives every field). This is
|not currently implemented.
----------------------------------------------------------------EVENTBIT0_KeyboardKeyPressed
|A keyboard key was pressed. This
|is not currently implemented.
----------------------------------------------------------------EVENTBIT0_KeyboardKeyReleased
|A keyboard key was released.
|This is not currently
|implemented.
----------------------------------------------------------------file:///C|/%23%23DDOC/spg/12spg004.html (3 of 6) [4/16/2002 11:12:31 PM]

Connecting a Task to the Event Broker

EVENTBIT0_KeyboardUpdate

|A keyboard key was pressed or
|released, or keyboard
|information may be lost in an
|event queue overflow. This is
|not currently implemented.
----------------------------------------------------------------EVENTBIT0_KeyboardDataArrived
|Data from a keyboard has arrived
|(it arrives every field). This
|is not currently implemented.
----------------------------------------------------------------EVENTBIT0_CharacterEntered
|A character was entered. This is
|not currently implemented.
----------------------------------------------------------------EVENTBIT0_GivingFocus
|This task was given focus.
----------------------------------------------------------------EVENTBIT0_LosingFocus
|This task lost focus.
----------------------------------------------------------------EVENTBIT0_LightGunButtonPressed |A light gun button was pressed.
----------------------------------------------------------------EVENTBIT0_LightGunButtonReleased|A light gun button was released.
----------------------------------------------------------------EVENTBIT0_LightGunUpdate
|A light gun button was pressed
|or released, or light gun button
|information may be lost in an
|event queue overflow.
----------------------------------------------------------------EVENTBIT0_LightGunFireTracking |Data from a light gun is being
|tracked.
----------------------------------------------------------------EVENTBIT0_LightGunDataArrived
|Data from a light gun has
|arrived (it arrives every
|field).
----------------------------------------------------------------EVENTBIT0_StickButtonPressed
|A joystick button was pressed.
----------------------------------------------------------------EVENTBIT0_StickButtonReleased
|A joystick button was released.
----------------------------------------------------------------EVENTBIT0_StickUpdate
|A joystick button was pressed or
|released, or joystick button
|information may be lost in an
|event queue overflow.
----------------------------------------------------------------EVENTBIT0_StickMoved
|A joystick has moved.
----------------------------------------------------------------EVENTBIT0_StickDataArrived
|Data from a joystick has arrived
|(it arrives every field).
----------------------------------------------------------------EVENTBIT0_IRKeyPressed
|An IR key was pressed and a
|button code is returned. This is
|device specific. This is not
|currently implemented.
----------------------------------------------------------------file:///C|/%23%23DDOC/spg/12spg004.html (4 of 6) [4/16/2002 11:12:31 PM]

Connecting a Task to the Event Broker

EVENTBIT0_IRKeyReleased

|An IR key was released and a
|button code is returned. This is
|device specific. This is not
|currently implemented.
----------------------------------------------------------------Table 2 shows the flag bit constants defined in event.h for the system events, along with the meaning for each of the event
types. These event type constants define flags for system-defined events, each of which can occur during a single control port
polling.
Table 2: Event type constants that define flags for system-defined events.
--------------------------------------------------------------System Non-UI Event Type
|Event Definition
Constants
|
--------------------------------------------------------------EVENTBIT2_DeviceOnline
|Media was inserted in a device.
--------------------------------------------------------------EVENTBIT2_DeviceOffline
|A device was removed.
--------------------------------------------------------------EVENTBIT2_FilesystemMounted
|A file system was mounted.
--------------------------------------------------------------EVENTBIT2_FilesystemOffline
|A file system went off-line.
--------------------------------------------------------------EVENTBIT2_FilesystemDismounted|A file system was dismounted.
--------------------------------------------------------------EVENTBIT2_ControlPortChange
|A new device was plugged into or
|disconnected from the control
|port.
--------------------------------------------------------------EVENTBIT2_PleaseSaveAndExit
|This task was requested to save
|current status and exit.
--------------------------------------------------------------EVENTBIT2_PleaseExitImmediatel|This task was requested to exit
y
|immediately.
--------------------------------------------------------------EVENTBIT2_EventQueueOverflow |This task's event queue has
|overflowed and the task has lost
|events.
---------------------------------------------------------------

Setting the Trigger and Capture Masks
Each of the masks in the ConfigurationRequest data structure is an 8-element array of 32-bit words that provides 256 bits, 1 bit
for each event type. To set a mask, the task logically ORs the desired constants defined for each word of the array, and stores
the results in the appropriate word. The constant name identifies the appropriate word for storage. For example, all the desired
flag constants starting with EVENTBIT0 must be logically ORed and then stored in word 0 of the array. All the desired flag
constants starting with EVENTBIT2 must be logically ORed and then stored in the second word of the array.

Sending the Configuration Message
file:///C|/%23%23DDOC/spg/12spg004.html (5 of 6) [4/16/2002 11:12:31 PM]

Connecting a Task to the Event Broker

Once the ConfigurationRequest data structure has been created and filled in, the listener task must send the message to the
event broker. To do this, the task first must find the event broker message port using the FindMsgPort() call, as shown in
Example 2.
Example 2: FindMsgPort().
{
Item ebPortItem;
ebPortItem = FindMsgPort(EventPortName);
if (ebPortItem < 0)
{
/* big trouble, the event broker can't be found! */
}
}
After the listener task has the event broker message port item number, the task sends its configuration message using
SendMsg():
SendMsg(ebPortItem, msg, &configuration, sizeof(configuration));
The SendMsg() call accepts four arguments: the item number of the event broker port, the item number of the message the
task has created, a pointer to the ConfigurationRequest data structure the task has initialized, and the size of that data structure.
When the event broker receives the configuration message, it adds the task as a listener. The event broker reads the reply port
contained in the message and uses that port whenever it needs to communicate with the listening task. The event broker also
reads the ConfigurationRequest data structure and sets up the listener's configuration accordingly.

Receiving the Configuration Reply Message
When the event broker finishes processing the configuration message, it changes the message to a configuration reply message.
That message contains a pointer to a single data structure: an EventBrokerHeader with the value EB_ConfigureReply. The
event broker returns the message to the task requesting configuration. The receiving task checks the configuration message's
result field (msg_Result, which is cast to an Err type) to see if the operation was successful or not. If the value is a
negative number, it is an error code, and the configuration was not successful (the task was not connected). If the value is 0 or
a positive number, the configuration was successful and the task is connected.

file:///C|/%23%23DDOC/spg/12spg004.html (6 of 6) [4/16/2002 11:12:31 PM]

High-Performance Event Broker Use

High-Performance Event Broker Use
The pod table interface gives applications a fast and efficient way to monitor the current state of certain
control port devices on a field-by-field basis. The pod table does not require applications to process a
large number of event messages.

The Pod Table
Devices such as analog joysticks and light guns provide applications with position information, as well as
with button-state information. Button-state information does not change frequently (a few times per
second in most cases), but positional information changes often during almost every video field (up to 60
times a second). These rapid position changes are inherent in the high resolutions of these input devices,
and their tendency to "jitter" slightly as a result of small mechanical movements or electrical noise in the
circuitry. Applications must track the position of an input device. For example, by moving a set of
crosshairs on the display, an application may need to parse and process messages from the event broker
many times each second This process can lead to an undesirable slowdown of the application.
The pod table is an alternative method for accessing the current position of devices such as the analog
joystick and light gun, with substantially lower overhead for both the application and the event broker.
This table (actually a set of arrays and data structures) contains the current position information, and
current button-state, for up to eight generic control port devices in each family. By examining the
contents of the pod table, applications can track device position whenever it is convenient for them to do
so.

Gaining Access to the Pod Table
The event broker constructs the pod table by the event broker when an application sends it a message
asking for access to the table. This message has the standard event broker format and uses a message
code of EB_MakeTable.
The event broker builds the table and replies to the application's message by sending an
EB_MakeTableReply message whose data structure includes a pointer to the table. The table is
updated whenever new data arrives from the control port. An application that gains access to the table in
this fashion can "poll" the contents of the table at its convenience. The table contains a semaphore that
the application must lock to ensure the event broker does not update the table while the application
examines it.

Relinquishing Access to the Pod Table
file:///C|/%23%23DDOC/spg/12spg006.html (1 of 7) [4/16/2002 11:12:33 PM]

High-Performance Event Broker Use

The pod table is retained in memory and kept up to date, as long as the application that requested it is
executing. The system maintains the table as long as the event broker receives a table-request message
from at least one message port. As soon as the event broker detects that the last such message port was
deleted, it ceases updating the pod table and releases the memory occupied by the table.

Structure of the Pod Table
The pod table consists of two portions: a fixed-size and fixed-format section and a set of variable-size
arrays, which are created when needed. The variable size arrays may not always be present. Figure 1
shows the fixed-size section and fixed-format.

Figure 1: Pod table structure fixed-size and fixed-format section.
The table begins with a semaphore item. It is followed by a total of 16 almost-identical substructures: one
substructure per generic class, with the names of the substructures indicating the generic class to which
they refer. Within each substructure are two pointers: one to an array of uint32 timestamps, and
another to an array of generic-class-specific event data structures. Each substructure also contains a
uint32 "how many" field that gives the number of elements in the event and timestamp arrays. The
"how many" field can contain 0, in which case the two pointers will contain NULL.

file:///C|/%23%23DDOC/spg/12spg006.html (2 of 7) [4/16/2002 11:12:33 PM]

High-Performance Event Broker Use

The event data structures used in these arrays are the same ones used to send information in a normal
event broker event frame. For example, the substructure for generic class 0 (control pads) contains a
pointer to an array of ControlPadEventData structures, and the substructure for generic class 8
(analog joysticks) contains a pointer to an array of StickEventData structures.

Empty Generic Class Substructures
If there are no devices of a particular generic class connected to the 3DO unit, the substructure for this
generic class can be left empty. In this case, the "how many" field contains 0, and the two array pointers
will contain NULL. For example, if the 3DO unit were started up without a control pad attached, the first
portion of the pod table might be as shown in Figure 2.

Figure 2: Pod substructure.

Non-Empty Generic Class Substructures
If one or more devices of a particular generic class are connected to the 3DO system, the pod table
reflects this. The "how many" field is nonzero, and the array pointers are non-NULL and point to valid
arrays. Figure 3 shows an example of the generic class substructure.

file:///C|/%23%23DDOC/spg/12spg006.html (3 of 7) [4/16/2002 11:12:33 PM]

High-Performance Event Broker Use

Figure 3: Generic class substructure.
The "how many" field does not necessarily contain the number of devices of a generic class that are
currently attached to the system; rather, this field identifies the sizes of the data arrays. Normally, the
event broker will reserve sufficient space in the arrays for up to eight devices in each class, and the "how
many" field will reflect this fact. If your application needs to get a complete and accurate listing of the
devices currently attached to the system, it should use the EB_DescribePods message to ask the
event broker for a current list.
The entries in the timestamp and device-data arrays should be accessed with a starting index of 1. That is,
the data for the first generic joystick will be found in StickEventData[1]. This ensures that the
numbering scheme for these arrays matches the generic-device numbers in the event broker's event-frame
and pod-description messages. Entry 0 in each array is reserved for future use, and should not be
accessed by applications.
The values in the timestamp arrays are standard Portfolio VBL counter timestamps. They have a
resolution of 1/60th of a second on NTSC systems and 1/50th of a second on PAL systems. They are
derived from the same source as the event timestamp values in an event broker event message, and also
correspond to the VBL-count times applications read using the timer device.
If a controller is unplugged from the control port, the event broker ceases updating its entries in the pod
table. An application can detect stale information by checking to see if the validity timestamp is
changing.

file:///C|/%23%23DDOC/spg/12spg006.html (4 of 7) [4/16/2002 11:12:33 PM]

High-Performance Event Broker Use

A substructure goes from empty to nonempty if a device of an as yet unseen generic class is connected to
the multiplayer, and a driver for this device is available. The array pointers in a substructure can be
changed if the event broker needs to enlarge the arrays to support a larger number of devices than
expected. In any case, a change in the table's structure will occur only when the event broker has locked
the semaphore on the pod table. Applications are urged to lock the semaphore before accessing the
contents of the table, and unlock it immediately afterwards, to avoid having data in the table change
while the application is reading it.

Use and Abuse of the Pod Table
It is easy to misuse the pod table, which can hurt the performance and reliability of your application,
rather than helping it.
The pod table mechanism is intended to give applications a way to view the most recent information for
each control port device on the system. As such, it lets you track a light gun's target position or the offset
of an analog joystick with very little effort and overhead. You may be tempted to use it for other, less
appropriate purposes: for example, to detect button-down and button-up interactions at the control pads
or light gun or analog joysticks. Do not do this. It can cause compatibility problems, now or in the future.
You can also get into trouble because an application has no guaranteed way of knowing just when the
data in the pod table is likely to be changed. If somebody taps and releases a button on the control pad
very quickly, it is possible for the pod table to be updated twice (reflecting both the button-down and
button-up changes) before your application gets around to polling it. As a result, your application will
never notice this particular button-press, and it will not react to the user's action.

Pod Table Polling
You may think that you can avoid this problem by polling the pod table frequently, perhaps once per
field (60 times a second on an NTSC machine). That might work today, but it might not work tomorrow.
Future versions of the 3DO hardware and software may scan the control port more frequently than
today's version to reduce the delay between the time a button is pressed and the time a program reacts to
it. In fact, this is very likely. If your application depends on polling the pod table more rapidly than the
event broker can update it, it will probably not run reliably on some future 3DO hardware.
Polling the pod table frequently adds quite a bit of overhead and complexity to an application. You will
either have to interrupt your main-line code several times per field to poll the table (making the code
bigger and bulkier) or it will be necessary to have a code thread wake up every few milliseconds to check
the table (thus adding more overhead than the pod table mechanism eliminated, and slowing down your
application's frame rate). You might be tempted to start writing "busy/wait" polling loops to wait for
events; these would make your program multitasking-hostile and network-unfriendly.

file:///C|/%23%23DDOC/spg/12spg006.html (5 of 7) [4/16/2002 11:12:33 PM]

High-Performance Event Broker Use

The event broker's event message system was designed specifically to eliminate such problems. The
event broker is a couple of steps closer to the hardware than your application is, and takes advantage of
this fact. It does all of the button-down/button-up detection for you. Every time new data arrives from the
control port it can queue up several event messages in a row for your application without losing any data,
and it will wake up your program or thread (sending a message) when an event arrives.
The best way to use the pod table is to use it only to keep track of position information (analog joystickposition, mouse offset, light gun target pulse count, and so on.). For all real user-interaction events
(button-down, trigger pulled, and so on), use the event broker event message mechanism.

Using the Pod Table Semaphore
When you lock the semaphore on the pod table before accessing the table, be sure to unlock it as quickly
as possible. If left locked, you will lock out the event broker and can cause your application to miss
events. Ideally, you should lock the semaphore, copy the information you need from the pod table to a
variable in your program's own storage, and then unlock the semaphore immediately.
It is tempting to not lock the semaphore and read the tables directly. This is dangerous, as you might get
inconsistent data within the table. It might also lead to crashes if new controllers are plugged into the
system and the event broker must alter table pointers.
Finally, since the array pointers within the pod table can change from event to event, it is important not
to cache these values anywhere. Whenever you lock the pod table semaphore, you must sample the array
pointers from the table.

Synchronization Between the Pod Table and Event
Messages
The event frames in an event broker message have timestamps associated with each event, as do the
arrays in the pod table. Both timestamps are derived from the same source (the timer device VBL
counter) and so are consistent with one another.
However, if you are checking timestamps in the event messages, and are also looking at timestamps in
the pod table, you should be cautious. It is possible for you to receive an event message (containing a
timestamped event), look in the pod table, and find that the timestamp for the corresponding device does
not match the one in the event message. This can (and often will) happen because the pod table was
updated between the time that the event message was sent to your application, and the time that your
application processed it. The pod table timestamp will usually be more recent than the event frame
timestamp.

file:///C|/%23%23DDOC/spg/12spg006.html (6 of 7) [4/16/2002 11:12:33 PM]

High-Performance Event Broker Use

This might cause some confusion if, for example, an application tracking the light gun cursor based on
pod table information but the application was "firing bullets" based on the event messages. The
application might mistakenly shoot a bullet at the position the gun was aimed before or after the moment
the trigger was pulled, rather than where it was aimed at the precise moment of firing.
All of the information in any particular event frame has the same timestamp. For example, if your
application receives a "light gun button down" event frame, then the button-bits and the light gun counter
in that event frame were sampled at exactly the same moment. Your application should fire at the spot
indicated in the event frame, rather than at the (possibly different) location currently indicated in the pod
table.

file:///C|/%23%23DDOC/spg/12spg006.html (7 of 7) [4/16/2002 11:12:33 PM]

Reconfiguring or Disconnecting a Task

Reconfiguring or Disconnecting a Task
As a task works with the event broker, it may want to reconfigure itself to monitor different event types,
change its focus dependence, reset the size of its event queue, or use a new reply port for event broker
messages. Or it may want to completely disconnect itself from the event broker so that it no longer
monitors events. In each case, the task sends a new configuration message to the event broker.

Reconfiguring the Event Broker Connection
The task initializes a new ConfigurationRequest structure with the new settings it wants. It then
sends an EB_Configure message to the event broker to have the new settings take effect. The event
broker uses the reply port of the EB_Configure message to determine which tasks are connected to
the event broker. When changing the configuration, the application should use the same reply port for the
message as it did when it first connected to the event broker.
If a task wants to change the reply port it uses to receive event broker messages, it must first disconnect
from the event broker using a configuration message with its old reply port. Then the task must create a
new configuration message with a new reply port, and send the new configuration message to the event
broker. The task must also close the old configuration message and old reply port.

Disconnecting From the Event Broker
If the task wishes to disconnect itself completely from the event broker, it sends a configuration request,
using its current reply port, and specifies a 0 for both the trigger and capture masks. The event broker
then disconnects the task. A task can also call DeleteMsgPort() on its current reply port. On the
next tick, the event broker will disconnect the task.

file:///C|/%23%23DDOC/spg/12spg007.html [4/16/2002 11:12:33 PM]

Other Event Broker Activities

Other Event Broker Activities
Although the event broker's primary activity is monitoring pod table events for listeners, it performs other activities such as
checking on connected listeners and pods, finding out where the focus lies, and controlling individual pods, such as
stereoscopic glasses and audio controllers.

Getting Lists of Listeners and Connected Pods
There are many times when a task needs a list of pods connected to the control port or listeners connected to the event broker.
There are two flavors of messages that retrieve this kind of information: EB_DescribePods asks for a list of connected
pods; EB_GetListeners asks for a list of connected listeners.

Asking for a List of Connected Pods
When a task uses an EB_DescribePods message to ask the event broker for a list of connected pods, the message data
block contains only the EventBrokerHeader data structure specifying the flavor EB_DescribePods. The message sent to
the event broker should be a buffered message, created with CreateBufferedMsg(), which contains sufficient room to
hold the complete list of connected pods.

Reading a Returned List of Connected Pods
When the event broker replies to an EB_DescribePods message, it turns the message into an
EB_DescribePodsReply message. The message's data buffer contains a list of pods currently attached to the control
port. Those pods are described in the data structure PodDescriptionList, which is defined as follows:
typedef struct
{
EventBrokerHeader
int32
PodDescription
} PodDescriptionList;

PodDescriptionList
pdl_Header;
pdl_PodCount;
pdl_Pod[1];

●

pdl_Header is an EventBrokerHeader data structure set to the message flavor EB_DescribePodsReply.

●

pdl_PodCount contains the number of pods described in the next field.

●

pdl_Pod[] is an array of pod descriptions, with one element for each pod currently attached to the control port.
Each pod description is contained in the data structure PodDescription, defined as follows:

typedef struct PodDescription
{
uint8
pod_Number;
uint8
pod_Position;
uint8
rfu[2];
uint32
pod_Type;
uint32
pod_BitsIn;

file:///C|/%23%23DDOC/spg/12spg008.html (1 of 6) [4/16/2002 11:12:35 PM]

Other Event Broker Activities

uint32
uint32
uint8
Item
} PodDescription;
●

●

●

●

●

pod_BitsOut;
pod_Flags;
pod_GenericNumber[16];
pod_LockHolder;

pod_Number gives the unique and unchanging pod number of the pod.
pod_Position gives the position of the pod in the control port daisy chain. It is an integer from 1 to the total
number of pods on the control port.
pod_Type lists the native pod type of the pod, that is, the specific type of device attached to the daisy chain (not the
generic type).
pod_BitsIn and pod_BitsOut give the number of bits shifted into the pod during the control port data stream
for each video field, and the number of bits shifted out of the pod during each data stream.
pod_Flags, contains flags that show the generic device type (or types) that the pod contains. These flags, shown in
Table 4, occupy the left-most bits of the pod_Flags word.
Table 1: Flag constants used for the pod_Flags field.
----------------------------------------------Flag Constant
|Hex Value
|Count From
|
|Left-Most
|
|Bit
----------------------------------------------POD_IsControlPad
|0x80000000
|0
----------------------------------------------POD_IsMouse
|0x40000000
|1
----------------------------------------------POD_IsGun
|0x20000000
|2
----------------------------------------------POD_IsGlassesCtlr |0x10000000
|3
----------------------------------------------POD_IsAudioCtlr
|0x08000000
|4
----------------------------------------------POD_IsKeyboard
|0x04000000
|5
----------------------------------------------POD_IsLightGun
|0x02000000
|6
----------------------------------------------POD_IsStick
|0x01000000
|7
----------------------------------------------POD_IsIRController |0x00800000
|8
-----------------------------------------------

●

pod_GenericNumber is an array of 16 unsigned 8-bit values. These values correspond to the bits of the
pod_Flags field: pod_GenericNumber[0] corresponds to flag bit 0, POD_IsControlPad;
pod_GenericNumber[1] corresponds to the first flag bit, POD_IsMouse; and so on. The value in each element
of the array stores the rank of this pod in the order of all other identical generic devices connected to the serial port.
For example, if pod_GenericNumber[2] contains a 4, then the pod contains a generic gun that is the fourth
generic gun connected to the serial port.

file:///C|/%23%23DDOC/spg/12spg008.html (2 of 6) [4/16/2002 11:12:35 PM]

Other Event Broker Activities

●

pod_LockHolder gives the item number of the task that has this pod locked for its exclusive use. If this field is set
to 0, then the pod is unlocked. Pod locking is not currently implemented, so this field should not be used.

Asking for a List of Connected Listeners
When a task asks for a list of connected listeners, it uses an EB_GetListeners message, whose data block contains only
the EventBrokerHeader data structure specifying the flavor EB_GetListeners. Messages used for this purpose must be
created with CreateBufferedMsg() in the same way as messages used with the EB_DescribePods command.
CreateBufferedMsg() is described in Creating a Configuration Message.

Reading a Returned List of Connected Listeners
When the event broker replies to an EB_GetListeners message, it turns the message into an
EB_GetListenersReply message. The message buffer contains a list of listeners currently connected to the event
broker. The list is contained in the data structure ListenerList, defined as follows:
typedef struct ListenerList
{
EventBrokerHeader
int32
struct {
Item
enum ListenerCategory
} ll_Listener[1];
} ListenerList;

ll_Header; /* { EB_GetListenersReply } */
ll_Count;
li_PortItem;
li_Category;

●

ll_Header is an EventBrokerHeader structure set to the message flavor EB_GetListenersReply.

●

ll_Count contains the number of listeners described in the next field.

●

ll_Listener is an array of listener descriptions with one element for each listener currently connected to the event
broker. Each listener element contains these fields:
❍

li_PortItem contains the item number of the listener's reply port

❍

li_Category gives the listener's focus-interest category

Working With Input Focus
It is often important for a listener to know which task currently has the input focus or to be able to change the input focus
from one task to another without user intervention. The event broker can handle both of these requests.

Finding the Current Focus Holder
To find the current focus holder, a listener can inquire with an EB_GetFocus message. Its data block is an
EventBrokerHeader data structure set to the message flavor EB_GetFocus.
file:///C|/%23%23DDOC/spg/12spg008.html (3 of 6) [4/16/2002 11:12:35 PM]

Other Event Broker Activities

When the event broker receives an EB_GetFocus message, it gets the item number of the task currently holding the focus,
writes that value in the error field of the message, and returns the message to the task. The task receiving the message reads
the current focus holder's item number from the error field. The error field will contain a negative number (an error code) if
the operation failed.

Setting the Current Focus Holder
Warning: Although the event broker currently allows any user task to set the current focus holder, in the future this request
may restricted to only privileged tasks.
To move the focus from one task to another without input from the user, a listener can use an EB_SetFocus message. The
data block for this message uses the SetFocus data structure, defined as follows:
typedef struct SetFocus
{
EventBrokerHeader sf_Header; /* { EB_SetFocus } */
Item
sf_DesiredFocusListener;
} SetFocus;
●

sf_Header is an EventBrokerHeader data structure set to the message flavor EB_SetFocus.

●

sf_DesiredFocusListener is the item number of the task to which the event broker should give the focus.

When the event broker receives the message, it changes the input focus to the requested task and writes that task's item
number into the error field of the message. It returns the message to the sending task. That task can now read the error field to
get the item number of the focus-holding task (if successful) or an error code (if unsuccessful).

Commanding a Pod
Sometimes a task may want to control a pod through the event broker. For example, a task may wish to alternate lens
opaqueness in a pair of stereoscopic glasses, or mute the sound coming through an audio controller. To issue commands to a
pod, the task uses a message of the flavor EB_IssuePodCmd. It accompanies the message with a data block that uses the
PodData data structure, defined as follows:
typedef struct PodData
{
EventBrokerHeader
int32
pd_PodNumber;
int32
pd_WaitFlag;
int32
pd_DataByteCount;
uint8
pd_Data[4];
} PodData;

pd_Header;

●

pd_Header is an EventBrokerHeader data structure set to the message flavor EB_IssuePodCmd.

●

pd_PodNumber gives the pod number of the pod to which the command is sent.

●

pd_WaitFlag can be set to either 1 or 0. If set to 1, it asks the event broker to send the command to the pod and

file:///C|/%23%23DDOC/spg/12spg008.html (4 of 6) [4/16/2002 11:12:35 PM]

Other Event Broker Activities

reply immediately. If set to 0, it asks the event broker to send the command to the pod, wait for the command to finish
execution, and then reply to command message.
●

●

pd_DataByteCount gives the size in bytes of the pd_Data field that follows.
pd_Data is an array of bytes that contains the command sent to the pod. The first element of the array (element 0)
contains the generic device class of the pod to which the command is sent; the second element (element 1) contains
the command subcode, which is specific to the generic class in the first element. If the command defined by these two
bytes requires extra data, that data goes into the elements of the array listed below.

Generic Device Class
The include file event.h currently defines the following constants to specify generic device classes:
●
●
●
●
●
●
●
●
●

GENERIC_ControlPad - a controller pad.
GENERIC_Mouse - a mouse.
GENERIC_Gun - a photo-optic gun.
GENERIC_GlassesCtlr - a stereoscopic glasses controller.
GENERIC_AudioCtlr - an audio controller.
GENERIC_Keyboard - a keyboard.
GENERIC_LightGun - a light gun.
GENERIC_Stick - a joystick.
GENERIC_IRController - a infrared controller pad (wireless).

The array element pd_Data[0] should hold the constant appropriate to the commanded pod.

Audio Controller Subcodes
The audio controller accepts commands defined by audio controller subcodes. At present, Portfolio offers one audio subcode,
specified by the following constant:
●

GENERIC_AUDIO_SetChannels controls the output of the two stereo audio channels.

This subcode goes in the array element pd_Data[1]. It requires one byte of data following it in pd_Data[2]. This data
specifies how the stereo channels are controlled. The four options, defined by the following constants, are:
●

AUDIO_Channels_Mute - turns off the audio output in both channels.

●

AUDIO_Channels_RightToBoth - feeds the right audio signal to both left and right channels.

●

AUDIO_Channels_LeftToBoth - feeds the left audio signal to both the left and right channels.

●

AUDIO_Channels_Stereo - feeds the left audio signal to the left channel and right audio signal to the right
channel.

Glasses Controller Subcodes
The stereoscopic glasses controller accepts commands defined by glasses controller subcodes. At present, Portfolio offers one

file:///C|/%23%23DDOC/spg/12spg008.html (5 of 6) [4/16/2002 11:12:35 PM]

Other Event Broker Activities

glasses subcode, specified by the following constant:
●

GENERIC_GLASSES_SetView - controls the opacity of each lens in a pair of stereoscopic glasses.

This subcode goes into the array element pd_Data[1]. It requires two bytes of data following it in pd_Data[2] and
pd_Data[3]. The first of the two data bytes controls the left lens of the glasses, the second byte controls the right lens. The
four possible values for each lens, defined by the following constants, are:
●

GLASSES_AlwaysOn - keeps the lens clear during both odd and even video fields.

●

GLASSES_OnOddField - turns the lens clear every odd video field, and turns it opaque every even field.

●

GLASSES_OnEvenField - turns the lens clear every even video field, and turns it opaque every odd field.

●

GLASSES_Opaque - turns the lens opaque during both odd and even video fields.

Lightgun Controller Subcode
Currently, Portfolio offers one light gun controller subcode, which is specified by the following constant:
●

GENERIC_LIGHTGUN_SetLEDs controls the setting of LEDs on the light gun. The setting of up to eight LEDs is
supported, although the stock light gun has only two.

The possible options, defined by the following constants, are:
●

LIGHTGUN_LED1 - controls the setting of the first LED on the light gun.

●

LIGHTGUN_LED2 - controls the setting of the second LED on the light gun.

The Event Broker's Reply to a Command
After the event broker processes a pod command message, it returns the message to the sending task to report on the
command execution. The returned message is of the flavor EB_IssuePodCmdReply, and contains a reply portion that is a
negative number if there was an error executing the command, or is 0 or a positive number if the command execution was
successful.

file:///C|/%23%23DDOC/spg/12spg008.html (6 of 6) [4/16/2002 11:12:35 PM]

Event Broker Convenience Calls

Event Broker Convenience Calls
Portfolio provides a set of convenience calls that allow a task to easily monitor events on controller pads
or mice.
Note: The convenience calls are "single threaded." Only one thread within any application can use them
at a time.

Connecting to the Event Broker
This call connects the task to the event broker, sets the task's focus interest, and determines how many
controller pads and mice the task wants to monitor:
Err InitEventUtility(int32 numControlPads, int32 numMice,int32
focusListener);
Where:
●

●

●

numControlPads sets the maximum number of controller pads the task wants to monitor.
numMice sets the maximum number of mice the task wants to monitor. These values should be
an integer of 0 or higher.
focusListener is a Boolean value that sets the focus of the task when it is connected as a
listener. If the parameter is true (nonzero), the task is connected as a focus-dependent listener. If
the parameter is false (0), the task is connected as a focus-independent listener.

When the call executes, it creates a reply port and a message, sends a configuration message to the event
broker that asks the event broker to report appropriate mouse and controller pad events, and deals with
the event broker's configuration reply. The call returns 0 if successful, and a negative number (an error
code) if unsuccessful.

Monitoring a Control Pad or a Mouse
This call specifies a controller pad or mouse to monitor, specifies whether the event broker should
respond immediately or wait until something happens on the controller pad, and provides a data structure
for data from the controller pad:

file:///C|/%23%23DDOC/spg/12spg009.html (1 of 3) [4/16/2002 11:12:36 PM]

Event Broker Convenience Calls

Err GetControlPad(int32 padNumber, int32 wait,
ControlPadEventData *data);
●

●

●

padNumber sets the number of the generic controller pad on the control port (i.e., the first,
second, third, and so on, pad in the control port daisy chain, counting out from the 3DO unit) that
the task wants to monitor. The first pad is 1, the second is 2, and so on.
wait is a Boolean value that specifies the event broker's response to this call. If it is true
(nonzero), the event broker waits along with the task until an event occurs on the specified pad,
and returns data only when there is a change in the pad. If it is false (0), the event broker
immediately returns with the status of the pad.
data is a pointer to a ControlPadEventData structure that shows where memory was allocated
for the returned control pad data to be stored. (The task must create an instance of this data
structure before it executes GetControlPad()).

When the call executes, it either returns immediately with event information, or waits to return with
event information until there is a change in the controller pad. It returns a 1 if an event has occurred on
the pad, a 0 if no event has occurred on the pad, or a negative number (an error code) if there was a
problem retrieving an event. If an event has occurred, the task must check the ControlPadEventData data
structure for details about the event.
This call performs the same function as GetControlPad(), but gets events from a specified mouse
instead of a specified controller pad:
Err GetMouse(int32 mouseNumber, int32 wait, MouseEventData
*data);
Its parameters are the same as those for GetControlPad(), but mouseNumber specifies a mouse
on the control port instead of a controller pad, and the pointer data is now a pointer to a data structure for
storing mouse event data instead of controller pad event data.

Disconnecting From the Event Broker
This call disconnects a task that was connected to the event broker with the InitEventUtility()
call:
Err KillEventUtility(void);
When executed, it disconnects the task from the event broker, closes the reply port, and frees all
resources used for the connection. It returns 0 if successful, and a negative number (error code) if
file:///C|/%23%23DDOC/spg/12spg009.html (2 of 3) [4/16/2002 11:12:36 PM]

Event Broker Convenience Calls

unsuccessful.

file:///C|/%23%23DDOC/spg/12spg009.html (3 of 3) [4/16/2002 11:12:36 PM]

Function Calls

Function Calls
These convenience calls allow a task to use the event broker to monitor controller pads and mice.

Connecting To and Disconnecting From the Event
Broker
●
●

InitEventUtility() Connects task to the event broker.
KillEventUtility() Disconnects a task from the event broker.

Monitoring Events
●
●

GetControlPad() Gets control pad events.
GetMouse() Gets mouse events.

file:///C|/%23%23DDOC/spg/12spg010.html [4/16/2002 11:12:36 PM]

InitEventUtility

InitEventUtility
Connects task to the event broker.

Synopsis
Err InitEventUtility( int32 numControlPads, int32 numMice,int32
focusListener )

Description
This convenience call allows a task to easily monitor events on controller pads or mice. This function
connects the task to the event broker, sets the tasksfocusinterest,and'determines how many controller
pads and mice the task wants to monitor.
The function creates a reply port and a message, sends a configuration message to the event broker
(which asks the event broker to report appropriate mouse and controller pad events), and deals with the
event brokersconfigurationreply.'

Arguments
numControlPads
The number of controller pads to monitor.
numMice
The number of mice to monitor.
focusListener
The focus of the task when it is connected as a listener. If the value is nonzero, the task is
connected as a focus-dependent listener. If the value is zero, the task is connected as a focusindependent listener.

Return Value
This function returns a value greater than or equal to 0 if all went well or a negative error code if an error
occurred.

Implementation
file:///C|/%23%23DDOC/spr/04spr003.html (1 of 2) [4/16/2002 11:12:36 PM]

InitEventUtility

Convenience call implemented in input.lib V20.

Associated Files
event.h, input.lib

See Also
GetControlPad(), GetMouse(), KillEventUtility()

file:///C|/%23%23DDOC/spr/04spr003.html (2 of 2) [4/16/2002 11:12:36 PM]

GetControlPad

GetControlPad
Gets control pad events.

Synopsis
Err GetControlPad( int32 padNumber, int32 wait,ControlPadEventData
*data )

Description
This is a convenience call that allows a task to easily monitor events on controller pads. This function
specifies a controller pad to monitor, specifies whether the routine should return immediately or wait
until something happens on the controller pad, and provides a data structure for data from the controller
pad.
When the function executes, it either returns immediately with event information or waits until there is a
change in the controller pad before returning. If an event has occurred, the task must check the
ControlPadEventData data structure for details about the event.

Arguments
padNumber
Sets the number of the generic controller pad on the control port (i.e., the first, second, third, and
so on pad in the control port daisy chain, counting out from the 3DO unit) that the task wants to
monitor. The first pad is 1, the second is 2, and so on.
wait
A boolean value that specifies the event brokersresponse.IfitisTRUE(a nonzero value), the event
broker waits along with the task until an event occurs on the specified pad and only returns with
data when there is a change in the pad. If it is FALSE
(zero), the event broker immediately returns with the status of the pad.
data
A pointer to a ControlPadEventData data structure for the returned control pad data to be stored.

Return Value
This function returns 1 if an event has occurred on the pad, 0 if no event has occurred on the pad, or a
file:///C|/%23%23DDOC/spr/04spr001.html (1 of 2) [4/16/2002 11:12:36 PM]

GetControlPad

negative number (an error code) if a problem occurred while retrieving an event.

Implementation
Convenience call implemented in input.lib V20.

Associated Files
event.h, input.lib

See Also
InitEventUtility(), GetMouse(), KillEventUtility()

file:///C|/%23%23DDOC/spr/04spr001.html (2 of 2) [4/16/2002 11:12:36 PM]

GetMouse

GetMouse
Gets mouse events.

Synopsis
Err GetMouse( int32 mouseNumber, int32 wait,MouseEventData *data )

Description
This convenience call allows a task to easily monitor mouse events.
This function is similar to GetControlPad() but gets events from a specified mouse instead of a
specified controller pad. It specifies a mouse to monitor, specifies whether the call should return
immediately or wait until something happens on the mouse, and provides a data structure for data from
the mouse.
When the function executes, it either returns immediately with event information or waits there is a
change in the mouse before returning. If an event has occurred, the task must check the MouseEventData
data structure for details about the event.

Arguments
mouseNumber
Sets the number of the generic mouse on the control port (i.e., the first, second, third, and so on
mouse in the control port daisy chain, counting out from the 3DO unit) that the task wants to
monitor. The first mouse is 1, the second is 2, and so on.
wait
A boolean value that specifies the event brokersresponse.IfitisTRUE(a non zero value), the event
broker waits along with the task until an event occurs on the specified pad and only returns with
data when there is a change in the pad. If it is FALSE
(zero), the event broker immediately returns with the status of the pad.
data
A pointer to a MouseEventData data structure that contains the mouse data that is returned.

Return Value

file:///C|/%23%23DDOC/spr/04spr002.html (1 of 2) [4/16/2002 11:12:37 PM]

GetMouse

This function returns 1 if an event has occurred on the mouse, 0 if no event has occurred on the mouse,
or an error code (a negative value) if an error occurred when attempting to retrieve an event.

Implementation
Convenience call implemented in input.lib V20.

Associated Files
event.h, input.lib

See Also
InitEventUtility(), GetControlPad(), KillEventUtility()

file:///C|/%23%23DDOC/spr/04spr002.html (2 of 2) [4/16/2002 11:12:37 PM]

KillEventUtility

KillEventUtility
Disconnects a task from the event broker.

Synopsis
Err KillEventUtility( void );

Description
This is a convenience function that allows a task to easily monitor events on controller pads or mice. This
function disconnects a task that was connected to the event broker with the InitEventUtility()
function.
When executed, the function disconnects the task from the event broker, closes the reply port, and frees
all resources used for the connection.

Return Value
This function returns a value greater than or equal to 0 if all went well or a negative error code if an error
occurs.

Implementation
Convenience call implemented in input.lib V20.

Associated Files
event.h, input.lib

See Also
GetControlPad(), GetMouse(), InitEventUtilitys()

file:///C|/%23%23DDOC/spr/04spr004.html [4/16/2002 11:12:37 PM]

I/O Architecture

I/O Architecture
Portfolio provides services to access hardware devices in a hardware-independant manner. This allows
applications to remain compatible across a wide range of hardware products. The Portfolio I/O model is a
central component that enables a wide range of exotic devices to coexist and evolve for many years.
The Portfolio I/O model is inherently asynchronous. Lengthy requests made by a task to a hardware
device are handled in the background. The client task receives a notification when the request has been
satisfied. This architecture allows a single task to have multiple outstanding requests pending on different
hardware devices, which tends to maximize the use of the system bandwidth by keeping all subsystems
working.
Imagine a task that needs to read a block of data from a CD-ROM. It sends a request to the CD-ROM
device driver. The driver does the setup necessary to initiate a hardware transfer. The CD-ROM
mechanism is then activated and the needed block of data is transferred to memory. When the transfer is
complete, an interrupt occurs that wakes up the driver. The driver then notifies the client task that the
data it needs has arrived. While the hardware is servicing the request from the task, the task is free to do
other activities, such as playing music.
The Portfolio I/O model relies on three basic abstractions: the device, the driver, and the I/O request.

Devices
A software device may or may not correspond to a hardware device. Technically, a software device is
anything that responds to I/O requests and lives in supervisor space. A software device might correspond
directly to a hardware device such as a timer, a CD-ROM player, or a controller pad; it might correspond
to a port or bus that controls many different devices; or it might correspond to a more abstract entity such
as an open file on a CD-ROM disk. Portfolio treats a software device as a single I/O mechanism, no
matter what the device's correspondence to actual hardware.
Note: Whenever you read the term "device" by itself, it refers to a software device. A hardware device is
always referred to as "hardware device."
Portfolio maintains a list of all devices resident or active on the 3DO unit. This list changes as devices
are added to or taken from the system. Each device in the list has an item number; a task that requests I/O
with a device must refer to the device by its item number. To find a device's item number, a task uses the
call OpenNamedDevice(), where the task names the device it wants and the kernel returns the
device's item number.

file:///C|/%23%23DDOC/spg/09spg003.html (1 of 3) [4/16/2002 11:12:38 PM]

I/O Architecture

Drivers
Every device maintained by the kernel must have a corresponding driver before any task can use the
device. The driver accepts and acts on every task request for I/O. The driver must be able to recognize at
least three I/O commands-CMD_READ, CMD_WRITE, and CMD_STATUS-and may recognize more
device-specific I/O commands as well. Not all devices are writable, so not all devices can perform the
CMD_WRITE command. For example, a CD-ROM drive will respond to the command without writing
data. All devices can execute CMD_STATUS commands and tell an enquiring task their current status.
A single driver can control several identical or very similar components. Each of these components is
called a unit. Each unit may respond to slightly different commands or may respond in slightly different
ways. Even so, the units are similar enough that a single driver can control them. When a task requests
I/O through such a driver, it specifies not only the device item number, but the unit number. For example,
the kernel provides a timer device that supports two timer units: the microsecond timer and the vertical
blank timer. Both timer units respond to the same commands, but one unit returns elapsed microseconds,
while the other returns elapsed vertical blanks. To read the timer, a task specifies the timer item number,
and then asks for either the microsecond or vertical blank unit.
Drivers are all privileged code. The 3DO Company provides them for 3DO-approved hardware devices
such as controller pads and for more abstract system software devices such as open files.

I/O Requests (IOReqs)
An I/O request (IOReq for short) is a data structure that the kernel passes back and forth between a task
and a device. Think of the IOReq as a messenger that goes from task to device, passing along an I/O
command and other I/O information. When an I/O operation is finished, the device returns the IOReq to
the task, passing along any reports it has to make on the I/O operation.
Before a task can communicate with a device, the task must create an IOReq using the
CreateIOReq() call. An IOReq is a system item that must be used to communicate with a device.
Within an IOReq lies information necessary for executing an I/O command. Part of that information is
the IOInfo data structure, which contains an I/O command, a unit specification, pointers to read and write
buffers, and other I/O parameters provided by the task requesting I/O.
To initiate an I/O operation, a task must give the IOReq to a device by calling SendIO() or DoIO().
When the device completes the operation, it notifies the calling task that the operation is complete. The
calling task is then free to use the IOReq to initiate further I/O operations.
A task gets notified that an I/O operation is complete by either receiving a signal or receiving a message.

file:///C|/%23%23DDOC/spg/09spg003.html (2 of 3) [4/16/2002 11:12:38 PM]

I/O Architecture

The notification mechanism is determined when the IOReq is created.

file:///C|/%23%23DDOC/spg/09spg003.html (3 of 3) [4/16/2002 11:12:38 PM]

Performing I/O

Performing I/O
From a task's point of view, the process of I/O between a task and a device can be broken down into four stages:
●

●

●

●

Preparing for I/O. Task opens a device, creates one or more IOReq data structures, and one or more IOInfo data
structures.
Sending an IOReq. Task fills in IOInfo values, writes output data into a write buffer (if appropriate), submits the task's
IOInfo values to the kernel for processing.
Receiving an IOReq. Task receives notification that an I/O operation is complete, reads data about the operation within
a returned IOReq, and (if appropriate) reads data from a read buffer.
Finishing I/O. Task finishes exchanging IOReqs with a device, deletes the IOReqs it created earlier, and closes the
device.

If a task wants to perform a series of I/O operations on a single device, it only needs to prepare for I/O once. The task can then
send and receive IOReqs to and from the device until it is finished.

Preparing for I/O
Before a task can send and receive IOReqs, it must prepare for I/O by opening a device and creating IOReq and IOInfo data
structures.
To open a device, a task uses the following function call:
Item OpenNamedDevice( const char *name, void *args )
The name argument is a pointer to a null-terminated string of characters that contains the name of the device. The a argument
is a pointer reserved for future use. Currently, this value must always be NULL.
When OpenNamedDevice() executes, it opens the named device and returns the item number of that device. Future I/O
calls to the device use the device's item number.

Creating an IOReq
Once a task opens a device, the task must create one or more IOReq items to communicate with the device. Before creating an
IOReq, it's important to consider how the task will be notified when the IOReq is returned. There are two options:
●
●

Notification by signal
Notification by message

Notification by signal is the default method. When the device finishes with an I/O operation and wants to return the IOReq to
the task, it sends the system signal SIGF_IODONE to the task. The task then knows there's a completed IOReq, and it can
retrieve the IOReq when it wants to.

file:///C|/%23%23DDOC/spg/09spg004.html (1 of 7) [4/16/2002 11:12:39 PM]

Performing I/O

Notification by message is specified by providing a message port when an IOReq is created. When the device finishes with an
I/O operation and wants to return the IOReq, it sends a message to the specified port. The task can read the message to get a
pointer to the IOReq and then read or reuse the IOReq when it wants to.
Either notification method has advantages and disadvantages. Notification by signal uses fewer resources, but doesn't identify
the returning IOReq. It merely says that an IOReq has returned. Notification by signal is useful for I/O operations that use a
single IOReq passed back and forth between the task and a device.
Notification by message uses more resources, but because each message identifies a particular IOReq, the task knows exactly
which IOReq is returned when it receives notification. Notification by message is useful for I/O operations that use more than
one IOReq.
Once a task opens a device, the task creates an IOReq data structure using this call:
Item CreateIOReq( const char *name, uint8 pri, Item dev, Item mp )
The name argument is a pointer to a null-terminated character string containing the name of this IOReq. If the IOReq is
unnamed, this argument should be NULL. The pri argument is a priority value from a low priority of 0 to a high priority of
255. The dev argument is the device number of the opened device to which this IOReq is to be sent.
The mp argument is the item number of a message port where the task is notified of the IOReq's completion. If the task wants
to be notified of IOReq completion by message, it must create a message port and supply its item number here. If the task
wants only to be notified of IOReq completion by signal, then this argument should be set 0.
When this call executes, the kernel creates an IOReq that is sent to the specified device and returns the item number of the
IOReq. All future I/O calls using this IOReq specify it with its item number.

Initializing an IOInfo Structure
Although a task can create an IOReq, it can't directly set values in it because an IOReq is an item. The task instead defines an
IOInfo data structure in its own memory, and then, when it requests an I/O operation, the task fills in the appropriate values
and passes the IOInfo on to the kernel with the IOReq.
The definitions of an IOInfo data structure and the IOBuf data structure used within it (both defined in io.h) are as follows:
typedef struct IOBuf
{
void
*iob_Buffer;
int32
iob_Len;
size*/
} IOBuf;
typedef struct IOInfo
{
uint8
ioi_Command;
uint8
ioi_Flags;
uint8
ioi_Unit;
uint8
ioi_Flags2;
uint32
ioi_CmdOptions;
uint32
ioi_User;
file:///C|/%23%23DDOC/spg/09spg004.html (2 of 7) [4/16/2002 11:12:39 PM]

/* ptr to users buffer */
/* len of this buffer, or transfer

/*
/*
/*
/*
/*
/*

Command to be executed */
misc flags */
unit of this device */
more flags, should be set to zero */
device dependent options */
for user use */

Performing I/O

int32

ioi_Offset;

/* offset into device for transfer to

ioi_Send;
ioi_Recv;

/*begin */
/* copy out information */
/* copy in info, (address validated) */

*/
IOBuf
IOBuf
} IOInfo;

The possible values for the IOInfo fields depend on the device to which the IOReq is sent. The fields include the following:
●

●

●

ioi_Command carries the I/O command to be executed by the device driver. Every driver can recognize at least three
commands defined in io.h: CMD_WRITE, CMD_READ, and CMD_STATUS.
ioi_Flags contains flags for I/O operation variations. Portfolio currently defines just one flag: IO_QUICK, which asks
that I/O take place immediately (synchronously) without notification. All other bits must be set to 0.
ioi_Unit specifies the unit of the device to communicate with. Available units change from device to device. The timer,
for example, offers the TIMER_UNIT_USEC unit and the TIMER_UNIT_VBLANK unit.

●

ioi_Flags2 currently is not used and is always set to 0.

●

ioi_CmdOptions sets command options that vary from device to device.

●

●

●

●

ioi_User contains a pointer to anything the user task wishes to point to. This is a handy field for keeping a reminder of
the data on which an I/O operation is working. When the I/O operation completes, you can then look in the
io_Info.ioi_User field of the IOReq structure to retrieve this pointer.
ioi_Offset contains an offset into the device-a location-where the I/O operation begins. For output operations, this
offset defines the starting point in the device where the task's data is written. For input operations, this offset defines the
starting point in the device where data is read. This value, when supported by a device, uses the units of block size for
whatever device it's addressing.
ioi_Send contains the pointer to and size of a write buffer in which the task stores output data to be written to the
device.
ioi_Recv contains the pointer to and size of a read buffer in which the driver stores input data read from the device.

The IOInfo structure should always contain a command value in ioi_Command, whether it's one of the three standard
commands-CMD_READ, CMD_WRITE, or CMD_STATUS-or a device-specific command. If the command involves writing
data, ioi_Send should be filled in with a write buffer definition; if the command involves reading data, ioi_Recv should
be filled in with a read buffer definition. And if the task wants the fastest possible I/O operation with a device that can respond
immediately (a timer, for example), ioi_Flags should be set to IO_QUICK. Any other fields should be filled in as
appropriate for the operation.

Passing IOInfo Values to the Device
To pass the IOInfo values to the system and send the IOReq, the task can use this call (found in io.h):
Err SendIO( Item ioReqItem, const IOInfo *ioiP )

file:///C|/%23%23DDOC/spg/09spg004.html (3 of 7) [4/16/2002 11:12:39 PM]

Performing I/O

The ioReqItem argument is the item number of the IOReq to be sent to the device. The ioiP, argument is a pointer to the
IOInfo structure that describes the I/O operation to perform.
When the kernel carries out SendIO(), it copies the IOInfo values into the IOReq, then checks the IOReq to be sure that all
values are appropriate. If they are, the kernel passes on the I/O request to the device responsible. The device then carries out
the request.
SendIO() returns 1 if immediate I/O was used and the IOReq is immediately available to the task. SendIO() returns a 0 if
I/O was done asynchronously, which means that the request is being serviced by the device in the background. SendIO()
returns a negative error code if there was an error in sending the IOReq. This usually occurs if there were inappropriate values
included in the IOInfo structure.

Asynchronous vs. Synchronous I/O
When a task sends an I/O request to a device using SendIO(), the device may or may not satisfy the request immediately. If
SendIO() returns 1, it means that the operation is completed and no other actions are expected. If SendIO() returns a 0, it
means that the I/O operation has been deferred and is being worked on in the background.
When an operation is deferred, your task is free to continue executing while the I/O is being satisfied. For example, if the CDROM device is doing a long seek operation in order to get to a block of data you have asked it to read, you can continue
executing the main loop of your task while you wait for the block to be transferred.
When SendIO() returns 0, which means the I/O request is being serviced asynchronously, you must wait for a notification
that the I/O operation has completed before you can assume anything about the state of the operation. As shown previously,
when you create an IOReq using CreateIOReq(), you can specify one of two types of notification: signal or message.
When an asynchronous I/O operation completes, the device sends your task a signal or a message to inform you of the
completion.
Once you receive the notification that an I/O operation is complete, you must call WaitIO() to complete the I/O process.
Err WaitIO( Item ioreq )
WaitIO() cleans up any loose ends associated with the I/O process. WaitIO() can also be used when you wish to wait for
an I/O operation to complete before proceeding any further. The function puts your task or thread on the wait queue until the
specified IOReq has been serviced by the device.
The return value of WaitIO() corresponds to the result code of the whole I/O operation. If the operation fails for some
reason, WaitIO() returns a negative error code describing the error.
If you have multiple I/O requests that are outstanding, and you receive a signal telling you an I/O operation is complete, you
might need to determine which I/O request is complete. Use the CheckIO() function:
int32 CheckIO( Item ioreq )
CheckIO() returns 0 if the I/O operation is still in progress. It returns greater than 0 if the operation completes; it returns a
negative error code if something is wrong.
Do not use CheckIO() to poll the state of an I/O request. You should use WaitIO() if you need to wait for a specific I/O
operation to complete, or use WaitSignal() or WaitPort() if you must wait for one of a number of I/O operations to

file:///C|/%23%23DDOC/spg/09spg004.html (4 of 7) [4/16/2002 11:12:39 PM]

Performing I/O

complete.
There are many cases where an I/O operation is very short and fast. In these cases, the overhead of notifying your task when
the I/O completes becomes significant. The I/O subsystem provides a quick I/O mechanism to help remove this overhead as
much as possible.
Quick I/O occurs whenever SendIO() returns 1. It tells you that the I/O operation is complete, and that no signal or message
will be sent to your task. You can request quick I/O by setting the IO_QUICK bit in the ioi_Flags field of the IOInfo
structure before you call SendIO(). IO_QUICK is merely a request for quick I/O. It is possible that the system cannot
perform the operation immediately. Therefore, check the return value of SendIO() to make sure the I/O was done
immediately. If it was not done synchronously, you have to use WaitIO() to wait for the I/O operation to complete.
The fastest and simplest way to do quick I/O is to use the DoIO() function:
Err DoIO( Item ioreq, const IOInfo *ioInfo )
DoIO() works just like SendIO(), except that it guarantees that the I/O operation is complete once it returns. You do not
need to call WaitIO() or CheckIO() if you use DoIO() on an IOReq. DoIO() always requests quick I/O, and if the
system is unable to do quick I/O, this function automatically waits for the I/O to complete before returning.

Completion Notification
When an I/O operation is performed asynchronously, the device handling the request always sends a notification to the client
task when the I/O operation is complete. As mentioned previously, the notification can be either a signal or a message.
When you create IOReq items with signal notification, the responsible devices send your task the SIGF_IODONE signal
whenever an I/O operation completes. If you have multiple I/O requests outstanding at the same time, you can use the
following to wait for any of the operations to complete.
WaitSignal(SIGF_IODONE);
When WaitSignal() returns, you must call CheckIO() on all of the outstanding I/O requests you have to determine
which one is complete. Once you find a completed request, call WaitIO() with that IOReq to mark the end of the I/O
operation.
If you created your IOReq structures with message notification, you will receive a message whenever an I/O operation
completes. The message is posted to the message port you specified when you created the IOReq. If you have multiple
message-based I/O requests outstanding, you could wait for them using:
msgItem = WaitPort(replyPort,0);
WaitPort() puts your task to sleep until any of the IOReqs complete. Once WaitPort() returns, you can look at three
fields of the message structure to obtain information about the IOReq that has completed:
{
Item msgItem;
Message *msg;
msg
ioreq

= (Message *) LookupItem(msgItem);
= (Item) msg->msg_DataPtr;

file:///C|/%23%23DDOC/spg/09spg004.html (5 of 7) [4/16/2002 11:12:39 PM]

Performing I/O

result
user

= (Err) msg->msg_Result;
= msg->msg_DataSize;

}
The msg_DataPtr field contains the item number of the IOReq that has completed. The msg_Result field contains the
result code of the I/O operation. This is the same value that WaitIO() would return for this IOReq. Finally,
msg_DataSize contains the value of the ioi_User field from the IOInfo structure used to initiate the I/O operation with
SendIO().

Reading an IOReq
Once an IOReq returns to a task, the task can read the IOReq for information about the I/O operation. To read an IOReq, a task
must get a pointer to the IOReq using the LookUpItem() call. For example:
ior = (IOReq *)LookupItem(IOReqItem);
Once a task has the address of an IOReq, it can read the values in the different fields of the IOReq. An IOReq data structure is
defined as follows:
typedef struct IOReq
{
ItemNode
MinNode
struct
struct
IOInfo
int32

io;
io_Link;
Device
*io_Dev;
IOReq
*(*io_CallBack)(struct IOReq *iorP);
/* call, do not ReplyMsg */
io_Info;
io_Actual;
/* actual size of request completed

*/
uint32
int32
int32
Item
Item
} IOReq;

io_Flags;
/* internal to device driver */
io_Error;
/* any errors from request? */
io_Extension[2];
/* extra space if needed */
io_MsgItem;
io_SigItem;

Fields that offer information to the average task are:
●

●

●

io_Info.ioi_User. A copy of the ioi_User field from the IOInfo structure supplied by the task when calling
SendIO() or DoIO(). This is a convenient location for the task to store context information associated with the
IOReq.
io_Actual. Supplies the size in bytes of the I/O operation just completed. This is a convenient place to find out the
size of the last I/O transfer.
io_Error. Contains any errors generated by the device carrying out the I/O operation. The meaning of this value
depends on the device that was used. This value is also returned by DoIO() or WaitIO().

Continuing I/O
file:///C|/%23%23DDOC/spg/09spg004.html (6 of 7) [4/16/2002 11:12:39 PM]

Performing I/O

Tasks often have a series of I/O operations to carry out with a device. If so, a task can recycle an IOReq once it's been
returned; the task supplies new values in an IOInfo data structure, and then uses SendIO() or DoIO() to request a new
operation.
A task isn't restricted to a single IOReq for a single device. If it's useful, a task can create two or more IOReqs for a device, and
work with one IOReq while others are sent to the device or are awaiting action by the task.

Aborting I/O
If an asynchronous I/O operation must be aborted while in process at the device, the issuing task can use this call (defined in
io.h):
Err AbortIO( Item ioreq )
AbortIO() accepts the item number of the IOReq that is responsible for the operation to be aborted. When executed, it
notifies the device that the operation should be aborted. When it is safe, the operation is aborted and the device sets the
IOReq's Io_Error field to ABORTED. The device then returns the IOReq to the task.
A task should always follow the AbortIO() call with a WaitIO() call so the task will wait for the abort to complete and
the IOReq to return.

Finishing I/O
When a task completely finishes I/O with a device, the task should clean up by deleting any IOReqs it created and by closing
the device. To delete an IOReq, a task uses this call (found in io.h):
Err DeleteIOReq( Item ioreq )
This call accepts the item number of an IOReq and frees any resources the IOReq used.
To close a device, a task uses the CloseNameDevice() call:
Err CloseNamedDevice( Item device )

file:///C|/%23%23DDOC/spg/09spg004.html (7 of 7) [4/16/2002 11:12:39 PM]

Examples

Examples
The following two examples show how to use the timer device to read the current system time and make
it wait a certain amount of time. See Portfolio Devices, for a complete description of the timer device.

Reading the System Time
Example 1 demonstrates how to use the timer device to read the current system time. The example does
the following:
●
●
●
●
●
●

Opens the timer device
Creates an IOReq
Initializes an IOInfo structure
Calls DoIO() to perform the read operation
Prints out the current time
Cleans up

Portfolio provides convenience calls that make using the timer device easier, for example,
CreateTimerIOReq() and DeleteTimerIOReq(). This example shows how to communicate
with devices in the Portfolio environment. Note that the SampleSystemTime() and
SampleSystemTimeTV() calls provide a more accurate reading of the system time than the calls used
in this example.
Example 1: Reading the current time (timerread.c).
#include
#include
#include
#include
#include
#include
#include
#include

"types.h"
"string.h"
"io.h"
"device.h"
"item.h"
"time.h"
"stdio.h"
"operror.h"

int main(int32 argc, char **argv)
{
Item
deviceItem;
Item
ioreqItem;
IOReq *ior;
IOInfo ioInfo;
file:///C|/%23%23DDOC/spg/09spg005.html (1 of 5) [4/16/2002 11:12:40 PM]

Examples

TimeVal tv;
Err
err;
deviceItem = OpenNamedDevice("timer",0);
if (deviceItem >= 0)
{
ioreqItem = CreateIOReq(0,0,deviceItem,0);
if (ioreqItem >= 0)
{
ior = (IOReq *)LookupItem(ioreqItem);
memset(&ioInfo,0,sizeof(ioInfo));
ioInfo.ioi_Command
= CMD_READ;
ioInfo.ioi_Unit
= TIMER_UNIT_USEC;
ioInfo.ioi_Recv.iob_Buffer = &tv;
ioInfo.ioi_Recv.iob_Len
= sizeof(tv);
err = DoIO(ioreqItem,&ioInfo);
if (err >= 0)
{
printf("Seconds %u, microseconds
%u\n",tv.tv_Seconds,tv.tv_Microseconds);
}
else
{
printf("DoIO() failed: ");
PrintfSysErr(err);
}
DeleteIOReq(ioreqItem);
}
else
{
printf("CreateIOReq() failed: ");
PrintfSysErr(ioreqItem);
}
CloseNamedDevice(deviceItem);
}
else
{
printf("OpenNamedDevice() failed: ");
PrintfSysErr(deviceItem);
}

file:///C|/%23%23DDOC/spg/09spg005.html (2 of 5) [4/16/2002 11:12:40 PM]

Examples

return 0;
}

Using the Timer Device to Wait
Example 2 demonstrates how to use the timer device to wait a certain amount of time. The program does
the following:
●
●
●
●
●
●

Parses the command-line arguments
Opens the timer device
Creates an IOReq
Initializes an IOInfo structure
Calls DoIO() to perform the wait operation
Cleans up

Note that Portfolio provides convenience calls to make using the timer device easier, for example,
CreateTimerIOReq(), DeleteTimerIOReq(), and WaitTime(). This example shows how to
communicate with devices in the Portfolio environment.
Example 2: Waiting for a specified time (timersleep.c).
#include
#include
#include
#include
#include
#include
#include
#include

"types.h"
"string.h"
"io.h"
"device.h"
"item.h"
"time.h"
"stdio.h"
"operror.h"

int main(int32 argc, char **argv)
{
Item
deviceItem;
Item
ioreqItem;
IOReq *ior;
IOInfo ioInfo;
TimeVal tv;
Err
err;
if (argc == 3)
{

file:///C|/%23%23DDOC/spg/09spg005.html (3 of 5) [4/16/2002 11:12:40 PM]

Examples

tv.tv_Seconds
= strtoul(argv[1],0,0);
tv.tv_Microseconds = strtoul(argv[2],0,0);
deviceItem = OpenNamedDevice("timer",0);
if (deviceItem >= 0)
{
ioreqItem = CreateIOReq(0,0,deviceItem,0);
if (ioreqItem >= 0)
{
ior = (IOReq *)LookupItem(ioreqItem);
memset(&ioInfo,0,sizeof(ioInfo));
ioInfo.ioi_Command
= TIMERCMD_DELAY;
ioInfo.ioi_Unit
= TIMER_UNIT_USEC;
ioInfo.ioi_Send.iob_Buffer = &tv;
ioInfo.ioi_Send.iob_Len
= sizeof(tv);
err = DoIO(ioreqItem,&ioInfo);
if (err >= 0)
{
printf("slept\n");
}
else
{
printf("DoIO() failed: ");
PrintfSysErr(err);
}
DeleteIOReq(ioreqItem);
}
else
{
printf("CreateIOReq() failed: ");
PrintfSysErr(ioreqItem);
}
CloseNamedDevice(deviceItem);
}
else
{
printf("OpenNamedDevice() failed: ");
PrintfSysErr(deviceItem);
}
}
else
{
file:///C|/%23%23DDOC/spg/09spg005.html (4 of 5) [4/16/2002 11:12:40 PM]

Examples

printf("Usage: timersleep  \n");
}
return 0;
}

file:///C|/%23%23DDOC/spg/09spg005.html (5 of 5) [4/16/2002 11:12:40 PM]

Portfolio Devices

Portfolio Devices
This chapter lists the standard Portfolio devices and their associated commands and options. It contains
the following topics:
●
●
●
●
●

Introduction
Communicating With Devices
The Timer Device
The SPORT Device
The File Pseudo-Device

file:///C|/%23%23DDOC/spg/10spg.html [4/16/2002 11:12:40 PM]

Introduction

Introduction
Some of the devices currently in the 3DO system include:
●
●
●
●
●
●

Timer device
File device
SPORT device
CD-ROM device (not documented here)
RAM device (not documented here)
xbus device (not documented here)

All devices use I/O request items for communicating information between tasks and the device. Refer to
The Portfolio I/O Model, for more information on devices and I/O requests.
The first step in the I/O process is for the task to open the device with the OpenNamedDevice() call.
A task must also get its own IOReq and IOInfo data structures to pass information to and from the
device. The IOReq data structure is created using the call CreateIOReq(). The IOInfo data structure
is allocated by the task either via a memory allocation call or on the stack.
Note: The IOInfo structure must be cleared of all unused bits before it is used.
After setting the IOInfo fields, a task uses the SendIO() or DoIO() functions to pass the item number
of the I/O request structure and a pointer to the IOInfo structure to the device. The I/O request is passed
to the device, and the appropriate action is taken by the device as specified by the IOInfo structure fields.

file:///C|/%23%23DDOC/spg/10spg001.html [4/16/2002 11:12:41 PM]

Communicating With Devices

Communicating With Devices
A task sends commands using the IOInfo data structure to a device. The IOInfo.ioi_Command field
is set to the command a task sends to a device. In addition to the command, some devices allow the task
to specify options to the command. The options are set up by defining the
IOInfo.ioi_CmdOptions field. The IOInfo.ioi_Send and IOInfo.ioi_Recv
substructures must also be set for the information to be sent to the device and to receive it back from the
device. The reference sections that follow provide detailed information about the commands and
command options, and send and receive buffers that a task uses to communicate with a device.

file:///C|/%23%23DDOC/spg/10spg002.html [4/16/2002 11:12:41 PM]

The Timer Device

The Timer Device
The timer device is a software component that provides a standardized interface to the timing
hardware.The 3DO hardware architecture includes a number of clocks and timers.
The timer device has two separate timer units that offer different timing characteristics: the microsecond
unit (TIMER_UNIT_USEC) and the vertical blank unit (TIMER_UNIT_VBLANK). The microsecond
timer deals with time quantities using seconds and microseconds, while the vertical blank timer counts
time in vertical blank intervals. Vertical blank intervals are discussed in more detail in The Vertical
Blank Unit. Both units respond to the same commands.
Using either of the timer units, you can do four basic operations:
●
●
●
●

Sample the current time
Ask the timer to notify you when a given time arrives
Ask the timer to notify you after a given amount of time passes
Ask the timer to notify you at regular intervals until you ask it to stop

The following sections describe how to perform these operations with either timer device units.
Note: The timer device currently doesn't provide real-time clocks. That is, the timer starts counting time
only when the machine is turned on, it stops counting time when the machine is shut down. Therefore, it
is not currently possible to automatically determine the current time of day. This capability may be added
to the 3DO architecture in the future.

Working With the Timer Device
Communicating with the two units of the timer device is done using the standard Portfolio I/O
commands. To send commands to the timer device, you must complete the following steps:
1.
2.
3.
4.

Open the timer device using the OpenNamedDevice() function.
Create an IOReq structure by calling the CreateIOReq() function.
Initialize an IOInfo structure that specifies the command and parameters to the command.
Send the command to the timer device using either DoIO() or SendIO().

The Microsecond Unit
The microsecond timer unit provides very high-resolution timing.
file:///C|/%23%23DDOC/spg/10spg003.html (1 of 8) [4/16/2002 11:12:42 PM]

The Timer Device

Although it has very high short-term accuracy, its time base can drift
slightly over extended periods of time.
This microsecond unit of the timer device deals in time quantities using the TimeVal structure, which is
defined as:
typedef struct timeval
{
int32 tv_Seconds;
int32 tv_Microseconds;
} TimeVal;

/* seconds */
/* and microseconds */

Reading the Current System Time
To read the current system time, you must initialize an IOInfo structure such as:
IOInfo ioInfo;
TimeVal tv;
memset(&ioInfo,0,sizeof(ioInfo));
ioInfo.ioi_Command
ioInfo.ioi_Unit
ioInfo.ioi_Recv.iob_Buffer = &tv;
ioInfo.ioi_Recv.iob_Len

= CMD_READ
= TIMER_UNIT_USEC;
= sizeof(tv);

The ioi_Command field is set to CMD_READ, indicating the current system time should be read.
ioi_Unit indicates which unit of the timer device to query. ioi_Recv.iob_Buffer points to a
TimeVal structure. This pointer is where the timer device stores the current time value. Finally,
ioi_Recv.iob_Len holds the size of the TimeVal structure.
Once an I/O operation is performed on the timer device using the above IOInfo, the timer device puts
the current system time in the supplied TimeVal structure, and completes the I/O operation by sending
your task a message or a signal, depending on how the I/O request was created.
For a high performance way to read the system's microseconds clock, see High-Performance Timing.

Waiting for a Specific Time to Arrive
A common use for the timer device is to provide automatic notification of the passage of time. For
example, if you want a given picture to remain on the display for exactly 1 second, you can send a
command to the timer device telling it to send you a signal when 1 second has passed. While you are
file:///C|/%23%23DDOC/spg/10spg003.html (2 of 8) [4/16/2002 11:12:42 PM]

The Timer Device

waiting for that second to pass, your task can do other work, such as play music, confident in the fact that
the timer device will notify it when the appropriate amount of time has passed.
You can ask the timer device to notify you when a specific time arrives. To do this, you must first ask the
system what the current time is by sending the device a CMD_READ. Once you know the current time,
you can use the AddTimes() and SubTimes() calls, explained below, to calculate the time to
receive a notification. Once you have calculated the time to be notified, you can send the
TIMERCMD_DELAYUNTIL command to the timer device. You must initialize the IOInfo structure in the
following way:
IOInfo ioInfo;
TimeVal tv;
memset(&ioInfo,0,sizeof(ioInfo));
ioInfo.ioi_Command
= TIMERCMD_DELAYUNTIL;
ioInfo.ioi_Unit
= TIMER_UNIT_USEC;
ioInfo.ioi_Send.iob_Buffer = &tv;
ioInfo.ioi_Send.iob_Len
= sizeof(tv);
The ioi_Command field is set to TIMERCMD_DELAYUNTIL, indicating that the timer will wait until
a specific time arrives. ioi_Unit indicates which unit of the timer device to use.
ioi_Send.iob_Buffer points to a TimeVal structure. This contains the amount of time to wait.
Finally, ioi_Send.iob_Len holds the size of the TimeVal structure.
You can send the I/O request to the timer device using either DoIO() or SendIO(). When using
DoIO(), your task is put to sleep until the requested time. If you use SendIO(), then your task is free
to continue working while the timer is counting time. When the requested time arrives, the timer device
will either send your task the SIGF_IODONE signal, or will send you a message as specified in your I/O
request.

Waiting a Specific Amount of Time
Instead of asking the timer to wait until a given time, you can tell it to wait for a fixed amount of time to
pass. To achieve this, you follow the procedure in the previous section except that you initialize the
IOInfo structure differently. For a specific amount of time, ioi_Command must be set to
TIMERCMD_DELAY, and the TimeVal structure you supply must specify an amount of time instead of a
certain time.

Getting Repeated Notifications
Often, it is desirable to have a timer automatically generate a signal in regular fixed intervals. The
TIMERCMD_METRONOME commands arranges to have a signal sent to your task for an undetermined
file:///C|/%23%23DDOC/spg/10spg003.html (3 of 8) [4/16/2002 11:12:42 PM]

The Timer Device

length of time at a fixed rate.
IOInfo ioInfo;
TimeVal tv;
int32
signals;
memset(&ioInfo,0,sizeof(ioInfo));
ioInfo.ioi_Command
= TIMERCMD_METRONOME;
ioInfo.ioi_Unit
= TIMER_UNIT_USEC;
ioInfo.ioi_CmdOptions
= signals;
ioInfo.ioi_Send.iob_Buffer = &tv;
ioInfo.ioi_Send.iob_Len
= sizeof(tv);
The ioi_Command field is set to TIMERCMD_METRONOME indicating that the timer acts as a
metronome, and sends your task signals every time a specified amount of time passes. ioi_Unit
indicates which unit of the timer device to use. ioi_CmdOptions specifies the signal mask that the
timer device should use when signalling your task. ioi_Send.iob_Buffer points to a TimeVal
structure. This contains the amount of time between each signal that the timer device sends your task.
Finally, ioi_Send.iob_Len holds the size of the TimeVal structure.
Send the I/O request to the timer device using SendIO(). Once this is done, the timer device will send
a signal to your task every time the specified amount of time passes. To stop the timer device from
sending these signals, you must abort the I/O request using the AbortIO() call.

The Vertical Blank Unit
The vertical blank timer unit provides a fairly coarse measure of time, but is very stable over long
periods of time. It offers a resolution of either 1/60th of a second on NTSC systems or 1/50th of a second
on PAL systems. Vertical blanking is a characteristic of raster scan displays, and occurs on a fixed timescale synchronized with the display hardware.
A vblank is the amount of time it takes for the video beam to perform an entire sweep of the display.
Given that displays operate at different refresh rates in NTSC (60 Hz) compared to PAL (50 Hz), the
amount of time taken by a vblank varies. Since the vblank unit of the timer device deals with time
exclusively in terms of vblank units, waiting for a fixed number of vblanks will take different amounts of
time on NTSC and PAL.
The advantages of the vertical blank timer are that it remains stable for very long periods of time; it
involves slightly less overhead than the microsecond unit; and it is synchronized with the video beam.
Being synchronized with the video beam is very important when creating animation sequences.

file:///C|/%23%23DDOC/spg/10spg003.html (4 of 8) [4/16/2002 11:12:42 PM]

The Timer Device

This vertical blank unit of the timer device deals in time quantities using the VBlankTimeVal structure,
which is defined as:
typedef struct VBlankTimeVal
{
uint32 vbltv_VBlankHi32;
uint32 vbltv_VBlankLo32;
} VBlankTimeVal;

* upper 32 bits of vblank counter */
/* lower 32 bits of vblank counter */

Vblanks are counted using a 64-bit counter. This is represented in two 32-bit words. The upper-32 bits,
which are the most significant, are stored in the vbltv_VBlankHi32 field, while the lower-32 bits are
stored in the vbltv_VBlankLo32 field.

Reading the Current System Time
To read the current system time, you must initialize an IOInfo structure such as:
IOInfo
ioInfo;
VBlankTimeVal vbltv;
memset(&ioInfo,0,sizeof(ioInfo));
ioInfo.ioi_Command
ioInfo.ioi_Unit
ioInfo.ioi_Recv.iob_Buffer
ioInfo.ioi_Recv.iob_Len

= CMD_READ
= TIMER_UNIT_VBLANK;
= &vbltv;
= sizeof(vbltv);

ioi_Command is set to CMD_READ, indicating that the current system time should be read.
ioi_Unit indicates which unit of the timer device to query. ioi_Recv.iob_Buffer points to a
VBlankTimeVal structure. This is where the timer device stores the current vblank count. Finally,
ioi_Recv.iob_Len holds the size of the VBlankTimeVal structure.
Once the I/O is complete, the supplied VBlankTimeVal structure is filled with the current vblank count.
Given that there are either 50 or 60 vblanks per second, over 800 days worth of vblanks can be stored in
vbltv_VBlankLo32. Whenever vbltv_VBlankLo32 exceeds the maximum value it can contain
(2^32 - 1), then the value of vbltv_VBlankHi32 is incremented by 1. This means that the
VBlankTimeVal structure being used to store vblank counts can hold up to (2^32 * 800) days, which is
probably longer than the time remaining before the sun goes supernova.

Waiting for a Specific Time
Similar to the microsecond unit, the vblank unit can wait for a specific time. You specify this time in
file:///C|/%23%23DDOC/spg/10spg003.html (5 of 8) [4/16/2002 11:12:42 PM]

The Timer Device

terms of vblanks. Unlike the microsecond unit, you do not specify the amount of time to wait using a
TimeVal structure. Instead, set the ioi_Offset field of the IOInfo structure to the vblank count.
IOInfo ioInfo;
memset(&ioInfo,0,sizeof(ioInfo));
ioInfo.ioi_Command
= TIMERCMD_DELAYUNTIL;
ioInfo.ioi_Unit
= TIMER_UNIT_VBLANK;
ioInfo.ioi_Offset
= vblankCountToWaitUntil;

Waiting for a Specific Amount of Time
The vblank unit can wait for a given number of vblanks, that is, a specific amount of time. This is done
by initializing an IOInfo structure such as:
IOInfo ioInfo;
memset(&ioInfo,0,sizeof(ioInfo));
ioInfo.ioi_Command
= TIMERCMD_DELAY;
ioInfo.ioi_Unit
= TIMER_UNIT_VBLANK;
ioInfo.ioi_Offset
= numberOfVBlanksToWait;
It is important to understand that the timer counts vblanks in a very strict way. Whenever the video beam
reaches a known location on the display, the vblank counter is incremented. So if you ask the timer to
wait for 1 vblank while the beam is near the trigger location, the I/O request will be returned in less than
1/60th or 1/50th of a second.
The WaitVBL() function is a wrapper function that initializes an IOInfo structure using the
TIMERCMD_DELAY command, and sends it to the timer device.

Getting Repeated Notifications
Similar to the microsecond unit, the vblank unit can automatically send you signals at specified intervals.
You specify the interval time in terms of vblanks. Unlike with the microsecond unit, you do not specify
the amount of time between signals using a TimeVal structure. Instead, set the ioi_Offset field of
the IOInfo structure to the vblank count between signals.
IOInfo
int32

ioInfo;
signals;

memset(&ioInfo,0,sizeof(ioInfo));
ioInfo.ioi_Command
file:///C|/%23%23DDOC/spg/10spg003.html (6 of 8) [4/16/2002 11:12:42 PM]

= TIMERCMD_METRONOME;

The Timer Device

ioInfo.ioi_Unit
ioInfo.ioi_CmdOptions
ioInfo.ioi_Offset

= TIMER_UNIT_VBLANK;
= signals;
= vblanksBetweenSignals;

You should send the I/O request to the timer device using SendIO(). Once this is done, the timer
device will send a signal to your task every time the specified number of vblanks occurs. To stop the
timer device from sending you these signals, you must abort the I/O request using the AbortIO() call.

High-Performance Timing
It is sometimes necessary to measure very short time intervals with very high accuracy. This is especially
useful when trying to measure the performance of various pieces of code. Although using the timer
device and the CMD_READ command gives fairly accurate readings, the overhead involved in doing
device I/O is often enough to skew the results of small time intervals.
Portfolio provides the SampleSystemTime() and SampleSystemTimeTV() functions that allow
low-overhead sampling of the system clock. These functions are based on the same hardware clock as the
microsecond unit of the timer device, and so refer to the same time base.
SampleSystemTime() returns the current seconds counter of the system clock. The function also
returns the current microseconds counter in the R1 CPU register of the ARM processor. This value is
only available if you program in assembly language. To get both values in C, you must use the
SampleSystemTimeTV() function, which puts the current values of the seconds and microseconds
counters in the TimeVal structure that you supply.

Time Arithmetic
The following calls calculate or compare time values.
●

AddTimes(). Adds two time values, yielding the total time for both. This call is useful for time
calculation.

●

CompareTimes(). Compares two time values. This call helps you determine what happens when.

●

SubTimes(). Subtracts one time value from another, yielding the time difference between the two.

●

TimeLaterThan(). Returns whether a time value comes before another time value.

●

TimeLaterThanOrEqual(). Returns whether a time value comes before or at the same time as
another time value.

file:///C|/%23%23DDOC/spg/10spg003.html (7 of 8) [4/16/2002 11:12:42 PM]

The Timer Device

Simplified Timer Device Interface
The following calls create I/O requests and wait fixed amounts of time. These are simple convenience
calls that interface to the timer device for you. All of these routines use the microsecond timer unit.
●

CreateTimerIOReq(). Creates an I/O request for communication with the timer device.

●

DeleteTimerIOReq(). Frees any resources used in a previous call to CreateTimerIOReq().

●
●

WaitUntil(). Puts the current context to sleep until the system clock reaches a given time.

file:///C|/%23%23DDOC/spg/10spg003.html (8 of 8) [4/16/2002 11:12:42 PM]

The SPORT Device

The SPORT Device
The 3DO hardware includes a minimum of 1 MB of VRAM. VRAM is a special type of memory that
offers a very wide interface bus, which allows for efficient implementation of display buffers.
SPORT stands for Serial PORT, and refers specifically to the VRAM's serial port, not to an external RS232 serial port. VRAM has special hardware that lets you copy pages of memory, clear pages of memory,
and replicate pages of memory at an amazing rate. The SPORT device provides access to these
capabilities. It is ideal for clearing a display to a specific color, or setting a display to a static background
picture.

Working With the SPORT Device
The SPORT device always operates on pages of VRAM. The size of VRAM pages is returned by the
GetPageSize(MEMTYPE_VRAM) function call. All operations performed by the SPORT device must
start on an even page boundary and be a multiple of the page size length. The current VRAM page size is
2 KB, but you must not rely on this fact. Always use the GetPageSize() function to get the actual
page size.
Communicating with the SPORT device is done with the standard Portfolio I/O commands. The SPORT
device only has a single unit, unit 0. To send commands to the SPORT device, you must complete the
following steps:
1.
2.
3.
4.

Open the SPORT device using the OpenNamedDevice() function.
Create an IOReq structure by calling the CreateIOReq() function.
Initialize an IOInfo structure that specifies the command and parameters of the command.
Send the command to the SPORT device using either DoIO() or SendIO().

Copying VRAM Pages
The SPORTCMD_COPY command copies pages of VRAM to other pages of VRAM. The copy operation
always occurs during vertical blanking because the serial port on the VRAM is always in use when video
is displayed. When vertical blanking occurs, the serial port becomes available for other duties such as
copying and cloning pages.
To use SPORTCMD_COPY, initialize an IOInfo structure such as:
IOInfo ioInfo;

file:///C|/%23%23DDOC/spg/10spg004.html (1 of 3) [4/16/2002 11:12:43 PM]

The SPORT Device

memset(&ioInfo,0,sizeof(ioInfo));
ioInfo.ioi_Command
ioInfo.ioi_Offset
ioInfo.ioi_Send.iob_Buffer
ioInfo.ioi_Send.iob_Len
ioInfo.ioi_Recv.iob_Buffer
ioInfo.ioi_Recv.iob_Len

= SPORTCMD_COPY;
= mask;
= sourceAddress;
= numBytes;
= destinationAddress;
= numBytes;

The sourceAddress field points to the source data to be copied, while the destinationAddress
field points to the address where the data is copied. Both of these addresses must be in VRAM, and both
must fall on even VRAM page boundaries. numBytes indicates the number of bytes to copy. This value
must be an even multiple of the VRAM page size. Finally, mask is a 32-bit value that determines which
bits of each word of data are copied. Every on bit indicates a bit that will be copied to the destination.
Every off bit indicates that the corresponding bit in the destination will remain unchanged.
Don't use a mask value other than 0xffffffff because future hardware implementations may impose serious
performance penalties for using masks with other values.

Replicating VRAM Pages
The SPORTCMD_CLONE command replicates a page of VRAM to a series of other pages. This is useful
when creating wallpaper backgrounds. The cloning operation always occurs during vertical blanking
because the serial port on the VRAM is always in use when video is being displayed. When vertical
blanking occurs, the serial port becomes available for other duties such as copying and cloning pages.
To use SPORTCMD_CLONE, you must initialize an IOInfo structure such as:
IOInfo ioInfo;
memset(&ioInfo,0,sizeof(ioInfo));
ioInfo.ioi_Command
ioInfo.ioi_Offset
ioInfo.ioi_Send.iob_Buffer
ioInfo.ioi_Send.iob_Len
ioInfo.ioi_Recv.iob_Buffer
ioInfo.ioi_Recv.iob_Len

= SPORTCMD_CLONE;
= mask;
= sourcePageAddress;
= pageSize;
= destinationAddress;
= numBytes;

The sourcePageAddress points to the source page to be replicated, while the
destinationAddress field points to the address where the data is copied. Both of these addresses
must be in VRAM, and both must fall on even VRAM page boundaries. pageSize is the size of a single
VRAM page, as returned by GetPageSize(MEMTYPE_VRAM). numBytes indicates the number of
file:///C|/%23%23DDOC/spg/10spg004.html (2 of 3) [4/16/2002 11:12:43 PM]

The SPORT Device

bytes to replicate. This value is typically calculated as (numPages * pageSize). This value must be
an even multiple of the VRAM page size. Finally, mask is a 32-bit value that determines which bits of
each word of data are put on the destination pages. Every on bit indicates a bit that will be copied to the
destination. Every off bit indicates that the corresponding bit in the destination will remain unchanged.
Don't use a mask value other than 0xffffffff because future hardware implementations may impose serious
performance penalties for using masks with other values.

Setting VRAM Pages to a Fixed Value
The FLASHWRITE_CMD command sets the value of a range of VRAM pages. Unlike the copy and clone
operations described above, this command does not operate in the vertical blank area and occurs
immediately.
To use FLASHWRITE_CMD, you must initialize an IOInfo structure such as:
IOInfo ioInfo;
memset(&ioInfo,0,sizeof(ioInfo));
ioInfo.ioi_Command
ioInfo.ioi_CmdOptions
= mask;
ioInfo.ioi_Offset
= value;
ioInfo.ioi_Send.iob_Buffer
ioInfo.ioi_Send.iob_Len
ioInfo.ioi_Recv.iob_Buffer
ioInfo.ioi_Recv.iob_Len

= FLASHCMD_WRITE;

= pageAddress;
= numBytes;
= pageAddress;
= numBytes;

The pageAddress field points to the pages of VRAM to be set to a fixed value. This address must be in
VRAM, and must fall on an even VRAM page boundary. The numBytes field indicates the number of
bytes to affect. This value must be an even multiple of the VRAM page size. value is the value to which
the words of data within the pages should be set. Finally, mask is a 32-bit value that determines which
bits of each word of data are affected. Every on bit indicates a bit that will be affected. Every off bit
indicates that the corresponding bit will remain unchanged.
Don't use a mask value other than 0xffffffff because future hardware implementations may impose serious
performance penalties for using masks with other values.

file:///C|/%23%23DDOC/spg/10spg004.html (3 of 3) [4/16/2002 11:12:43 PM]

The File Pseudo-Device

The File Pseudo-Device
The File folio, in cooperation with the various file systems, provides the services needed to access filesystemoriented external storage; for example, reading files from a CD-ROM, or writing files to the 3DO NVRAM
(non-volatile RAM).
When you open a file using the File folio OpenDiskFile() function, the item that is returned serves as a
handle to the file. The Item is of type Device. This enables communication to the filesystem that controls this
file using the standard Portfolio I/O model.
When you send a command to a file device, the file system responsible for the file wakes up and executes the
command. Therefore, the file device is only a pseudo-device, serving as a gateway to the underlying filesystem.
The File folio provides many high-level functions to control file systems. For example, you can create files
using the CreateFile() function, or you can delete files using the DeleteFile() function. These File
folio functions are merely wrappers for file system commands. The functions internally create file devices and
send commands to the device to perform work.
This section explains the various commands you can send to a file device. It is often much easier to use the
higher-level File folio functions to interact with the file system. However, there are some operations that can
only be performed by interfacing to the file device directly.

Getting Filesystem Status
Once you open a file, you can obtain information about the filesystem the file resides on. This is done by using
the FILECMD_FSSTAT command.
IOInfo
ioInfo;
FileSystemStat fsStat;
memset(&ioInfo,0,sizeof(ioInfo));
ioInfo.ioi_Command
ioInfo.ioi_Recv.iob_Buffer
ioInfo.ioi_Recv.iob_Len

= FILECMD_FSSTAT;
= &fsStat;
= sizeof(FileSystemStat);

Once the command returns successfully, you can look at the fields in the fsStat structure for the status
information. The fst_BitMap field of the FileSystemStat structure indicates which fields in the rest of the
structure are valid and can be examined. Different file systems cannot always provide all the information in a
FileSystemStat structure. For example, if the FSSTAT_SIZE bit is set in fst_BitMap, it means the
fst_Size field of the FileSystemStat structure is valid.
The fields in the FileSystemStat structure are:
file:///C|/%23%23DDOC/spg/10spg005.html (1 of 5) [4/16/2002 11:12:44 PM]

The File Pseudo-Device

●

●

●

fst_BitMap. Indicates which fields of the structure contain valid data.
fst_CreateTime. Indicates when the filesystem was created. This field is currently never valid and
always contains 0.
fst_BlockSize. Indicates the nominal size of data blocks in the filesystem. To determine the block size to
use when reading and writing files, query the file's status and extract the block size from that
information.

●

fst_Size. Indicates the total size of the filesystem in blocks.

●

fst_MaxFileSize. Indicates the maximum size of a file in the filesystem

●

fst_Free. Indicates the total number of blocks currently not in use on the filesystem

●

fst_Used. Indicates the total number of blocks currently in use on the filesystem.

Getting File Status
Once you open a file, you can obtain information about the file by using the CMD_STATUS command.
IOInfo
ioInfo;
FileStatus fStat;
memset(&ioInfo,0,sizeof(ioInfo));
ioInfo.ioi_Command
ioInfo.ioi_Recv.iob_Buffer
ioInfo.ioi_Recv.iob_Len

= CMD_STATUS;
= &fStat;
= sizeof(FileStatus);

Once the command completes successfully, you can look at the fields in the fStat structure for the status
information. Fields of interest are:
●
●
●

fs.ds_DeviceBlockSize. The block size to use when reading or writing this file.
fs.ds_DeviceBlockCount. The number of blocks of data in the file.
fs_ByteCount. The number of bytes currently in the file.

Creating and Deleting Files
To create a file, use the File folio's CreateFile() function. You supply the path name of the file to create,
and the function does the necessary work to create a new file entry on the filesystem.
To delete an existing file, use the File folio's DeleteFile() function. You supply it the path name of the file
file:///C|/%23%23DDOC/spg/10spg005.html (2 of 5) [4/16/2002 11:12:44 PM]

The File Pseudo-Device

to delete, and the function does the necessary work to remove the file's entry from the filesystem.

Allocating Blocks for a File
Before you can write data to a file, you must allocate enough free blocks in the file to hold the data to be
written. This is done by using the FILECMD_ALLOCBLOCKS command.
IOInfo ioInfo;
memset(&ioInfo,0,sizeof(ioInfo));
ioInfo.ioi_Command
= FILECMD_ALLOCBLOCKS;
ioInfo.ioi_Offset
= numBlocks;
The numBlocks variable contains the number of blocks by which to extend the file. If this value is negative,
the size of the file is reduced by the specified number of blocks.

Writing Data to a File
You must use the CMD_WRITE command to write data to a file. All write operations must be performed in full
blocks. The size of the blocks can be obtained by sending a CMD_STATUS command to the file device. The
write operation must also be aligned on a block boundary within the file.
IOInfo ioInfo;
memset(&ioInfo,0,sizeof(ioInfo));
ioInfo.ioi_Command
ioInfo.ioi_Offset
ioInfo.ioi_Send.iob_Buffer
ioInfo.ioi_Send.iob_Len

=
=
=
=

CMD_WRITE;
blockOffset;
dataAddress;
numBytes;

The blockOffset field indicates the offset in blocks from the beginning of the file where the data is to be
written. The dataAddress value points to the data that is to be written. Finally, the numBytes value
indicates the number of bytes to write out. This value must be an even multiple of the block size for the file.

Marking the End of a File
Once you are done writing data to a file, you must mark the end of the file using the FILECMD_SETEOF
command. This command tells the filesystem how many useful bytes of data are in the file. Because you can
only transfer data in terms of blocks, sending this command tells the filesystem how many bytes of the last
written block are useful bytes.
IOInfo ioInfo;

file:///C|/%23%23DDOC/spg/10spg005.html (3 of 5) [4/16/2002 11:12:44 PM]

The File Pseudo-Device

memset(&ioInfo,0,sizeof(ioInfo));
ioInfo.ioi_Command
ioInfo.ioi_Offset

= FILECMD_SETEOF;
= numBytesInFile;

Reading Data From a File
Reading information from a file is done much the same way you write information to a file. You must supply
the offset in blocks where to start reading data, and the number of bytes of data to read.
IOInfo ioInfo;
memset(&ioInfo,0,sizeof(ioInfo));
ioInfo.ioi_Command
ioInfo.ioi_Offset
ioInfo.ioi_Recv.iob_Buffer
ioInfo.ioi_Recv.iob_Len

=
=
=
=

CMD_READ;
blockOffset;
dataAddress;
numBytes;

The blockOffset value indicates the offset in blocks from the beginning of the file from which data is read.
dataAddress indicates an address in memory where the data will be copied once read from the filesystem.
Finally, numBytes contains the number of bytes to read. This number must be an even multiple of the block
size of the file.

Getting Directory Information
The OpenDiskFile() function opens a directories. You can then use the FILECMD_READDIR command
to scan the directory and obtain information about files in the directory.
IOInfo
ioInfo;
DirectoryEntry dirEntry;
memset(&ioInfo,0,sizeof(ioInfo));
ioInfo.ioi_Command
ioInfo.ioi_Offset
ioInfo.ioi_Recv.iob_Buffer
ioInfo.ioi_Recv.iob_Len

=
=
=
=

FILECMD_READDIR;
fileNum;
&dirEntry;
sizeof(DirectoryEntry);

The fileNum value indicates the number of the file within the directory to read. You start with file 0, and keep
going until the I/O cannot be completed because there are no more files. The dirEntry structure will be filled out
with information about the specified file.

Getting the Path of a File
Once you have an open file, you may need to determine the exact path to reach this file. The
file:///C|/%23%23DDOC/spg/10spg005.html (4 of 5) [4/16/2002 11:12:44 PM]

The File Pseudo-Device

FILECMD_GETPATH command determines the exact path to an open file.
IOInfo ioInfo;
char

path[FILESYSTEM_MAX_PATH_LEN];

memset(&ioInfo,0,sizeof(ioInfo));
ioInfo.ioi_Command
ioInfo.ioi_Recv.iob_Buffer
ioInfo.ioi_Recv.iob_Len

= FILECMD_GETPATH;
= path;
= sizeof(path);

Once the command completes successfully, the path variable contains a complete unambiguous path to reach
the file. You can then use this path to issue another OpenDiskFile() command or a DeleteFile()
command.

file:///C|/%23%23DDOC/spg/10spg005.html (5 of 5) [4/16/2002 11:12:44 PM]

Function Calls

Function Calls
I/O operations use the following calls. See Kernel Folio Calls, in the 3DO System Programmer's
Reference for complete details on these calls.

Opening and Closing Devices
The following calls open and close devices:
●
●
●
●

CloseNamedDevice() Closes a device previously opened with OpenNamedDevice().
FindDevice() Returns the item number of a device.
FindAndOpenDevice() Finds and opens a device item.
OpenNamedDevice() Opens a named device.

Creating, Deleting, and Creating Pointers for
IOReqs
The following calls handle IO requests:
●
●
●

CreateIOReq() Creates an I/O request.
DeleteIOReq() Deletes an I/O request.
LookupItem() Gets a pointer to an item.

Controlling the I/O Process
The following calls handle I/O processes:
●
●
●
●
●

AbortIO() Aborts an I/O operation.
CheckIO() Checks if an asynchronous I/O request has completed.
DoIO() Performs synchronous I/O.
SendIO() Requests asynchronous I/O.
WaitIO() Waits for an asynchronous I/O request to complete.

file:///C|/%23%23DDOC/spg/09spg006.html [4/16/2002 11:12:44 PM]

Kernel Folio Calls

Kernel Folio Calls
This chapter describes the kernel folio procedure calls in alphabetical order. The list provides a quick
summary of each procedure and the page number of the first page of its description.
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●

AbortIO Aborts an I/O operation.
AddHead Adds a node to the head of a list.
AddTail Adds a node to the tail of a list.
AllocMem Allocate a memory block of a specific type.
AllocMemBlocks Transfers pages of memory from the system-wide free memory pool.
AllocMemFromMemList Allocates memory from a private memory pool.
AllocMemFromMemLists Allocates a memory block from a list of memory lists.
AllocMemList Creates a private memory list.
AllocSignal Allocates signals.
AvailMem Gets information about available memory.
CallFolio Invokes from the folio vector table a folio procedure that doesn't return a value.
CallFolioRet Invokes from the folio vector table a folio procedure that returns a value.
CheckIO Checks for I/O request completion.
CheckItem Checks to see if an item exists.
ClearCurrentSignals Clears some received signal bits.
CloseItem Closes a system item.
CloseNamedDevice Closes a device previously opened with OpenNamedDevice().
ControlMem Controls memory permissions and ownership.
CountBits Counts the number of bits set in a word.
CreateBufferedMsg Creates a buffered message.
CreateIOReq Creates an I/O request.
CreateItem Creates an item.
CreateMemDebug Initializes memory debugging package.
CreateMsg Creates a standard message.
CreateMsgPort Creates a message port.
CreateSemaphore Creates a semaphore.
CreateSmallMsg Creates a small message.
CreateThread Creates a thread.
CreateUniqueMsgPort Creates a message port with a unique name.

file:///C|/%23%23DDOC/spr/01spr.html (1 of 4) [4/16/2002 11:12:46 PM]

Kernel Folio Calls
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●

●

●
●
●
●
●
●
●
●
●

CreateUniqueSemaphore Creates a semaphore with a unique name.
DeleteIOReq Deletes an I/O request.
DeleteItem Deletes an item.
DeleteMemDebug Releases memory debugging resources.
DeleteMsg Deletes a message.
DeleteMsgPort Deletes a message port.
DeleteSemaphore Deletes a semaphore.
DeleteThread Deletes a thread.
DoIO Performs synchronous I/O.
DumpMemDebug Dumps memory allocation debugging information.
DumpNode Prints contents of a node.
DumpTagList Prints contents of a tag list.
exit Exits from a task or thread.
ffs Finds the first set bit.
FindAndOpenDevice Finds a device by name and opens it.
FindAndOpenFolio Finds a folio by name and opens it.
FindAndOpenItem Finds an item by type and tags and opens it.
FindAndOpenNamedItem Finds an item by name and opens it.
FindDevice Finds a device by name.
FindFolio Finds a folio by name.
FindItem Finds an item by type and tags.
FindLSB Finds the least-significant bit.
FindMSB Finds the highest-numbered bit.
FindMsgPort Finds a message port by name.
FindNamedItem Finds an item by name.
FindNamedNode Finds a node by name.
FindNodeFromHead Returns a pointer to a node appearing at a given ordinal position from
the head of the list.
FindNodeFromTail Returns a pointer to a node appearing at a given ordinal position from
the tail of the list.
FindSemaphore Finds a semaphore by name.
FindTagArg Looks through a tag list for a specific tag.
FindTask Finds a task by name.
FindVersionedItem Finds an item by name and version.
FirstNode Gets the first node in a list.
free Frees memory from malloc().
FreeMem Frees memory from AllocMem().
FreeMemList Frees a memory list.
FreeMemToMemList Frees a private block of memory.

file:///C|/%23%23DDOC/spr/01spr.html (2 of 4) [4/16/2002 11:12:46 PM]

Kernel Folio Calls
●
●
●
●
●
●
●

●
●
●
●

●

●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●

FreeMemToMemLists Returns memory to the free pool.
FreeSignal Frees signals.
GetBankBits Finds out which VRAM bank contains a memory location.
GetCurrentSignals Gets the currently received signal bits.
GetFolioFunc Returns a pointer to a folio function.
GetMemAllocAlignment Gets the memory-allocation alignment size
GetMemTrackSize Get the size of a block of memory allocated with
MEMTYPE_TRACKSIZE.
GetMemType Gets the type of the specified memory.
GetMsg Gets a message from a message port.
GetNodeCount Counts the number of nodes in a list.
GetNodePosFromHead Gets the ordinal position of a node within a list, counting from the
head of the list.
GetNodePosFromTail Gets the ordinal position of a node within a list, counting from the tail
of the list.
GetPageSize Gets the number of bytes in a memory page.
GetSysErr Gets the error string for an error.
GetTagArg Finds a TagArg in list and returns its ta_Arg field.
GetTaskSignals Gets the currently received signal bits.
GetThisMsg Gets a specific message.
InitList Initializes a list.
InsertNodeAfter Inserts a node into a list after another node already in the list.
InsertNodeBefore Inserts a node into a list before another node already in the list.
InsertNodeFromHead Inserts a node into a list.
InsertNodeFromTail Inserts a node into a list.
IsEmptyList Checks whether a list is empty.
IsItemOpened Determines whether a task or thread has opened a given item.
IsListEmpty Checks whether a list is empty.
IsMemReadable Determines whether a region of memory is fully readable by the current task.
IsMemWritable Determines whether a region of memory is fully writable by the current task.
IsNode Checks that a node pointer is not the head list anchor.
IsNodeB Checks that a node pointer is not the tail list anchor.
LastNode Gets the last node in a list.
LockItem Locks an item.
LockSemaphore Locks a semaphore.
LookupItem Gets a pointer to an item.
malloc Allocates memory.
MkNodeID Creates an item type value
NextNode Gets the next node in a list.

file:///C|/%23%23DDOC/spr/01spr.html (3 of 4) [4/16/2002 11:12:46 PM]

Kernel Folio Calls
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●

●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●

NextTagArg Finds the next TagArg in a tag list.
OpenItem Opens an item.
OpenNamedDevice Opens a named device.
PrevNode Gets the previous node in a list.
PrintError Prints the error string for an error
PrintfSysErr Prints the error string for an error.
ReadHardwareRandomNumber Gets a 32-bit random number.
RemHead Removes the first node from a list.
RemNode Removes a node from a list.
RemTail Removes the last node from a list.
ReplyMsg Sends a reply to a message.
ReplySmallMsg Sends a reply to a small message.
SampleSystemTime Samples the system time with very low overhead.
SampleSystemTimeTV Samples the system time with very low overhead.
SanityCheckMemDebug Checks all current memory allocations to make sure all of the
allocation cookies are intact
ScanList Walks through all the nodes in a list.
ScanListB Walks through all the nodes in a list backwards.
ScavengeMem Returns task's free memory pages to the system memory pool.
SendIO Requests asynchronous I/O.
SendMsg Sends a message.
SendSignal Sends a signal to another task.
SendSmallMsg Sends a small message.
SetItemOwner Changes the owner of an item.
SetItemPri Changes the priority of an item.
SetNodePri Changes the priority of a list node.
UniversalInsertNode Inserts a node into a list.
UnlockItem Unlocks a locked item.
UnlockSemaphore Unlocks a semaphore.
WaitIO Waits for an I/O request to complete.
WaitPort Waits for a message to arrive.
WaitSignal Waits until a signal is received.
Yield Give up the CPU to a task of equal priority.

file:///C|/%23%23DDOC/spr/01spr.html (4 of 4) [4/16/2002 11:12:46 PM]

AbortIO

AbortIO
Aborts an I/O operation.

Synopsis
Err AbortIO( Item ior )

Description
This procedure aborts an I/O operation. If the I/O operation has already completed, calling AbortIO()
has no effect. If it is not complete, it will be aborted.
A task should call WaitIO() immediately after calling AbortIO(). When WaitIO() returns, the
task knows that the I/O operation is no longer active. It can then confirm that the I/O operation was
aborted before it was finished by checking the io_Error field of the IOReq structure. If the operation
aborted, the value of this field is ER_Aborted.

Arguments
ior
The item number of the I/O request to abort.

Return Value
The procedure returns 0 if the I/O operation was successfully aborted or an error code (a negative value)
if an error occurs. Possible error codes include:
BADITEM
The ior argument is not an IOReq.
NOTOWNER
The ior argument is an IOReq but the calling task is not its owner.

Implementation
SWI implemented in kernel folio V20.

file:///C|/%23%23DDOC/spr/01spr001.html (1 of 2) [4/16/2002 11:12:46 PM]

AbortIO

Associated Files
io.h
ANSI C Prototype

See Also
CheckIO(), CreateIOReq(), DeleteIOReq(), DoIO(), SendIO(), WaitIO()

file:///C|/%23%23DDOC/spr/01spr001.html (2 of 2) [4/16/2002 11:12:46 PM]

CheckIO

CheckIO
Checks for I/O request completion.

Synopsis
int32 CheckIO( Item ior )

Description
This procedure checks to see if an I/O request has completed.

Arguments
ior
The item number of the I/O request to be checked.

Return Value
The procedure returns 0 if the I/O is not complete. It returns > 0 if it is complete. It returns BADITEM if
ior is bad.

Implementation
Convenience call implemented in clib.lib V20. Became a folio call in kernel folio V24.

Associated Files
io.h
ANSI C Prototype

See Also
AbortIO(), CreateIOReq(), DeleteIOReq(), DoIO(), SendIO(), WaitIO()

file:///C|/%23%23DDOC/spr/01spr013.html [4/16/2002 11:12:47 PM]

CreateIOReq

CreateIOReq
Creates an I/O request.

Synopsis
Item CreateIOReq( const char *name, uint8 pri, Item dev, Item mp )

Description
This convenience procedure creates an I/O request item.
When you create an I/O request, you must decide how the device will notify you when an I/O operation
completes. There are two choices:
●
●

Notification by signal
Notification by message

With notification by signal, the device will send your task the SIGF_IODONE signal whenever an I/O
operation completes. This is a low-overhead mechanism, which is also low on information. When you
get the signal, all you know is that an I/O operation has completed. You do not know which operation
has completed. This has to be determined by looking at the state of all outstanding I/O requests.
Notification by message involves slightly more overhead, but provides much more information. When
you create the I/O request, you indicate a message port. Whenever an I/O operation completes, the device
will send a message to that message port. The message will contain the following information:
●

●
●

msg_Result Contains the io_Error value from the I/O request. This indicates the state of the I/O
operation, whether it worked or failed.
msg_DataPtr Contains the item number of the I/O request that completed.
msg_DataSize Contains the value of the ioi_User field taken from the IOInfo structure used when
initiating the I/O operation.

Arguments
name
The name of the I/O request (see "Notes").
pri

file:///C|/%23%23DDOC/spr/01spr021.html (1 of 3) [4/16/2002 11:12:47 PM]

CreateIOReq

The priority of the I/O request. For some device drivers, this value determines the order in which
I/O requests are processed. When in doubt about what value to use, use 0.
dev
The item number of the device to which to send the I/O request.
mp
If a task wants to receive a message when an I/O request is finished, this argument must be the
item number of the message port to receive the message. If the task wants to receive a signal when
an I/O request is finished instead of a message, this argument must be 0.

Return Value
The procedure returns the item number of the new I/O request or one of the following error codes if an
error occurs:
BADITEM
The mp argument was not zero but did not specify a valid message port.
ER_Kr_ItemNotOpen
The device specified by the dev argument is not open.
NOMEM
There was not enough memory to complete the operation.

Implementation
Convenience call implemented in clib.lib V20.

Associated Files
io.h
ANSI C Prototype
clib.lib
ARM Link Library

Notes
When you no longer need an I/O request, use DeleteIOReq() to delete it.
file:///C|/%23%23DDOC/spr/01spr021.html (2 of 3) [4/16/2002 11:12:47 PM]

CreateIOReq

You can use FindNamedItem() to find a I/O request by name. When creating I/O requests, you
should assign unique names whenever possible.
The kernel may change the priority of an I/O request to help optimize throughput.

See Also
DeleteIOReq()

file:///C|/%23%23DDOC/spr/01spr021.html (3 of 3) [4/16/2002 11:12:47 PM]

DeleteIOReq

DeleteIOReq
Deletes an I/O request.

Synopsis
Err DeleteIOReq( Item item )

Description
This macro deletes an I/O request item. You can use this macro in place of DeleteItem() to delete
the item. If there was any outstanding I/O with this IOReq, it will be aborted first.

Arguments
item
The item number of the I/O request to delete.

Return Value
The macro returns 0 if the I/O request was successfully deleted or an error code (a negative value) if an
error occurs.

Implementation
Macro implemented in io.h V20.

Associated Files
io.h
ANSI C Macro

See Also
CreateIOReq()

file:///C|/%23%23DDOC/spr/01spr031.html [4/16/2002 11:12:47 PM]

DoIO

DoIO
Performs synchronous I/O.

Synopsis
Err DoIO( Item ior, const IOInfo *ioiP )

Description
This procedure is the most efficient way to perform synchronous I/O (I/O in which the task waits for the
I/O request to complete before continuing). It automatically requests quick I/O (see below), sends the I/O
request, and then puts the calling task into wait state until the request is complete.
DoIO() automatically sets the IO_QUICK flag in the IOInfo structure. This flag specifies quick I/O,
which works as follows: The kernel tries to perform the I/O operation immediately and, if it is successful,
it sends back the resulting IOReq immediately and returns 1 as the result code. The calling task can then
get the necessary information from the IOReq. If quick I/O is not successful, the kernel performs normal
asynchronous I/O and notifies the task with a signal or message when the I/O request is complete. This
wakes up the task and DoIO() returns.
Starting with kernel folio V24, this function will automatically sample the io_Error field of the I/O
request and return this to you. It is, therefore, no longer necessary to have code such as:
err = DoIO(iorItem,&ioinfo);
0r err = DoIO(iorItem,&ioinfo);
if (err >= 0)
err = ior->io_Error;
You can now just look at the return value of DoIO().

Arguments
ior
The item number of the I/O request to use.
ioiP
A pointer to the IOInfo structure containing the I/O command to be executed, input and/or output
data, and other information.

file:///C|/%23%23DDOC/spr/01spr038.html (1 of 2) [4/16/2002 11:12:48 PM]

DoIO

Return Value
The procedure returns when the I/O was successful (which means that the IOReq structure has already
been returned and its contents can be examined).

Implementation
Convenience call implemented in clib.lib V20. Became a SWI in kernel folio V24.

Associated Files
io.h
ANSI C Prototype

See Also
AbortIO(), CheckIO(), CreateIOReq(), DeleteIOReq(), SendIO(), WaitIO()

file:///C|/%23%23DDOC/spr/01spr038.html (2 of 2) [4/16/2002 11:12:48 PM]

SendIO

SendIO
Requests asynchronous I/O.

Synopsis
Err SendIO( Item ior, const IOInfo *ioiP )

Description
This procedure sends an I/O request that is to be executed asynchronously. Because the request is
asynchronous, control returns to the calling task as soon as the request is sent (unlike synchronous I/O,
where control doesn't return until after the request has been completed).
Call this procedure after creating the necessary IOReq item (for the ior argument, created by calling
CreateIOReq() ) and an IOInfo structure (for the ioiP argument). The IOReq item specifies the
device to which to send the request and the reply port, if any, while the IOInfo structure includes the I/O
command to be executed and a variety of other information. For descriptions of the IOReq and IOInfo
data structures, see the Data Structures and Variable Type's chapter.
To request quick I/O, set the IO_QUICK flag in the ioi_Flags field of the IOInfo structure. Quick I/O
works as follows: The kernel tries to perform the I/O operation immediately; if it is successful, it sends
back the resulting IOReq item immediately without setting any signal bits or sending a message. If quick
I/O was successful, the IO_QUICK bit in the io_Flags field of the IOReq is set. If quick I/O was not
successful, the kernel performs normal asynchronous I/O and notifies the task with a signal or message
when the I/O request is complete.
The IOInfo structure must be fully initialized before calling this function. You can use the ioi_User field
of the IOInfo structure to contain whatever you want. This is a useful place to store a pointer to
contextual data that needs to be associated with the I/O request. If you use message-based notification for
your I/O requests, the msg_DataSize field of the notification messages will contain the value of ioi_User
from the IOInfo structure.

Arguments
ior
The item number of the IOReq structure for the request. This structure is normally created by
calling CreateIOReq().
ioiP
file:///C|/%23%23DDOC/spr/01spr121.html (1 of 3) [4/16/2002 11:12:48 PM]

SendIO

A pointer to an IOInfo structure.

Return Value
The procedure returns 1 if the I/O was completed immediately or 0 if the I/O request is still in progress
(the task will be notified with either a signal or message when the request is complete, depending on
what you specified when you called CreateIOReq()). It returns an error code (a negative value) if an
error occurs. Possible error codes include:
BADITEM
The ior argument does not specify an IOReq.
NOTOWNER
The I/O request specified by the ior argument is not owned by this task.
ER_IONotDone
The I/O request is already in progress.
BADPTR
A pointer is invalid: Either the IOInfo structure specified by the ioiP argument is not entirely
within the task's memory, the IOInfo receive buffer (specified by the ioi_Recv field in the IOInfo
structure) is not entirely within the task's memory, or the IOInfo send buffer (specified by the
ioi_Send field in the IOInfo structure) is not in legal memory.
BADIOARG
One or more reserved I/O flags are set (either reserved flags in the ioi_Flags field of the IOInfo
structure or any of the flags in the ioi_Flags2 field of the IOInfo structure).
BADUNIT
The unit specified by the ioi_Unit field of the IOInfo structure is not supported by this device.
If quick I/O occurs, the IO_QUICK flag is set in the io_Flags field of the IOReq structure.
If the ior and ioiP arguments were valid but an error occurred during the I/O operation, an error code is
returned in the io_Error field of the IOReq structure. If SendIO() returns 0 and a error occurs during
I/O, the IOReq is returned as if it were completed, and it contains the error code in io_Error of the IOReq
structure.

Implementation
SWI implemented in kernel folio V20.
file:///C|/%23%23DDOC/spr/01spr121.html (2 of 3) [4/16/2002 11:12:48 PM]

SendIO

Associated Files
io.h
ANSI C Prototype

Caveats
SendIO() returns only BADITEM, NOTOWNER, and ER_IONotDone. All other errors codes are
returned in the io_Error field of the IOReq.

See Also
AbortIO(), CheckIO(), DoIO(), WaitIO()

file:///C|/%23%23DDOC/spr/01spr121.html (3 of 3) [4/16/2002 11:12:48 PM]

WaitIO

WaitIO
Waits for an I/O request to complete.

Synopsis
Err WaitIO( Item ior )

Description
The procedure puts the calling task into wait state until the specified I/O request completes. When a task
is in wait state, it uses no CPU time.
Note: If the I/O request has already completed, the procedure returns immediately. If the I/O request
never completes and it is not aborted, the procedure never returns.
Starting with kernel folio V24, this function will automatically sample the io_Error field of the IO
request, and return this to you. It is, therefore, no longer necessary to have code such as:
err = WaitIO(iorItem);
if (err > = 0)
err = ior->io_Error;
You can now just look at the return value of WaitIO().

Arguments
ior
The item number of the I/O request to wait for.

Return Value
The procedure returns a value greater than or equal to 0 if the I/O request was successful or an error code
if an error occurs.

Implementation

file:///C|/%23%23DDOC/spr/01spr131.html (1 of 2) [4/16/2002 11:12:49 PM]

WaitIO

Convenience call implemented in clib.lib V20. Became a SWI in kernel folio V24.

Associated Files
io.h
ANSI C Prototype
clib.lib
ARM Link Library

See Also
AbortIO(), CheckIO(), DoIO(), SendIO()

file:///C|/%23%23DDOC/spr/01spr131.html (2 of 2) [4/16/2002 11:12:49 PM]

AddHead

AddHead
Adds a node to the head of a list.

Synopsis
void AddHead( List *l, Node *n )

Description
This procedure adds a node to the head (the beginning) of the specified list.

Arguments
l
A pointer to the list in which to add the node.
n
A pointer to the node to add.

Implementation
Folio call implemented in kernel folio V20.

Associated Files
list.h
ANSI C Prototype
clib.lib
ARM Link Library

Notes
A node can be included in only one list.

Caveats

file:///C|/%23%23DDOC/spr/01spr002.html (1 of 2) [4/16/2002 11:12:49 PM]

AddHead

Attempting to insert a node into a list while it is a member of another list is not reported as an error, and
may confuse the other list.

See Also
AddTail(), InitList(), InsertNodeFromHead(), InsertNodeFromTail(),
RemHead(), RemNode(), RemTail(), UniversalInsertNode()

file:///C|/%23%23DDOC/spr/01spr002.html (2 of 2) [4/16/2002 11:12:49 PM]

file:///C|/%23%23DDOC/spr/01spr003.html

AddTail
Adds a node to the tail of a list.

Synopsis
void AddTail( List *l, Node *n )

Description
This procedure adds the specified node to the tail (the end) of the specified list.

Arguments
l
A pointer to the list in which to add the node.
n
A pointer to the node to add.

Implementation
Folio call implemented in kernel folio V20.

Associated Files
list.h
ANSI C Prototype
clib.lib
ARM Link Library

Notes
A node can be included only in one list.

Caveats

file:///C|/%23%23DDOC/spr/01spr003.html (1 of 2) [4/16/2002 11:12:49 PM]

file:///C|/%23%23DDOC/spr/01spr003.html

Attempting to insert a node into a list while it is a member of another list is not reported as an error, and
may confuse the other list.

See Also
AddHead(), InitList(), InsertNodeFromHead(), InsertNodeFromTail(),
RemHead(), RemNode(), RemTail(), UniversalInsertNode()

file:///C|/%23%23DDOC/spr/01spr003.html (2 of 2) [4/16/2002 11:12:49 PM]

InitList

InitList
Initializes a list.

Synopsis
void InitList( List *l, const char *name )

Description
When you create a List structure, you must initialize it with a call to InitList() before using it.
InitList() creates an empty list by initializing the head (beginning-of-list) and tail (end-of-list)
anchors and by providing a name for a list.

Arguments
l
A pointer to the list to be initialized.
name
The name of the list, or NULL to get the default name.

Implementation
Folio call implemented in kernel folio V20.

Associated Files
list.h
ANSI C Prototype
clib.lib
ARM Link Library

Caveats
GIGO (garbage in, garbage out)

file:///C|/%23%23DDOC/spr/01spr084.html (1 of 2) [4/16/2002 11:12:49 PM]

InitList

See Also
AddHead(), AddTail(), InsertNodeFromHead(), InsertNodeFromTail(),
IsListEmpty(), RemHead(), RemNode(), RemTail(), UniversalInsertNode()

file:///C|/%23%23DDOC/spr/01spr084.html (2 of 2) [4/16/2002 11:12:49 PM]

IsertNodeFromHead

InsertNodeFromHead
Inserts a node into a list.

Synopsis
void InsertNodeFromHead( List *l, Node *n )

Description
This procedure inserts a new node into a list. The order of nodes in a list is normally determined by their
priority. The procedure compares the priority of the new node to the priorities of nodes currently in the
list, beginning at the head of the list, and inserts the new node immediately after all nodes whose priority
is higher. If the priorities of all the nodes in the list are higher, the node is added at the end of the list.

Arguments
l
A pointer to the list into which to insert the node.
n
A pointer to the node to insert.

Implementation
Folio call implemented in kernel folio V20.

Associated Files
list.h
ANSI C Prototype
clib.lib
ARM Link Library

Notes
To arrange the nodes in a list by a value or values other than priority, use
file:///C|/%23%23DDOC/spr/01spr087.html (1 of 2) [4/16/2002 11:12:50 PM]

IsertNodeFromHead

UniversalInsertNode().
A node can only be included in one list.

See Also
AddHead(), AddTail(), RemHead(), RemNode(), RemTail(),
InsertNodeFromTail(), UniversalInsertNode()

file:///C|/%23%23DDOC/spr/01spr087.html (2 of 2) [4/16/2002 11:12:50 PM]

RemHead

RemHead
Removes the first node from a list.

Synopsis
Node *RemHead( List *l )

Description
This procedure removes the head (first) node from a list.

Arguments
l
A pointer to the list to be beheaded.

Return Value
The procedure returns a pointer to the node that was removed from the list or NULL if the list is empty.

Implementation
Folio call implemented in kernel folio V20.

Associated Files
list.h
ANSI C Prototype
clib.lib
ARM Link Library

See Also
AddHead(), AddTail(), InsertNodeFromTail(), RemNode(), RemTail()

file:///C|/%23%23DDOC/spr/01spr110.html [4/16/2002 11:12:50 PM]

InsertNodeFromTail

InsertNodeFromTail
Inserts a node into a list.

Synopsis
void InsertNodeFromTail( List *l, Node *n )

Description
This procedure inserts a new node into a list. The order of nodes in a list is determined by their priority.
The procedure compares the priority of the new node to the priorities of nodes currently in the list,
beginning at the tail of the list, and inserts the new node immediately before the nodes whose priority is
lower. If there are no nodes in the list whose priority is lower, the node is added at the head of the list.

Arguments
l
A pointer to the list into which to insert the node.
n
A pointer to the node to insert.

Implementation
Folio call implemented in kernel folio V20.

Associated Files
list.h
ANSI C Prototype
clib.lib
ARM Link Library

Notes
To arrange the nodes in a list by a value or values other than priority, use
file:///C|/%23%23DDOC/spr/01spr088.html (1 of 2) [4/16/2002 11:12:50 PM]

InsertNodeFromTail

UniversalInsertNode().
A node can only be included in one list.

See Also
AddHead(), AddTail(), RemHead(), RemNode(), RemTail(),
InsertNodeFromHead(), UniversalInsertNode()

file:///C|/%23%23DDOC/spr/01spr088.html (2 of 2) [4/16/2002 11:12:50 PM]

file:///C|/%23%23DDOC/spr/01spr111.html

RemNode
Removes a node from a list.

Synopsis
void RemNode( Node *n )

Description
This procedure removes the specified node from a list.
Note: If the specified node structure is not in a list you may get an abort.

Arguments
n
A pointer to the node to remove.

Implementation
Folio call implemented in kernel folio V20.

Associated Files
list.h
ANSI C Prototype
clib.lib
ARM Link Library

See Also
RemTail(), AddTail(), InsertNodeFromTail(), RemHead()

file:///C|/%23%23DDOC/spr/01spr111.html [4/16/2002 11:12:51 PM]

RemTail

RemTail
Removes the last node from a list.

Synopsis
Node *RemTail( List *l )

Description
This procedure removes the tail (last) node from a list.

Arguments
l
A pointer to the list structure that will have its tail removed.

Return Value
The procedure returns a pointer to the node that was removed from the list or NULL if the list is empty.
The anchor nodes are never returned.

Implementation
Folio call implemented in kernel folio V20.

Associated Files
list.h
ANSI C Prototype
clib.lib
ARM Link Library

See Also
AddHead(), AddTail(), InsertNodeFromTail(), RemHead(), RemNode()

file:///C|/%23%23DDOC/spr/01spr112.html (1 of 2) [4/16/2002 11:12:51 PM]

RemTail

file:///C|/%23%23DDOC/spr/01spr112.html (2 of 2) [4/16/2002 11:12:51 PM]

UniversalInsertNode

UniversalInsertNode
Inserts a node into a list.

Synopsis
void UniversalInsertNode( List *l, Node *n, bool (*f)(Node *n,Node *m)
)

Description
Every node in a list has a priority (a value from 0 to 255 that is stored in the n_Priority field of the node
structure). When a new node is inserted with InsertNodeFromHead() or
InsertNodeFromTail(), the position at which it is added is determined by its priority. The
UniversalInsertNode() procedure allows tasks to arrange list nodes according to values other
than priority.
UniversalInsertNode() uses a comparison function provided by the calling task to determine
where to insert a new node. It compares the node to be inserted with nodes already in the list, beginning
with the first node. If the comparison function returns TRUE, the new node is inserted immediately
before the node to which it was compared. If the comparison function never returns TRUE, the new node
becomes the last node in the list. The comparison function, whose arguments are pointers to two nodes,
can use any data in the nodes for the comparison.

Arguments
l
A pointer to the list into which to insert the node.
n
A pointer to the node to insert. This same pointer is passed as the first argument to the comparison
function.
f
A comparison function provided by the calling task that returns TRUE if the node to be inserted
(pointed to by the first argument to the function) should be inserted immediately before the node
to which it is compared (pointed to by the second argument to the function).
m
A pointer to the node in the list to which to compare the node to insert.
file:///C|/%23%23DDOC/spr/01spr128.html (1 of 2) [4/16/2002 11:12:51 PM]

UniversalInsertNode

Implementation
Folio call implemented in kernel folio V20.

Associated Files
list.h
ANSI C Prototype
clib.lib
ARM Link Library

Notes
A node can be included only in one list.

See Also
AddHead(), AddTail(), InsertNodeFromHead(), InsertNodeFromTail(),
RemHead(), RemNode(), RemTail()

file:///C|/%23%23DDOC/spr/01spr128.html (2 of 2) [4/16/2002 11:12:51 PM]

IsListEmpty

IsListEmpty
Checks whether a list is empty.

Synopsis
bool IsListEmpty( List *l )

Description
This macro checks whether a list is empty.

Arguments
l
A pointer to the list to check.

Return Value
The macro returns TRUE if the list is empty or FALSE if it isn't.

Implementation
Macro implemented in list.h V24.

Associated Files
list.h
ANSI C Macro definition

See Also
FirstNode(), IsNode(), IsNodeB(), LastNode(), NextNode(), PrevNode(),
ScanList()

file:///C|/%23%23DDOC/spr/01spr091.html [4/16/2002 11:12:52 PM]

FirstNode

FirstNode
Gets the first node in a list.

Synopsis
Node *FirstNode( List *l )

Description
This macro returns a pointer to the first node in the specified list. If the list is empty, the macro returns a
pointer to the tail (end-of-list) anchor. To determine if the return value is an actual node rather than the
tail anchor, call the IsNode() procedure.
Example 1: Use of FirstNode in forward list traversal
for (n = FirstNode(list); IsNode(list, n); n = NextNode( n ))
{
. . .
};

Arguments
l
A pointer to the list from which to get the first node.

Return Value
The macro returns a pointer to first node in the list or, if the list is empty, a pointer to the tail (end-of-list)
anchor.

Implementation
Macro implemented in list.h V20.

Associated Files
list.h
ANSI C Macro

file:///C|/%23%23DDOC/spr/01spr062.html (1 of 2) [4/16/2002 11:12:52 PM]

FirstNode

See Also
IsListEmpty(), IsNode(), IsNodeB(), LastNode(), NextNode(),
PrevNode(), ScanList()

file:///C|/%23%23DDOC/spr/01spr062.html (2 of 2) [4/16/2002 11:12:52 PM]

IsNode

IsNode
Checks that a node pointer is not the head list anchor.

Synopsis
bool IsNode( const List *l, const Node *n )

Description
This macro is used to test whether the specified node is an actual node or is the tail (end-of-list) anchor.
Use this macro when traversing a list from head to tail. When traversing a list from tail to head, use the
IsNodeB() macro.

Arguments
l
A pointer to the list containing the node to check.
n
A pointer to the node to check.

Return Value
The macro returns TRUE if the node is an actual node or FALSE if it is the tail (end-of-list) anchor.
Note: This macro currently returns TRUE for any node that is not the tail anchor, whether or not the
node is in the specified list.

Implementation
Macro implemented in list.h V20.

Associated Files
list.h
ANSI C Macro Definition

file:///C|/%23%23DDOC/spr/01spr094.html (1 of 2) [4/16/2002 11:12:52 PM]

IsNode

See Also
FirstNode(), IsListEmpty(), IsNodeB(), LastNode(), NextNode(),
PrevNode(), ScanList()

file:///C|/%23%23DDOC/spr/01spr094.html (2 of 2) [4/16/2002 11:12:52 PM]

IsNodeB

IsNodeB
Checks that a node pointer is not the tail list anchor.

Synopsis
bool IsNodeB( const List *l, const Node *n )

Description
This macro is used to test whether the specified node is an actual node or is the head (beginning-of-list)
anchor. Use this macro when traversing a list from tail to head. When traversing a list from head to tail,
use the IsNode() macro.

Arguments
l
A pointer to the list containing the node to check.
n
A pointer to the node to check.

Return Value
The macro returns TRUE if the node is an actual node or FALSE if it is the head (beginning-of-list)
anchor.
Note: This macro currently returns TRUE for any node that is not the head anchor, whether or not the
node is in the specified list.

Implementation
Macro implemented in list.h V20.

Associated Files
list.h
ANSI C Macro Definition
file:///C|/%23%23DDOC/spr/01spr095.html (1 of 2) [4/16/2002 11:12:53 PM]

IsNodeB

See Also
FirstNode(), IsListEmpty(), IsNode(), LastNode(), NextNode(),
PrevNode(), ScanList()

file:///C|/%23%23DDOC/spr/01spr095.html (2 of 2) [4/16/2002 11:12:53 PM]

LastNode

LastNode
Gets the last node in a list.

Synopsis
Node *LastNode( const List *l )

Description
This macro returns a pointer to the last node in a list. If the list is empty, the macro returns a pointer to
the head (beginning-of-list) anchor. To determine if the return value is an actual node rather than the head
anchor, call the IsNodeB() procedure.
Example 1: Example 15-3 Use of LastNode in reverse list traversal
for (n = LastNode(list); IsNodeB(list, n); n = PrevNode( n ))
{
. . .
};

Arguments
l
A pointer to the list structure to be examined.

Return Value
The macro returns a pointer to last node in the list or, if the list is empty, a pointer to the head (beginningof-list) anchor.

Implementation
Macro implemented in list.h V20.

Associated Files
list.h
ANSI C Macro definition

file:///C|/%23%23DDOC/spr/01spr096.html (1 of 2) [4/16/2002 11:12:53 PM]

LastNode

See Also
FirstNode(), IsListEmpty(), IsNode(), IsNodeB(), NextNode(),
PrevNode(), ScanList()

file:///C|/%23%23DDOC/spr/01spr096.html (2 of 2) [4/16/2002 11:12:53 PM]

NextNode

NextNode
Gets the next node in a list.

Synopsis
Node *NextNode( const Node *n )

Description
This macro gets a pointer to the next node in a list. If the current node is the last node in the list, the
result is a pointer to the tail (end-of-list) anchor. To determine if the return value is an actual node rather
than the tail anchor, call the IsNode() procedure.
Example 1: Use of NextNode in forward list traversal
for (n = FirstNode( l ); IsNode( l, n ); n = NextNode( n ))
{
. . .
};

Arguments
n
Pointer to the current node.

Return Value
The macro returns a pointer to the next node in the list or, if the current node is the last node in the list, to
the tail (end-of-list) anchor.

Implementation
Macro implemented in list.h V20.

Associated Files
list.h
ANSI C Macro definition

file:///C|/%23%23DDOC/spr/01spr102.html (1 of 2) [4/16/2002 11:12:53 PM]

NextNode

Caveats
Assumes that n is a node in a list. If not, watch out.

See Also
FirstNode(), IsListEmpty(), IsNode(), IsNodeB(), LastNode(),
PrevNode(), ScanList()

file:///C|/%23%23DDOC/spr/01spr102.html (2 of 2) [4/16/2002 11:12:53 PM]

PrevNode

PrevNode
Gets the previous node in a list.

Synopsis
Node *PrevNode( const Node *node )

Description
This macro returns a pointer to the previous node in a list. If the current node is the first node in the list,
the result is a pointer to the head (beginning-of-list) anchor. To determine whether the return value is an
actual node rather than the head anchor, use the IsNodeB() procedure.
Example 1: Use of PrevNode in reverse list traversal
for (n = LastNode( l ); IsNodeB( l, n ); n = PrevNode( n ))
{
. . .
};

Arguments
node
A pointer to the current node.

Return Value
The macro returns a pointer to the previous node in the list or, if the current node is the first node in the
list, to the head (beginning-of-list) anchor.

Implementation
Macro implemented in list.h V20.

Associated Files
list.h
ANSI C Macro definition

file:///C|/%23%23DDOC/spr/01spr106.html (1 of 2) [4/16/2002 11:12:54 PM]

PrevNode

See Also
FirstNode(), IsListEmpty(), IsNode(), IsNodeB(), LastNode(),
ScanList()

file:///C|/%23%23DDOC/spr/01spr106.html (2 of 2) [4/16/2002 11:12:54 PM]

SanList

ScanList
Walks through all the nodes in a list.

Synopsis
ScanList ( const List *1, void *n, )

Description
This macro lets you easily walk through all the elements in a list from the first to the last.
Example 1: For Example
List
*l;
DataStruct *d;
uint32
i;
i = 0;
ScanList(l,d,DataStruct)
{
printf("Node %d is called %s\n",i,d->d.n_Name);
i++;
}

Arguments
l
A pointer to the list to scan.
n
A variable which will be altered to hold a pointer to every node in the list in succession.

The data type of the nodes on the list. This is used for type casting within the macro.

Implementation
Macro implemented in list.h V22.
file:///C|/%23%23DDOC/spr/01spr118.html (1 of 2) [4/16/2002 11:12:54 PM]

SanList

Associated Files
list.h
ANSI C Macro definition

See Also
ScanListB()

file:///C|/%23%23DDOC/spr/01spr118.html (2 of 2) [4/16/2002 11:12:54 PM]

ScanListB

ScanListB
Walks through all the nodes in a list backwards.

Synopsis
ScanListB(List *l, void *n, )

Description
This macro lets you easily walk through all the elements in a list from the last to the first.
Example 1: For Example
List
*l;
DataStruct *d;
uint32
i;
i = 0;
ScanListB(l,d,DataStruct)
{
printf("Node %d (counting from the end) is called %s=n".o.d>d.n_Name=;
i++;
}

Arguments
l
A pointer to the list to scan.
n
A variable which will be altered to hold a pointer to every node
in the list in succession.

The data type of the nodes on the list. This is used for type

file:///C|/%23%23DDOC/spr/01spr119.html (1 of 2) [4/16/2002 11:12:54 PM]

ScanListB

casting within the macro.

Implementation
Macro implemented in list.h V24.

Associated Files
list.h
ANSI C Macro definition

See Also
ScanList()

file:///C|/%23%23DDOC/spr/01spr119.html (2 of 2) [4/16/2002 11:12:54 PM]

AllocMem

AllocMem
Allocate a memory block of a specific type.

Synopsis
void *AllocMem( int32 s, uint32 t )

Description
This macro allocates a memory block of a specific type.

Arguments
s
The size of the memory block to allocate, in bytes.
t
Flags that specify the type, alignment, and fill characteristics of memory to allocate.
One of the following flags must be set:
MEMTYPE_ANY
Any memory can be allocated.
MEMTYPE_VRAM
Allocate only video random-access memory (VRAM).
MEMTYPE_DRAM
Allocate only dynamic random-access memory (DRAM).
If a block of VRAM must come from a specific VRAM bank, the following flag must be set:
MEMTYPE_BANKSELECT
Allocate VRAM from a specific VRAM bank. In addition, one of the following two VRAM bank
selection flags must be set:
MEMTYPE_BANK1
Allocate only memory from VRAM bank 1.
file:///C|/%23%23DDOC/spr/01spr004.html (1 of 4) [4/16/2002 11:12:55 PM]

AllocMem

MEMTYPE_BANK2
Allocate only memory from VRAM bank 2.
The following flags are provided for compatibility with future hardware. You can set them in addition to
the preceding flags.
MEMTYPE_DMA
Allocate only memory that is accessible via direct memory access (DMA). Currently, all memory
is accessible via DMA, but this may not be true in future hardware. Set this flag if you know the
memory must be accessible via DMA.
MEMTYPE_CEL
Allocate only memory that is accessible to the cel engine. Currently, all memory is accessible to
the cel engine, but this may not be true in future hardware. Set this flag if you know the memory
will be used for graphics.
MEMTYPE_AUDIO
Allocate only memory that can be used for audio data (such as digitized sound). Currently, all
memory can be used for audio, but this may not be true in future hardware. Set this flag if you
know the memory will be used for audio data.
MEMTYPE_DSP
Allocate only memory that is accessible to the digital signal processor (DSP). Currently, all
memory is accessible to the DSP, but this may not be true in future hardware. Set this flag if you
know the memory must be accessible to the DSP.
The following flags specify alignment, fill, and other allocation characteristics:
MEMTYPE_FILL
Set every byte in the memory block to the value of the lower eight bits of the flags. If this flag is
not set, the previous contents of the memory block are not changed. (Using 0 as the fill value can
be useful for debugging: Any memory that is inadvertently changed can easily be detected.)
MEMTYPE_INPAGE
Allocate a memory block that does not cross page boundaries.
MEMTYPE_STARTPAGE
Allocate a memory block that starts on a page boundary.
MEMTYPE_MYPOOL
Specifies that the memory block must be allocated only from the task's free memory pool. This
file:///C|/%23%23DDOC/spr/01spr004.html (2 of 4) [4/16/2002 11:12:55 PM]

AllocMem

means that if there is not sufficient memory in the task's pool, the kernel must not allocate
additional memory from the system-wide free memory pool (see Notes).
MEMTYPE_SYSTEMPAGESIZE
Use the system's protection page size for that type of memory and not the special feature page
size. This is necessary for MEMTYPE_VRAM to distinguish between allocations on page
boundaries for graphics operations (normally 2 K) and task page sizes (normally 16 K).

Return Value
The procedure returns a pointer to the memory block that was allocated or NULL if the memory couldn't
be allocated.

Implementation
Macro implemented in mem.h V20.

Associated Files
mem.h
C Macro Definition

Notes
Use FreeMem() to free a block of memory that was allocated with AllocMem().
If there is insufficient memory in a task's free memory pool to allocate the requested memory, the kernel
automatically transfers the necessary pages of additional memory from the system-wide free memory
pool to the task's free memory pool. The only exceptions are (1) when there is not enough memory in
both pools together to satisfy the request, or (2) when the MEMTYPE_MYPOOL memory flag-which
specifies that the memory block must be allocated only from the task's free memory pool-is set.
You can enable memory debugging in your application by compiling your entire project with the
MEMDEBUG value defined on the compiler's command-line. Refer to the CreateMemDebug()
function for more details.

See Also
AllocMemBlocks(), AllocMemFromMemList(), AllocMemList(), ControlMem(),
FreeMem(), FreeMemList(), FreeMemToMemList(), malloc(), ScavengeMem(),
file:///C|/%23%23DDOC/spr/01spr004.html (3 of 4) [4/16/2002 11:12:55 PM]

AllocMem

file:///C|/%23%23DDOC/spr/01spr004.html (4 of 4) [4/16/2002 11:12:55 PM]

AllocMemBlocks

AllocMemBlocks
Transfers pages of memory from the system-wide free memory pool.

Synopsis
void *AllocMemBlocks( int32 size, uint32 typebits )

Description
When there is insufficient memory in a task's free memory pool to allocate a block of memory, the kernel
automatically provides additional memory pages from the system-wide free memory pool. Tasks can also
get pages from the system-wide free memory pool by calling AllocMemBlocks().
Note: Normal applications do not need to call this procedure. It should only be used by applications that
need additional control over the memory-allocation process.
You must set MEMTYPE_TASKMEM in the typebits argument otherwise the memory will not be
allocated to the current task.
AllocMemBlocks() is different from other memory-allocation procedures:
●

The pages of memory that are transferred are not automatically added to the task's free memory
pool. To move the memory into its free memory pool, thereby making it available to tasks, the
task must call one of the procedures for freeing memory (FreeMem(),
FreeMemToMemList(), or FreeMemToMemLists()) with the pointer returned by
AllocMemBlocks() as the argument. (Note that in the memory returned by
AllocMemBlocks(), the first four bytes specify the amount of memory, in bytes, that was
transferred. You should use this value as the size to be freed.)

Arguments
size
The amount of memory to transfer, in bytes. If the size is not an integer multiple of the page size
for the type of memory requested, the system transfers the number of full pages needed to satisfy
the request.
typebits
Flags that specify the type of memory to transfer. These flags can include MEMTYPE_ANY,
MEMTYPE_VRAM, MEMTYPE_DRAM, MEMTYPE_BANKSELECT, MEMTYPE_BANK1,
file:///C|/%23%23DDOC/spr/01spr005.html (1 of 2) [4/16/2002 11:12:56 PM]

AllocMemBlocks

MEMTYPE_BANK2, MEMTYPE_DMA, MEMTYPE_CEL, MEMTYPE_AUDIO,
MEMTYPE_DSP, MEMTYPE_TASKMEM. For information about these flags, see the
description of AllocMem().
MEMTYPE_TASKMEM must always be set.

Return Value
The procedure returns a pointer to the pages of memory that were transferred or NULL if the memory
couldn't be transferred. The first four bytes of the memory specify the amount of memory that was
transferred, in bytes.

Implementation
SWI implemented in kernel folio V20.

Associated Files
mem.h
ARM C "swi" declaration

Notes
To return memory to the system-wide free memory pool, use ScavengeMem() or ControlMem().
ScavengeMem() finds pages of memory in the task's free memory pool from which no memory has
been allocated and returns those pages to the system-wide memory pool. You can use ControlMem()
to transfer ownership of memory to the system-wide memory pool.

See Also
ControlMem(), FreeMem(), FreeMemToMemList(), FreeMemToMemLists(),
ScavengeMem()

file:///C|/%23%23DDOC/spr/01spr005.html (2 of 2) [4/16/2002 11:12:56 PM]

ControlMem

ControlMem
Controls memory permissions and ownership.

Synopsis
Err ControlMem( void *p, int32 size, int32 cmd, Item task )

Description
When a task allocates memory, it becomes the owner of that memory. Other tasks cannot write to the
memory unless they are given permission by its owner. A task can give another task permission to write
to one or more of its memory pages, revoke write permission that was previously granted, or transfer
ownership of memory to another task or the system by calling ControlMem().
Each page of memory has a control status that specifies which task owns the memory and which tasks
can write to it. Calls to ControlMem() change the control status for entire pages. If the p and size
arguments (which specify the memory to change) specify any part of a page, the changes apply to the
entire page.
A task can grant write permission for a page that it owns (or for some number of contiguous pages) to
any number of tasks. To accomplish this, the task must make a separate call to ControlMem() for each
task that is to be granted write permission.
A task that calls ControlMem() must own the memory whose control status it is changing, with one
exception: A task that has write access to memory it doesn't own can relinquish its write access (by using
MEMC_NOWRITE as the value of the cmd argument). If a task transfers ownership of memory it still
retains write access.

Arguments
p
A pointer to the memory whose control status to change.
size
The amount of memory for which to change the control status, in bytes. If the size and p
arguments specify any part of a page, the control status is changed for the entire page.
cmd
A constant that specifies the change to be made to the control status; possible values are listed
file:///C|/%23%23DDOC/spr/01spr018.html (1 of 3) [4/16/2002 11:12:56 PM]

ControlMem

below.
task
The item-number task for which to change the control status or zero for global changes (see
"Notes").
The possible values of "cmd" are:
MEMC_OKWRITE
Grants permission to write to this memory to the task specified by the task argument.
MEMC_NOWRITE
Revokes permission to write to this memory from the task specified by the task argument. If task
is 0 revokes write permission for all tasks.
MEMC_GIVE
If the calling task is the owner of the memory, this transfers ownership of the memory to the task
specified by the task argument. If the specified task is 0, it gives the memory back to the system
free memory pool.

Return Value
The procedure returns 0 if the change was successful or an error code (a negative value) if an error
occurs. Possible error codes include:
BADITEM
The task argument does not specify a current task.
ER_Kr_BadMemCmd
The cmd argument is not one of the valid values.
ER_BadPtr
The p argument is not a valid pointer to memory.

Implementation
SWI implemented in kernel folio V20.

Associated Files

file:///C|/%23%23DDOC/spr/01spr018.html (2 of 3) [4/16/2002 11:12:56 PM]

ControlMem

mem.h
ANSI C Prototype

Notes
A task can use ControlMem() to prevent itself from writing to memory it owns.
A task must own the memory for its I/O buffers.
A task can use ControlMem() to return ownership of memory pages to the system, thereby returning
them to the system-wide free memory pool. You can do this by using 0 as the value of the task argument.
A task can use ControlMem() to unshare or write protect memory from all other tasks. Specify 0 for
the task for this to happen.
We would like to support making a piece of memory writable by all other tasks by using task==0 and
MEMC_OKWRITE, but this is not implemented yet.

See Also
ScavengeMem(), AllocMemBlocks()

file:///C|/%23%23DDOC/spr/01spr018.html (3 of 3) [4/16/2002 11:12:56 PM]

ScavengeMem

ScavengeMem
Returns task's free memory pages to the system memory pool.

Synopsis
int32 ScavengeMem( void )

Description
This procedure finds pages of memory in the task's free memory pool from which no memory is
allocated and returns those pages to the system-wide memory pool.
If there is not enough memory in a task's free memory pool to satisfy a memory-allocation request,
AllocMem() tries to get reclaim the necessary memory by calling ScavengeMem().

Return Value
The procedure returns the amount of memory that was returned to the system-wide memory pool, in
bytes. If no memory was returned, the procedure returns 0.

Implementation
Folio call implemented in kernel folio V20.

Associated Files
mem.h
ANSI C Prototype
clib.lib
ARM Link Library

See Also
AllocMem(), AllocMemFromMemLists(), FreeMem(), FreeMemToMemLists()

file:///C|/%23%23DDOC/spr/01spr120.html [4/16/2002 11:12:56 PM]

AllocMemFromMemLists

AllocMemFromMemLists
Allocates a memory block from a list of memory lists.

Synopsis
void *AllocMemFromMemLists( List *l, int32 size, uint32 memflags)

Description
This procedure allocates a memory block of the specified type from a list of free memory lists. Although
it is used most often by the kernel, it can also be called by user tasks that need to do their own memory
management.
Note: Most applications do not need to do their own memory management. When you use standard
memory-allocation procedures like AllocMem(), the details of memory management are handled for
you by the kernel.
The free memory pools in Portfolio are implemented as lists of memory lists:
●

●

The system-wide free memory pool is the list of memory lists that contain the free memory pages
owned by the system.
A task's free memory pool is a list of memory lists that have been allocated for the task. These
include (1) the two memory lists - one for VRAM and one for DRAM -that are allocated
automatically for a task when the task is created.

AllocMemFromMemLists() allocates memory directly from a particular memory pool. This is in
contrast to AllocMemFromMemList(), which allocates memory from a specific memory list,
typically one that was created by the task for doing its own memory management.
Note: Tasks can only allocate memory from memory lists that belong to them. This means that user tasks
cannot use AllocMemFromMemLists() to allocate memory directly from the system-wide free
memory pool, because the memory in that pool belongs to the system.
If a task requests more memory from its free memory pool than is available, the kernel automatically
allocates the necessary additional memory pages from the system-wide free memory pool if they are
available. The task gets ownership of the additional memory and, when the memory is later freed, it is
added to the task's free memory pool.

Arguments
file:///C|/%23%23DDOC/spr/01spr007.html (1 of 3) [4/16/2002 11:12:57 PM]

AllocMemFromMemLists

l
A pointer to the memory pool from which to allocate the block.
size
The size of the memory block to allocate, in bytes.
memflags
Flags that specify the type of memory to allocate. These flags can include MEMTYPE_ANY,
MEMTYPE_VRAM, MEMTYPE_DRAM, MEMTYPE_BANKSELECT, MEMTYPE_BANK1,
MEMTYPE_BANK2, MEMTYPE_DMA, MEMTYPE_CEL, MEMTYPE_AUDIO,
MEMTYPE_DSP, MEMTYPE_FILL, MEMTYPE_INPAGE, MEMTYPE_TRACKSIZE,
MEMTYPE_STARTPAGE, and MEMTYPE_MYPOOL. For information about these flags, see
the description of AllocMem().

Return Value
The procedure returns a pointer to memory block that was allocated or NULL if the memory couldn't be
allocated.

Implementation
Folio call implemented in kernel folio V20.

Associated Files
mem.h
ANSI C Prototype
clib.lib
ARM Link Library

Notes
To free a memory block allocated with AllocMemFromMemLists(), use the
FreeMemToMemLists() procedure.
You can enable memory debugging in your application by compiling your entire project with the
MEMDEBUG value defined on the compiler's command-line. Refer to the CreateMemDebug()
function for more details.
file:///C|/%23%23DDOC/spr/01spr007.html (2 of 3) [4/16/2002 11:12:57 PM]

AllocMemFromMemLists

See Also
AllocMemFromMemLists()

file:///C|/%23%23DDOC/spr/01spr007.html (3 of 3) [4/16/2002 11:12:57 PM]

FreeMem

FreeMem
Frees memory from AllocMem().

Synopsis
void FreeMem( void *p, int32 size )

Description
This macro frees memory that was previously allocated by a call to AllocMem(). The size argument
specifies the number of bytes to free. The freed memory is automatically returned to the memory list
from which it was allocated.

Arguments
p
A pointer to the memory block to free. This value may be NULL, in which case this function just
returns.
size
The size of the block to free, in bytes. This must be the same size that was specified when the
block was allocated. If the memory being freed was allocated using MEMTYPE_TRACKSIZE,
this argument should be set to -1.

Implementation
Macro implemented in mem.h V20.

Associated Files
mem.h
ANSI C Macro definition

Notes
You can enable memory debugging in your application by compiling your entire project with the
MEMDEBUG value defined on the compiler's command-line. Refer to the CreateMemDebug()

file:///C|/%23%23DDOC/spr/01spr064.html (1 of 2) [4/16/2002 11:12:57 PM]

FreeMem

function for more details.

See Also
AllocMem()

file:///C|/%23%23DDOC/spr/01spr064.html (2 of 2) [4/16/2002 11:12:57 PM]

FreeMemToMemLists

FreeMemToMemLists
Returns memory to the free pool.

Synopsis
void FreeMemToMemLists( List *l, void *p, int32 size )

Description
The procedure returns a block of memory that was allocated with AllocMemFromMemLists() to the
specified free memory pool (a list of memory lists).
Note: Unless you are trying to move memory from one memory pool to another, you should always free
memory to the same pool that you obtained it from.

Arguments
l
A pointer to the memory pool (a list of memory lists) to which to return the memory block.
p
A pointer to the memory to free. This value may be NULL, in which case this function just
returns.
size
Number of bytes to free. This must be the same size that was passed to
AllocMemFromMemLists() to allocate the block. See FreeMem for additional information.

Implementation
Folio call implemented in kernel folio V20.

Associated Files
mem.h
ANSI C Prototype

file:///C|/%23%23DDOC/spr/01spr067.html (1 of 2) [4/16/2002 11:12:57 PM]

FreeMemToMemLists

clib.lib
ARM Link Library

Notes
You can enable memory debugging in your application by compiling your entire project with the
MEMDEBUG value defined on the compiler's command-line. Refer to the CreateMemDebug()
function for more details.

See Also
AllocMem(), AllocMemFromMemLists(), FreeMem()

file:///C|/%23%23DDOC/spr/01spr067.html (2 of 2) [4/16/2002 11:12:57 PM]

FreeMemToMemList

FreeMemToMemList
Frees a private block of memory.

Synopsis
void FreeMemToMemList( MemList *ml, void *p, int32 size )

Description
This procedure frees a private block of memory that was previously allocated by a call to
AllocMemFromMemList(). You can also use it to add memory to a private memory list created by
AllocMemList().
Note: The memory you free to a memory list must be either memory that was previously allocated from
the list or (when adding new memory to the list) memory of the type specified (by the p argument of
AllocMemList()) when the memory list was created.
The block of memory is expected to begin and end on nicely aligned bounds; the alignment size can be
obtained by calling GetMemAllocAlignment(). If the block is not properly aligned, the base is
rounded up and the size is rounded down until alignment is achieved.

Arguments
ml
A pointer to the memory list to which to free the memory.
p
A pointer to the memory to free. This value may be NULL, in which case this function just
returns.
size
The number of bytes to free. This must be the same size that was passed to
AllocMemFromMemList() to allocate the block. See FreeMem for additional information.

Implementation
Folio call implemented in kernel folio V20.

file:///C|/%23%23DDOC/spr/01spr066.html (1 of 2) [4/16/2002 11:12:58 PM]

FreeMemToMemList

Associated Files
mem.h
ANSI C Prototype
clib.lib
ARM Link Library

See Also
AllocMemFromMemList(), AllocMemList(), FreeMemList(),
GetMemAllocAlignment()

file:///C|/%23%23DDOC/spr/01spr066.html (2 of 2) [4/16/2002 11:12:58 PM]

AllocMemFromMemList

AllocMemFromMemList
Allocates memory from a private memory pool.

Synopsis
void *AllocMemFromMemList( MemList *ml, int32 size, uint32 memflags)

Description
A task can do its own memory management by creating one or more private memory lists. Use this
procedure to allocate a memory block from a private memory list.
Note: Most applications do not need to do their own memory management. When you use standard
memory-allocation procedures like AllocMem(), the details of memory management are handled for
you by the kernel.
To create a private memory list, use the AllocMemList() procedure.

Arguments
ml
A pointer to the private memory list from which to allocate the memory block.
size
The size of the memory block to allocate, in bytes.
memflags
Flags that specify the type of memory to allocate. These flags include MEMTYPE_ANY,
MEMTYPE_VRAM, MEMTYPE_DRAM, MEMTYPE_BANKSELECT, MEMTYPE_BANK1,
MEMTYPE_BANK2, MEMTYPE_DMA, MEMTYPE_CEL, MEMTYPE_AUDIO,
MEMTYPE_DSP, MEMTYPE_FILL, MEMTYPE_INPAGE, MEMTYPE_TRACKSIZE, and
MEMTYPE_STARTPAGE. For information about these flags, see the description of
AllocMem().

Return Value
The procedure returns a pointer to the allocated memory or NULL if the memory couldn't be allocated.

file:///C|/%23%23DDOC/spr/01spr006.html (1 of 2) [4/16/2002 11:12:58 PM]

AllocMemFromMemList

Implementation
Folio call implemented in kernel folio V20.

Associated Files
mem.h
ANSI C Prototype
clib.lib
ARM Link Library

Notes
To free a memory block allocated with AllocMemFromMemList(), use the
FreeMemToMemList() procedure.

See Also
AllocMemList(), FreeMemToMemList()

file:///C|/%23%23DDOC/spr/01spr006.html (2 of 2) [4/16/2002 11:12:58 PM]

AllocMemList

AllocMemList
Creates a private memory list.

Synopsis
MemList *AllocMemList( const void *p, char *name )

Description
A task can do its own memory management by creating one or more private memory lists. Use this
procedure to allocate a private memory list.
A memory list you create with AllocMemList() is initially empty. To add memory to the list, use the
FreeMemToMemList() procedure.
Note: A single memory list can store either DRAM or VRAM, but not both. The p argument points to an
example of the memory the task wants to manage with this MemList.

Arguments
p
A pointer to a memory address whose memory type (either DRAM or VRAM) is the type you
want to store in the list. You control actual type of memory in the list by controlling what you free
into the list.
name
The optional name of the memory list.

Return Value
The procedure returns a pointer to the MemList structure that is created or NULL if an error occurs.

Implementation
Folio call implemented in kernel folio V20.

Associated Files
file:///C|/%23%23DDOC/spr/01spr008.html (1 of 2) [4/16/2002 11:12:58 PM]

AllocMemList

mem.h
ANSI C Prototype
clib.lib
ARM Link Library

Notes
To deallocate a memory list created with AllocMemList(), use FreeMemList().

See Also
AllocMemFromMemList(), FreeMemList(), FreeMemToMemList()

file:///C|/%23%23DDOC/spr/01spr008.html (2 of 2) [4/16/2002 11:12:58 PM]

FreeMemList

FreeMemList
Frees a memory list.

Synopsis
void FreeMemList( MemList *ml )

Description
This procedure frees a memory list that was allocated by a call to AllocMemList().

Arguments
ml
A pointer to the memory list to free. This value may be NULL, in which case this function just
returns.

Implementation
Folio call implemented in kernel folio V20.

Associated Files
mem.h
ANSI C Prototype
clib.lib
ARM Link Library

Caveats
If the list is not empty, any memory it contains is lost.

See Also
AllocMemList()

file:///C|/%23%23DDOC/spr/01spr065.html (1 of 2) [4/16/2002 11:12:59 PM]

FreeMemList

file:///C|/%23%23DDOC/spr/01spr065.html (2 of 2) [4/16/2002 11:12:59 PM]

GetMemAllocAlignment

GetMemAllocAlignment
Gets the memory-allocation alignment size

Synopsis
int32 GetMemAllocAlignment( uint32 memflags )

Description
This function returns the alignment guaranteed by AllocMem() and friends, and required by FreeMem()
and friends.

Arguments
memflags
Similar to the usage in GetPageSize(); different allocators may be in use for different kinds of
memory, which may have different alignment guarantees and restrictions.

Return Value
The return value is the alignment modulus for the memory specified; for example, if AllocMem()
guarantees (and FreeMem() requires) long-word alignment, it returns 4. If no alignment is guaranteed or
required, it returns 1.

Implementation
Folio call implemented in kernel folio V22.

Associated Files
mem.h
ANSI C Prototype
clib.lib
ARM Link Library

Caveat
file:///C|/%23%23DDOC/spr/01spr072.html (1 of 2) [4/16/2002 11:12:59 PM]

GetMemAllocAlignment

Note that malloc() does not necessarily provide same alignment guarantee as AllocMem(), as
malloc() reserves some space at the front of the block it gets from AllocMem() to contain the size of
the block allocated.

See Also
GetMemType(), AllocMem(), FreeMem(), malloc(), free()

file:///C|/%23%23DDOC/spr/01spr072.html (2 of 2) [4/16/2002 11:12:59 PM]

GetMemType

GetMemType
Gets the type of the specified memory.

Synopsis
uint32 GetMemType( const void *p )

Description
The procedure returns flags that describe the type of memory at a specified memory location.

Arguments
p
A pointer to the memory whose type to return.

Return Value
The procedure returns a set of flags that specify the type of memory. For information about these flags,
see the description of AllocMem().

Implementation
Convenience call implemented in clib.lib V20.

Associated Files
mem.h
ANSI C Prototype
clib.lib
ARM Link Library

See Also
AllocMem()

file:///C|/%23%23DDOC/spr/01spr074.html (1 of 2) [4/16/2002 11:12:59 PM]

GetMemType

file:///C|/%23%23DDOC/spr/01spr074.html (2 of 2) [4/16/2002 11:12:59 PM]

malloc

malloc
Allocates memory.

Synopsis
void *malloc( int32 size )

Description
This procedure allocates a memory block. It is identical to the malloc() procedure in the standard C
library. The memory is guaranteed only to be memory that is accessible to the CPU; you cannot specify
the memory type (such as VRAM), alignment (such as a memory block that begins on a page boundary),
or any other memory characteristics.
Note: You should only use malloc() when porting existing C programs to Portfolio. If you are writing
programs specifically for Portfolio, use AllocMem(), which allows you to specify the type of memory
to allocate, such as VRAM or memory that begins on a page boundary.

Arguments
size
Size of the memory block to allocate, in bytes.

Return Value
The procedure returns a pointer to the memory that was allocated or NULL if the memory couldn't be
allocated.

Implementation
Convenience call implemented in clib.lib V20.

Associated Files
stdlib.h
ANSI C Prototype

file:///C|/%23%23DDOC/spr/01spr100.html (1 of 2) [4/16/2002 11:13:00 PM]

malloc

clib.lib
ARM Link Library

Notes
You can enable memory debugging in your application by compiling your entire project with the
MEMDEBUG value defined on the compiler's command-line. Refer to the CreateMemDebug()
function for more details.

See Also
AllocMem(), AvailMem(), free()

file:///C|/%23%23DDOC/spr/01spr100.html (2 of 2) [4/16/2002 11:13:00 PM]

AvailMem

AvailMem
Gets information about available memory.

Synopsis
void AvailMem(MemInfo *minfo, uint32 memflags);

Description
This procedure returns information about the amount of memory that is currently available. You can get
information about a particular kind of memory by setting the corresponding flags, such as
MEMTYPE_VRAM or MEMTYPE_DRAM, in the flags argument. To get information about all
memory that is available to the CPU, use MEMTYPE_ANY as the value of the flags argument.
The information about available memory is returned in a MemInfo structure:
Example 1: Memory Information Structure for
typedef struct MemInfo
{
uint32 minfo_SysFree;
uint32 minfo_SysLargest;
uint32 minfo_TaskFree;
uint32 minfo_TaskLargest;
} MemInfo;
The fields contain the following information:
minfo_SysFree
The amount of memory of the specified memory type in the system-wide free memory pool, in
bytes. The pool contains only full pages of memory.
minfo_SysLargest
The size, in bytes, of the largest series of contiguous pages of the specified memory type in the
system-wide free memory pool.
minfo_TaskFree
The amount of memory of the specified type in the task's free memory pool, in bytes.

file:///C|/%23%23DDOC/spr/01spr010.html (1 of 3) [4/16/2002 11:13:00 PM]

AvailMem

minfo_TaskLargest
The size, in bytes, of the largest contiguous block of the specified memory type that can be
allocated from the task's free memory pool.

Arguments
minfo
A pointer to the MemInfo structure used to return the result.
memflags
Flags that specify the type of memory to get information about. These flags can include
MEMTYPE_ANY, MEMTYPE_VRAM, MEMTYPE_DRAM, MEMTYPE_BANKSELECT,
MEMTYPE_BANK1, MEMTYPE_BANK2, MEMTYPE_DMA, MEMTYPE_CEL,
MEMTYPE_AUDIO, and MEMTYPE_DSP. For information about these flags, see the
description of AllocMem().

Implementation
Library routine implemented in clib.lib V20.

Associated Files
mem.h
ANSI C Prototype
clib.lib
ARM Link Library

Caveats
When you call AvailMem(), you must request information about only one memory type. Attempting to
find out about more than one memory type may produce unexpected results.
If you pass in a garbage minfo pointer, sparks may fly.
The information returned by AvailMem() is inherently flawed, since you are existing in a multitasking
environment. Memory can be allocated or freed asynchronous to the operation of the task calling
AvailMem().

See Also
file:///C|/%23%23DDOC/spr/01spr010.html (2 of 3) [4/16/2002 11:13:00 PM]

AvailMem

AllocMem(), free(), FreeMem(), malloc()

file:///C|/%23%23DDOC/spr/01spr010.html (3 of 3) [4/16/2002 11:13:00 PM]

free

free
Frees memory from malloc().

Synopsis
void free( void *p )

Description
The procedure frees a memory block that was allocated by a call to malloc(). It is identical to the
free() procedure in standard C library. The freed memory is automatically returned to the memory list
from which it was allocated.
Note: You should only use malloc() and free() when porting existing C programs to Portfolio. If
you are writing programs specifically for Portfolio, use AllocMem() and FreeMem(), which allow
you to specify the type of memory to allocate, such as VRAM or memory that begins on a page
boundary.

Arguments
p
A pointer to the memory to be freed. This pointer may be NULL, in which case this function just
returns.

Implementation
Convenience call implemented in clib.lib V20.

Associated Files
stdlib.h
ANSI C Prototype
clib.lib
ARM Link Library

Notes
file:///C|/%23%23DDOC/spr/01spr063.html (1 of 2) [4/16/2002 11:13:01 PM]

free

You can enable memory debugging in your application by compiling your entire project with the
MEMDEBUG value defined on the compiler's command-line. Refer to the CreateMemDebug()
function for more details.

Caveats
Trusts that p is a result of a previous malloc() call.

See Also
FreeMem(), FreeMemToMemList(), FreeMemToMemLists(), malloc()

file:///C|/%23%23DDOC/spr/01spr063.html (2 of 2) [4/16/2002 11:13:01 PM]

AllocSignal

AllocSignal
Allocates signals.

Synopsis
int32 AllocSignal( uint32 sigMask )

Description
One of the ways tasks communicate is by sending signals to each other. Signals are 1-bit flags that
indicate that a particular event has occurred.
Tasks that send and receive signals must agree on which signal bits to use and the meanings of the
signals. Except for system signals, there are no conventions for the meanings of individual signal bits; it
is up to software developers to define their meanings.
You allocate bits for new signals by calling AllocSignal(). To define one signal at a time - by far
the most common case - call AllocSignal() with 0 as the argument:
theSignal = AllocSignal( 0 )
This allocates the next unused bit in the signal word. In the return value, the bit that was allocated is set.
If the allocation fails (which happens if all the non-reserved bits in the signal word are already allocated),
the procedure returns 0.
In rare cases, you may need to define more than one signal with a single call. You do this by creating a
uint32 value and setting any bits you want to allocate for new signals, then calling AllocSignal()
with this value as the argument. If all the signals are successfully allocated, the bits set in the return value
are the same as the bits that were set in the argument.
Signals are implemented as follows:
●

●

Each task has a 32-bit signal mask that specifies the signals it understands. Tasks allocate bits for
new signals by calling AllocSignal(). The bits are numbered from 0 (the least-significant
bit) to 31 (the most-significant bit). Bits 0 through 7 are reserved for system signals (signals sent
by the kernel to all tasks); remaining bits can be allocated for other signals. Note: Bit 31 is also
reserved for the system. It is set when the kernel returns an error code to a task instead of signals.
For example, trying to allocate a system signal or signal number 31.
A task calls SendSignal() to send one or more signals to another task. Each bit set in the

file:///C|/%23%23DDOC/spr/01spr009.html (1 of 3) [4/16/2002 11:13:01 PM]

AllocSignal

●

●

●

signalWord argument specifies a signal to send. Normally, only one signal is sent at a time.
When SendSignal() is called, the kernel gets the incoming signal word and ORs it into the
received signal mask of the target task. If the task was in the wait queue, it compares the received
signals with the WaitSignalMask. If there are any bits set in the target, the task is moved from the
wait queue to the ready queue.
If the SIGF_ABORT system signal is sent to the task, the corresponding bit in the task's signal
word is automatically set. This signal cannot be masked.
A task gets incoming signals by calling WaitSignal(). If any bits are set in the task's signal
word , WaitSignal() returns immediately. If no bits are set in the task's signal word, the task
remains in wait state until a signal arrives that matches one of the signals the task is waiting for.

The following system signals are currently defined:
SIGF_ABORT
Informs the task that the current operation has been aborted.
SIGF_IODONE
Informs the task that an asynchronous I/O request is complete.
SIGF_DEADTASK
Informs the task that one of its child tasks or threads has been deleted. Note: This signal does not
specify which task was deleted. To find this out, the parent task must check to see which of its
child tasks still exist.
SIGF_SEMAPHORE
Informs a task waiting to lock a semaphore that it can do so. Note: This signal is for system
internal use only.

Arguments
signalMask
An uint32 value in which the bits to be allocated are set, or 0 to allocate the next available bit.
You should use 0 whenever possible (see Notes).

Return Value
The procedure returns a int32 value with bits set for any bits that were allocated or 0 if not all of the
requested bits could be allocated. It returns ILLEGALSIGNAL if the signalMask specified a reserved
signal.

Implementation
file:///C|/%23%23DDOC/spr/01spr009.html (2 of 3) [4/16/2002 11:13:01 PM]

AllocSignal

SWI implemented in kernel folio V20.

Associated Files
task.h
ARM C Prototype

Notes
Use FreeSignal() to deallocate signals.
Future versions of Portfolio may define additional system signals. To help ensure that the signal bits you
allocate in current applications do not conflict with future system signals, you should always use 0 as the
value of the signalMask argument when allocating signals. If you must allocate specific signal bits
(which is discouraged), use bits 17-31.

See Also
FreeSignal(), GetCurrentSignals(), SendSignal(), WaitSignal()

file:///C|/%23%23DDOC/spr/01spr009.html (3 of 3) [4/16/2002 11:13:01 PM]

FreeSignal

FreeSignal
Frees signals.

Synopsis
Err FreeSignal( uint32 sigMask )

Description
This procedure frees one or more signal bits allocated by AllocSignal(). The freed bits can then be
reallocated.
For information about signals, see the description of the AllocSignal() procedure and the
"Communicating Among Tasks" chapter in the 3DO Portfolio Programmer's Guide.

Arguments
sigMask
A 32-bit value in which any signal bits to deallocate are set. The bits are numbered from 0 (the
least-significant bit) to 31 (the most-significant bit). Bits 0 through 7 and bit 31 cannot be freed.

Return Value
The procedure returns 0 if the signal(s) were freed successfully or an error code if an error occurs.

Implementation
SWI implemented in kernel folio V20.

Associated Files
task.h
ANSI C Prototype

See Also
AllocSignal(), WaitSignal(), SendSignal()
file:///C|/%23%23DDOC/spr/01spr068.html (1 of 2) [4/16/2002 11:13:02 PM]

FreeSignal

file:///C|/%23%23DDOC/spr/01spr068.html (2 of 2) [4/16/2002 11:13:02 PM]

WaitSignal

WaitSignal
Waits until a signal is received.

Synopsis
int32 WaitSignal( uint32 sigMask )

Description
This procedure puts the calling task into wait state until any of the signal(s) specified in the sigMask have
been received. When a task is in wait state, it uses no CPU time.
When WaitSignal() returns, bits set in the result indicate which of the signal(s) the task was waiting
for were received since the last call to WaitSignal(). (The SIGF_ABORTED bit is also set if that
signal was received, even if it is not in the signal mask.) If the task was not waiting for certain signals,
the bits for those signals remain set in the task's signal word, and all other bits in the signal word are
cleared.
See AllocSignal() for a description of the implementation of signals.

Arguments
sigMask
A mask in which bits are set to specify the signals the task wants to wait for.

Return Value
The procedure returns a mask that specifies which of the signal(s) a task was waiting for have been
received or an error code (a negative value) if an error occurs. Possible error codes include:
ILLEGALSIGNAL
One or more of the signal bits in the sigMask argument was not allocated by the task.

Implementation
SWI implemented in kernel folio V20.

file:///C|/%23%23DDOC/spr/01spr133.html (1 of 2) [4/16/2002 11:13:02 PM]

WaitSignal

Associated Files
task.h
ANSI C Prototype

Notes
Because it is possible for tasks to send signals in error, it is up to tasks to confirm that the actual event
occurred when they receive a signal.
For example, if you were waiting for SIGF_IODONE and the return value from WaitSignal indicated
that the signal was sent, you should still call CheckIO using the IOReq to make sure it is actually done. If
it was not done you should go back to WaitSignal.

See Also
SendSignal()

file:///C|/%23%23DDOC/spr/01spr133.html (2 of 2) [4/16/2002 11:13:02 PM]

SendSignal

SendSignal
Sends a signal to another task.

Synopsis
Err SendSignal( Item task, uint32 sigMask )

Description
This procedure sends one or more signals to the specified task. See the description of AllocSignal()
for more information about signals.
It is an error for a user task to send a system signal or a signal that has not been allocated by the receiving
task.

Arguments
task
The item number of the task to send signals to. If this parameter is 0, then the signals are sent to
the calling task. This is sometimes useful to set initial conditions.
sigMask
The signals to send.

Return Value
The procedure returns 0 if successful or an error code (a negative value) if an error occurs. Possible error
codes include:
BADPRIV
The task attempted to send a system signal.
ILLEGALSIGNAL
The task attempted to send a signal to a task that was not allocated by that task, or bit 32 in the
sigMask argument (which is reserved by the system software) was set.

Implementation
file:///C|/%23%23DDOC/spr/01spr123.html (1 of 2) [4/16/2002 11:13:02 PM]

SendSignal

SWI implemented in kernel folio V20.

Associated Files
task.h
ANSI C Prototype

See Also
AllocSignal(), FreeSignal(), GetCurrentSignals(), WaitSignal()

file:///C|/%23%23DDOC/spr/01spr123.html (2 of 2) [4/16/2002 11:13:02 PM]

GetCurrentSignals

GetCurrentSignals
Gets the currently received signal bits.

Synopsis
int32 GetCurrentSignals( void )

Description
This macro returns the signal bits that have been received for the current task. For information about
signals, see the description of the AllocSignal() procedure and the "Communicating Among Tasks"
chapter in the 3DO Portfolio Programmer's Guide.

Return Value
A 32-bit word in which all currently received signal bits are set.

Implementation
Macro implemented in kernel.h V20.

Associated Files
kernel.h
ANSI C Macro

See Also
AllocSignal(), FreeSignal(), SendSignal(), WaitSignal()

file:///C|/%23%23DDOC/spr/01spr070.html [4/16/2002 11:13:02 PM]

CallFolio

CallFolio
Invokes from the folio vector table a folio procedure that doesn't return a value.

Synopsis
void CallFolio( const Folio *folio, int32 func, args )

Description
This macro allows a task to invoke a folio procedure directly from the folio vector table, thereby
bypassing the normal procedure interface. It can be used only for folio procedures that do not return a
value. (To invoke a folio procedure that does return a value, use CallFolioRet().) This approach,
which is slightly faster than invoking the procedure through the normal interface, is intended for use by
the folios themselves, but it can be also be used by applications.
Note: Most tasks should invoke folio procedures in the normal way, using the interfaces described in this
manual. Only tasks that require the utmost in speed and efficiency should invoke folio procedures
directly from the vector table.
Example of AddTail(listP, nodeP) using CallFolio: CallFolio(KernelBase, KBV_ADDTAIL, (listP,
nodeP));

Arguments
folio
A pointer to the folio item that contains the procedure. Use LookupItem() to get this pointer. For
the item number of a folio (which you pass to LookupItem() see the Portfolio Items chapter or call
FindAndOpenFolio().
func
The index of the vector table entry for the procedure. This index (which is always a negative
integer, because the table grows backward in memory) is listed in the header file for the folio that
contains the procedure.
args
The arguments for the procedure, separated by commas and enclosed within parentheses.

Implementation
file:///C|/%23%23DDOC/spr/01spr011.html (1 of 2) [4/16/2002 11:13:03 PM]

CallFolio

Macro implemented in folio.h V20.

Associated Files
folio.h

See Also
CallFolioRet()

file:///C|/%23%23DDOC/spr/01spr011.html (2 of 2) [4/16/2002 11:13:03 PM]

CallFolioRet

CallFolioRet
Invokes from the folio vector table a folio procedure that returns a value.

Synopsis
void CallFolioRet( const Folio *folio, int32 func, args, ret, cast )

Description
This macro allows a task to invoke a folio procedure directly from the folio vector table, thereby
bypassing the normal procedure interface. It can be used only for folio procedures that return a value. (To
invoke a folio procedure that does not return a value, use CallFolio().) This approach, which is
slightly faster than invoking the procedure through the normal interface, is intended for use by the folios
themselves, but it can be also be used by applications.
Note: Most tasks should invoke folio procedures in the normal way, using the interfaces described in this
manual. Only tasks that require the utmost in speed and efficiency should invoke folio procedures
directly from the vector table.
Example of n = RemTail(l) using CallFolioRet: CallFolioRet(KernelBase, KBV_REMTAIL, (l), n,
(Node *));

Arguments
folio
A pointer to the folio item that contains the procedure. Use LookupItem() to get this pointer. For
the item number of a folio (which you pass to LookupItem()), see the Portfolio Items chapter or
call FindAndOpenFolio().
func
The index of the vector table entry for the folio procedure to invoke. This index (a negative
integer, because the table grows backward in memory) is listed in the header file for the folio.
args
The arguments for the procedure, separated by commas and enclosed within parentheses.
ret
A variable to receive the result from the folio procedure. The result is coerced to the type
specified by the cast argument before it is assigned to this variable.
file:///C|/%23%23DDOC/spr/01spr012.html (1 of 2) [4/16/2002 11:13:03 PM]

CallFolioRet

cast
The desired type for the result, surrounded by parentheses. The result returned by the folio
procedure is cast to this type.

Implementation
Macro implemented in folio.h V20.

Associated Files
folio.h

See Also
CallFolio()

file:///C|/%23%23DDOC/spr/01spr012.html (2 of 2) [4/16/2002 11:13:03 PM]

CheckItem

CheckItem
Checks to see if an item exists.

Synopsis
void *CheckItem( Item i, uint8 ftype, uint8 ntype )

Description
This procedure checks to see if a specified item exists. To specify the item, you use an item number, an
item-type number, and the item number of the folio in which the item type is defined. If all three of these
values match those of the item, the procedure returns a pointer to the item.

Arguments
i
The item number of the item to be checked.
ftype
The item number of the folio that defines the item type. (This is the same value that is passed to
the MkNodeID() macro.) For a list of folio item numbers, see the Portfolio Item's chapter.
ntype
The item-type number for the item. (This is the same value that is passed to the MkNodeID()
macro.) For a list of item-type numbers, see the Portfolio Item's chapter.

Return Value
If the item exists (and the values of all three arguments match those of the item), the procedure returns a
pointer to the item. If the item does not exist, the procedure returns NULL.

Implementation
Folio call implemented in kernel folio V20.

Associated Files

file:///C|/%23%23DDOC/spr/01spr014.html (1 of 2) [4/16/2002 11:13:04 PM]

CheckItem

item.h
ANSI C Prototype
clib.lib
ARM Link Library

See Also
CreateItem(), FindItem(), FindNamedItem(), FindVersionedItem(),
LookupItem(), MkNodeID()

file:///C|/%23%23DDOC/spr/01spr014.html (2 of 2) [4/16/2002 11:13:04 PM]

CreateItem

CreateItem
Creates an item.

Synopsis
Item CreateItem( int32 ct, TagArg *p )
Item CreateItemVA( int32 ct, uint32 tags, ... );

Description
This macro creates an item.
Note: There are convenience procedures for creating most types of items (such as CreateMsg() to
create a message and CreateIOReq() to create an I/O request). You should use CreateItem()
only when no convenience procedure is available or when you need to supply additional arguments for
the creation of the item beyond what the convenience routine provides.

Arguments
ct
Specifies the type of item to create. Use MkNodeID() to generate this value.
p
A pointer to an array of tag arguments. The tag arguments can be in any order. The last element of
the array must be the value TAG_END. If there are no tag arguments, this argument must be
NULL. For a list of tag arguments for each item type, see the Portfolio Item's chapter.

Return Value
The procedure returns the item number of the new item or an error code if an error occurs.

Implementation
Macro implemented in item.h V20.

Associated Files

file:///C|/%23%23DDOC/spr/01spr022.html (1 of 2) [4/16/2002 11:13:04 PM]

CreateItem

item.h
ANSI C Macro

Notes
When you no longer need an item created with CreateItem(), use DeleteItem() to delete it.

See Also
CheckItem(), CreateIOReq(), CreateMsg(), CreateMsgPort(),
CreateSemaphore(), CreateSmallMsg(), CreateThread(), DeleteItem()

file:///C|/%23%23DDOC/spr/01spr022.html (2 of 2) [4/16/2002 11:13:04 PM]

CreateMsg

CreateMsg
Creates a standard message.

Synopsis
Item CreateMsg( const char *name, uint8 pri, Item mp )

Description
One of the ways tasks communicate is by sending messages to each other. This procedure creates an item
for a standard message (a message where any data to be communicated to the receiving task is contained
in a data block allocated by the sending task). You can use this procedure in place of CreateItem()
to create the item.
To create a buffered message (a message that includes an internal buffer for sending data to the receiving
task), use CreateBufferedMsg(). To create a small message (a message that can contain up to eight
bytes of data), use CreateSmallMsg().

Arguments
name
The name of the message (see "Notes").
pri
The priority of the message. This determines the position of the message in the receiving task's
message queue and thus, how soon it is likely to be handled. A larger number specifies a higher
priority.
mp
The item number of the message port at which to receive the reply.

Return Value
The procedure returns the item number of the message or an error code (a negative value) if an error
occurs.

Implementation
file:///C|/%23%23DDOC/spr/01spr024.html (1 of 2) [4/16/2002 11:13:04 PM]

CreateMsg

Convenience call implemented in clib.lib V20.

Associated Files
msgport.h
ANSI C Prototype
clib.lib
ARM Link Library

Notes
The same message item can be reused for any number of messages. When you are finished with a
message item, use DeleteMsg() to delete it.
You can use FindNamedItem() to find a message item by name. When creating messages, you
should assign unique names whenever possible.

See Also
CreateMsgPort(), CreateBufferedMsg(), CreateSmallMsg(), DeleteMsg(),
DeleteMsgPort(), SendMsg()

file:///C|/%23%23DDOC/spr/01spr024.html (2 of 2) [4/16/2002 11:13:04 PM]

CreateMsgPort

CreateMsgPort
Creates a message port.

Synopsis
Item CreateMsgPort( const char *name, uint8 pri, uint32 signal )

Description
This convenience procedure creates a message port item. It also creates a message queue for the port in
system RAM. You can use this procedure in place of CreateItem() to create the item.

Arguments
name
The name of the message port (see "Notes").
pri
The priority of the message port. The priority has no effect on the way message ports operate, but
it does determine the order of the message ports in the global list of message ports and thus, the
order in which a message ports are found.
signal
Specifies the bit in the signal word that is set when a message arrives at this port. If zero is
supplied a new signal will be allocated. (See the description of AllocSignal() for information
about allocating signal bits.)

Return Value
The procedure returns the item number of the new message port or an error code if an error occurs.

Implementation
Convenience call implemented in clib.lib V20.

Associated Files

file:///C|/%23%23DDOC/spr/01spr025.html (1 of 2) [4/16/2002 11:13:05 PM]

CreateMsgPort

msgport.h
ANSI C Prototype
clib.lib
ARM Link Library

Notes
When you no longer need a message port use DeleteMsgPort() to delete it.
You can use FindMsgPort() to find a message port by name. When creating message ports you
should assign unique names whenever possible.

See Also
CreateMsg(), DeleteMsg(), DeleteMsgPort(), SendMsg(), SendSmallMsg()

file:///C|/%23%23DDOC/spr/01spr025.html (2 of 2) [4/16/2002 11:13:05 PM]

DeleteMsg

DeleteMsg
Deletes a message.

Synopsis
Err DeleteMsg( Item it )

Description
This macro deletes the specified message and any resources (including the internal data buffer for a
buffered message) that were allocated for it.

Arguments
it
The item number of the message to be deleted.

Return Value
The macro returns a value greater than or equal to 0 if successful or an error code if an error occurs.

Implementation
Macro implemented in msgport.h V20.

Associated Files
msgport.h
ANSI C Macro

See Also
CreateMsg()

file:///C|/%23%23DDOC/spr/01spr034.html [4/16/2002 11:13:05 PM]

DeleteMsgPort

DeleteMsgPort
Deletes a message port.

Synopsis
Err DeleteMsgPort( Item it )

Description
This macro deletes the specified message port.

Arguments
it
The item number of the message port to be deleted.

Return Value
The macro returns a value greater than or equal to 0 if successful or an error code if an error occurs.

Implementation
Macro implemented in msgport.h V20.

Associated Files
msgport.h
ANSI C Macro

See Also
CreateMsg(), CreateMsgPort()

file:///C|/%23%23DDOC/spr/01spr035.html [4/16/2002 11:13:05 PM]

SendMsg

SendMsg
Sends a message.

Synopsis
Err SendMsg( Item mp, Item msg, const void *dataptr, int32 datasize )

Description
This procedure sends a message to the specified message port. (To send a small message use
SendSmallMsg().
The message is queued on the message port's list of messages according to its priority. Messages that
have the same priority are queued on first come, first served basis.
Whether a message is standard or buffered is determined by the procedure you use to create the message:
CreateMsg() creates a standard message (one whose message data belongs to the sending task; the
receiving task reads from this block), while CreateBufferedMsg creates a buffered message (one in
which a buffer for the message data is included in the message). For standard messages, the dataptr and
datasize arguments refer to the data block owned by the message sender. For buffered messages, the
dataptr and datasize arguments specify the data to be copied into the message's internal buffer before the
message is sent.
If the message is a buffered message, SendMsg() checks the size of the data block to see whether it
will fit in the message's buffer. If it won't fit, SendMsg() returns an error.

Arguments
mp
The item number of the message port to which to send the message.
msg
The item number of the message to send.
dataptr
A pointer to the message data, or NULL if there is no data to include in the message. For a
standard message, the pointer specifies a data block owned by the sending task, which can later be
read by the receiving task. For a buffered message, the pointer specifies a block of data to be
copied into the message's internal data buffer.
file:///C|/%23%23DDOC/spr/01spr122.html (1 of 2) [4/16/2002 11:13:06 PM]

SendMsg

datasize
The size of the message data, in bytes, or 0 if there is no data to include in the message.

Return Value
The procedure returns 0 if the message was sent successfully or an error code if an error occurs.

Implementation
SWI implemented in kernel folio V20.

Associated Files
msgport.h
ANSI C Prototype

See Also
GetMsg(), GetThisMsg(), ReplyMsg(), ReplySmallMsg(), SendSmallMsg(),
WaitPort()

file:///C|/%23%23DDOC/spr/01spr122.html (2 of 2) [4/16/2002 11:13:06 PM]

GetMsg

GetMsg
Gets a message from a message port.

Synopsis
Item GetMsg( Item mp )

Description
This procedure gets the first message in the message queue for the specified message port and removes
the message from the queue.

Arguments
mp
The item number of the message port from which to get the message.

Return Value
The procedure returns the item number of the first message in the message queue or an error code (a
negative value) if an error occurs. Possible error codes include the following:
0
The queue is empty.
BADITEM
The mp argument does not specify a message port.
NOTOWNER
The message port specified by the mp argument is not owned by this task.

Implementation
SWI implemented in kernel folio V20.

Associated Files

file:///C|/%23%23DDOC/spr/01spr075.html (1 of 2) [4/16/2002 11:13:06 PM]

GetMsg

msgport.h
ANSI C Prototype

See Also
DeleteMsg(), GetThisMsg(), ReplyMsg(), ReplySmallMsg(), SendMsg(),
SendSmallMsg(), WaitPort()

file:///C|/%23%23DDOC/spr/01spr075.html (2 of 2) [4/16/2002 11:13:06 PM]

GetThisMsg

GetThisMsg
Gets a specific message.

Synopsis
Item GetThisMsg( Item message )

Description
This procedure gets a specific message and removes it from the message queue that contains it, if any.
A task that is receiving messages can use GetThisMsg() to get an incoming message. Unlike
GetMsg(), which gets the first message in a specific message queue, GetThisMsg() can get any
message from any of the task's message queues.
A task that has sent a message can use GetThisMsg() to get it back. If the receiving task hasn't
already taken the message from its message queue, GetThisMsg() removes it from the queue. If the
message is not on any MsgPort a zero is returned.

Arguments
message
The item number of the message to get.

Return Value
The procedure returns the item number of the message or an error code (a negative value) if an error
occurred. Possible error codes include:
BADITEM
The message argument does not specify a message.
BADPRIV
The calling task is not allowed to get this message.

Implementation
SWI implemented in kernel folio V20.
file:///C|/%23%23DDOC/spr/01spr083.html (1 of 2) [4/16/2002 11:13:06 PM]

GetThisMsg

Associated Files
msgport.h
ANSI C Prototype

Caveats
Prior to V21, if the message was not on any message port this procedure still returned the item number of
the message. In V21 and beyond, if the message is not on any port, the procedure returns an error.

See Also
CreateMsg(), GetMsg(), ReplyMsg(), ReplySmallMsg(), SendMsg(),
SendSmallMsg(), WaitPort()

file:///C|/%23%23DDOC/spr/01spr083.html (2 of 2) [4/16/2002 11:13:06 PM]

ReplyMsg

ReplyMsg
Sends a reply to a message.

Synopsis
Err ReplyMsg( Item msg, int32 result, const void *dataptr,int32
datasize )

Description
This procedure sends a reply to a message.
When replying to a message, send back the same message item you received. (Think of this as sending a
reply in the same envelope as the original letter.) Note that you must include a result code (which you
provide in the result argument).
The meanings of the dataptr and datasize arguments depend on the type of the original message. (You
can find out what type of message it is by looking at its msg.n_Flags field. If it is a small message, the
value of the field is MESSAGE_SMALL. If it is a buffered message, the value of the field is
MESSAGE_PASS_BY_VALUE.)
●

●

If the original message was a small message, the dataptr and datasize are put in the corresponding
fields of the message as eight bytes of data.
If the original message was a standard message, these refer to a data block that your task allocates
for returning reply data. For standard messages, the sending task and the replying task must each
allocate their own memory blocks for message data. If the message was also buffered, the data is
copied into the internal buffer of the message.

Arguments
msg
The item number of the message. Note: The reply message item must be same message item that
was received.
result
A result code. This code is placed in the msg_Result field of the message data structure before the
reply is sent. Note: There are no standard result codes currently defined; the code must be a value
whose meaning is agreed upon by the calling and receiving tasks. In general, you should use
negative values to specify errors and 0 to specify that no error occurred.
file:///C|/%23%23DDOC/spr/01spr113.html (1 of 2) [4/16/2002 11:13:07 PM]

ReplyMsg

dataptr
See the "Description" section above for a description of this argument. If the message is not
buffered, set this to 0.
datasize
See the "Description" section above for a description of this argument. If the message is not
buffered, set this to 0.

Return Value
The procedure returns 0 if the reply was sent successfully or an error code if an error occurs.

Implementation
SWI implemented in kernel folio V20.

Associated Files
msgport.h
ANSI C Prototype

Notes
Most programs handle only one type of message per message port. Each type of message moves
information in a different way; programs choose a particular message type to meet their specific needs.

See Also
GetMsg(), GetThisMsg(), ReplySmallMsg(), SendMsg(), SendSmallMsg(),
WaitPort()

file:///C|/%23%23DDOC/spr/01spr113.html (2 of 2) [4/16/2002 11:13:07 PM]

ReplySmallMsg

ReplySmallMsg
Sends a reply to a small message.

Synopsis
Err ReplySmallMsg( Item msg, int32 result, uint32 val1, uint32val2)

Description
This procedure sends a reply to a small message. (To reply to a standard or buffered message, use
ReplyMsg().)
This procedure is identical to ReplyMsg() except that arguments are cast as (uint32) instead of (void
*) and (int32). A small message can return only eight bytes of data: four that you provide in the val1
argument, and four that you provide in the val2 argument.
When replying to a message, send back the same message item you received. (Think of this as sending a
reply in the same envelope as the original letter.) You can include an optional result code (which you
provide in the result argument). Note that no standard result codes are currently defined; the result code
must be a value whose meaning is agreed upon by the sending and receiving tasks. For consistency, use
negative numbers for errors.

Arguments
msg
The item number of the message. Note: The reply message item must be same message item that
was received.
result
A result code. This code is placed in the msg_Result field of the message data structure before the
reply is sent.
val1
The first four bytes of data for the reply. This data is put into the msg_DataPtr field of the
message structure.
val2
The last four bytes of data for the reply. This data is put into the msg_DataSize field of the
message structure.
file:///C|/%23%23DDOC/spr/01spr114.html (1 of 2) [4/16/2002 11:13:07 PM]

ReplySmallMsg

Return Value
The procedure returns 0 if the reply was sent successfully or an error code if there was an error.

Implementation
SWI implemented in kernel folio V20.

Associated Files
msgport.h
ANSI C Prototype

See Also
GetMsg(), GetThisMsg(), ReplyMsg(), SendMsg(), SendSmallMsg(),
WaitPort()

file:///C|/%23%23DDOC/spr/01spr114.html (2 of 2) [4/16/2002 11:13:07 PM]

SendSmallMsg

SendSmallMsg
Sends a small message.

Synopsis
Err SendSmallMsg( Item mp, Item msg, uint32 val1, uint32 val2 )

Description
This procedure sends a small message (a message that contains no more than eight bytes of data) to the
specified message port. (To send a standard or buffered message, use SendMsg().) This routine is
identical to SendMsg(). It is provided only to avoid having to cast uint32 to the types needed by
SendMsg().

Arguments
mp
The item number of the message port to which to send the message
msg
The item number of the message to send.
val1
The first four bytes of message data. This data is put into the msg_DataPtr field of the message
structure.
val2
The last four bytes of message data. This data is put into the msg_DataSize field of the message
structure.

Return Value
The procedure returns 0 if the message is sent successfully or an error code if an error occurs.

Implementation
SWI implemented in kernel folio V20.

file:///C|/%23%23DDOC/spr/01spr124.html (1 of 2) [4/16/2002 11:13:07 PM]

SendSmallMsg

Associated Files
msgport.h
ANSI C Prototype

See Also
GetMsg(), GetThisMsg(), ReplyMsg(), ReplySmallMsg(), SendMsg(),
WaitPort()

file:///C|/%23%23DDOC/spr/01spr124.html (2 of 2) [4/16/2002 11:13:07 PM]

WaitPort

WaitPort
Waits for a message to arrive.

Synopsis
Item WaitPort( Item mp, Item msg )

Description
The procedure puts the calling task into wait state until a message is received at the specified message
port. When a task is in wait state, it uses no CPU time.
The task can wait for a specific message by providing the item number of the message in the message
argument. To wait for any incoming message, the task uses 0 as the value of the message argument.
Note: If the desired message is already in the message queue for the specified message port, the
procedure returns immediately. If the message never arrives, the procedure may never return.
When the message arrives, the task is moved from the wait queue to the ready queue, the item number of
the message is returned as the result, and the message is removed from the message port.

Arguments
mp
The item number of the message port to check for incoming messages.
msg
The item number of the message to wait for. If this argument is 0, control is returned to the task
when any message arrives at the specified message port.

Return Value
The procedure returns the item number of the incoming message or an error code if an error occurs.

Implementation
Folio call implemented in kernel folio V20. Became an SWI in kernel folio V24.

file:///C|/%23%23DDOC/spr/01spr132.html (1 of 2) [4/16/2002 11:13:08 PM]

WaitPort

Associated Files
msgport.h
ANSI C Prototype
clib.lib
ARM Link Library

See Also
GetMsg(), ReplyMsg(), SendMsg()

file:///C|/%23%23DDOC/spr/01spr132.html (2 of 2) [4/16/2002 11:13:08 PM]

CreateBufferedMsg

CreateBufferedMsg
Creates a buffered message.

Synopsis
Item CreateBufferedMsg( const char *name, uint8 pri, Item mp,uint32
datasize )

Description
One of the ways tasks communicate is by sending messages to each other. This procedure creates an item
for a buffered message (a message that includes an internal buffer for sending data to the receiving task).
You can use this procedure in place of CreateItem() to create the message.

Arguments
name
The name of the message (see "Notes").
pri
The priority of the message. This determines the position of the message in the receiving task's
message queue and thus, how soon it is likely to be handled. A larger number specifies a higher
priority.
mp
The item number of the message port at which to receive the reply.
datasize
The maximum size of the message's internal buffer, in bytes.

Return Value
The procedure returns the item number of the message or an error code if an error occurs.

Implementation
Convenience call implemented in clib.lib V20.

file:///C|/%23%23DDOC/spr/01spr020.html (1 of 2) [4/16/2002 11:13:08 PM]

CreateBufferedMsg

Associated Files
msgport.h
ANSI C Prototype
clib.lib
ARM Link Library

Notes
The advantage of using a buffered message instead of a standard message is that the sending task doesn't
need to keep the data block containing the message data after the message is sent. All the necessary data
is included in the message.
The same message item can be resent any number of times. When you are finished with a message item,
use DeleteMsg() to delete it.
You can use FindNamedItem() to find a message item by name. When creating messages, you
should assign unique names whenever possible.

Caveats
The priority value (set with the pri argument) is not used consistently.

See Also
CreateMsg(), CreateMsgPort(), CreateSmallMsg(), DeleteMsg(),
DeleteMsgPort(), SendMsg()

file:///C|/%23%23DDOC/spr/01spr020.html (2 of 2) [4/16/2002 11:13:08 PM]

CreateSmallMsg

CreateSmallMsg
Creates a small message.

Synopsis
Item CreateSmallMsg( const char *name, uint8 pri, Item mp )

Description
This convenience procedure creates the item for a small message (a message that can contain up to eight
bytes of data). You can use this procedure in place of CreateItem() to create the item.
To create a standard message (a message in which any data to be communicated to the receiving task is
contained in a data block allocated by the sending task), use CreateMsg(). To create a buffered
message (a message that includes an internal buffer for sending data to the receiving task), use
CreateBufferedMsg().

Arguments
name
The name of the message (see "Notes").
pri
The priority of the message. This determines the position of the message in the receiving task's
message queue and thus, how soon it is likely to be handled. A larger number specifies a higher
priority.
mp
The item number of the message port for the return message.

Return Value
The procedure returns the item number of the message that was created or an error code if an error
occurs.

Implementation
Convenience call implemented in clib.lib V20.
file:///C|/%23%23DDOC/spr/01spr027.html (1 of 2) [4/16/2002 11:13:09 PM]

CreateSmallMsg

Associated Files
msgport.h
ANSI C Prototype
clib.lib
ARM Link Library

Notes
The same message item can be resent any number of times. When you are finished with a message item,
use DeleteMsg() to delete it.
You can use FindNamedItem() to find a message by name. When naming messages, you should
assign unique names whenever possible.

See Also
CreateMsg(), CreateMsgPort(), CreateBufferedMsg(), DeleteMsg(),
DeleteMsgPort(), SendMsg()

file:///C|/%23%23DDOC/spr/01spr027.html (2 of 2) [4/16/2002 11:13:09 PM]

CreateSemaphore

CreateSemaphore
Creates a semaphore.

Synopsis
Item CreateSemaphore( const char *name, uint8 pri )

Description
This convenience procedure creates a semaphore item with the specified name and priority. You can use
this procedure in place of CreateItem() to create the semaphore.
For information about semaphores, which are used to control access to shared resources, see the Sharing
System Resources chapter in the 3DO Portfolio Programmer's Guide.

Arguments
name
The name of the semaphore (see "Notes").
pri
The priority of the semaphore; use 0 for now.

Return Value
The procedure returns the item number of the semaphore or an error code if an error occurs.

Implementation
Convenience call implemented in clib.lib V20.

Associated Files
semaphore.h
ANSI C Prototype
clib.lib
file:///C|/%23%23DDOC/spr/01spr026.html (1 of 2) [4/16/2002 11:13:09 PM]

CreateSemaphore

ARM Link Library

Notes
When you no longer need a semaphore, use DeleteSemaphore() to delete it.
You can use FindSemaphore() to find a semaphore by name. When creating semaphores, you should
assign unique names whenever possible.

See Also
DeleteSemaphore(), LockSemaphore(), UnlockSemaphore()

file:///C|/%23%23DDOC/spr/01spr026.html (2 of 2) [4/16/2002 11:13:09 PM]

DeleteSemaphore

DeleteSemaphore
Deletes a semaphore.

Synopsis
Err DeleteSemaphore( Item s )

Description
This macro deletes a semaphore.
For information about semaphores, which are used to control access to shared resources, see the Sharing
System Resources chapter in the 3DO Portfolio Programmer's Guide.

Arguments
s
The item number of the semaphore to be deleted.

Return Value
The macro returns a value greater than or equal to 0 if successful or an error code if an error occurred.

Implementation
Macro implemented in semaphore.h V20.

Associated Files
semaphore.h
ANSI C Macro

Notes
As with all items, the item number of a deleted semaphore is not reused. If a task specifies the item
number of a deleted semaphore, the kernel informs the task that the item no longer exists.

file:///C|/%23%23DDOC/spr/01spr036.html (1 of 2) [4/16/2002 11:13:09 PM]

DeleteSemaphore

See Also
CreateSemaphore()

file:///C|/%23%23DDOC/spr/01spr036.html (2 of 2) [4/16/2002 11:13:09 PM]

LockSemaphore

LockSemaphore
Locks a semaphore.

Synopsis
int32 LockSemaphore( Item s, uint32 flags )

Description
This procedure locks a semaphore. For information about semaphores, which are used to control access
to shared resources, see the "Sharing System Resources" chapter in the 3DO System Programmer's
Guide.

Arguments
s
The number of the semaphore to be locked.
flags
Semaphore flags.
Only one flag is currently defined:
SEM_WAIT
If the item to be locked is already locked, put the calling task into wait state until the item is
available.

Return Value
The procedure returns 1 if the semaphore was successfully locked. If the semaphore is already locked
and the SEM_WAIT flag is not set (which indicates that the calling task does not want to wait until the
semaphore is available), the procedure returns 0. If an error occurs, the procedure returns an error code.

Implementation
SWI implemented in kernel folio V20.
This is the same SWI as LockItem().
file:///C|/%23%23DDOC/spr/01spr098.html (1 of 2) [4/16/2002 11:13:10 PM]

LockSemaphore

Associated Files
semaphore.h
ANSI C Prototype

Caveats
There are currently no asynchronous locks or shared read locks.

See Also
FindSemaphore(), UnlockSemaphore()

file:///C|/%23%23DDOC/spr/01spr098.html (2 of 2) [4/16/2002 11:13:10 PM]

FindSemaphore

FindSemaphore
Finds a semaphore by name.

Synopsis
Item FindSemaphore( const char *name )

Description
This macro finds a semaphore with the specified name. The search is not case-sensitive (that is, the
kernel does not distinguish uppercase and lowercase letters in semaphore names). You can use this macro
in place of FindNamedItem() to find a semaphore.
For information about semaphores, which are used to control access to shared resources, see the "Sharing
System Resources" chapter in the 3DO Portfolio Programmer's Guide.

Arguments
name
The name of the semaphore to find.

Return Value
The macro returns the item number of the semaphore that was found or an error code if an error occurs.

Implementation
Macro implemented in semaphore.h V20.

Associated Files
semaphore.h
ANSI C Macro

See Also
CreateSemaphore()
file:///C|/%23%23DDOC/spr/01spr058.html (1 of 2) [4/16/2002 11:13:10 PM]

FindSemaphore

file:///C|/%23%23DDOC/spr/01spr058.html (2 of 2) [4/16/2002 11:13:10 PM]

UnlockSemaphore

UnlockSemaphore
Unlocks a semaphore.

Synopsis
Err UnlockSemaphore( Item s )

Description
This is an alternate entry point for UnlockItem(). This procedure unlocks the specified semaphore.
For information about semaphores, which are used to control access to shared resources, see the "Sharing
System Resource's" chapter in the 3DO Portfolio Programmer's Guide.

Arguments
s
The item number of the semaphore to unlock.

Return Value
The procedure returns 0 if successful or an error code (a negative value) if an error occurs. Possible error
codes include:
NOTOWNER
The semaphore specified by the s argument is not owned by the task.

Implementation
SWI implemented in kernel folio V20.
This is the same SWI as UnlockItem().

Associated Files
semaphore.h
ANSI C Prototype

file:///C|/%23%23DDOC/spr/01spr130.html (1 of 2) [4/16/2002 11:13:10 PM]

UnlockSemaphore

See Also
LockSemaphore(), LockItem(), UnlockItem()

file:///C|/%23%23DDOC/spr/01spr130.html (2 of 2) [4/16/2002 11:13:10 PM]

LockItem

LockItem
Locks an item.

Synopsis
int32 LockItem( Item s, uint32 flags )

Description
This procedure locks an item.
Note: Currently, semaphores are the only items that can be locked. You can lock semaphores by calling
LockSemaphore().

Arguments
s
The number of the item to be locked.
flags
Semaphore flags.
Only one flag is currently defined:
SEM_WAIT
If the item to be locked is already locked, put the calling task into wait state until the item is
available.

Return Value
The procedure returns 1 if the item was successfully locked. If the item is already locked and the
SEM_WAIT flag is not set (which indicates that the calling task does not want to wait until the item is
available), the procedure returns 0. If an error occurs, the procedure returns an error code.

Implementation
SWI implemented in kernel folio V20.

file:///C|/%23%23DDOC/spr/01spr097.html (1 of 2) [4/16/2002 11:13:10 PM]

LockItem

This is the same SWI as LockSemaphore()

Associated Files
item.h
ANSI C Prototype

See Also
DeleteItem(), UnlockItem()

file:///C|/%23%23DDOC/spr/01spr097.html (2 of 2) [4/16/2002 11:13:10 PM]

DeleteItem

DeleteItem
Deletes an item.

Synopsis
Err DeleteItem( Item i )

Description
This procedure deletes the specified item and frees any resources (including memory) that were allocated
for the item.
Note: There are convenience procedures for deleting most types of items (such as DeleteMsg() to
delete a message and DeleteIOReq() to delete an I/O request). You should use DeleteItem()
only if you used CreateItem() to create the item. If you used a convenience routine to create an item,
you must use the corresponding convenience routine to delete the item.

Arguments
i
Number of the item to be deleted.

Return Value
The procedure returns a value greater than of equal to 0 if successful or an error code if an error occurs.

Implementation
SWI implemented in kernel folio V20.

Associated Files
item.h
ANSI C Prototype

Notes

file:///C|/%23%23DDOC/spr/01spr032.html (1 of 2) [4/16/2002 11:13:11 PM]

DeleteItem

The item number of a deleted item is not reused. If a task specifies the item number of a deleted item, the
kernel informs the task that the item no longer exists.
Tasks can only delete items that they own. If a task transfers ownership of an item to another task, it can
no longer delete the item. The lone exception to this is the task itself. You can always commit sepaku.
When a task dies, the kernel automatically deletes all of the items in its resource table.

See Also
CheckItem(), CreateItem(), DeleteIOReq(), DeleteMsg(),
DeleteMsgPort(), DeleteThread(), exit()

file:///C|/%23%23DDOC/spr/01spr032.html (2 of 2) [4/16/2002 11:13:11 PM]

DeleteThread

DeleteThread
Deletes a thread.

Synopsis
Err DeleteThread( Item x )

Description
This procedure deletes a thread.

Arguments
x
The item number of the thread to be deleted.

Return Value
The procedure returns a value greater than or equal to 0 if the thread was successfully deleted or an error
code if an error occurs.

Implementation
Convenience call implemented in clib.lib V20.

Associated Files
task.h
ANSI C Prototype
clib.lib
ARM Link Library

Notes
Although threads may be deleted as soon as the parent task has finished using it by calling
DeleteThread(), threads are automatically deleted when they return, call exit(), or when their
file:///C|/%23%23DDOC/spr/01spr037.html (1 of 2) [4/16/2002 11:13:11 PM]

DeleteThread

parent task is deleted or dies.
Threads share memory with their parent tasks. This means that:
●
●

Memory that was allocated by a thread also belongs to the parent task.
Memory that was allocated by a thread is not automatically deallocated when the thread is deleted
but instead remains the property of the parent task.

If you create a thread using CreateThread(), you must delete it using DeleteThread(), which
does special cleanup work.

See Also
CreateThread(), exit()

file:///C|/%23%23DDOC/spr/01spr037.html (2 of 2) [4/16/2002 11:13:11 PM]

CreateThread

CreateThread
Creates a thread.

Synopsis
Item CreateThread( const char *name, uint8 pri, void (*code) (),int32
stacksize )

Description
This procedure creates a thread. The resulting thread belongs to the calling task.

Arguments
name
The name of the thread to be created (see "Notes").
pri
The priority of the thread. This can be a value from 11 to 199 (0 to 10 and 200 to 255 can only be
assigned by system software). A larger number specifies a higher priority. For all tasks, including
threads, the highest priority task - if there is only one task with that priority - is always the task
that is executed. If more than one task in the ready queue has the highest priority, the kernel
divides the available CPU time among the tasks by providing each task with a time quantum.
code
A pointer to the code that the thread executes.
stacksize
The size of the thread's stack, in bytes (see "Notes").

Return Value
The procedure returns the item number of the thread or an error code if an error occurs.

Implementation
Convenience call implemented in clib.lib V20.

file:///C|/%23%23DDOC/spr/01spr028.html (1 of 2) [4/16/2002 11:13:12 PM]

CreateThread

Associated Files
task.h
ANSI C Prototype
clib.lib
ARM Link Library

Notes
There is no default size for a thread's stack. To avoid stack overflow errors, the stack must be large
enough to handle any possible uses. One way to find the proper stack size for a thread is to start with a
very large stack, reduce its size until a stack overflow occurs, and then double its size.
When you no longer need a thread, use DeleteThread() to delete it. Alternatively, the thread can
return or call exit().
You can use FindTask() to find a thread by name. When naming threads, you should assign unique
names whenever possible.

See Also
DeleteThread(), exit()

file:///C|/%23%23DDOC/spr/01spr028.html (2 of 2) [4/16/2002 11:13:12 PM]

exit

exit
Exits from a task or thread.

Synopsis
void exit( int status )

Description
This procedure deletes the calling task or thread. If the CREATETASK_TAG_MSGFROMCHILD tag
was set when creating the calling task, then the status is sent to the parent process through a message.

Arguments
status
The status to be returned to the parent of the calling task or thread. Negative status is reserved for
system use.

Return Value
This procedure never returns.

Implementation
Folio call implemented in kernel folio V20.

Associated Files
stdlib.h
ANSI C Prototype

Notes
When tasks (including threads) have finished their work, they should call exit() to die gracefully. The
system will call exit() on behalf of the task that returns from the top-level routine. exit() does
necessary clean-up work when a task is finished, including the cleanup required for a thread created by
the CreateThread() library routine.
file:///C|/%23%23DDOC/spr/01spr042.html (1 of 2) [4/16/2002 11:13:12 PM]

exit

See Also
CreateThread(), DeleteItem(), DeleteThread()

file:///C|/%23%23DDOC/spr/01spr042.html (2 of 2) [4/16/2002 11:13:12 PM]

UnlockItem

UnlockItem
Unlocks a locked item.

Synopsis
Err UnlockItem( Item s )

Description
This procedure unlocks the specified item.
Note: Currently, semaphores are the only items that can be locked. You can also unlock semaphores by
calling UnlockSemaphore().

Arguments
s
The item number of the item to be unlocked.

Return Value
The procedure returns 0 if successful or an error code (a negative value) if an error occurs. Possible error
codes include:
NOTOWNER
The item specified by the s argument is not owned by the task.

Implementation
SWI implemented in kernel folio V20.
This is the same SWI as UnlockSemaphore().

Associated Files
item.h
ANSI C Prototype
file:///C|/%23%23DDOC/spr/01spr129.html (1 of 2) [4/16/2002 11:13:12 PM]

UnlockItem

See Also
DeleteItem(), LockItem(), UnlockSemaphore()

file:///C|/%23%23DDOC/spr/01spr129.html (2 of 2) [4/16/2002 11:13:12 PM]

FindItem

FindItem
Finds an item by type and tags.

Synopsis
Item FindItem( int32 cType, TagArg *tp )
Item FindItemVA( int32 cType, uint32 tags, ...)

Description
This procedure finds an item of the specified type whose tag arguments match those pointed to by the tp
argument. If more than one item of the specified type has matching tag arguments, the procedure returns
the item number for the first matching item.

Arguments
cType
Specifies the type of the item to find. Use MkNodeID() to create this value.
tp
A pointer to an array of tag arguments. The tag arguments can be in any order. The array can
contain some, all, or none of the possible tag arguments for an item of the specified type; to make
the search more specific, include more tag arguments. The last element of the array must be the
value TAG_END. If there are no tag arguments, this argument must be NULL. For a list of tag
arguments for each item type, see the Portfolio Item's chapter.

Return Value
The procedure returns the number of the first item that matches or an error code if it can't find the item or
if an error occurs.

Implementation
SWI implemented in kernel folio V20.

Associated Files

file:///C|/%23%23DDOC/spr/01spr050.html (1 of 2) [4/16/2002 11:13:13 PM]

FindItem

item.h
ANSI C Prototype

Caveats
The procedure currently ignores most tag arguments.

See Also
CheckItem(), FindNamedItem(), FindVersionedItem(), LookupItem(),
MkNodeID()

file:///C|/%23%23DDOC/spr/01spr050.html (2 of 2) [4/16/2002 11:13:13 PM]

FindNamedItem

FindNamedItem
Finds an item by name.

Synopsis
Item FindNamedItem( int32 ctype, const char *name )

Description
This procedure finds an item of the specified type whose name matches the name argument. The search
is not case-sensitive (that is, the kernel does not distinguish uppercase and lowercase letters in item
names).

Arguments
ctype
The type of the item to find. Use MkNodeID() to create this value.
name
The name of the item to find.

Return Value
The procedure returns the number of the item that was found. It returns an error code if an error occurs.

Implementation
Convenience call implemented in clib.lib V20.

Associated Files
item.h
ANSI C Prototype
clib.lib
ARM Link Library

file:///C|/%23%23DDOC/spr/01spr054.html (1 of 2) [4/16/2002 11:13:13 PM]

FindNamedItem

See Also
FindItem(), FindVersionedItem()

file:///C|/%23%23DDOC/spr/01spr054.html (2 of 2) [4/16/2002 11:13:13 PM]

FindVersionedItem

FindVersionedItem
Finds an item by name and version.

Synopsis
Item FindVersionedItem( int32 ctype, const char *name, uint8 vers,
uint8 rev )

Description
This procedure finds an item of a specified type by its name, version number, and revision number.
These values are required tag arguments for all items. If all three values match, the procedure returns the
item number of the matching item.

Arguments
ctype
The type of the item to find. Use MkNodeID() to create this value.
name
The name of the item to find.
vers
The version number of the item to find.
rev
The revision number of the item to find.

Return Value
The procedure returns the number of the item that matches or an error code if an error occurs.

Implementation
Convenience call implemented in clib.lib V20.

Associated Files
file:///C|/%23%23DDOC/spr/01spr061.html (1 of 2) [4/16/2002 11:13:13 PM]

FindVersionedItem

item.h
ANSI C Prototype
clib.lib
ARM Link Library

Caveats
This currently returns a match if the version number and revision number are greater than or equal to the
values specified.

See Also
CheckItem(), FindItem(), FindNamedItem(), LookupItem()

file:///C|/%23%23DDOC/spr/01spr061.html (2 of 2) [4/16/2002 11:13:13 PM]

LookupItem

LookupItem
Gets a pointer to an item.

Synopsis
void *LookupItem( Item i )

Description
This procedure finds an item by its item number and returns the pointer to the item.
Note: Because items are owned by the system, user tasks cannot change the values of their fields. They
can, however, read the values contained in the public fields.

Arguments
i
The number of the item to look up.

Return Value
The procedure returns the pointer to the item or NULL if the item does not exist.

Implementation
Folio call implemented in kernel folio V20.

Associated Files
item.h
ANSI C Prototype
clib.lib
ARM Link Library

See Also

file:///C|/%23%23DDOC/spr/01spr099.html (1 of 2) [4/16/2002 11:13:14 PM]

LookupItem

CheckItem(), CreateItem(), FindItem(), FindNamedItem(),
FindVersionedItem()

file:///C|/%23%23DDOC/spr/01spr099.html (2 of 2) [4/16/2002 11:13:14 PM]

MkNodeID

MkNodeID
Creates an item type value

Synopsis
int32 MkNodeID( uint8 a , uint8 b )

Description
This macro creates an item type value, a 32-bit value that specifies an item type and the folio in which
the item type is defined. This value is required by other procedures that deal with items, such as
CreateItem() and FindItem().

Arguments
a
The item number of the folio in which the item type of the item is defined. For a list of folio item
numbers, see the "Portfolio Items" chapter.
b
The item type number for the item. For a list of item type numbers, see the "Portfolio Items"
chapter.

Return Value
The macro returns an item type value or an error code (a negative value) if an error occurs.

Implementation
Macro implemented in nodes.h V20.

Associated Files
nodes.h
ANSI C Macro definition

See Also
file:///C|/%23%23DDOC/spr/01spr101.html (1 of 2) [4/16/2002 11:13:14 PM]

MkNodeID

CreateItem(), FindItem(), FindNamedItem(), FindVersionedItem()

file:///C|/%23%23DDOC/spr/01spr101.html (2 of 2) [4/16/2002 11:13:14 PM]

ClearCurrentSignal

ClearCurrentSignals
Clears some received signal bits.

Synopsis
Err ClearCurrentSignals( int32 sigMask )

Description
This macro resets the requested signal bits of the current task to 0.

Arguments
sigMask
A 32-bit word indicating which signal bits should be cleared.

Return Value
Returns > = 0 for success or a negative error code for failure.

Implementation
Macro implemented in kernel.h V24.

Associated Files
kernel.h
ANSI C Macro definition

See Also
AllocSignal(), FreeSignal(), SendSignal(), WaitSignal()

file:///C|/%23%23DDOC/spr/01spr015.html [4/16/2002 11:13:14 PM]

CloseItem

CloseItem
Closes a system item.

Synopsis
Err CloseItem( Item i )

Description
System items are items that are created automatically by the operating system, such as folios and device
drivers, and thus do not need to be created by tasks. To use a system item, a task first opens it by calling
OpenItem(). When a task is done using a system item, it calls CloseItem() to inform the operating
system that it is no longer using the item.

Arguments
i
Number of the item to close.

Return Value
The procedure returns 0 if the item was closed successfully or an error code (a negative value) if an error
occurs. Possible error codes include:
BADITEM
The i argument is not an item.
ER_Kr_ItemNotOpen
The i argument is not an opened item.

Implementation
SWI implemented in kernel folio V20.

Associated Files
item.h
file:///C|/%23%23DDOC/spr/01spr016.html (1 of 2) [4/16/2002 11:13:15 PM]

CloseItem

ANSI C Prototype

See Also
OpenItem()

file:///C|/%23%23DDOC/spr/01spr016.html (2 of 2) [4/16/2002 11:13:15 PM]

OpenItem

OpenItem
Opens an item.

Synopsis
Item OpenItem( Item FoundItem, void *args )

Description
This procedure opens an item for access.

Arguments
item
The number of the item to open. To find the item number of a system item, use FindItem(),
FindDevice(), FindFolio(), or FindNamedItem().
args
A pointer to an array of tag arguments. Currently, there are no system items that require tag
arguments; for these and for any future items you're not sending tag arguments to, this argument
must be NULL. If you send tag arguments (for any items in the future that use them), the tag
arguments can be in any order, and the last element of the array must be the value TAG_END.
For a list of tag arguments for each item type, see the "Portfolio Items" chapter.

Return Value
The procedure returns the number of the item that was opened or an error code if an error occurs.
Note: The item number for the opened item is not always the same as the item number returned by
FindItem(). When accessing the opened item you should use the return from OpenItem(), not the
return from FindItem(). You can also call the FindAndOpenItem() function for to do both a
search and an open operation in an atomic manner.

Implementation
SWI implemented in kernel folio V20.

file:///C|/%23%23DDOC/spr/01spr104.html (1 of 2) [4/16/2002 11:13:15 PM]

OpenItem

Associated Files
item.h
ANSI C Prototype

Notes
To close an opened item, use CloseItem().

See Also
CloseItem(), FindItem()

file:///C|/%23%23DDOC/spr/01spr104.html (2 of 2) [4/16/2002 11:13:15 PM]

CloseNamedDevice

CloseNamedDevice
Closes a device previously opened with OpenNamedDevice().

Synopsis
Err CloseNamedDevice(Item devItem);

Description
This macro closes a device that was previously opened via a call to OpenNamedDevice().

Arguments
devItem
The device's item, as returned by OpenNamedDevice().

Return Value
The procedure returns 0 if the item was closed successfully or an error code (a negative value) if an error
occurs. Possible error codes include:
BADITEM
The devItem argument is not an item.
ER_Kr_ItemNotOpen
The devItem argument is not an opened item.

Implementation
Macro implemented in device.h V22.

Associated Files
device.h
ANSI C Macro

See Also
file:///C|/%23%23DDOC/spr/01spr017.html (1 of 2) [4/16/2002 11:13:15 PM]

CloseNamedDevice

OpenItem(), CloseItem(), FindItem()

file:///C|/%23%23DDOC/spr/01spr017.html (2 of 2) [4/16/2002 11:13:15 PM]

CountBits

CountBits
Counts the number of bits set in a word.

Synopsis
int CountBits(uint32 mask);

Description
CountBits examines the longword passed in as a parameter and returns the number of bits that are turned
on in the word, using an algorithm derived from a note in MIT's HAKMEM.

Arguments
mask
The data word to count the bits of.

Return Value
The number of bits that were turned on in the supplied value.

Implementation
Convenience call implemented in clib.lib V21.

Associated Files
string.h
ANSI C Prototype
clib.lib
ARM Link library

See Also
FindMSB(), FindLSB()

file:///C|/%23%23DDOC/spr/01spr019.html (1 of 2) [4/16/2002 11:13:15 PM]

CountBits

file:///C|/%23%23DDOC/spr/01spr019.html (2 of 2) [4/16/2002 11:13:15 PM]

FindMSB

FindMSB
Finds the highest-numbered bit.

Synopsis
int FindMSB( uint32 bits )

Description
This procedure finds the highest-numbered bit that is set in the argument. The least-significant bit is bit
number 1, and the most-significant bit is bit 32.

Arguments
bits
The 32-bit word to check.

Return Value
The procedure returns the number of the highest-numbered bit that is set in the argument. If no bits are
set, the procedure returns 0.

Implementation
Convenience call implemented in clib.lib V20.

Associated Files
clib.lib
ARM Link Library

See Also
FindLSB(), ffs()

file:///C|/%23%23DDOC/spr/01spr052.html [4/16/2002 11:13:16 PM]

FindLSB

FindLSB
Finds the least-significant bit.

Synopsis
int FindLSB( uint32 mask )

Description
FindLSB() finds the lowest-numbered bit that is set in the argument. The least-significant bit is bit
number 1, and the most-significant bit is bit 32.

Arguments
flags
The 32-bit word to check.

Return Value
FindLSB() returns the number of the lowest-numbered bit that is set in the argument (for example, 1 if
the value of the argument is 1 or 3 or 7, 3 if the value of the argument is 4 or 12). If no bits are set, the
procedure returns 0.

Implementation
Convenience call implemented in clib.lib V20.

Associated Files
clib.lib
ARM Link Library

See Also
FindMSB(), ffs()

file:///C|/%23%23DDOC/spr/01spr051.html [4/16/2002 11:13:16 PM]

ffs

ffs
Finds the first set bit.

Synopsis
int ffs( uint32 mask )

Description
ffs finds the lowest-numbered bit that is set in the argument. The least-significant bit is bit number 1, and
the most-significant bit is bit 32.

Arguments
flags
The 32-bit word to check

Return Value
ffs returns zero if no bits are set in the parameter, or the bit index of the first bit is set in the parameter.
For example, ffs returns 1 if the value of the argument is 1 or 3 or 7; and 3 if the value of the argument is
4 or 12. If no bits are set, ffs returns 0.

Implementation
Convenience call implemented in clib.lib V20.

Associated Files
clib.lib
ARM Link Library

Notes
This entry point is provided for portability and compatibility only; code written specifically for Portfolio
should use FindLSB() or FindMSB() to reduce any ambiguity over whether the least-significant or mostsignificant bit is desired.
file:///C|/%23%23DDOC/spr/01spr043.html (1 of 2) [4/16/2002 11:13:16 PM]

ffs

See Also
FindMSB(), FindLSB()

file:///C|/%23%23DDOC/spr/01spr043.html (2 of 2) [4/16/2002 11:13:16 PM]

CreateMemDebug

CreateMemDebug
Initializes memory debugging package.

Synopsis
Err CreateMemDebug(uint32 controlFlags, const TagArg *args);

Description
This function creates the needed data structures and initializes them as needed for memory debugging.
This function actually only does anything if MEMDEBUG is defined, otherwise it is a NOP.
Memory debugging provides a general-purpose mechanism to track and validate all memory allocations
done by an application. Using memory debugging, you can easily determine where memory leaks occur
within a title, and find illegal uses of the memory subsystem.
To enable memory debugging in a title, do the following:
●

●

●

●

Add a call to CreateMemDebug() as the first instruction in the main() routine of your
program.
Add calls to DumpMemDebug() and DeleteMemDebug() as the last instructions in the
main() routine of your program.
Recompile your entire project with MEMDEBUG defined on the compiler's command-line (for
the ARM compiler, this is done by adding _DMEMDEBUG).
Link your code with memdebug.lib

With these steps taken, all memory allocations done by your program will be tracked, and specially
managed. On exiting your program, any memory left allocated will be displayed to the console, along
with the line number and source file where the memory was allocated from.
In addition, the memory debugging code makes sure that illegal or dangerous uses of memory are
detected and flagged. Most messages generated by the debugging code indicate the offending source file
and line within your source code where the problem originated.
When all options are turned on, the debugging code will check and report the following problems:
●
●
●

memory allocations with a size of 0
memory free with a bogus memory pointer
memory free with a size not matching the size used when the memory was allocated

file:///C|/%23%23DDOC/spr/01spr023.html (1 of 4) [4/16/2002 11:13:17 PM]

CreateMemDebug
●
●

NULL memory list passed to AllocMemFromMemLists() or FreeMemToMemLists()
cookies on either side of all memory allocations are checked to make sure they are not altered
from the time a memory allocation is made to the time the memory is released. This would
indicate that something is writing beyond the bounds of allocated memory.

When MEMDEBUG is defined during compilation, all standard memory allocation calls are
automatically vectored through the debugging code. This includes even memory allocation calls made
inside of previously compiled.lib files you might be linking with. However, you can get better debugging
information if you recompile everything in your project, including .lib files, with MEMDEBUG defined.
By calling the DumpMemDebug() function at any time within your program, you can get a detailed
listing of all memory currently allocated, showing from which source line and source file the allocation
occurred.
Link order can be important when using memdebug.lib. The library should come before clib.lib, but after
everything else. That is, the link order should be:
[many .lib files] memdebug.lib clib.lib

Arguments
controlFlags
A set of bit flags controlling various options of the memory debugging code.
MEMDEBUGF_ALLOC_PATTERNS
When this flag is specified, it instructs the debugging code to fill newly allocated memory with
the constant MEMDEBUG_ALLOC_PATTERN. Doing so will likely cause your program to fail
in some way if it tries to read newly allocated memory without first initializing it. Note that this
option has no effect if memory is allocated using the MEMTYPE_FILL memory flag.
MEMDEBUGF_FREE_PATTERNS
When this flag is specified, it instructs the debugging code to fill memory that is being freed with
the constant MEMDEBUG_FREE_PATTERN. Doing so will likely cause your program to fail in
some way if it tries to read memory that has been freed.
MEMDEBUG_PAD_COOKIES
When this flag is specified, it causes the debugging code to put special memory cookies in the
bytes before and 16 bytes after every block of memory it allocates. When a memory block is
freed, the cookies are checked to make sure that they have not been altered. This option makes
sure that your program is not writing outside the bounds of memory it allocates.
MEMDEBUG_DEBUG_ON_ERRORS
file:///C|/%23%23DDOC/spr/01spr023.html (2 of 4) [4/16/2002 11:13:17 PM]

CreateMemDebug

When this flag is specified, the debugging code will automatically invoke the debugger if any
error is detected. Errors includes such things as mangled pad cookies, incorrect size for a
FreeMem() call, etc. Normally, the debugging code simply prints out the error to the console and
keeps executing.
MEMDEBUG_ALLOW_OWNER_SWITCH
This flag tells the memory debugging code that it is OK for memory to be allocated by one thread
and freed by a different thread. Normally, this condition would be flagged as an error.
MEMDEBUGF_CHECK_ALLOC_FAILURES
When this flag is specified, the debugging code will emit a message whenever a memory
allocation call fails due to lack of memory. This can be useful to track down where in a title
memory is running out.
MEMDEBUGF_KEEP_TASK_DATA
The debugging code maintains some thread-specific statistics about memory allocations
performed by that thread. This information gets displayed by DumpMemDebug(). Whenever all
of the memory allocated by a thread is freed, the data structure holding the statistics for that
thread automatically gets freed by the debugging code. This is undesirable if you wish to dump
out statistics of the code just before a title exits. Specifying this flag causes the data structure not
to be freed, making the statistical information available to DumpMemDebug().
MEMDEBUGF_USE_VRAM
The debugging code needs to allocate private memory to track information about every memory
allocation call made. This flag tells the debugging code to allocate this private memory using
MEMTYPE_VRAM instead of MEMTYPE_ANY. This is useful if you need as much DRAM as
possible, and do not want the debugging code to take any away from you.
args
A pointer to an array of tag arguments containing extra data for this function. This must currently
always be NULL.

Return Value
Returns > = 0 if successful or a negative error code. Current possible error codes are:
MEMDEBUG_ERR_BADTAG
An undefined tag was supplied. Currently the arg's parameter to this function should always be
NULL.
MEMDEBUG_ERR_BAD

file:///C|/%23%23DDOC/spr/01spr023.html (3 of 4) [4/16/2002 11:13:17 PM]

CreateMemDebug

FLAGS
An undefined flag bit was set in the control Flags parameter to this function.

Implementation
Library call implemented in memdebug.lib V24.

Associated Files
mem.h, memdebug.lib

Notes
You should make sure to turn off memory debugging prior to creating the final version of your program.
Enabling memory debugging incurs an overhead of currently 32 bytes per allocation made. If you use the
MEMDEBUGF_PAD_COOKIES option, this overhead grows to 64 bytes per allocation.
In addition, specifying the MEMDEBUGF_ALLOC_PATTERNS and
MEMDEBUGF_FREE_PATTERNS options will slow down memory allocations and free operations,
due to the extra work of filling the memory with the patterns.
When reporting errors to the console, the memory debugging subsystem will normally print the source
file and line number where the error occurred. When using link libraries which have not been recompiled
with MEMDEBUG defined, the memory debugging subsystem will still be able to track the allocations,
but will not report the source file or line number where the error occurred. It will report < unknown
source file > instead.

Caveat
If you link your program with memdebug.lib, you must call CreateMemDebug() at the beginning of
your program. Any attempt to allocate memory prior to calling CreateMemDebug() will fail.

See Also
DeleteMemDebug(), DumpMemDebug(), SanityCheckMemDebug()

file:///C|/%23%23DDOC/spr/01spr023.html (4 of 4) [4/16/2002 11:13:17 PM]

DeleteMemDebug

DeleteMemDebug
Releases memory debugging resources.

Synopsis
Err DeleteMemDebug(void);

Description
Deletes any resources allocated by CreateMemDebug(). This function only actually does anything if
MEMDEBUG is defined, otherwise it is a NOP.
This function also frees any memory allocated that has not been freed yet.

Return Value
Returns > = 0 if successful, or a negative error code if not.

Implementation
Library call implemented in memdebug.lib V24.

Associated Files
mem.h, memdebug.lib

See Also
CreateMemDebug(), DumpMemDebug(), SanityCheckMemDebug()

file:///C|/%23%23DDOC/spr/01spr033.html [4/16/2002 11:13:17 PM]

DumpMemDebug

DumpMemDebug
Dumps memory allocation debugging information.

Synopsis
Err DumpMemDebug(const TagArg *args);

Description
This function outputs a table showing all memory currently allocated through the memory debugging
code. This table shows the allocation size, address, as well as the source file and the source line where
the allocation took place.
This function also outputs statistics about general memory allocation patterns. This includes the number
of memory allocation calls that have been performed, the maximum number of bytes allocated at any one
time, current amount of allocated memory, etc. All this information is displayed on a per-thread basis, as
well as globally for all threads.
To use this function, the memory debugging code must have been previously initialized using the
CreateMemDebug() function.

Arguments
args
A pointer to an array of tag arguments containing extra data for this function. This must currently
always be NULL.

Return Value
Returns > = 0 if successful, or a negative error code if not. Current Possible error code is:
MEMDEBUG_ERR_BADTAG
An undefined tag was supplied. Currently the arg's parameter to this function should always be
NULL.

Implementation
Library routine implemented in memdebug.lib V24.
file:///C|/%23%23DDOC/spr/01spr039.html (1 of 2) [4/16/2002 11:13:18 PM]

DumpMemDebug

Associated Files
mem.h, memdebug.lib

See Also
CreateMemDebug(), DeleteMemDebug(), SanityCheckMemDebug()

file:///C|/%23%23DDOC/spr/01spr039.html (2 of 2) [4/16/2002 11:13:18 PM]

SanityCheckMemDebug

SanityCheckMemDebug
Checks all current memory allocations to make sure all of the allocation cookies are intact

Synopsis
Err SanityCheckMemDebug(const TagArg *args);

Description
This function checks all current memory allocations to see if any of the memory cookies have been
corrupted. This is useful when trying to track down at which point in a program's execution memory
cookies are being trashed.
The routine will also complain about any memory allocated by a task or thread that doesn't exist
anymore. This only happens if the MEMDEBUGF_ALLOW_OWNER_SWITCH flag was not specified
when calling CreateMemDebug().

Arguments
args
A pointer to an array of tag arguments containing extra data for this function. This must currently
always be NULL.

Return Value
Returns > = 0 if successful or a negative error code if not. Current possible error code is.
MEMDEBUG_ERR_BADTAG
An undefined tag was supplied. Currently the args parameter to this function should always be
NULL.

Implementation
Library routine implemented in memdebug.lib V24.

Associated Files

file:///C|/%23%23DDOC/spr/01spr117.html (1 of 2) [4/16/2002 11:13:18 PM]

SanityCheckMemDebug

mem.h, memdebug.lib

See Also
CreateMemDebug(), DeleteMemDebug(), DumpMemDebug()

file:///C|/%23%23DDOC/spr/01spr117.html (2 of 2) [4/16/2002 11:13:18 PM]

CreateUniqueMsgPort

CreateUniqueMsgPort
Creates a message port with a unique name.

Synopsis
Item CreateUniqueMsgPort( const char *name, uint8 pri, uint32 signal )

Description
This convenience procedure creates a message port item. It also creates a message queue for the port in
system RAM. You can use this procedure in place of CreateItem() to create the item.
This function works much like CreateMsgPort(), except that it guarantees that no other message
port item of the same name already exists. And once this port created, no other port of the same name
will be allowed to be created.

Arguments
name
The name of the message port (see "Notes").
pri
The priority of the message port. The priority has no effect on the way message ports operate, but
it does determine the order of the message ports in the global list of message ports and thus, the
order in which message ports are found.
signal
Specifies the bit in the signal word that is set when a message arrives at this port. If zero is
supplied a new signal will be allocated. (See the description of AllocSignal() for information
about allocating signal bits.)

Return Value
The procedure returns the item number of the new message port or an error code if an error occurs. If a
port of the same name already existed when this call was made, the ER_Kr_UniqueItemExists error will
be returned.

Implementation
file:///C|/%23%23DDOC/spr/01spr029.html (1 of 2) [4/16/2002 11:13:18 PM]

CreateUniqueMsgPort

Convenience call implemented in clib.lib V24.

Associated Files
msgport.h
ANSI C Prototype
clib.lib
ARM Link Library

Notes
When you no longer need a message port, use DeleteMsgPort() to delete it.
You can use FindMsgPort() to find a message port by name.

See Also
CreateMsg(), DeleteMsg(), DeleteMsgPort(), SendMsg(), SendSmallMsg()

file:///C|/%23%23DDOC/spr/01spr029.html (2 of 2) [4/16/2002 11:13:18 PM]

CreateUniqueSemaphore

CreateUniqueSemaphore
Creates a semaphore with a unique name.

Synopsis
Item CreateUniqueSemaphore( const char *name, uint8 pri )

Description
This convenience procedure creates a semaphore item with the specified name and priority. You can use
this procedure in place of CreateItem() to create the semaphore.
This function works much like CreateSemaphore(), except that it guarantees that no other
semaphore item of the same name already exists. And once this semaphore created, no other semaphore
of the same name is allowed to be created.
For information about semaphores, which are used to control access to shared resources, see the Sharing
System Resources chapter in the 3DO Portfolio Programmer's Guide.

Arguments
name
The name of the semaphore (see "Notes").
pri
The priority of the semaphore; use 0 for now.

Return Value
The procedure returns the item number of the semaphore or an error code if an error occurs. If a
semaphore of the same name already existed when this call was made, the ER_Kr_UniqueItemExists
error will be returned.

Implementation
Convenience call implemented in clib.lib V24.

file:///C|/%23%23DDOC/spr/01spr030.html (1 of 2) [4/16/2002 11:13:19 PM]

CreateUniqueSemaphore

Associated Files
semaphore.h
ANSI C Prototype
clib.lib
ARM Link Library

Notes
When you no longer need a semaphore, use DeleteSemaphore() to delete it.
You can use FindSemaphore() to find a semaphore by name.

See Also
DeleteSemaphore(), LockSemaphore(), UnlockSemaphore()

file:///C|/%23%23DDOC/spr/01spr030.html (2 of 2) [4/16/2002 11:13:19 PM]

DumpNode

DumpNode
Prints contents of a node.

Synopsis
void DumpNode (const Node *node, const char *banner)

Description
This function prints out the contents of a Node structure for debugging purposes.

Arguments
node
The node to print.
banner
Descriptive text to print before the node contents. May be NULL.

Implementation
Convenience call implemented in clib.lib V24.

Associated Files
list.h
ANSI C Prototype
clib.lib
ARM Link Library

file:///C|/%23%23DDOC/spr/01spr040.html [4/16/2002 11:13:19 PM]

DumpTagList

DumpTagList
Prints contents of a tag list.

Synopsis
void DumpTagList (const TagArg *tagList, const char *desc)

Description
This function prints out the contents of a TagArg list.

Arguments
tagList
The list of tags to print.
desc
Description of tag list to print. Can be NULL.

Implementation
Convenience call implemented in clib.lib V24.

Associated Files
tags.h
ANSI C Prototype
clib.lib
ARM Link Library

See Also
NextTagArg(), GetTagArg()

file:///C|/%23%23DDOC/spr/01spr041.html [4/16/2002 11:13:19 PM]

NextTagArg

NextTagArg
Finds the next TagArg in a tag list.

Synopsis
TagArg *NextTagArg( const TagArg **tagList );

Description
This function iterates through a tag list, skipping and chaining as dictated by control tags. There are three
control tags:
TAG_NOP
Ignores that single entry and moves to the next one.
TAG_JUMP
Has a pointer to another array of tags.
TAG_END
Marks the end of the tag list.
This function only returns TagArgs which are not system tags. Each call returns either the next TagArg
you should examine, or NULL when the end of the list has been reached.

Arguments
tagList
This is a pointer to a storage location used by the iterator to keep track of its current location in
the tag list. The variable that this parameter points to should be initialized to point to the first
TagArg in the tag list, and should not be changed thereafter.

Return Value
This function returns a pointer to a TagArg structure, or NULL if all the tags have been visited. None of
the control tags are ever returned to you, they are handled transparently by this function.

Example
file:///C|/%23%23DDOC/spr/01spr103.html (1 of 2) [4/16/2002 11:13:20 PM]

NextTagArg

Example 1: Example for NextTagArg
void WalkTagList(const TagArg *tags)
{
TagArg *state;
TagArg *currentTag;
state = tags;
while ((tag = NextTagItem(&state)) != NULL)
{
switch (tag->ta_Tag)
{
case TAG1: // process this tag
break;
case TAG2: // process this tag
break;
default

: // unknown tag, return an error
break;

}
}
}

Implementation
Folio call implemented in kernel folio V24.

Associated Files
tags.h

See Also
FindTagArg()

file:///C|/%23%23DDOC/spr/01spr103.html (2 of 2) [4/16/2002 11:13:20 PM]

FindTagArg

FindTagArg
Looks through a tag list for a specific tag.

Synopsis
TagArg *FindTagArg( const TagArg *tagList, uint32 tag );

Description
This function scans a tag list looking for a TagArg structure with a ta_Tag field equal to the tag
parameter. The function always returns the last TagArg structure in the list which matches the tag.
Finally, this function deals with the various control tags such as TAG_JUMP and TAG_NOP.

Arguments
tagList
The list of tags to scan.
tag
The value to look for.

Return Value
This function returns a pointer to a TagArg structure with a value of ta_Tag that matches the tag
parameter, or NULL if no match can be found. The function always returns the last tag in the list which
matches.

Implementation
Folio call implemented in kernel folio V24.

Associated Files
tags.h

See Also

file:///C|/%23%23DDOC/spr/01spr059.html (1 of 2) [4/16/2002 11:13:20 PM]

FindTagArg

NextTagArg()

file:///C|/%23%23DDOC/spr/01spr059.html (2 of 2) [4/16/2002 11:13:20 PM]

GetTagArg

GetTagArg
Finds a TagArg in list and returns its ta_Arg field.

Synopsis
TagData GetTagArg (const TagArg *tagList, uint32 tag,TagData defaultValue)

Description
This function calls FindTagArg() to locate the specified tag. If it is found, it returns the ta_Arg value from the found
TagArg. Otherwise, it returns the default value supplied. This is handy when resolving a tag list that has optional tags that
have suitable default values.

Arguments
tagList
The list of tags to scan. Can be NULL.
tag
The tag ID to look for.
defaultValue
Default value to use when specified tag isn't found in tagList.

Return Value
ta_Arg value from found TagArg or defaultValue.

Implementation
Convenience call implemented in clib.lib V24.

Examples
void dosomething (const TagArg *tags)
{
uint32 amplitude = (uint32)GetTagData (tags, MY_TAG_AMPLITUDE, (TagData)0x7fff);
.
.
.
}

Caveats
It's a good idea to always use casts for the default value and result. Don't assume anything about the type definition of
file:///C|/%23%23DDOC/spr/01spr081.html (1 of 2) [4/16/2002 11:13:20 PM]

GetTagArg

TagData other than that it is a 32-bit value.

Associated Files
tags.h
ANSI C Prototype
clib.lib
ARM Link Library

See Also
FindTagArg(), NextTagArg()

file:///C|/%23%23DDOC/spr/01spr081.html (2 of 2) [4/16/2002 11:13:20 PM]

FindAndOpenDevice

FindAndOpenDevice
Finds a device by name and opens it.

Synopsis
Item FindAndOpenDevice( const char *name )

Description
This macro finds a device whose name matches the name argument. The search is not case-sensitive (that
is, the kernel does not distinguish uppercase and lowercase letters in device names). If the device is
found, it is opened.

Arguments
name
The name of the device to find.

Return Value
The macro returns the item number of the device or an error code if an error occurs.

Implementation
Macro implemented in device.h V24.

Associated Files
device.h
ANSI C Macro

See Also
OpenNamedDevice(), FindAndOpenItem()

file:///C|/%23%23DDOC/spr/01spr044.html [4/16/2002 11:13:21 PM]

OpenNamedDevice

OpenNamedDevice
Opens a named device.

Synopsis
Item OpenNamedDevice( const char *name, a )

Description
This macro opens a device that you specify by name.

Arguments
name
The name of the device to open.
a
This argument, which is not currently used, must be 0.

Return Value
The procedure returns the item number for the opened device or an error code if an error occurs.

Implementation
Macro implemented in device.h V20.

Associated Files
device.h
ANSI C Macro definition

See Also
CloseNamedDevice(), OpenItem(), CloseItem(), FindItem()

file:///C|/%23%23DDOC/spr/01spr105.html [4/16/2002 11:13:21 PM]

FindAndOpenItem

FindAndOpenItem
Finds an item by type and tags and opens it.

Synopsis
Item FindAndOpenItem( int32 cType, TagArg *tp )
Item FindAndOpenItemVA( int32 cType, uint32 tags, ... );

Description
This procedure finds an item of the specified type whose tag arguments match those pointed to by the tp
argument. If more than one item of the specified type has matching tag arguments, the procedure returns
the item number for the first matching item. When an item is found, it is automatically opened and
prepared for use.

Arguments
cType
Specifies the type of the item to find. Use MkNodeID() to create this value.
tp
A pointer to an array of tag arguments. The tag arguments can be in any order. The array can
contain some, all, or none of the possible tag arguments for an item of the specified type; to make
the search more specific, include more tag arguments. The last element of the array must be the
value TAG_END. If there are no tag arguments, this argument must be NULL. For a list of tag
arguments for each item type, see the Portfolio Item's chapter.

Return Value
The procedure returns the number of the first item that matches or an error code if it can't find the item or
if an error occurs.The returned item is already opened, so there is no need to call OpenItem() on it.
You should call CloseItem() on the supplied item when you are done with it.

Implementation
SWI implemented in kernel folio V24.

Associated Files
file:///C|/%23%23DDOC/spr/01spr046.html (1 of 2) [4/16/2002 11:13:21 PM]

FindAndOpenItem

item.h
ANSI C Prototype

Notes
To close an opened item, use CloseItem().

See Also
CheckItem(), FindNamedItem(), FindVersionedItem(), LookupItem(),
MkNodeID(), OpenItem(), FindItem()

file:///C|/%23%23DDOC/spr/01spr046.html (2 of 2) [4/16/2002 11:13:21 PM]

FindAndOpenFolio

FindAndOpenFolio
Finds a folio by name and opens it.

Synopsis
Item FindAndOpenFolio( const char *name )

Description
This macro finds a folio whose name matches the name argument. The search is not case-sensitive (that
is, the kernel does not distinguish uppercase and lowercase letters in folio names). You can use this
macro in place of FindAndOpenNamedItem() to find a folio and open it.

Arguments
name
The name of the folio to find.

Return Value
The macro returns the item number of the folio or an error code if an error occurs.

Implementation
Macro implemented in folio.h V24.

Associated Files
folio.h
ANSI C Macro

See Also
CallFolio(), CallFolioRet(), FindAndOpenNamedItem()

file:///C|/%23%23DDOC/spr/01spr045.html [4/16/2002 11:13:22 PM]

FindAndOpenNamedItem

FindAndOpenNamedItem
Finds an item by name and opens it.

Synopsis
Item FindAndOpenNamedItem( int32 ctype, const char *name )

Description
This procedure finds an item of the specified type whose name matches the name argument. The search
is not case-sensitive (that is, the kernel does not distinguish uppercase and lowercase letters in item
names). When an item is found, it is automatically opened and prepared for use.

Arguments
ctype
The type of the item to find. Use MkNodeID() to create this value.
name
The name of the item to find.

Return Value
The procedure returns the number of the item that was opened. It returns an error code if an error occurs.

Implementation
Convenience call implemented in clib.lib V24.

Associated Files
item.h
ANSI C Prototype
clib.lib
ARM Link Library

file:///C|/%23%23DDOC/spr/01spr047.html (1 of 2) [4/16/2002 11:13:22 PM]

FindAndOpenNamedItem

See Also
FindAndOpenItem()

file:///C|/%23%23DDOC/spr/01spr047.html (2 of 2) [4/16/2002 11:13:22 PM]

FindDevice

FindDevice
Finds a device by name.

Synopsis
Item FindDevice( const char *name )

Description
This macro finds a device whose name matches the name argument. The search is not case-sensitive (that
is, the kernel does not distinguish uppercase and lowercase letters in device names).

Arguments
name
The name of the device to find.

Return Value
The macro returns the item number of the device or an error code if an error occurs.

Implementation
Macro implemented in device.h V20.

Associated Files
device.h
ANSI C Macro

See Also
OpenNamedDevice(), FindItem()

file:///C|/%23%23DDOC/spr/01spr048.html [4/16/2002 11:13:22 PM]

FindFolio

FindFolio
Finds a folio by name.

Synopsis
Item FindFolio( const char *name )

Description
This macro finds a folio whose name matches the name argument. The search is not case-sensitive (that
is, the kernel does not distinguish uppercase and lowercase letters in folio names). You can use this
macro in place of FindNamedItem() to find a folio.

Arguments
name
The name of the folio to find.

Return Value
The macro returns the item number of the folio or an error code if an error occurs.

Implementation
Macro implemented in folio.h V20.

Associated Files
folio.h
ANSI C Macro

See Also
CallFolio(), CallFolioRet()

file:///C|/%23%23DDOC/spr/01spr049.html [4/16/2002 11:13:22 PM]

FindMsgPort

FindMsgPort
Finds a message port by name.

Synopsis
Item FindMsgPort( const char *name )

Description
This macro finds a message port with the specified name. The search is not case-sensitive (that is, the
kernel does not distinguish uppercase and lowercase letters in message port names). You can use this
macro in place of FindNamedItem() to find a message port.

Arguments
name
The name of the message port to find.

Return Value
The macro returns the item number of the message port that was found or an error code if an error
occurs.

Implementation
Macro implemented in msgport.h V20.

Associated Files
msgport.h
ANSI C Macro

See Also
CreateMsgPort()

file:///C|/%23%23DDOC/spr/01spr053.html [4/16/2002 11:13:23 PM]

FindNamedNode

FindNamedNode
Finds a node by name.

Synopsis
Node *FindNamedNode( const List *l, const char *name )

Description
This procedure searches a list for a node with the specified name. The search is not case-sensitive (that is,
the kernel does not distinguish uppercase and lowercase letters in node names).

Arguments
l
A pointer to the list to search.
name
The name of the node to find.

Return Value
The procedure returns a pointer to the node structure or NULL if the named node couldn't be found.

Implementation
Folio call implemented in kernel folio V20.

Associated Files
list.h
ANSI C Prototype
clib.lib
ARM Link Library

See Also
file:///C|/%23%23DDOC/spr/01spr055.html (1 of 2) [4/16/2002 11:13:23 PM]

FindNamedNode

FirstNode(), LastNode(), NextNode(), PrevNode()

file:///C|/%23%23DDOC/spr/01spr055.html (2 of 2) [4/16/2002 11:13:23 PM]

FindNodeFromHead

FindNodeFromHead
Returns a pointer to a node appearing at a given ordinal position from the head of the list.

Synopsis
Node *FindNodeFromHead(const List *l, uint32 position);

Description
This function scans the supplied list and returns a pointer to the node appearing in the list at the given
ordinal position. NULL is returned if the list doesn't contain that many items.

Arguments
l
A pointer to the list to scan for the node.
position
The node position to look for.

Return Value
A pointer to the node found, or NULL if the list doesn't contain enough nodes.

Implementation
Convenience call implemented in clib.lib V24.

Associated Files
list.h
ANSI C Prototype
clib.lib
ARM Link Library

Caveats
file:///C|/%23%23DDOC/spr/01spr056.html (1 of 2) [4/16/2002 11:13:23 PM]

FindNodeFromHead

GIGO (\Qgarbage in, garbage out)

See Also
AddHead(), AddTail(), InsertNodeFromHead(), InsertNodeFromTail(),
RemHead(), RemNode(), RemTail()

file:///C|/%23%23DDOC/spr/01spr056.html (2 of 2) [4/16/2002 11:13:23 PM]

FindNodeFromTail

FindNodeFromTail
Returns a pointer to a node appearing at a given ordinal position from the tail of the list.

Synopsis
Node *FindNodeFromTail(const List *l, uint32 position);

Description
This function scans the supplied list and returns a pointer to the node appearing in the list at the given
ordinal position counting from the end of the list. NULL is returned if the list doesn't contain that many
items.

Arguments
l
A pointer to the list to scan for the node.
position
The node position to look for, relative to the end of the list.

Return Value
A pointer to the node found, or NULL if the list doesn't contain enough nodes.

Implementation
Convenience call implemented in clib.lib V24.

Associated Files
list.h
ANSI C Prototype
clib.lib
ARM Link Library

file:///C|/%23%23DDOC/spr/01spr057.html (1 of 2) [4/16/2002 11:13:24 PM]

FindNodeFromTail

Caveats
GIGO (garbage in, garbage out)

See Also
AddHead(), AddTail(), InsertNodeFromHead(), InsertNodeFromTail(),
RemHead(), RemNode(), RemTail()

file:///C|/%23%23DDOC/spr/01spr057.html (2 of 2) [4/16/2002 11:13:24 PM]

FindTask

FindTask
Finds a task by name.

Synopsis
Item FindTask( const char *name )

Description
This macro finds a task with the specified name. The search is not case-sensitive (that is, the kernel does
not distinguish uppercase and lowercase letters in task names). You can use this macro in place of
FindNamedItem() to find a task.

Arguments
name
The name of the task to find.

Return Value
The macro returns the item number of the task that was found or an error code if an error occurs.

Implementation
Macro implemented in task.h V20.

Associated Files
task.h
ANSI C Macro

See Also
CreateThread()

file:///C|/%23%23DDOC/spr/01spr060.html [4/16/2002 11:13:24 PM]

GetBankBits

GetBankBits
Finds out which VRAM bank contains a memory location.

Synopsis
uint32 GetBankBits( const void *a )

Description
In the current 3DO hardware, 2 MB of video random-access memory (VRAM) is divided into two banks,
each containing 1 MB of VRAM. Fast VRAM memory transfers using the SPORT bus can take place
only between memory locations in the same bank. Use this procedure to find out which VRAM bank
contains a specified memory location.
When a task allocates VRAM, the memory block contains memory from one VRAM bank or the other; it
never contains memory from both banks. Thus, if any memory location in a block is in one VRAM bank,
the entire block is guaranteed to be in the same bank.

Arguments
a
A pointer to the memory to be examined.

Return Value
The procedure returns a set of memory flags in which the following flags can be set:
MEMTYPE_BANKSELECT
Set if the memory is contained in VRAM.
MEMTYPE_BANK1
Set if the memory is in the primary VRAM Bank.
MEMTYPE_BANK2
Set if the memory is in the secondary VRAM bank.
If the memory is not in VRAM, the procedure returns 0.

file:///C|/%23%23DDOC/spr/01spr069.html (1 of 2) [4/16/2002 11:13:24 PM]

GetBankBits

Implementation
Macro implemented in mem.h V20.

Associated Files
mem.h
ANSI C Macro

See Also
GetMemType()

file:///C|/%23%23DDOC/spr/01spr069.html (2 of 2) [4/16/2002 11:13:24 PM]

GetFolioFunc

GetFolioFunc
Returns a pointer to a folio function.

Synopsis
FolioFunc GetFolioFunc (const Folio *folio, int32 func)

Description
This macro returns the address of a folio function from a folio vector table.

Arguments
folio
A pointer to the folio item that contains the procedure. Use LookupItem() to get this pointer. For
the item number of a folio (which you pass to LookupItem()), see the "Portfolio Items" chapter or
call FindAndOpenFolio().
func
The index of the vector table entry for the procedure. This index (which is always a negative
integer, because the table grows backward in memory) is listed in the header file for the folio that
contains the procedure.

Implementation
Macro implemented in folio.h V24.

Associated Files
folio.h

See Also
CallFolio(), CallFolioRet()

file:///C|/%23%23DDOC/spr/01spr071.html [4/16/2002 11:13:25 PM]

GetMemTrackSize

GetMemTrackSize
Get the size of a block of memory allocated with MEMTYPE_TRACKSIZE.

Synopsis
int32 GetMemTrackSize( const void *p )

Description
This function returns the size that was used to allocate a block of memory. The block of memory must
have been allocated using the MEMTYPE_TRACKSIZE flag, otherwise this function will return
garbage.

Arguments
p
Pointer obtained from a system memory allocation routine. The block of memory must have been
allocated using the MEMTYPE_TRACKSIZE flag, otherwise the value returned by this function
will be random.

Return Value
The function returns the size, in bytes, of the memory block. This size corresponds to the size provided to
the system memory allocation routine when the block was first allocated.

Implementation
Folio call implemented in kernel folio V24.

Associated Files
mem.h
ANSI C Prototype
clib.lib
ARM Link Library

file:///C|/%23%23DDOC/spr/01spr073.html (1 of 2) [4/16/2002 11:13:25 PM]

GetMemTrackSize

Caveats
This function will not return the correct value for allocations made using MEMTYPE_STARTPAGE and
using a private MemList structure. Allocations done with AllocMem() will always work, since they
use the task's memory lists and not any private MemList.

See Also
AllocMem(), FreeMem()

file:///C|/%23%23DDOC/spr/01spr073.html (2 of 2) [4/16/2002 11:13:25 PM]

GetNodeCount

GetNodeCount
Counts the number of nodes in a list.

Synopsis
uint32 GetNodeCount(const List *l);

Description
This function counts the number of nodes currently in the list.

Arguments
l
A pointer to the list to count the nodes of.

Return Value
The number of nodes in the list.

Implementation
Convenience call implemented in clib.lib V24.

Associated Files
list.h
ANSI C Prototype
clib.lib
ARM Link Library

Caveats
GIGO (garbage in, garbage out)

See Also
file:///C|/%23%23DDOC/spr/01spr076.html (1 of 2) [4/16/2002 11:13:25 PM]

GetNodeCount

AddHead(), AddTail(), InsertNodeFromHead(), InsertNodeFromTail(),
RemHead(), RemNode(), RemTail()

file:///C|/%23%23DDOC/spr/01spr076.html (2 of 2) [4/16/2002 11:13:25 PM]

GetNodePosFromHead

GetNodePosFromHead
Gets the ordinal position of a node within a list, counting from the head of the list.

Synopsis
int32 GetNodePosFromHead(const List *l, const Node *n);

Description
This function scans the supplied list looking for the supplied node, and returns the ordinal position of the
node within the list. If the node doesn't appear in the list, the function returns -1.

Arguments
l
A pointer to the list to scan for the node.
n
A pointer to a node to locate in the list.

Return Value
The ordinal position of the node within the list counting from the head of the list, or -1 if the node isn't in
the list. The first node in the list has position 0, the second node has position 1, etc.

Implementation
Convenience call implemented in clib.lib V24.

Associated Files
list.h
ANSI C Prototype
clib.lib
ARM Link Library

file:///C|/%23%23DDOC/spr/01spr077.html (1 of 2) [4/16/2002 11:13:26 PM]

GetNodePosFromHead

Caveats
GIGO (garbage in, garbage out)

See Also
AddHead(), AddTail(), InsertNodeFromHead(), InsertNodeFromTail(),
RemHead(), RemNode(), RemTail()

file:///C|/%23%23DDOC/spr/01spr077.html (2 of 2) [4/16/2002 11:13:26 PM]

GetNodePosFromTail

GetNodePosFromTail
Gets the ordinal position of a node within a list, counting from the tail of the list.

Synopsis
int32 GetNodePosFromTail(const List *l, const Node *n);

Description
This function scans the supplied list backward looking for the supplied node, and returns the ordinal
position of the node within the list. If the node doesn't appear in the list, the function returns -1.

Arguments
l
A pointer to the list to scan for the node.
n
A pointer to a node to locate in the list.

Return Value
The ordinal position of the node within the list counting from the tail of the list, or -1 if the node isn't in
the list. The last node in the list has position 0, the second to last node has position 1, etc.

Implementation
Convenience call implemented in clib.lib V24.

Associated Files
list.h
ANSI C Prototype
clib.lib
ARM Link Library

file:///C|/%23%23DDOC/spr/01spr078.html (1 of 2) [4/16/2002 11:13:26 PM]

GetNodePosFromTail

Caveats
GIGO (garbage in, garbage out)

See Also
AddHead(), AddTail(), InsertNodeFromHead(), InsertNodeFromTail(),
RemHead(), RemNode(), RemTail()

file:///C|/%23%23DDOC/spr/01spr078.html (2 of 2) [4/16/2002 11:13:26 PM]

GetPageSize

GetPageSize
Gets the number of bytes in a memory page.

Synopsis
int32 GetPageSize( uint32 memflags )

Description
This procedure gets the number of bytes in a page of the specified type of memory.

Arguments
memflags
Flags that specify the type of memory whose page size to get. These flags can include
MEMTYPE_ANY, MEMTYPE_VRAM, MEMTYPE_DRAM, MEMTYPE_BANKSELECT,
MEMTYPE_BANK1, MEMTYPE_BANK2, MEMTYPE_DMA, MEMTYPE_CEL,
MEMTYPE_AUDIO, MEMTYPE_DSP, and MEMTYPE_SYSTEMPAGESIZE. For
information about these flags, see the description of AllocMem().

Return Value
The procedure returns the size, in bytes, of a page of the specified type of RAM. If there is no memory of
the specified type, the procedure returns 0.

Implementation
Folio call implemented in kernel folio V20.

Associated Files
mem.h
ANSI C Prototype
clib.lib
ARM Link Library

file:///C|/%23%23DDOC/spr/01spr079.html (1 of 2) [4/16/2002 11:13:26 PM]

GetPageSize

Caveats
If you do not specify the type of memory you're asking about, the page size you get may be for memory
you're not interested in. The page size for a particular piece of memory may be not what you expected if
the amount of memory requested causes the allocator to jump to a different type of memory that can
satisfy your request, but which may have a different page size. To ensure that you get the actual page size
of the memory you're interested, call GetMemType() to get the memory flags for the memory, then call
GetPageSize() with those flags as the memflags argument.

See Also
GetMemType()

file:///C|/%23%23DDOC/spr/01spr079.html (2 of 2) [4/16/2002 11:13:26 PM]

GetSysErr

GetSysErr
Gets the error string for an error.

Synopsis
int32 GetSysErr( char *buff, int32 buffsize, Err err )

Description
This procedure returns a character string that describes an error code. The resulting string is placed in a
buffer.
The procedure interprets all the fields in the err argument and returns corresponding text strings for all of
them. If an error-text table is not found for the specific error, the routine uses numbers for the final error
code value.

Arguments
buff
A pointer to a buffer to hold the error string.
buffsize
The size of the error-text buffer, in bytes. This should be 128.
err
The error code whose error string to get.

Return Value
The procedure returns the number of bytes in the description string, or a negative error code if a bad
buffer pointer is supplied.

Implementation
Folio call implemented in kernel folio V20.

Associated Files
file:///C|/%23%23DDOC/spr/01spr080.html (1 of 2) [4/16/2002 11:13:27 PM]

GetSysErr

operror.h
ANSI C Prototype
clib.lib
ARM Link Library

See Also
PrintfSysErr()

file:///C|/%23%23DDOC/spr/01spr080.html (2 of 2) [4/16/2002 11:13:27 PM]

PrintSysErr

PrintfSysErr
Prints the error string for an error.

Synopsis
void PrintfSysErr( Err err )

Description
This procedure prints the error string for an error to the debugging terminal for a 3DO development
system. This has the same effect as using Printf() to print the string constructed by GetSysErr().
The string is not displayed on production machines.
To copy an error string into a buffer instead of sending it the console, use GetSysErr().

Arguments
err
An error code.

Implementation
Convenience call implemented in clib.lib V20.

Associated Files
operror.h
ANSI C Prototype
clib.lib
ARM Link Library

See Also
GetSysErr()

file:///C|/%23%23DDOC/spr/01spr108.html [4/16/2002 11:13:27 PM]

GetTaskSignals

GetTaskSignals
Gets the currently received signal bits.

Synopsis
int32 GetTaskSignals( Task *t )

Description
This macro returns the signal bits that have been received by the specified task. For information about
signals, see the description of the AllocSignal() procedure and the "Communicating Among Tasks"
chapter in the 3DO Portfolio Programmer's Guide.

Return Value
A 32-bit word in which all currently received signal bits for the task are set.

Implementation
Macro implemented in task.h V21.

Associated Files
task.h
ANSI C Macro

See Also
AllocSignal(), FreeSignal(), SendSignal(), WaitSignal()

file:///C|/%23%23DDOC/spr/01spr082.html [4/16/2002 11:13:27 PM]

InsertNodeAfter

InsertNodeAfter
Inserts a node into a list after another node already in the list.

Synopsis
void InsertNodeAfter(Node *oldNode, Node *newNode);

Description
This function lets you insert a new node into a list, AFTER another node that is already in the list.

Arguments
oldNode
The node after which to insert the new node.
newNode
The node to insert in the list.

Implementation
Convenience call implemented in clib.lib V24.

Associated Files
list.h
ANSI C Prototype
clib.lib
ARM Link Library

Notes
A node can be included only in one list.

Caveats

file:///C|/%23%23DDOC/spr/01spr085.html (1 of 2) [4/16/2002 11:13:27 PM]

InsertNodeAfter

GIGO (garbage in, garbage out)

See Also
AddHead(), AddTail(), InsertNodeFromHead(), InsertNodeFromTail(),
RemHead(), RemNode(), RemTail(), InsertNodeBefore()

file:///C|/%23%23DDOC/spr/01spr085.html (2 of 2) [4/16/2002 11:13:27 PM]

InsertNodeBefore

InsertNodeBefore
Inserts a node into a list before another node already in the list.

Synopsis
void InsertNodeBefore(Node *oldNode, Node *newNode);

Description
This function lets you insert a new node into a list, BEFORE another node that is already in the list.

Arguments
oldNode
The node before which to insert the new node.
newNode
The node to insert in the list.

Implementation
Convenience call implemented in clib.lib V24.

Associated Files
list.h
ANSI C Prototype
clib.lib
ARM Link Library

Notes
A node can be included only in one list.

Caveats

file:///C|/%23%23DDOC/spr/01spr086.html (1 of 2) [4/16/2002 11:13:28 PM]

InsertNodeBefore

GIGO (garbage in, garbage out)

See Also
AddHead(), AddTail(), InsertNodeFromHead(), InsertNodeFromTail(),
RemHead(), RemNode(), RemTail(), InsertNodeAfter()

file:///C|/%23%23DDOC/spr/01spr086.html (2 of 2) [4/16/2002 11:13:28 PM]

IsEmptyList

IsEmptyList
Checks whether a list is empty.

Synopsis
bool IsEmptyList( List *l )

Description
This macro checks whether a list is empty.

Arguments
l
A pointer to the list to check.

Return Value
The macro returns TRUE if the list is empty or FALSE if it isn't.

Implementation
Macro implemented in list.h V20.

Associated Files
list.h
ANSI C Macro definition

See Also
FirstNode(), IsNode(), IsNodeB(), LastNode(), NextNode(), PrevNode(),
ScanList(), IsListEmpty()

file:///C|/%23%23DDOC/spr/01spr089.html [4/16/2002 11:13:28 PM]

IsItemOpened

IsItemOpened
Determines whether a task or thread has opened a given item.

Synopsis
Err IsItemOpened( Item task, Item i )

Description
This function determines whether a task or thread has currently got an item opened.

Arguments
task
The task or thread to inquire about. For the current task, use:
KernelBase->kb_CurrentTask>
i
The number of the item to verify.

Return Value
This function returns >=0 if the item was opened, or a negative error
code if it is not, or if the parameters are bogus.

Implementation
Folio call implemented in kernel folio V24.

Associated Files
item.h
ANSI C Prototype
clib.lib
ARM Link Library
file:///C|/%23%23DDOC/spr/01spr090.html (1 of 2) [4/16/2002 11:13:28 PM]

IsItemOpened

See Also
OpenItem(), CloseItem(), CheckItem(), LookupItem()

file:///C|/%23%23DDOC/spr/01spr090.html (2 of 2) [4/16/2002 11:13:28 PM]

IsMemReadable

IsMemReadable
Determines whether a region of memory is fully readable by the current task.

Synopsis
bool IsMemReadable( const void *p, int32 size )

Description
This function considers the described block of the address space in relation to the known locations of
RAM in the system, and returns TRUE if the block is entirely contained within RAM, and FALSE
otherwise.
The low 512 (0x200) bytes of the address space have been declared to be "not memory" for all
reasonable purposes; this function will therefore return FALSE for any block of memory that uses any
portion of low memory.

Arguments
p
A pointer to the start of the block.
size
The number of bytes in the block.

Return Value
This function returns TRUE if the block is entirely readable by the current task, or FALSE if any part of
the block is not.

Implementation
Folio call implemented in kernel folio V24.

Associated Files
mem.h
file:///C|/%23%23DDOC/spr/01spr092.html (1 of 2) [4/16/2002 11:13:29 PM]

IsMemReadable

ANSI C Prototype
clib.lib
ARM Link Library

See Also
IsMemWritable()

file:///C|/%23%23DDOC/spr/01spr092.html (2 of 2) [4/16/2002 11:13:29 PM]

IsMemWritable

IsMemWritable
Determines whether a region of memory is fully writable by the current task.

Synopsis
bool IsMemWritable( const void *p, int32 size )

Description
This function considers the described block of the address space in relation to the pages of memory the
current task has write access to. This function returns TRUE If the current task can write to the memory
block, and FALSE if it cannot.

Arguments
p
A pointer to the start of the block.
size
The number of bytes in the block.

Return Value
This function returns TRUE if the block can be written to by the calling task, and FALSE if it cannot.

Implementation
Folio call implemented in kernel folio V24.

Associated Files
mem.h
ANSI C Prototype
clib.lib
ARM Link Library

file:///C|/%23%23DDOC/spr/01spr093.html (1 of 2) [4/16/2002 11:13:29 PM]

IsMemWritable

See Also
IsMemReadable()

file:///C|/%23%23DDOC/spr/01spr093.html (2 of 2) [4/16/2002 11:13:29 PM]

PrintError

PrintError
Prints the error string for an error

Synopsis
void PrintError( char *who, char *what, char *whom, Err err )

Description
On DEVELOPMENT builds, this macro calls a procedure that prints the error string for an error to the
Macintosh console for a 3DO development system. This has the same effect as using printf() to print
the who, what, and whom strings with the string constructed by GetSysErr().
On non-DEVELOPMENT builds, this macro expands to an empty statement, reducing code size and
avoiding pulling in lots of extraneous junk from the support libraries.
To copy an error string into a buffer instead of sending it the console, use GetSysErr().
In the task called "shell", the C statement
PrintError((char *)0, "open", filename, errno)
might result in something like this:
+================ Terminal ================ | FFS-Severe-System-extended-No such file |
shell: unable to open "badfile"

Arguments
who
A string that identifies the task, folio, or module that encountered the error; if a NULL pointer or
a zero-length string is passed, the name of the current task is used (or, if there is no current task,
"notask").
what
A string that describes what action was being taken that failed. Normally, the words "unable to"
are printed before this string to save client data space; if the first character of the "what" string is a
backslash, these words are not printed.
file:///C|/%23%23DDOC/spr/01spr107.html (1 of 2) [4/16/2002 11:13:29 PM]

PrintError

whom
A string that describes the object to which the described action is being taken (for instance, the
name of a file). It is printed surrounded by quotes; if a NULL pointer or zero length string is
passed, the quotes are not printed.
err
A (normally negative) number denoting the error that occurred, which will be decoded with
GetSysErr. If not negative, then no decoded error will be printed.

Implementation
Macro implemented in the operror.h V21.

Associated Files
operror.h
ANSI C Prototype
clib.lib
ARM Link Library

See Also
PrintfSysErr() , GetSysErr()

file:///C|/%23%23DDOC/spr/01spr107.html (2 of 2) [4/16/2002 11:13:29 PM]

ReadHardwareRandomNumber

ReadHardwareRandomNumber
Gets a 32-bit random number.

Synopsis
uint32 ReadHardwareRandomNumber( void )

Description
The procedure returns a random number generated by the hardware. This is useful for providing a seed to
the software random-number generator.

Return Value
The procedure returns an unsigned 32-bit random number. The number can be any integer from 0 to
(2^32 - 1), inclusive.

Implementation
SWI implemented in kernel folio V20.

Associated Files
hardware.h
ANSI C Prototype

file:///C|/%23%23DDOC/spr/01spr109.html [4/16/2002 11:13:30 PM]

SampleSystemTime

SampleSystemTime
Samples the system time with very low overhead.

Synopsis
uint32 SampleSystemTime( void )

Description
This function samples the current system time, and returns it to you. The primary return value is the
seconds count of the system clock. A secondary value available in the r1 register on ARM processors is
the microseconds count of the system clock. For a C-friendly version of this call, see
SampleSystemTimeTV().
This function has very low overhead and is meant for high-accuracy timings.
The time value returned by this function corresponds to the time maintained by the TIMERUNIT_USEC
unit of the timer device.

Return Value
This function returns the seconds count of the system clock. It also returns the microseconds count in the
r1 ARM processor register.

Implementation
SWI implemented in kernel folio V24.

Associated Files
time.h

See Also
SampleSystemTimeTV() ANSI C Prototype

file:///C|/%23%23DDOC/spr/01spr115.html [4/16/2002 11:13:30 PM]

SampleSystemTimeTV

SampleSystemTimeTV
Samples the system time with very low overhead.

Synopsis
void SampleSystemTimeTV( TimeVal *time )

Description
This function records the current system time in the supplied TimeVal structure. This is a very low
overhead call giving a very high-accuracy timing.
The time value returned by this function corresponds to the time maintained by the TIMERUNIT_USEC
unit of the timer device.

Arguments
time
A pointer to a TimeVal structure which will receive the current system time.

Implementation
Convenience call implemented in clib.lib V24.

Associated Files
time.h
ANSI C Prototype
clib.lib
ARM Link Library

See Also
SampleSystemTime()

file:///C|/%23%23DDOC/spr/01spr116.html [4/16/2002 11:13:30 PM]

SetItemOwner

SetItemOwner
Changes the owner of an item.

Synopsis
Err SetItemOwner( Item i, Item newOwner )

Description
This procedure makes another task the owner of an item. A task must be the owner of the item to change
its ownership. The item is removed from the current task's resource table and placed in the new owner's
resource table.
You normally use this procedure to keep a resource available after the task that created it terminates.

Arguments
i
The item number of the item to give to a new owner.
newOwner
The item number of the new owner task.

Return Value
The procedure returns 0 if ownership of the item is changed or an error code if an error occurs.

Implementation
SWI implemented in kernel folio V20.

Associated Files
item.h
ANSI C Prototype

Caveats
file:///C|/%23%23DDOC/spr/01spr125.html (1 of 2) [4/16/2002 11:13:30 PM]

SetItemOwner

This is not implemented for all items that should be able to have their ownership changed.

See Also
CreateItem(), FindItem(), DeleteItem()

file:///C|/%23%23DDOC/spr/01spr125.html (2 of 2) [4/16/2002 11:13:30 PM]

SetItemPri

SetItemPri
Changes the priority of an item.

Synopsis
int32 SetItemPri( Item i, uint8 newpri )

Description
This procedure changes the priority of an item. Some items in the operating system are maintained in
lists; for example, tasks and threads. Some lists are ordered by priority, with higher-priority items coming
before lower-priority items. When the priority of an item in a list changes, the kernel automatically
rearranges the list of items to reflect the new priority. The item is moved immediately before the first
item whose priority is lower.
A task must own an item to change its priority. A task can change its own priority even if it does not own
itself.

Arguments
i
The item number of the item whose priority to change.
newpri
The new priority for the item.

Return Value
The procedure returns the previous priority of the item or an error code if an error occurs.

Implementation
SWI implemented in kernel folio V20.

Associated Files
item.h
file:///C|/%23%23DDOC/spr/01spr126.html (1 of 2) [4/16/2002 11:13:31 PM]

SetItemPri

ANSI C Prototype

Notes
For certain item types, such as devices, the kernel may change the priority of an item to help optimize
throughput.

Caveats
This function is not implemented for all known item types.

See Also
CreateItem()

file:///C|/%23%23DDOC/spr/01spr126.html (2 of 2) [4/16/2002 11:13:31 PM]

SetNodePri

SetNodePri
Changes the priority of a list node.

Synopsis
uint8 SetNodePri( Node *n, uint8 newpri )

Description
This procedure changes the priority of a node in a list. The kernel arranges lists by priority, with higherpriority nodes coming before lower-priority nodes. When the priority of a node changes, the kernel
automatically rearranges the list to reflect the new priority. The node is moved immediately before the
first node whose priority is lower.

Arguments
n
A pointer to the node whose priority to change.
newpri
The new priority for the node. This can be a value from 0 to 255.

Return Value
The procedure returns the previous priority of the node.

Implementation
Folio call implemented in kernel folio V20.

Associated Files
list.h
ANSI C Prototype
clib.lib
ARM Link Library
file:///C|/%23%23DDOC/spr/01spr127.html (1 of 2) [4/16/2002 11:13:31 PM]

SetNodePri

Caveats
GIGO (garbage in, garbage out)

See Also
InsertNodeFromHead(), InsertNodeFromTail(), UniversalInsertNode()

file:///C|/%23%23DDOC/spr/01spr127.html (2 of 2) [4/16/2002 11:13:31 PM]

Yield

Yield
Give up the CPU to a task of equal priority.

Synopsis
void Yield( void )

Description
In Portfolio, high-priority tasks always have precedence over lower priority tasks. Whenever a high
priority task becomes ready to execute, it will instantly interrupt lower priority tasks and start running.
The lower priority tasks do not get to finish their time quantum, and just get put into the system's ready
queue for future scheduling.
If there are a number of tasks of equal priority which are all ready to run, the kernel does round-robin
scheduling of these tasks. This is a process by which each task is allowed to run for a fixed amount of
time before the CPU is taken away from it, and given to another task of the same priority. The amount of
time a task is allowed to run before being preempted is called the task's "quantum".
The purpose of the Yield() function is to let a task voluntarily give up the remaining time of its
quantum. Since the time quantum is only an issue when the kernel does round-robin scheduling, it means
that Yield() actually only does something when there are multiple ready tasks at the same priority.
However, since the yielding task does not know exactly which task, if any, is going to run next,
Yield() should not be used for implicit communication amongst tasks. The way to cooperate amongst
tasks is using signals, messages, and semaphores.
In short, if there are higher-priority tasks in the system, the current task will only run if the higherpriority tasks are all in the wait queue. If there are lower-priority tasks, these will only run if the current
task is in the wait queue. And if there are other tasks of the same priority, the kernel automatically cycles
through all the tasks, spending a quantum of time on each task, unless a task calls Yield(), which will
cut short its quantum.
If there are no other ready tasks of the same priority as the task that calls Yield(), then that task will
keep running as if nothing happened.
Yield() is only useful in very specific circumstances. If you plan on using it, think twice. In most
cases it is not needed, and using it will result in a decrease in performance.

Implementation
file:///C|/%23%23DDOC/spr/01spr134.html (1 of 2) [4/16/2002 11:13:31 PM]

Yield

SWI implemented in kernel folio V20.

Associated Files
task.h
ANSI C Prototype

See Also
WaitSignal()

file:///C|/%23%23DDOC/spr/01spr134.html (2 of 2) [4/16/2002 11:13:31 PM]

Tasks and Threads

Tasks and Threads
Overview
This chapter provides the background and necessary programming details to create and run tasks and
threads. Tasks and threads, although similar, function differently in certain key respects. For details about
the calls discussed, see Kernel Folio Calls, in 3DO System Programmer's Reference.
This chapter contains the following topics:
●
●
●
●
●
●
●

What Is a Task?
Starting and Ending Tasks
Controlling the State of a Task
Starting and Ending Threads
Loading and Executing Separate Code Modules
Example
Function Calls

file:///C|/%23%23DDOC/spg/02spg.html [4/16/2002 11:13:32 PM]

What Is a Task?

What Is a Task?
Tasks can be viewed as independent programs, with their own unique memory space. Tasks can spawn
other tasks. These spawned tasks (child tasks) quit when the spawning task (parent task) quits, unless the
parent task explicitly transfers ownership of the child task to another task before it quits. Although parent
and child tasks are tied together when it's time to quit, they don't share memory. They can't share
common data structures, and the child task must allocate its own memory pages, which, if its memory
requirements are small, can be wasteful.
Threads are a different kind of spawned or child task, which is more tightly bound to the parent task than
a standard child task. A thread shares the parent task's memory. The ownership of a thread cannot be
transferred to a task that is outside the parent's task family. When the parent dies, each of its threads dies
with it because the threads are considered resources of the parent task.
The calls described in this chapter handle both tasks and threads. To use them, include the task.h header
file in your application. This file contains the definitions for the tag arguments and data structures, plus
the prototypes, for task-related functions.

file:///C|/%23%23DDOC/spg/02spg001.html [4/16/2002 11:13:33 PM]

Starting and Ending Tasks

Starting and Ending Tasks
A user task on a CD can start on boot-up if it's named "LaunchMe." The operating system loads on bootup and runs the executable code in LaunchMe, which starts a task that becomes the child of the shell-a
user task. Once the user task is running, it can spawn child tasks in a manner similar to someone running
a program from a terminal-the original user task uses a filesystem call to supply the filename of a file
containing the executable code of a second task. The kernel launches the second task as a child of the
first task.

Creating a Task
Each task is an item in the system. Tasks are created through the CreateItem() function call, a lowlevel call that returns the item number of the new task. (CreateItem() is discussed in Managing
Items.)
Each task has a TCB (task control block) associated with it. The TCB data structure is created and
maintained by the kernel; a user task can't write to the TCB directly. The settings of the various fields in
the TCB are determined by the kind of task (privileged or non-privileged), the parameters passed to the
kernel when the task is started, and changes made to the task while it runs. The kernel uses the TCB to
allocate and control task resources, memory usage, and so on.
While you can create a task using CreateItem(), it's easier to use the following File folio calls which
in turn call CreateItem():
Item LoadProgram( char *path )
Item LoadProgramPrio( char *path, int32 prio )
LoadProgram() launches a child task that has the same priority as the launching, or parent, task. The
path argument for LoadProgram() contains the pathname for the file containing the executable code
for the task. This parameter can also include arguments for the application, if arguments are required.
Specifying the path argument is very much like specifying a program to run, with arguments, on a
UNIX system.
LoadProgramPrio() allows you to specify a priority for the task. As with LoadProgram(), you
include a path argument that specifies your program file and any arguments that you wish to pass to the
task when it begins. The second argument, priority, specifies a new priority for the child task so it
can run at a higher or lower priority than the parent task.
Both LoadProgram() and LoadProgramPrio() return the item number of the newly started task.
file:///C|/%23%23DDOC/spg/02spg002.html (1 of 3) [4/16/2002 11:13:34 PM]

Starting and Ending Tasks

Example 1 shows how to set up a text string for your program and launch it:
Example 1: Setting up a text string and launching it as a task.
char *cmdline = "mysrc/testprogram arg1 arg2"
Item
task_id
...
{
...
task_id = LoadProgram(cmdline);
...
}

Setting Priority
If you use LoadProgramPrio(), you should get the parent task's priority before setting up a new
priority value for the child task. You can read the current task's priority by reading the n_Priority
field of the ItemNode data structure that's embedded in the TCB of each task- CURRENTTASK>t.n_Priority as shown in Example 2:
Example 2: Getting a parent task's priority.
/* Determine the priority of the current task. */
Priority = CURRENTTASK->t.n_Priority;

The Life of a Task
Child tasks created through LoadProgram() or LoadProgramPrio() allocate completely separate
memory areas for the parent task and its child tasks. Once a child task is launched, it remains in the
system as an item until:
●
●
●

The parent task naturally ends (the program completes its function and dies)
The parent task quits (if it still owns the child task)
The task that owns the child task explicitly deletes it using DeleteItem()

The launching task remains the owner of the child task throughout the life of the child task unless it
passes ownership to another task.

Ending a Task
file:///C|/%23%23DDOC/spg/02spg002.html (2 of 3) [4/16/2002 11:13:34 PM]

Starting and Ending Tasks

Typically, a child task ends when its parent task ends. It's good practice to end a child task, before the
parent task quits, if you no longer need it to free up resources. To end a task, use DeleteItem(),
passing in the task's item number. An error code (a negative number) is returned if an error occurs.
Err DeleteItem( Item i )
Alternatively, a child task can end itself by calling exit() or just return:
void exit (int status)
The function exit() never returns.
Note: The return or exit status can be passed on to the parent task through an exit message if the child
was created with CREATETASK_TAG_MSGFROMCHILD.
Deleting the child task lets the kernel clean up all the task's allocated resources, freeing that space for
other tasks.

file:///C|/%23%23DDOC/spg/02spg002.html (3 of 3) [4/16/2002 11:13:34 PM]

Managing Items

Managing Items
This chapter provides the programming details necessary to create or open items, manage items and,
when finished, delete or close items. For more information about the function calls in this chapter, see
see Kernel Folio Calls, in 3DO System Programmer's Reference.
This chapter contains the following topics:
●
●
●
●
●
●
●

About Items
Creating an Item
Using an Item
Deleting an Item
Opening an Item
Closing an Item
Function Calls

file:///C|/%23%23DDOC/spg/06spg.html [4/16/2002 11:13:34 PM]

About Items

About Items
Items are system-maintained handles for shared resources. Each item contains a globally unique
identification number and a pointer to the resource. Items can refer to any one of many different system
components such as data structures, I/O devices, folios, tasks, and so on. You need to understand and use
the item function calls in order to use these various system components.
The procedure for working with an item is the same, regardless of the item type. The procedure is as
follows:
1.
2.
3.
4.

Define the necessary parameters (tag arguments) for the item you want.
Create or open the item using the tag arguments.
Use the item.
Delete or close the item when you're finished with it.

Portfolio provides a set of kernel calls that manage items while they're in use. These calls allow a task to
check for the existence of an item, find the item number of a named object, get a pointer to an item, lock
and unlock an item, and change the item's priority and owner.
To create items for you application, you need to include the following header files:
●
●
●
●
●

kernelnodes.h
nodes.h
folio.h
item.h
types.h

These header files declare structures, types, parameters, routine definitions, and other definitions needed
for items. You also need the include file for some items that are associated with that folio. For example,
to create an item used by the Audio folio, you'll have to include the audio.h file.
The kernel creates and keeps track of items in system memory. When the kernel creates an item, it
creates a node for that item using the ItemNode data structure:
typedef struct ItemNode
{
struct ItemNode *n_Next; /*pointer to next itemnode in */
/* list */
struct ItemNode *n_Prev; /*pointer to previous itemnode in
file:///C|/%23%23DDOC/spg/06spg001.html (1 of 2) [4/16/2002 11:13:34 PM]

About Items

/* list */
uint8 n_SubsysType;
/* what folio manages this node */
uint8 n_Type;
/* what type of node for the folio */
uint8 n_Priority;
/* queueing priority */
uint8 n_Flags;
/* misc flags, see below */
int32 n_Size;
/* total size of node including hdr */
char *n_Name;
/* ptr to null terminated string or NULL*/
uint8 n_Version;
/* version of of this itemnode */
uint8 n_Revision;
/* revision of this itemnode */
uint8 n_FolioFlags;
/* flags for this item's folio */
uint8 n_ItemFlags;
/* additional system item flags */
Item n_Item;
/* ItemNumber for this data structure */
Item n_Owner;
/* creator, present owner, disposer */
void *n_ReservedP;
/* Reserved pointer */
} ItemNode, *ItemNodeP;
The fields in this data structure define the status of the item and give information about the item. User
tasks can't change their values, but they can look at them for information such as the version and revision
numbers of an item (useful for items such as folios or devices). LookupItem(), described later,
returns a pointer to the ItemNode structure for a specific item.

Creating or Opening an Item
To use most items such as message ports and semaphores, a task must first create them. The system,
however, supplies some items premade on disk: folios, devices, and drivers. To use a folio or a device, a
task opens it instead of creating it from scratch.
The difference between item creation and item opening is important: a created item is owned by the
creating task, which can delete the item at any time. A created item is automatically deleted if the owning
task quits without deleting it. On the other hand, an opened item is owned by the original creator and is
shared among tasks. When a task opens the item, the item is loaded into memory and the kernel registers
the opening task as a user. When another task opens the same item, the kernel registers that task as well.

file:///C|/%23%23DDOC/spg/06spg001.html (2 of 2) [4/16/2002 11:13:34 PM]

Creating an Item

Creating an Item
To create an item, use the CreateItem() function call:
Item CreateItem( int32 ct, const TagArg *p )
CreateItem() takes two arguments. The first, ct, specifies the type of folio in which the item is used
and, the type of item within that folio. This value must always be present-it defines the item type. To
generate this value, use the MkNodeID() macro (described later), which accepts the folio type and folio
item values, and then returns the proper value for CreateItem().
The second argument, p, is a pointer to additional arguments that define the characteristics of the item.
These arguments, known as tag arguments, are specific to each item type, and are discussed later in the
chapter.
CreateItem() returns the item number of the newly created item or an error code (a negative value)
if an error occurs.

Specifying the Item Type
To come up with the item type value for CreateItem(), use MkNodeID():
int32 MkNodeID( Int32 folioNum, Int32 itemTypeNum )
The macro accepts two values: folioNum, which specifies the number of the folio responsible for the
item, and itemTypeNum, which specifies the item type for the item being created. This item type
number is folio-specific. Both values are set by constants defined within the header file for the
appropriate folio. For example, audio.h defines AUDIONODE as the constant that specifies the Audio
folio, and lists audio folio item constants such as AUDIO_TEMPLATE_NODE. The Portfolio I/O Model
lists the constants for all the folio types and folio items used for each folio. To use those constants, you
must be sure to include the .h file of the proper folio. The constants for kernel items, such as message
ports or tasks, are in the kernelnodes.h file.
User tasks can't create the following items: drivers, devices, firqs, and timers. These items can only be
created by privileged tasks.

Tag Arguments
file:///C|/%23%23DDOC/spg/06spg002.html (1 of 5) [4/16/2002 11:13:35 PM]

Creating an Item

The values of the tag arguments determine the values of the fields in an item's ItemNode structure.
CreateItem() creates an ItemNode structure for a new item. The call reads the values of the tag
arguments, interprets them, and writes the corresponding values in the ItemNode fields.
All item types use a standard set of tag arguments defined in item.h. Many items also use additional tag
arguments to specify properties that are unique to those item types.
To define values for an item's associated tag arguments, you must first declare an array of type TagArg,
which is defined in types.h as follows:
Example 1: Defining values for an item's associated tag argument.
typedef struct TagArg
{
uint32 ta_Tag;
TagData ta_Arg;
} TagArg, *TagArgP;
The first field, ta_Tag, is a value that specifies the type of tag argument. The second field, ta_Arg, is
a 32-bit value that contains the actual argument.
The standard tag argument types for all items are defined in item.h. They include:
●
●
●
●
●
●

TAG_ITEM_PRI, sets the priority of an item.
TAG_ITEM_NAME, sets the name of an item.
TAG_ITEM_VERSION, sets the version number of an item.
TAG_ITEM_REVISION, sets the revision number of an item.
TAG_ITEM_UNIQUE_NAME, specifies the item must be uniquely named within its type.
TAG_ITEM_END or TAG_END, ends a list of tag arguments.

The value for each of these arguments is precisely the same as the value for corresponding fields in
ItemNode. When an item is created, these values are simply written into the appropriate ItemNode fields.
You'll find custom tag arguments used for each item type in Portfolio Items, in the 3DO System
Programmer's Reference.
When you provide tag arguments for an item, some of the arguments for that item, are required and some
are optional. You must provide values for required tag arguments. You must also provide specific values
for optional tag arguments, because any values that you do not provide are filled in with default values
by the operating system when it creates the item. Defaults aren't guaranteed to be 0, so you must provide
the value of 0 if that's what you want set for a tag argument.

file:///C|/%23%23DDOC/spg/06spg002.html (2 of 5) [4/16/2002 11:13:35 PM]

Creating an Item

If an entire array of tag arguments is optional and you want to use the system default values for all the
arguments, then you do not need to declare the TagArg array in your application. Instead, pass NULL as
the pointer to the tag arguments argument. When you create a tag arguments array, its general format is:
Example 2: Tag arguments array.
TagArg
TagArrayName[] =
{
command tag,
value assigned,
...
...
TAG_END,
0
};
TagArrayName is the name of the array for the tag argument values; command tag is the name of
the tag argument, and value assigned is the value assigned to that tag argument. The last tag
argument in an array is always called TAG_END, and must be set to 0. This signals the end of the tag
argument list.

VarArgs Tag Arguments
Most functions in Portfolio that accept tag arguments have a split personality. The standard version of a
function has a parameter of type const TagArg *. A varargs version of a function, which is denoted
with the VA suffix, CreateItemVA() for example. The varargs functions offer a much more
convenient way to provide the system with tag arguments.
When you use the varargs versions of a function, you do not need to create arrays of TagArg structures to
pass to the function. Instead, you can construct a tag list on the stack directly within the function call.
Example 3 shows a standard call with TagArg structures:
Example 3: A standard function call with TagArg structures.
{
TagArg tags[3];
tags[0].ta_Tag
tags[0].ta_Arg
tags[1].ta_Tag
tags[1].ta_Arg
tags[2].ta_Tag

=
=
=
=
=

CREATEMSG_TAG_REPLYPORT;
(void *)replyPort;
CREATEMSG_TAG_MSG_IS_SMALL;
0;
TAG_END;

item = CreateItem(MKNODEID(KERNELNODE,MESSAGENODE),tags);
}
file:///C|/%23%23DDOC/spg/06spg002.html (3 of 5) [4/16/2002 11:13:35 PM]

Creating an Item

Instead of this cumbersome and error prone array, you can build the tag list on the stack using the
CreateItemVA() function as shown in Example 4:
Example 4: Using VarArgs to provide tag arguments.
{
item = CreateItemVA(MKNODEID(KERNELNODE,MESSAGENODE),
CREATEMSG_TAG_REPLYPORT,
replyPort,
CREATEMSG_TAG_MSG_IS_SMALL, 0,
TAG_END);
}
As you can see, this method of providing tag arguments is much easier to read and maintain. There is no
casting needed, no array to maintain, and so on.

The Item Number
Once an item is created, the call that creates it returns a positive 32-bit number, which is the unique item
number for the new item. A task uses this number whenever it needs to refer to the item in later calls-this
item number is important, and should be stashed away in a handy variable. If an error occurs, a negative
number is returned.

The Easy Way Out
Now that you've seen the details of creating items using CreateItem(), you should know that most
folios provide higher-level convenience calls that do the same thing for commonly used items in a folio,
which makes programming much easier. The convenience calls usually take arguments that define the
characteristics of the item, translate arguments into the appropriate tag arguments, and then call a lowerlevel item creation call to create the item. Some of those calls include:
●
●
●
●
●
●

CreateIOReq() creates an IOReq.
CreateScreenGroup() creates a screen group.
CreateMsgPort() creates a message port.
CreateMsg() creates a message.
CreateSemaphore() creates a semaphore.
CreateThread() creates a thread.

Generally, use a convenience call whenever one is available for the type of item you want to create.
You'll find details about these calls in the 3DO System Programmer's Reference and in the chapters of
file:///C|/%23%23DDOC/spg/06spg002.html (4 of 5) [4/16/2002 11:13:35 PM]

Creating an Item

this volume that discuss specific folios.

file:///C|/%23%23DDOC/spg/06spg002.html (5 of 5) [4/16/2002 11:13:35 PM]

Portfolio Items

Portfolio Items
This chapter provides lists of item types and system items. The following table is a brief description of
each item.
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●

Attachment The binding of a sample or an envelope to an instrument.
Bitmap Frame buffer into which rendering may be performed.
Cue Audio cue item.
Envelope Audio envelope.
ErrorText A table of error messages.
File A handle to a data file.
File alias A character string for referencing the pathname to a file or a directory of files.
FolioA family of function calls.
Instrument DSP instrument item.
IOReq An item used to communicate between a task and an I/O device.
Knob An item for adjusting an instrument's parameters.
Locale A database of international information.
Message The means of sending data from one task to another.
Message port An item through which a task receives messages.
Probe An item to permit the CPU to read the output of a DSP instrument.
Sample A digital recording of a sound.
ScreenGroup A collection of one or more screens.
Semaphore An item used to arbitrate access to shared resources.
Task A process.
Template A description of an audio instrument.
Tuning An item that contains information for tuning an instrument.
VDL A display control object.

file:///C|/%23%23DDOC/spr/09spr.html [4/16/2002 11:13:36 PM]

Attachment

Attachment
The binding of a sample or an envelope to an instrument.

Description
An attachment is the item to binds a sample or an envelope to a particular instrument.
An Attachment is associated with precisely one Envelope and one Instrument, or one Sample and one
Instrument. An Attachment is said to be an Envelope Attachment if it is attached to an Envelope, or a
Sample Attachment if attached to a Sample.
Sample attachments actually come in two flavors: one for input FIFOs and another for output FIFOs,
defined by the Hook to which the Sample is attached. Both kinds are considered Sample Attachments
and no distinction is made between them.
A single Instrument can have one Envelope Attachment per Envelope hook and one Sample Attachment
per Output FIFO. A single Instrument can have multiple Sample Attachments per Input FIFO, but only
one will be selected to be played when the instrument is started. This is useful for creating multi-sample
instruments, where the sample selected to be played depends on the pitch to be played.
A single Sample or Envelope can have multiple Attachments made to it.

Folio
audio

Item Type
AUDIO_ATTACHMENT_NODE

Create
AttachSample(), AttachEnvelope(), CreateItem()

Delete
DetachSample(), DetachEnvelope(), DeleteItem()

file:///C|/%23%23DDOC/spr/09spr001.html (1 of 3) [4/16/2002 11:13:36 PM]

Attachment

Modify
SetAudioItemInfo()

Use
LinkAttachments(), MonitorAttachment(), ReleaseAttachment(),
StartAttachment(), StopAttachment(), WhereAttachment()

Tags
AF_TAG_CLEAR_FLAGS
(uint32) Modify. Set of AF_ATTF_ flags to clear. Clears every flag for which a 1 is set in ta_Arg.
See also AF_TAG_SET_FLAGS. The final state of any flag is determined by the last occurrence
of that flag in a AF_TAG_SET_FLAGS or AF_TAG_CLEAR_FLAGS.
AF_TAG_ENVELOPE
(Item) Create. Envelope Item to attach to Instrument. Exactly one of AF_TAG_ENVELOPE or
AF_TAG_SAMPLE must be specified.
AF_TAG_HOOKNAME
(const char *) Create. The name of the sample or envelope hook in the instrument to attach to. For
sample hooks, defaults to the first one listed for each instrument. For envelopes, defaults to "Env".
AF_TAG_INSTRUMENT
(Item) Create. Instrument or Template item to attach envelope or sample to. Must be specified
when creating an Attachment.
AF_TAG_SAMPLE
(Item) Create. Sample Item to attach to instrument. Exactly one of AF_TAG_ENVELOPE or
AF_TAG_SAMPLE must be specified.
AF_TAG_SET_FLAGS
(uint32) Create, Modify. Set of AF_ATTF_ flags to set. Sets every flag for which a 1 is set in
ta_Arg. See also AF_TAG_CLEAR_FLAGS. The final state of any flag is determined by the last
occurrence of that flag in a AF_TAG_SET_FLAGS or AF_TAG_CLEAR_FLAGS.
AF_TAG_START_AT
(int32) Create, Modify. Specifies the point at which to start when the attachment is started (with
StartAttachment() or StartInstrument()) .
file:///C|/%23%23DDOC/spr/09spr001.html (2 of 3) [4/16/2002 11:13:36 PM]

Attachment

For sample attachments, specifies a sample frame number in the sample at which to begin playback.
For envelopes, attachments specifies the segment index at which to start.
AF_TAG_TIME_SCALE
(ufrac16) Create. Scales all of the times in the attached envelopes by the supplied ufrac16.
Defaults to 1.0. Only applies to envelope attachments.

Flags
AF_ATTF_FATLADYSINGS
If set, causes the instrument to stop when the attachment finishes playing. This bit can be used to
mark the one or more envelope(s) or sample(s) that are considered to be the determiners of when
the instrument is completely done. For envelopes, the default setting for this flag comes from the
AF_ENVF_FATLADYSINGS flag. Defaults to cleared for samples.
AF_ATTF_NOAUTOSTART
When set, causes StartInstrument() to not automatically start this attachment. This allows
later starting of the attachment by using StartAttachment(). Defaults to cleared (attachment
defaults to starting when instrument is started).

file:///C|/%23%23DDOC/spr/09spr001.html (3 of 3) [4/16/2002 11:13:36 PM]

Bitmap

Bitmap
Frame buffer into which rendering may be performed.

Description
A Bitmap is the logical destination for all graphics rendering operations. Bitmap items describe the
dimensions of the frame buffer, its starting address in RAM, optional clipping area, and other
characteristics.

Folio
graphics

Item Type
BITMAPNODE

Create
CreateBitmap()
CreateBitmapVA()
CreateItem()

Delete
DeleteBitmap()
DeleteItem()

Query
None

Modify
None

file:///C|/%23%23DDOC/spr/09spr002.html (1 of 3) [4/16/2002 11:13:37 PM]

Bitmap

Use
CreateScreenGroup()
DisplayOverlay()
DrawCels()
GetPixelAddress()
SetCEControl()
SetCEWatchDog()
SetClipHeightt()
SetClipOrigin()
SetClipWidth()
SetReadAddress()
ReadPixel()
ResetReadAddress()
WritePixel()

Tags
The following tags must be present:
CBM_TAG_WIDTH(int32)
Sets the bitmap width, in pixels.
CBM_TAG_HEIGHT(int32)
Specifies the bitmap height, in pixels.
CBM_TAG_BUFFER(void *)
Specifies the starting address of the bitmap buffer.
The following tags are optional:
CBM_TAG_CLIPWIDTH(int32)
Specifies the width of the clipping region, in pixels. (default: the value of CBM_TAG_WIDTH)
CBM_TAG_CLIPHEIGHT(int32)
Specifies the height of the clipping region, in pixels. (default: the value of CBM_TAG_HEIGHT)

file:///C|/%23%23DDOC/spr/09spr002.html (2 of 3) [4/16/2002 11:13:37 PM]

Bitmap

CBM_TAG_CLIPX(int32)
Specifies the left edge of the clipping region, in pixels. (default: 0)
CBM_TAG_CLIPY(int32) Specifies the top edge of the clipping region, in pixels. (default: 0)
CBM_TAG_WATCHDOGCTR(int32)
Specifies the cel engine timeout value, in msec. (default: 1000000)
CBM_TAG_CECONTROL(uint32)
Specifies the CEControl register value to be used when this bitmap is being rendered to by the cel
engine. (default: (B15POS_PDC | B0POS_PPMP | CFBDSUB | CFBDLSB_CFBD0 |
PDCLSB_PDC0) )

file:///C|/%23%23DDOC/spr/09spr002.html (3 of 3) [4/16/2002 11:13:37 PM]

Cue

Cue
Audio Cue Item.

Description
This Item type is used to receive completion notification from the Audio folio for these kinds of
operations:
sample playback completion
envelope completion
audio timer request completion
Each Cue has a signal bit associated with it. Because signals are task-relative, Cues cannot be shared
between multiple tasks.

Folio
audio

Item Type
AUDIO_CUE_NODE

Create
CreateCue()
CreateItem()

Delete
DeleteCue()
DeleteItem()

file:///C|/%23%23DDOC/spr/09spr003.html (1 of 2) [4/16/2002 11:13:38 PM]

Cue

Query
GetCueSignal()

Modify
None

Use
AbortTimerCue()
MonitorAttachment()
SignalAtTime()
SleepUntilTime()

Tags
None

See Also
Attachment

file:///C|/%23%23DDOC/spr/09spr003.html (2 of 2) [4/16/2002 11:13:38 PM]

Envelope

Envelope
Audio envelope.

Description
An envelope is a time-variant control signal which can be used to control parameters of sounds that are to
change over time (e.g. amplitude, frequency, filter characteristics, modulation amount, etc.).
Envelope Items use a function defined by a set of points in time-level space described by an array of
DataTimePairs (defined in audio.h). The function is a continuous set of line segments drawn between the
points in the DataTimePair array.
Envelopes are used in conjunction with Instruments that accept the Envelope Item's data and output the
control signal (e.g. envelope.dsp).

Folio
audio

Item Type
AUDIO_ENVELOPE_NODE

Create
CreateEnvelope()
CreateItem()

Delete
DeleteEnvelope()
DeleteItem()

Query
file:///C|/%23%23DDOC/spr/09spr004.html (1 of 3) [4/16/2002 11:13:38 PM]

Envelope

None

Modify
SetAudioItemInfo()

Use
AttachEnvelope()

Tags
AF_TAG_ADDRESS
(const DataTimePair *) Create, Modify. Pointer to array of DataTimePairs used to define the
envelope. All of the points in this array must be sorted in increasing order by time. The length of
the array is specified with AF_TAG_FRAMES.
AF_TAG_CLEAR_FLAGS
(uint32) Create, Modify. Set of AF_ENVF_ flags to clear. Clears every flag for which a 1 is set in
ta_Arg.
AF_TAG_FRAMES
(int32) Create, Modify. Number of DataTimePairs in array pointed to by AF_TAG_ADDRESS.
AF_TAG_MICROSPERUNIT
(int32) Create, Modify. Number of microseconds for each time unit specified in DataTimePairs
and time related envelope tags. Defaults to 1000 on creation, which sets each time unit equal to
one millisecond.
AF_TAG_RELEASEBEGIN
(int32) Create, Modify. Index in DataTimePair array for beginning of release loop. -1 indicates no
loop, which is the default on creation. If not -1, must <= the value set by
AF_TAG_RELEASEEND.
AF_TAG_RELEASEEND
(int32) Create, Modify. Index in DataTimePair array for end of release loop. -1 indicates no loop,
which is the default on creation. If not -1, must >= the value set by AF_TAG_RELEASEBEGIN.
AF_TAG_RELEASEJUMP
(int32) Create, Modify. Index in DataTimePair array to jump to on release. When set, release

file:///C|/%23%23DDOC/spr/09spr004.html (2 of 3) [4/16/2002 11:13:38 PM]

Envelope

causes escape from normal envelope processing to the specified index without disturbing the
current output envelope value. From there, the envelope proceeds to the next DataTimePair from
the current value. -1 to disable, which is the default on creation.
AF_TAG_RELEASETIME
(int32) Create, Modify. The time in units used when looping from the end of the release loop back
to the beginning. Defaults to 0 on creation.
AF_TAG_SET_FLAGS
(uint32) Create, Modify. Set of AF_ENVF_ flags to set. Sets every flag for which a 1 is set in
ta_Arg.
AF_TAG_SUSTAINBEGIN
(int32) Create, Modify. Index in DataTimePair array for beginning of sustain loop. -1 indicates no
loop, which is the default on creation. If not -1, <= the value set by AF_TAG_SUSTAINEND.
AF_TAG_SUSTAINEND
(int32) Create, Modify. Index in DataTimePair array for end of sustain loop. -1 indicates no loop,
which is the default on creation. If not -1, >= the value set by AF_TAG_SUSTAINBEGIN.
AF_TAG_SUSTAINTIME
(int32) Create, Modify. The time in units used when looping from the end of the sustain loop back
to the beginning. Defaults to 0 on creation.

Flags
AF_ENVF_FATLADYSINGS
The state of this flag indicates the default setting for the AF_ATTF_FATLADYSINGS flag
whenever this envelope is attached to an instrument.

See Also
Attachment, Instrument, envelope.dsp

file:///C|/%23%23DDOC/spr/09spr004.html (3 of 3) [4/16/2002 11:13:38 PM]

Instrument

Instrument
DSP Instrument Item.

Description
Instrument items are created from Template items. They correspond to actual instances of DSP code
running on the DSP. Several Instruments can be connected together to create a patch. Instruments can be
played (by starting them), and controlled (by tweaking knobs). An Instrument is monophonic in the sense
that it corresponds to a single voice. Multiple voices require creating an Instrument per voice.

Folio
audio

Item Type
AUDIO_INSTRUMENT_NODE

Create
AllocInstrument()
CreateInstrument() (new for V24)
CreateItem()
LoadInstrument()

Delete
DeleteInstrument() (new for V24)
DeleteItem()
FreeInstrument()

file:///C|/%23%23DDOC/spr/09spr009.html (1 of 4) [4/16/2002 11:13:39 PM]

Instrument

UnloadInstrument()

Query
GetAudioItemInfo()

Modify
None

Use
AbandonInstrument()
AttachEnvelope()
AttachSample()
BendInstrumentPitch()
ConnectInstruments()
CreateProbe() (new for V24)
DisconnectInstruments()
GetKnobName()
GetNumKnobs()
GrabKnob()
PauseInstrument()
ReleaseInstrument()
ResumeInstrument()

file:///C|/%23%23DDOC/spr/09spr009.html (2 of 4) [4/16/2002 11:13:39 PM]

Instrument

StartInstrument()
StopInstrument()
TuneInstrument()

Tags
AF_TAG_AMPLITUDE
(uint32) Start. Value to set instrument's Amplitude knob to before starting instrument (for
instruments that have an Amplitude knob). Valid range is 0..0x7fff. Has no effect if Amplitude
knob is connected to the output from another instrument. This tag is mutually exclusive with
AF_TAG_VELOCITY.
AF_TAG_CALCRATE_DIVIDE
(uint32) (new tag for V24) Create. Specifies the the denominator of the fraction of the total DSP
cycles on which this instrument is to run. The only valid settings at this time are 1 to run on all
DSP cycles (i.e. e and 2 to run on only 1/2 of the DSP cycles (i.e. execute at 22,050 cycles/sec).
Defaults to 1.
AF_TAG_FREQUENCY
(ufrac16) Start. Value to set Frequency knob to in 16.16 Hertz (for instruments that have a
Frequency knob). Has no effect if Frequency knob is connected to the output from another
instrument. This tag is mutually exclusive with AF_TAG_PITCH and AF_TAG_RATE.
AF_TAG_PITCH
(uint32) Start. Value to set Frequency knob (for instruments that have a Frequency knob)
expressed as a MIDI note number. The range is 0 to 127; 60 is middle C. For multisample
instruments, picks the sample associated with the MIDI pitch number. This tag is mutually
exclusive with AF_TAG_FREQUENCY and AF_TAG_RATE.
AF_TAG_PRIORITY
(uint32) Create, Query. The priority of execution in DSP in the range of 0..255, where 255 is the
highest priority. Defaults to 100 on creation.
AF_TAG_RATE
(uint32) Start. Value to set Frequency knob to in instrument-specific frequency units (e.g. phase
increment, proportion of original sample rate) for instruments that have a Frequency knob. Has no
effect if Frequency knob is connected to the output from another instrument. This tag is mutually
exclusive with AF_TAG_FREQUENCY and AF_TAG_PITCH.

file:///C|/%23%23DDOC/spr/09spr009.html (3 of 4) [4/16/2002 11:13:39 PM]

Instrument

AF_TAG_SET_FLAGS
(uint32) Create. AF_INSF_ flags to set at creation time. Defaults to all cleared.
AF_TAG_START_TIME
(AudioTime) Query. Returns the AudioTime value of when the instrument was last started.
AF_TAG_STATUS
(uint32) Query. Returns the current instrument status: AF_STARTED, AF_RELEASED,
AF_STOPPED, or AF_ABANDONED.
AF_TAG_TEMPLATE
(Item) Create. DSP Template Item used from which to create instrument. Note: this tag cannot be
used with CreateInstrument().
AF_TAG_TIME_SCALE
(ufrac16) Start, Release. Scale times for all Envelopes attached to this Instrument. Original value
is derived from the AF_TAG_TIME_SCALE
provided when the Envelope Attachment was made. This value remains in effect until another
AF_TAG_TIME_SCALE is passed to StartInstrument() or ReleaseInstrument().
AF_TAG_VELOCITY
(uint32) Start. MIDI note velocity indicating the value to set instrument's Amplitude knob to
before starting instrument (for instruments that have an Amplitude knob). Valid range is 0..127.
Has no effect if Amplitude knob is connected to the output from another instrument. This tag is
mutually exclusive with AF_TAG_AMPLITUDE.

Flags
AF_INSF_AUTOABANDON
When set, causes instrument to automatically go to the AF_ABANDONED state when stopped
(either automatically because of an AF_ATTF_FATLADYSINGS flag, or manually because of a
StopInstrument() call). Otherwise, the instrument goes to the AF_STOPPED state when
stopped. Note that regardless of the state of this flag, instruments are created in the
AF_STOPPED state.

See Also
Template, Attachment, Knob, Probe

file:///C|/%23%23DDOC/spr/09spr009.html (4 of 4) [4/16/2002 11:13:39 PM]

Template

Template
A description of an audio instrument.

Description
A Template is the description of a DSP audio instrument (including the DSP code, resource
requirements, parameter settings, etc.) from which Instrument items are created. A Template can either
be a standard system instrument template (e.g. envelope.dsp, sampler.dsp, etc) or a custom template
created by ARIA.

Folio
audio

Item Type
AUDIO_TEMPLATE_NODE

Create
CreateInsTemplate()
CreateItem()
DefineInsTemplate()
LoadInsTemplate()

Delete
DeleteItem()
UnloadInsTemplate()

Use

file:///C|/%23%23DDOC/spr/09spr020.html (1 of 3) [4/16/2002 11:13:40 PM]

Template

AdoptInstrument()

Tags
AF_TAG_ALLOC_FUNCTION
(void *(*)(uint32 memsize, uint32 memflags)) Create. Sets custom memory allocation function to
be called during template creation for objects that can be created in user memory. Currently this
only applies to samples embedded in ARIA instruments. Defaults to AllocMem(). If you supply
a custom allocation function you must also provide a custom free function with
AF_TAG_FREE_FUNCTION.
AF_TAG_DEVICE
(Item) Create. Audio device Item for instrument template. 0 indicates the default audio device, the
DSP, which is the only valid audio device item at the present time.
AF_TAG_FREE_FUNCTION
(void (*)(void *memptr, uint32 memsize)) Create. Sets custom memory free function to be called
during template deletion. Defaults to FreeMem(). If you supply a custom free function you must
also provide a custom allocation function with AF_TAG_ALLOC_FUNCTION.
AF_TAG_IMAGE_ADDRESS
(const char *) Create. Specifies a memory location containing a template file image. Must use in
conjunction with AF_TAG_IMAGE_LENGTH. Mutually exclusive AF_TAG_NAME.
AF_TAG_IMAGE_LENGTH
(uint32) Create. Specifies number of bytes in template file image pointed to by
AF_TAG_IMAGE_ADDRESS.
AF_TAG_LEAVE_IN_PLACE
(bool) Create. When TRUE and used in conjunction with AF_TAG_IMAGE_ADDRESS, causes
any user memory objects read from the template file that would otherwise be copied into freshly
allocated memory, to be used in-place (i.e. point to a part of the file image instead of allocating
more memory). Currently this is only applies to samples embedded in an ARIA instrument.
Mutually exclusive with AF_TAG_ALLOC_FUNCTION. See Sample Item and
CreateSample() for more details and caveats.
Note that sample data may have to be moved down two bytes to align it properly for Portfolio DMA.
This will destroy the sample image so that it cannot be reused.
AF_TAG_NAME
(const char *) Create. Name of template file to load. Mutually exclusive with
AF_TAG_IMAGE_ADDRESS.
file:///C|/%23%23DDOC/spr/09spr020.html (2 of 3) [4/16/2002 11:13:40 PM]

Template

See Also
Instrument, Attachment

file:///C|/%23%23DDOC/spr/09spr020.html (3 of 3) [4/16/2002 11:13:40 PM]

Knob

Knob
An item for adjusting an Instrument's parameters.

Description
A Knob is an Item for adjusting an Instrument's parameters.

Folio
audio

Item Type
AUDIO_KNOB_NODE

Create
CreateItem()
GrabKnob()

Delete
DeleteItem()
ReleaseKnob()

Query
GetAudioItemInfo()

Modify
None

Use
file:///C|/%23%23DDOC/spr/09spr011.html (1 of 2) [4/16/2002 11:13:40 PM]

Knob

TweakKnob()
TweakRawKnob()

Tags
AF_TAG_CURRENT
(int32) Query. Returns the current raw value of knob.
AF_TAG_DEFAULT
(int32) Query. Returns the default raw value of knob.
AF_TAG_INSTRUMENT
(Item) Create. Specifies from which instrument to grab knob.
AF_TAG_MAX
(int32) Query. Returns maximum raw value of knob.
AF_TAG_MIN
(int32) Query. Returns minimum raw value of knob.
AF_TAG_NAME
(const char *) Create, Query. Knob name. On creation, specifies name of knob to grab. On query,
returns a pointer to knob's name.

See Also
Instrument, Probe

file:///C|/%23%23DDOC/spr/09spr011.html (2 of 2) [4/16/2002 11:13:40 PM]

Probe

Probe
An item to permit the CPU to read the output of a DSP instrument.

Description
A probe is an item that allows the CPU to read the output of a DSP instrument. It is sort of like the
opposite of a knob. Multiple probes can be connected to a single output. A probe does not interfere with
a connection between instruments.

Folio
audio (new for V24)

Item Type
AUDIO_PROBE_NODE

Create
CreateProbe()
CreateItem()

Delete
DeleteProbe()
DeleteItem()

Query
None

Modify
None
file:///C|/%23%23DDOC/spr/09spr015.html (1 of 2) [4/16/2002 11:13:41 PM]

Probe

Use
ReadProbe()

Tags
None

file:///C|/%23%23DDOC/spr/09spr015.html (2 of 2) [4/16/2002 11:13:41 PM]

ErrorText

ErrorText
A table of error messages.

Description
An error text item is a table of error messages. The kernel maintains a list of these items and uses them to
convert a Portfolio error code into a descriptive string.

Folio
kernel

Item Type
ERRORTEXTNODE

Create
CreateItem()

Delete
DeleteItem()

Use
GetSysErr()

Tags
ERRTEXT_TAG_OBJID
(uint32) Create. This tag specifies the 3 6-bit characters that idenify these errors. You use the
Make6Bit() macro to convert from ASCII into the 6-bit character set.
ERRTEXT_TAG_MAXERR
(uint8) Create. Indicates the number of error strings being defined. This corresponds to the
number of entries in the string table.
file:///C|/%23%23DDOC/spr/09spr005.html (1 of 2) [4/16/2002 11:13:41 PM]

ErrorText

ERRTEXT_TAG_TABLE
(char **) Create. A pointer to an array of string pointers. These strings will be used when
converting an error code into a string. The array is indexed by the lower 8 bits of the error code.
ERRTEXT_TAG_MAXSTR
(uint32) Create. Specifies the maximum string length of any string in the string table.

file:///C|/%23%23DDOC/spr/09spr005.html (2 of 2) [4/16/2002 11:13:41 PM]

File

File
A handle to a data file.

Description
A file item is created by the file folio when a file is opened. It is a private item used to maintain context
information about the file being accessed.

Folio
file

Item Type
FILENODE

Create
OpenDiskFile(), ChangeDirectory()

Delete
CloseDiskFile()

file:///C|/%23%23DDOC/spr/09spr006.html [4/16/2002 11:13:41 PM]

file:///C|/%23%23DDOC/spr/02spr016.html

OpenDiskFile
Opens a disk file.

Synopsis
Item OpenDiskFile( char *path )

Description
This function opens a disk file, given an absolute or relative pathname, and returns its item number.

Arguments
path
An absolute or relative pathname (a null- terminated text string) for the file to open, or an alias for
the pathname.

Return Value
The function returns the item number of the opened file (which can be used later to refer to the file), or a
negative error code if an error occurs.

Implementation
SWI implemented in file folio V20.

Associated Files
filefunctions.h

See Also
CloseDiskFile(), OpenDiskFileInDir(), OpenDiskStreams()

file:///C|/%23%23DDOC/spr/02spr016.html [4/16/2002 11:13:42 PM]

CloseDiskFile

CloseDiskFile
Closes a file.

Synopsis
int32 CloseDiskFile( Item fileItem )

Description
Closes a disk file that was opened with a call to OpenDiskFile() or OpenDiskFileInDir().
The specified item may not be used after successful completion of this call.

Arguments
fileItem
The item number of the disk file to close.

Return Value
The function returns a value greater than or equal to 0 if successful or a negative error code if an error
occurs.

Implementation
SWI implemented in file folio V20.

Associated Files
filefunctions.h

See Also
OpenDiskFile(), OpenDiskFileInDir()

file:///C|/%23%23DDOC/spr/02spr003.html [4/16/2002 11:13:42 PM]

OpenDiskFileInDir

OpenDiskFileInDir
Opens a disk file contained in a specific directory.

Synopsis
Item OpenDiskFileInDir( Item dirItem, char *path )

Description
Similar to OpenDiskFile(), this function allows the caller to specify the item of a directory that
should serve as a starting location for the file search.

Arguments
dirItem
The item number of the directory containing the file.
path
A pathname for the file that is relative to the directory specified by the dirItem argument.

Return Value
The function returns the item number of the opened file (which can be used later to refer to the file), or a
negative error code if an error occurs.

Implementation
SWI implemented in file folio V20.

Associated Files
filefunctions.h

See Also
OpenDiskFile(), OpenDirectoryItem(), OpenDirectoryPath(),
OpenDiskStream(), CloseDiskFile()
file:///C|/%23%23DDOC/spr/02spr017.html (1 of 2) [4/16/2002 11:13:42 PM]

OpenDiskFileInDir

file:///C|/%23%23DDOC/spr/02spr017.html (2 of 2) [4/16/2002 11:13:42 PM]

OpenDirectoryItem

OpenDirectoryItem
Opens a directory specified by an item.
Directory *OpenDirectoryItem( Item openFileItem )
This function opens a directory. It allocates a new directory structure, opens the directory, and prepares
for a traversal of the contents of the directory. Unlike OpenDirectoryPath(), you specify the file
for the directory by its item number rather than by its pathname.
openFileItem
The item number of the open file to use for the directory. When you later call CloseDirectory(),
this file item will automatically be deleted for you, you do not need to call CloseDiskFile().
The function returns a pointer to the directory structure that is created or NULL if an error occurs.
Folio call implemented in file folio V20.
When you are done scanning the directory and call CloseDirectory(), the item you gave to
OpenDirectoryItem() will automatically be closed for you. In essence, when you call
OpenDirectoryItem(), you are giving away the File item to the file folio, which will dispose of it
when the directory is closed.
directoryfunctions.h, filesystem.lib
OpenDiskFile(), OpenDiskFileInDir(), OpenDirectoryPath(),
CloseDirectory()

file:///C|/%23%23DDOC/spr/02spr014.html [4/16/2002 11:13:42 PM]

OpenDirectoryPath

OpenDirectoryPath
Opens a directory specified by a pathname.

Synopsis
Directory *OpenDirectoryPath( char *thePath )

Description
This function opens a directory. It allocates a new directory structure, opens the directory, and prepares
for a traversal of the contents of the directory. Unlike OpenDirectoryItem(), you specify the file
for the directory by its pathname rather than by its item number.

Arguments
thePath
An absolute or relative pathname (a null- terminated text string) for the file to use for the
directory, or an alias for the pathname.

Return Value
The function returns a pointer to a directory structure that is created or NULL if an error occurs.

Implementation
Folio call implemented in file folio V20.

Associated Files
directoryfunctions.h, filesystem.lib

See Also
OpenDiskFile(), OpenDiskFileInDir(), OpenDirectoryItem(),
CloseDirectory()

file:///C|/%23%23DDOC/spr/02spr015.html [4/16/2002 11:13:43 PM]

CloseDirectory

CloseDirectory
Closes a directory.

Synopsis
void CloseDirectory( Directory *dir )

Description
This function closes a directory that was previously opened using OpenDirectoryItem() or
OpenDirectoryPath(). All resources get released.

Arguments
dir
A pointer to the directory structure for the directory to close.

Implementation
Folio call implemented in file folio V20.

Associated Files
directoryfunctions.h, filesystem.lib

See Also
OpenDirectoryItem(), OpenDirectoryPath(), ReadDirectory()

file:///C|/%23%23DDOC/spr/02spr002.html [4/16/2002 11:13:43 PM]

ReadDirectory

ReadDirectory
Reads the next entry from a directory.

Synopsis
int32 ReadDirectory( Directory *dir, DirectoryEntry *de )

Description
This routine reads the next entry from the specified directory. It stores the information from the directory
entry into the supplied DirectoryEntry structure. You can then examine the DirectoryEntry structure for
information about the entry.
The most interesting fields in the DirectoryEntry structure are:
de_FileName
The name of the entry.
de_Flags
This contains a series of bit flags that describe characteristics of the entry. Flags of interest are
FILE_IS_DIRECTORY, which indicates the entry is a nested directory and
FILE_IS_READONLY, which tells you the file cannot be written to.
de_Type
This is currently one of FILE_TYPE_DIRECTORY, FILE_TYPE_LABEL, or
FILE_TYPE_CATAPULT.
de_BlockSize
This is the size in bytes of the blocks when reading this entry.
de_ByteCount
The logical count of the number of useful bytes within the blocks allocated for this file.
de_BlockCount
The number of blocks allocated for this file.
You can use OpenDirectoryPath() and ReadDirectory() to scan the list of mounted file
systems. This is done by supplying a path of "/" to OpenDirectoryPath(). The entries that
ReadDirectory() returns will correspond to all of the mounted file systems. You can then look at
file:///C|/%23%23DDOC/spr/02spr019.html (1 of 2) [4/16/2002 11:13:43 PM]

ReadDirectory

the de_Flags field to determine if a file system is readable or not.

Arguments
dir
A pointer to the directory structure for the directory.
de
A pointer to a DirectoryEntry structure in which to receive the information about the next
directory entry.

Return Value
This function returns zero if successful or a negative error code if an error (such as end-of-directory)
occurs.

Implementation
Folio call implemented in file folio V20.

Associated Files
directoryfunctions.h, filesystem.lib

See Also
OpenDirectoryItem(), OpenDirectoryPath()

file:///C|/%23%23DDOC/spr/02spr019.html (2 of 2) [4/16/2002 11:13:43 PM]

OpenDiskStream

OpenDiskStream
Opens a disk stream for stream-oriented I/O.

Synopsis
Stream *OpenDiskStream( char *theName, int32 bSize )

Description
This routine allocates a new stream structure, opens the disk file identified by an absolute or relative
pathname, allocates the specified amount of buffer space, and initiates an asynchronous read to fill the
buffer with the first portion of the file's data. It returns NULL if any of these functions cannot be
performed for any reason.
The bSize field specifies the amount of buffer space to be allocated to the file stream. It may be positive
(giving the number of bytes to be allocated), zero (indicating that a default allocation of two blocks
should be used), or negative (giving the two's complement of the number of blocks worth of memory that
should be allocated).

Arguments
theName
An absolute or relative pathname (a null- terminated text string) for the file to open.
bSize
The size of the buffer to allocate for the stream. This can be (1) a positive value that specifies the
size of the buffer to allocate, in bytes; (2) zero, which specifies to allocate the default buffer
(currently two blocks); or (3) a negative value, the two's complement of which specifies the
number of blocks of memory to allocate for the buffer.

Return Value
The function returns a pointer to the stream structure for the opened file or NULL if an error occurs.

Implementation
Folio call implemented in file folio V20.

file:///C|/%23%23DDOC/spr/02spr018.html (1 of 2) [4/16/2002 11:13:44 PM]

OpenDiskStream

Associated Files
filestreamfunctions.h

See Also
CloseDiskStream(), ReadDiskStream(), SeekDiskStream(), OpenDiskFile()

file:///C|/%23%23DDOC/spr/02spr018.html (2 of 2) [4/16/2002 11:13:44 PM]

CloseDiskStream

CloseDiskStream
Closes a disk stream.

Synopsis
void CloseDiskStream( Stream *theStream )

Description
This function closes a disk stream that was opened with a call to OpenDiskStream(). It closes the
stream's file, deallocates the buffer memory, and releases the stream structure.

Arguments
theStream
A pointer to the stream structure for an open file.

Implementation
Folio call implemented in file folio V20.

Associated Files
filestreamfunctions.h, filesystem.lib

See Also
OpenDiskStream(), ReadDiskStream(), SeekDiskStream()

file:///C|/%23%23DDOC/spr/02spr004.html [4/16/2002 11:13:44 PM]

ReadDiskStream

ReadDiskStream
Reads from a disk stream.

Synopsis
int32 ReadDiskStream( Stream *theStream, char *buffer,int32 nBytes )

Description
This routine transfers the specified number of bytes (or, as many as are left before the end-of-file) from
the stream (beginning at the stream's current position) to the specified buffer. It advances the stream
position past the bytes that have been transferred, and returns the actual number of bytes transferred. It
will initiate an asynchronous read to read additional data into the stream's internal buffer, if possible and
appropriate.

Arguments
theStream
A pointer to the stream structure from which to read.
buffer
A pointer to the buffer into which to read the data.
nBytes
The number of bytes to read.

Return Value
The function returns the actual number of bytes read or a negative error code if an error occurs.

Implementation
Folio call implemented in file folio V20.

Associated Files
filestreamfunctions.h, filesystem.lib
file:///C|/%23%23DDOC/spr/02spr020.html (1 of 2) [4/16/2002 11:13:44 PM]

ReadDiskStream

See Also
CloseDiskStream(), OpenDiskStream(), SeekDiskStream()

file:///C|/%23%23DDOC/spr/02spr020.html (2 of 2) [4/16/2002 11:13:44 PM]

SeekDiskStream

SeekDiskStream
Performs a seek operation on a disk stream.

Synopsis
int32 SeekDiskStream( Stream *theStream, int32 offset,enum SeekOrigin
whence )

Description
This function does a seek operation on a stream file, thereby changing the I/O byte position within the
file. After calling this function, data transfers start with the first byte at the new file position. The whence
argument specifies whether the operation is to be relative to either the beginning or end of the file or to
the current position in the file. The offset argument specifies the number of bytes of offset relative to the
whence position. The result is the actual absolute file position that results from the seek or an error code
if anything went wrong.
The offset is specified in any of three ways: absolute (positive) byte offset from the beginning of file
(SEEK_SET); relative byte offset from the current position in the file (SEEK_CUR); or absolute
(negative) byte offset from the end of the file (SEEK_END).
This function doesn't actually perform the seek, or do any I/O, or invalidate the data in the stream, or
abort a read-ahead in progress. It simply stores the desired offset and a "please seek" request into the
stream structure. The actual seeking, if any, occurs on the next call to ReadDiskStream().
Seeks are very efficient if they are backward seeks that don't take you outside of the current block, or
forward seeks that don't take you outside of the amount of data actually read ahead into the buffer. Short
seeks of this nature simply adjust the pointers, and then allow the read to continue from the appropriate
place in the buffer.
Seeks that move you backward outside of the current block or forward past the amount of data in the
buffer force all of the data in the buffer to be flushed. Data from the sought after portion of the file will
be read into the buffer (synchronously) and the read will be completed. As a result, you'll see some
latency when you issue the ReadDiskStream call.
If you wish to do a seek-ahead that is, you wish to seek to a specified location in the file but not
necessarily read anything immediately the best thing to do is a SeekDiskStream followed immediately by
a zero-byte ReadDiskStream. This is a special case that will start the read-ahead for the data you're
seeking, and then return without waiting for the I/O to complete. When you issue a non-zero-length
file:///C|/%23%23DDOC/spr/02spr021.html (1 of 3) [4/16/2002 11:13:45 PM]

SeekDiskStream

ReadDiskStream some time later, the data will probably have been read in, and there will be no delay in
accessing it.

Arguments
theStream
A pointer to an open Stream. "offset" is a byte offset into the file, and whence is SEEK_SET,
SEEK_CUR, or SEEK_END.
offset
Specified in any of three ways: absolute (positive) byte offset from the beginning of file
(SEEK_SET); relative byte offset from the current position in the file (SEEK_CUR); or absolute
(negative) byte offset from the end of the file (SEEK_END).
whence
The anchor point (either the beginning of the file, the current position, or the end of the file) to
which the offset should be applied to create the new file position.

Return Value
The function returns the actual (absolute) offset to which the seek occurs or a negative error code if (1)
the offset is outside of the legal range; (2) the whence field contains an illegal value; or (3) there was any
other problem.

Implementation
Folio call implemented in file folio V20.

Associated Files
filestreamfunctions.h, filesystem.lib

Notes
Seeks that move backward outside the current block or forward past the amount of data in the buffer
flush all of the data from the buffer. Data from the sought-after portion of the file is read synchronously
into the buffer and the read operation is then completed. As a result, you'll see some latency when you
call ReadDiskStream().
To perform a seek-ahead (seeking to an actual physical location in the file but not necessarily read
file:///C|/%23%23DDOC/spr/02spr021.html (2 of 3) [4/16/2002 11:13:45 PM]

SeekDiskStream

anything immediately), call SeekDiskStream() followed immediately by a zero-byte
ReadDiskStream(). This is a special case that starts the read-ahead for the data you're seeking. You
then return without waiting for the I/O to complete. Later, you can call ReadDiskStream() with a
non-zero read-length value, and if the data has been read in, you have immediate access to it.

See Also
CloseDiskStream(), OpenDiskStream(), ReadDiskStream()

file:///C|/%23%23DDOC/spr/02spr021.html (3 of 3) [4/16/2002 11:13:45 PM]

ChangeDirectory

ChangeDirectory
Changes the current directory.

Synopsis
Item ChangeDirectory( char *path )

Description
Changes the current task's working directory to the absolute or relative location specified by the path, and
returns the item number for the directory.

Arguments
path
An absolute or relative pathname for the new current directory.

Return Value
The function returns the item number of the new directory or a negative error code if an error occurs.

Implementation
SWI implemented in file folio V20.

Associated Files
filefunctions.h

See Also
GetDirectory()

file:///C|/%23%23DDOC/spr/02spr001.html [4/16/2002 11:13:45 PM]

GetDirectory

GetDirectory
Gets the item number and pathname for the current directory.

Synopsis
Item GetDirectory( char *pathBuf, int32 pathBufLen )

Description
This function returns the item number of the calling task's current directory. If pathBuf is non-NULL, it
must point to a buffer of writable memory whose length is given in pathBufLen; the absolute pathname
of the current working directory is stored into this buffer.

Arguments
pathBuf
A pointer to a buffer in which to receive the absolute pathname for the current directory. If you do
not want to get the pathname string, use NULL as the value of this argument.
pathBufLen
The size of the buffer pointed to by the pathBuf argument, in bytes, or zero if you don't provide a
buffer.

Return Value
The function returns the item number of the current directory.

Implementation
SWI implemented in file folio V20.

Associated Files
filefunctions.h

See Also

file:///C|/%23%23DDOC/spr/02spr010.html (1 of 2) [4/16/2002 11:13:46 PM]

GetDirectory

ChangeDirectory()

file:///C|/%23%23DDOC/spr/02spr010.html (2 of 2) [4/16/2002 11:13:46 PM]

File alias

File alias
A character string for referencing the pathname to a file or a directory of files.

Description
A file alias is a character string for referencing the pathname to a file or directory of files on disk.
Whenever the file folio parses pathnames, it looks for path components starting with $, and treats the rest
of the component at the name of an alias. The file folio then finds the alias of that name, and extracts a
replacement string from the alias to use as the path component.

Folio
file

Item Type
FILEALIASNODE

Create
CreateAlias()

Delete
DeleteItem()

file:///C|/%23%23DDOC/spr/09spr007.html [4/16/2002 11:13:46 PM]

CreateAlias

CreateAlias
Creates a file system alias.

Synopsis
Item CreateAlias( char *aliasPath, char *realPath )

Description
This function creates an alias for a file. The alias can be used in place of the full pathname for the file.
Note that the file system maintains separate alias entries for each task.

Arguments
aliasPath
The alias name.
realPath
The substitution string for the alias.

Return Value
The function returns the item number for the file alias that is created, or a negative error code if an error
occurs.

Implementation
SWI implemented in file folio V20.

Associated Files
filefunctions.h

See Also
OpenDiskFile(), OpenDiskFileInDir()

file:///C|/%23%23DDOC/spr/02spr005.html [4/16/2002 11:13:46 PM]

Folio

Folio
A family of function calls.

Description
A folio is a family of function calls available in the Portfolio operating system.
Folios provide a standard way to package groups of related functions. Portfolio is composed of a number
of folios, such as the kernel folio, the graphics folio, and the compression folio. Some folios are
permanent, such as the kernel folio, while other are demand-loaded, which means they only exist when
they are needed.
You can create folios for your own use. It is a convenient way to share code amongst multiple
independant tasks or threads.

Folio
kernel

Item Type
FOLIONODE

Create
CreateItem(), CreateNamedItem(), CreateVersionedItem()

Delete
DeleteItem()

Query
FindItem(), FindFolio(), FindNamedNode(), FindVersionedItem()

Modify
file:///C|/%23%23DDOC/spr/09spr008.html (1 of 2) [4/16/2002 11:13:46 PM]

Folio

OpenItem(), CloseItem(), FindAndOpenItem(), FindAndOpenFolio()

Tags
CREATEFOLIO_TAG_NUSERVECS
(uint32) Create. This value indicates the number of elements in the function table.
CREATEFOLIO_TAG_USERFUNCS
(void *) Create. A pointer to a table of function pointers. Once the folio is created, clients of the folio
will be able to call the functions within this table.

file:///C|/%23%23DDOC/spr/09spr008.html (2 of 2) [4/16/2002 11:13:46 PM]

IOReq

IOReq
An item used to communicate between a task and an I/O device.

Description
An IOReq item is used to carry information from a client task to a device in order to have the device
perform some operation. Once the device is stores return information in the IOReq, and returns it to the
client task.

Folio
kernel

Item Type
IOREQNODE

Create
CreateIOReq(), CreateItem()

Delete
DeleteIOReq(), DeleteItem()

Query
FindItem()

Modify
SetItemOwner(), SetItemPri()

Use
SendIO(), DoIO(), AbortIO(), WaitIO(), CheckIO()
file:///C|/%23%23DDOC/spr/09spr010.html (1 of 2) [4/16/2002 11:13:47 PM]

IOReq

Tags
CREATEIOREQ_TAG_REPLYPORT
(Item) Create. The item number of a message port.This is where the device will send a message
whenever an I/O operation completes. This argument is optional. If you do not specify it, the device will
send your task the SIGF_IODONE signal instead of a message.
CREATEIO_TAG_DEVICE
(Item) Create. This specifies the item number of the device that this IOReq will be used to
communicate with. This item number is obtained by calling OpenNamedDevice() or
FindAndOpenNamedDevice().

file:///C|/%23%23DDOC/spr/09spr010.html (2 of 2) [4/16/2002 11:13:47 PM]

Locale

Locale
A database of international information.

Description
A Locale structure contains a number of definitions to enable a title to operate transparently accross a
wide range of cultural and language environments.

Folio
international

Item Type
LOCALENODE

Use
intlOpenLocale(), intlCloseLocale(), intlLookupLocale()

file:///C|/%23%23DDOC/spr/09spr012.html [4/16/2002 11:13:47 PM]

intlOpenLocale

intlOpenLocale
Gains access to a locale item.

Synopsis
Item intlOpenLocale(const TagArg *tags);

Description
This function returns a locale item. You can then use intlLookupLocale() to gain access to the
localization information within the locale item. This information enables software to adapt to different
languages and customs automatically at run-time, thus creating truly international software.

Arguments
tags
A pointer to an array of tag arguments containing extra data for this function. This must currently
always be NULL.

Return Value
The function returns the item number of a locale. You can use intlLookupLocale() to get a pointer
to the locale structure, which contains localization information.

Implementation
Macro implemented in intl.h V24.

Associated Files
intl.h

Notes
Once you are finished with the locale item, you should call intlCloseLocale().

See Also
file:///C|/%23%23DDOC/spr/06spr008.html (1 of 2) [4/16/2002 11:13:47 PM]

intlOpenLocale

intlCloseLocale(), intlLookupLocale()

file:///C|/%23%23DDOC/spr/06spr008.html (2 of 2) [4/16/2002 11:13:47 PM]

intlCloseLocale

intlCloseLocale
Terminates use of a given locale item.

Synopsis
Err intlCloseLocale(Item locItem);

Description
This function concludes the title's use of the given locale item. After this call is made, the locale item
may no longer be used.

Arguments
locItem
The locale item, as obtained from intlOpenLocale().

Return Value
>=0
Item successfully closed.
INTL_ERR_BADITEM
locItem was not an existing locale item.
INTL_ERR_CANTCLOSEITEM
At attempt was made to close this locale item more often than it was opened.

Implementation
Macro implemented in intl.h V24.

Associated Files
intl.h

See Also
file:///C|/%23%23DDOC/spr/06spr001.html (1 of 2) [4/16/2002 11:13:48 PM]

intlCloseLocale

intlOpenLocale(), intlLookupLocale()

file:///C|/%23%23DDOC/spr/06spr001.html (2 of 2) [4/16/2002 11:13:48 PM]

intlLookupLocale

intlLookupLocale
Returns a pointer to a locale structure.

Synopsis
Locale *intlLookupLocale(Item locItem);

Description
This macro returns a pointer to a locale structure. The structure can then be examined and its contents
used to localize titles.

Arguments
locItem
A locale item, as obtained from intlOpenLocale().

Return Value
The macro returns a pointer to a locale structure, which contains localization information, or NULL if the
supplied Item was not a valid locale item.

Implementation
Macro implemented in intl.h V24.

Associated Files
intl.h

Example
{
Item
|t;
Locale *loc;
it = intlOpenLocale(NULL);
0
file:///C|/%23%23DDOC/spr/06spr007.html (1 of 2) [4/16/2002 11:13:48 PM]

intlLookupLocale

{
loc = intlLookupLocale(it);
// you can now read fields in the Locale structure.
e
intlCloseLocale(it);
}
}

See Also
intlOpenLocale(), intlCloseLocale()

file:///C|/%23%23DDOC/spr/06spr007.html (2 of 2) [4/16/2002 11:13:48 PM]

Message

Message
The means of sending data from one task to another.

Description
Messages are used to communicate amongst tasks. Messages come in three flavors: small, standard, and
buffered. The flavors each carry their own type or amount of information. The small message carries
exactly eight bytes of data. Standard messages contain a pointer to some data. Buffered messages contain
an arbitrary amount of data within them.
Messages are closely associated with message ports. In order to send a message, a task must indicate a
destination message port. Essentially, messages shuttle back and forth between message ports, and tasks
can get and put messages from and to message ports.

Folio
kernel

Item Type
MESSAGENODE

Create
CreateMsg(), CreateSmallMsg(), CreateBufferedMsg(), CreateItem()

Delete
DeleteMsg(), DeleteItem()

Query
FindItem(), FindNamedItem(), FindVersionedItem()

Use

file:///C|/%23%23DDOC/spr/09spr013.html (1 of 2) [4/16/2002 11:13:48 PM]

Message

ReplyMsg(), ReplySmallMsg(), SendMsg(), SendSmallMsg(), GetThisMsg(),
GetMsg(), WaitPort()

Tag Arguments
CREATEMSG_TAG_REPLYPORT
(Item) Create. The item number of the message port to use when replying this message. This must be a
port that was created by the same task or thread that is creating the message.
CREATEMSG_TAG_MSG_IS_SMALL
Create. When this tag is present, it specifies that this message should be small. This means that this
message should be used with SendSmallMsg() and ReplySmallMsg(), and can only pass 8 bytes
of information.
CREATEMSG_TAG_DATA_SIZE
(uint32) Create. When this tag is present, it specifies that the message should be buffered. The argument
of this tag specifies the size of the buffer that should be allocated.

file:///C|/%23%23DDOC/spr/09spr013.html (2 of 2) [4/16/2002 11:13:48 PM]

Message port

Message port
An item through which a task receives messages.

Description
A message port is an item through which a task receives messages.

Folio
kernel

Item Type
MSGPORTNODE

Create
CreateMsgPort(), CreateItem()

Delete
DeleteMsgPort(), DeleteItem()

Query
FindMsgPort(), FindItem(), FindNamedItem(), FindVersionedItem()

Use
WaitPort(), GetMsg(), SendMsg(), SendSmallMsg(), ReplyMsg(),
ReplySmallMsg()

Tags
CREATEPORT_TAG_SIGNAL
(int32) Create. Whenever a message arrives at a message port, the kernel sends a signal to the
file:///C|/%23%23DDOC/spr/09spr014.html (1 of 2) [4/16/2002 11:13:49 PM]

Message port

owner of the message port. This tag lets you specify which signal should be sent. If this tag is not
provided, the kernel will allocate a signal for the message port itself.
CREATEPORT_TAG_USERDATA
(void *) Create. Lets you specify the 32-bit value that gets put into the mp_UserData field of the
MsgPort structure. This can be anything you want, and is sometimes useful to idenify a message
port.

file:///C|/%23%23DDOC/spr/09spr014.html (2 of 2) [4/16/2002 11:13:49 PM]

Sample

Sample
A digital recording of a sound.

Description
A Sample Item is a handle to a digital recording of a sound in memory. Samples come in two kinds:
●

●

Ordinary Samples - sample loaded from a sample file, or created from scratch. User memory is
used for samples. CreateSample() and a myriad of special purpose functions create ordinary
samples.
Delay Lines - special samples suitable for receiving the DMA output from delay instruments (e.g.
delaymono.dsp). The memory for delay lines is allocated in system memory. Use
CreateDelayLine() to create a delay line.

Most sample operations can be performed on both kinds of samples.

Folio
audio

Item Type
AUDIO_SAMPLE_NODE

Create
CreateDelayLine()
CreateItem()
CreateSample()
DefineSampleHere()
LoadSample()

file:///C|/%23%23DDOC/spr/09spr016.html (1 of 6) [4/16/2002 11:13:50 PM]

Sample

LoadSampleHere()
ScanSample()

Delete
DeleteDelayLine()
DeleteItem()
UnloadSample()

Query
GetAudioItemInfo()

Modify
SetAudioItemInfo()

Use
AttachSample()
DebugSample()

Tags
Loading:
AF_TAG_NAME
(const char *) Create. Name of sample file to load.
AF_TAG_IMAGE_ADDRESS
(const char *) Create. Specifies a memory location containing a sample file image from which to
read sample. Must use in conjunction with AF_TAG_IMAGE_LENGTH.
AF_TAG_IMAGE_LENGTH

file:///C|/%23%23DDOC/spr/09spr016.html (2 of 6) [4/16/2002 11:13:50 PM]

Sample

(uint32) Create. Specifies number of bytes in sample file image pointed to by
AF_TAG_IMAGE_ADDRESS.
AF_TAG_SCAN
(int32) Create. Specifies the maximum number of bytes of sound data to read from the file. This
can be used to cause the Audio folio to simply load sample parameters without loading sample
data.
AF_TAG_ALLOC_FUNCTION
(void *(*)(uint32 memsize, uint32 memflags)) Create. Sets custom memory allocation function to
be called to allocate sample memory while loading sample file. Defaults to AllocMem(). If you
supply a custom allocation function you must also provide a custom free function with
AF_TAG_FREE_FUNCTION.
AF_TAG_FREE_FUNCTION
(void (*)(void *memptr, uint32 memsize)) Create. Sets custom memory free function to free
sample memory to be called during sample deletion. Defaults to FreeMem(). If you supply a
custom free function you must also provide a custom allocation function with
AF_TAG_ALLOC_FUNCTION.
AF_TAG_LEAVE_IN_PLACE
(bool) When TRUE, causes sample being read from AF_TAG_IMAGE_ADDRESS to be used inplace instead of allocating more memory to hold the sample data. Mutually exclusive with
AF_TAG_ALLOC_FUNCTION. See CreateSample() for more details and caveats.
Note that sample data may have to be moved down two bytes to align it properly for Opera DMA.
This will destroy the sample image so that it cannot be reused.
AF_TAG_DATA_OFFSET
(uint32) Query. Byte offset in sample file of the beginning of the sample data.
AF_TAG_DATA_SIZE
(uint32) Query. Size of sample data in sample file in bytes. Note that this may differ from the
length of the sample as loaded into memory (as returned by AF_TAG_NUMBYTES).
Data:
AF_TAG_ADDRESS
(void *) Create, Query, Modify. Address of sample data.
This tag, and the all the other Data tags, can be used to query or modify the data address/length of
ordinary samples. They can only be used to query the address/length of a delay line.
file:///C|/%23%23DDOC/spr/09spr016.html (3 of 6) [4/16/2002 11:13:50 PM]

Sample

AF_TAG_FRAMES
(uint32) Create, Query, Modify. Length of sample data expressed in frames. In a stereo sample,
this would be the number of stereo pairs.
AF_TAG_NUMBYTES
(uint32) Create, Query, Modify. Length of sample data expressed in bytes.
Format:
AF_TAG_CHANNELS
(uint32) Create, Query, Modify. Number of channels (or samples per sample frame). For example:
1 for mono, 2 for stereo. Valid range is 1..255.
AF_TAG_WIDTH
(uint32) Create, Query, Modify. Number of bytes per sample (uncompressed). Valid range is 1..2.
AF_TAG_NUMBITS
(uint32) Create, Query, Modify. Number of bits per sample (uncompressed). Valid range is 1..32.
Width is rounded up to the next byte when computed from this tag.
AF_TAG_COMPRESSIONTYPE
(uint32) Create, Query, Modify. 32-bit ID representing AIFC compression type of sample data
(e.g. ID_SDX2). 0 for no compression.
AF_TAG_COMPRESSIONRATIO
(uint32) Create, Query, Modify. Compression ratio of sample data. Uncompressed data has a
value of 1. 0 is illegal.
Loops:
AF_TAG_SUSTAINBEGIN
(int32) Create, Query, Modify. Frame index of the first frame of the sustain loop. Valid range is
0..NumFrames-1. -1 for no sustain loop. Use in conjunction with AF_TAG_SUSTAINEND.
AF_TAG_SUSTAINEND
(int32) Create, Query, Modify. Frame index of the first frame after the last frame in the sustain
loop. Valid range is 1..NumFrames. -1 for no sustain loop. Use in conjunction with
AF_TAG_SUSTAINBEGIN.
AF_TAG_RELEASEBEGIN
(int32) Create, Query, Modify. Frame index of the first frame of the release loop. Valid range is
file:///C|/%23%23DDOC/spr/09spr016.html (4 of 6) [4/16/2002 11:13:50 PM]

Sample

0..NumFrames-1. -1 for no release loop. Use in conjunction with AF_TAG_RELEASEEND.
AF_TAG_RELEASEEND
(int32) Create, Query, Modify. Frame index of the first frame after the last frame in the release
loop. Valid range is 1..NumFrames. -1 for no release loop. Use in conjunction with
AF_TAG_RELEASEBEGIN.
Tuning:
AF_TAG_BASENOTE
(uint32) Create, Query, Modify. MIDI note number for this sample when played at the original
sample rate (as set by AF_TAG_SAMPLE_RATE). Defaults to middle C (60). This defines the
frequency conversion reference note for the StartInstrument() AF_TAG_PITCH tag.
AF_TAG_DETUNE
(int32) Create, Query, Modify. Amount to detune the MIDI base note in cents to reach the original
pitch. Must be in the range of -100 to 100.
AF_TAG_SAMPLE_RATE
(ufrac16) Create, Query, Modify. Original sample rate for sample expressed in 16.16 fractional
Hz. Defaults to 44,100 Hz.
AF_TAG_BASEFREQ
(ufrac16) Query. The frequency of the sample, expressed in 16.16 Hz, when played at the original
sample rate. This value is computed from the other tuning tag values.
Multisample:
AF_TAG_LOWNOTE
(uint32) Create, Query, Modify. Lowest MIDI note number at which to play this sample when
part of a multisample. StartInstrument() AF_TAG_PITCH tag is used to perform
selection. Valid range is 0 to 127. Defaults to 0.
AF_TAG_HIGHNOTE
(uint32) Create, Query, Modify. Highest MIDI note number at which to play this sample when
part of a multisample. Valid range is 0 to 127. Defaults to 127.

Notes
Sample creation tags have a lot mutual interaction. See CreateSample() for a complete explanation
of this.

file:///C|/%23%23DDOC/spr/09spr016.html (5 of 6) [4/16/2002 11:13:50 PM]

Sample

Caveats
There's currently no way to enforce that memory pointed to by AF_TAG_ADDRESS or file image
memory used with AF_TAG_LEAVE_IN_PLACE is actually of MEMTYPE_AUDIO. Be careful.
All sample data, loop points, and lengths must be quad-byte aligned. For example, a 1-channel, 8-bit
sample (which has 1 byte per frame) is only legal when the lengths and loop points are at multiples of 4
frames. For mono ADPCM samples (which have only 4 bits per frame), lengths and loop points must be
at multiples of 8 frames. The Audio folio, however, does not report any kind of an error for using nonquad-byte aligned sample data. Sample addresses, lengths, and loop points, are internally truncated to
quad-byte alignment when performing the DMA without warning. Misalignments may result in noise at
loop points, or slight popping at the beginning and ending of sound playback. It is recommended that you
pay very close attention to sample lengths and loop points when creating, converting, and compressing
samples.
Setting AF_TAG_WIDTH does not set the AF_TAG_NUMBITS attribute (e.g. if you create a sample
with AF_TAG_WIDTH set to 1, GetAudioItemInfo() AF_TAG_NUMBITS will return 16).
Setting AF_TAG_NUMBITS does however correctly update the AF_TAG_WIDTH field.

See Also
Attachment, Instrument, Template, StartInstrument(), sampler.dsp,
delaymono.dsp

file:///C|/%23%23DDOC/spr/09spr016.html (6 of 6) [4/16/2002 11:13:50 PM]

ScreenGroup

ScreenGroup
A collection of one or more screens.

Description
A screen group is a collection of one or more screens.

Folio
graphics

Item Type
SCREENGROUPNODE

Create
CreateScreenGroup()

Delete
DeleteScreenGroup()

Use
AddScreenGroup(), RemoveScreenGroup()

Tags
CSG_TAG_DISPLAYHEIGHT
(uint32) Create. This optional tag lets you specify the visible height of each screen within the
screen group. This determines the number of lines of the bitmaps that make up the screen will be
visible at any one time. When this
CSG_TAG_SCREENCOUNT
(uint32) Create. This optional tag lets you specify the number of screens to create within the
screen group. If the tag is not supplied, then two screens is created.
file:///C|/%23%23DDOC/spr/09spr017.html (1 of 2) [4/16/2002 11:13:50 PM]

ScreenGroup

CSG_TAG_SCREENHEIGHT
(uint32) Create. This optional tag lets you specify the number of lines that make up each screen
within the screen group. When this tag is not supplied, the current default height is used.
CSG_TAG_BITMAPCOUNT
(uint32) Create. This optional tag lets you specify the number of bitmaps per screen. This tag
should currently not be used.
CSG_TAG_BITMAPWIDTH_ARRAY
(uint32 *) Create. This optional tag provides a pointer to an array of width values, indicating the
width of each bitmap.
CSG_TAG_BITMAPHEIGHT_ARRAY
(uint32 *) Create. This optional tag provides a pointer to an array of height values, indicating the
height of each bitmap.
CSG_TAG_BITMAPBUF_ARRAY
(void **) Create. This optional tag points to an array of pointers to memory buffers. This array
must contain as many entries as the screen group has screens. The array points to the memory to
use for bitmaps when creating the screen group. If this tag is not provided, the graphics folio will
allocate memory for the bitmaps itself.
CSG_TAG_VDLTYPE
(uint32) Create. This optional tag specifies the type of VDL for each screen.
CSG_TAG_VDLPTR_ARRAY
(uint32 **) Create. This tag maps the bitmaps to the video display lists. Each element of the array
is a pointer to a VDL.
CSG_TAG_VDLLENGTH_ARRAY
(uint32 *) Create. This optional tag specifies the length in words for each custom VDL referenced
by the CSG_TAG_VDLPTR_ARRAY.
CSG_TAG_SPORTBITS
(uint32) Create. Specifies the memory allocation bits to use when allocating memory for the
screen group, which lets you control from which bank of VRAM an allocation comes from. If this
tag is not supplied, the graphics folio will allocate the memory from any bank of VRAM. The
values you supply to this tag are either (MEMTYPE_BANKSELECT | MEMTYPE_BANK1) or
(MEMTYPE_BANKSELECT | MEMTYPE_BANK2).

file:///C|/%23%23DDOC/spr/09spr017.html (2 of 2) [4/16/2002 11:13:50 PM]

Semaphore

Semaphore
An item used to arbitrate access to shared resources.

Description
Semaphores are used to protect shared resources. Before accessing a shared resource, a task must first try
to lock the associated semaphore. Only one task at a time can have the semaphore locked at any one
moment. This prevents multiple tasks from accessing the same data at the same time.

Folio
kernel

Item Type
SEMA4NODE

Create
CreateSemaphore(), CreateItem()

Delete
DeleteSemaphore(), DeleteItem()

Query
FindSemaphore()

Use
LockSemaphore(), UnlockSemaphore(), LockItem(), UnlockItem()

file:///C|/%23%23DDOC/spr/09spr018.html [4/16/2002 11:13:51 PM]

Task

Task
A process.

Description
A task item contains all the information needed by the kernel to support multitasking. It contains room to
store CPU registers when the associated task context goes to sleep, it contains pointers to various
resources used by the task, and it specifies the task's priority. There is one task item for every task or
thread that exists.

Folio
kernel

Item Type
TASKNODE

Create Call
CreateThread(), ExecuteAsThread(), LoadProgram(), CreateItem()

Delete
DeleteThread(), DeleteItem()

Query
FindTask(), FindItem()

Modify
SetItemOwner(), SetItemPri()

Tags

file:///C|/%23%23DDOC/spr/09spr019.html (1 of 3) [4/16/2002 11:13:51 PM]

Task

CREATETASK_TAG_MAXQ-a value indicating the maximum quanta for the task.
CREATETASK_TAG_PC-initial PC.
CREATETASK_TAG_STACKSIZE-the size of a task's call stack.
CREATETASK_TAG_ARGC-the initial argc value passed to the task when it starts up.
CREATETASK_TAG_ARGP-the initial argp value passed to the task when it starts up.
CREATETASK_TAG_SP-initial stack pointer value (thread only).
CREATETASK_TAG_BASE-the initial r9 value.
TAG_ITEM_NAME
(char *) Create. Provide a pointer to the name of the task.
TAG_ITEM_PRI
(uint8) Create. Provide a priority for the taskin the range 10 to 199. If this tag is not given, the
task will inherit the priority of the current context.
CREATETASK_TAG_PC
(void *) Create. Provide a pointer to the code to be executed.
CREATETASK_TAG_SP
(void *) Create. Provide a pointer to the memory buffer to use as stack for a thread. When this tag
is present, a thread is created. If the tag is not present, then a task is created.
CREATETASK_TAG_STACKSIZE
(uint32) Create. Specifies the size in bytes of the memory buffer reserved for a thread's stack.
CREATETASK_TAG_ARGC
(uint32) Create. A 32-bit value that will be passed to the task or thread being launched as a first
argument. If this is omitted, the first argument will be 0.
CREATETASK_TAG_ARGP
(void *) Create. A 32-bit value that will be passed to the task or thread being launched as a second
argument. If this is omitted, the second argument will be 0.
CREATETASK_TAG_USERONLY
Create. Specifies that a thread being launched will not make any folio calls. This will be the case
file:///C|/%23%23DDOC/spr/09spr019.html (2 of 3) [4/16/2002 11:13:51 PM]

Task

for some threads which are used as pure computation engines. Specifying this tag causes the
thread to use fewer system resources (no supervisor stack is allocated), but prevents the task from
making any calls to a folio.
CREATETASK_TAG_MSGFROMCHILD
(Item) Create. Provides the item number of a message port. The kernel will send a status message
to this port whenever the thread or task being created exits. The message is sent by the kernel after
the task has been deleted. The msg_Result field of the message contains the exit status of the
task. This is the value the task provided to exit(), or the value returned by the task's primary
function. The msg_DataPtr field of the message contains the item number of the task that just
terminated. Finally, the msg_DataSize field contains the item number of the thread or task that
terminated the task. If the task exited on its own, this will be the item number of the task itself. It
is the responsibility of the task that receives the status message to delete it when it is no longer
needed by using DeleteMsg().
CREATETASK_TAG_ALLOCDTHREADSP
Create. When this tag is supplied, it tells the kernel that if this thread dies by itself, by either
returning to the kernel or by calling exit(), then the memory used for its stack must be freed
automatically. When this tag is not provided, you are responsible for freeing the stack whenever
the thread terminates.

file:///C|/%23%23DDOC/spr/09spr019.html (3 of 3) [4/16/2002 11:13:51 PM]

ExecuteAsThread

ExecuteAsThread
Executes previously loaded code as a thread.

Synopsis
Item ExecuteAsThread(CodeHandle code,int32 argc, char **argv,char
*threadName, int32 priority);

Description
This function lets you execute a chunk of code that was previously loaded from disk using
LoadCode(). The code will execute as a thread of the current task.
In order to function correctly, code being run as a thread should be linked with threadstartup.o instead of
the usual cstartup.o.
The argc and argv parameters are passed directly to the main() entry point of the loaded code.
The values you supply for argc and argv are irrelevant to this function. They are simply passed through
to the loaded code. Therefore, their meaning must be agreed upon by the caller of this function and by
the loaded code.
threadName specifies the name of the thread.
priority specifies the priority the new thread should have. Providing a negative priority makes the thread
inherit the priority of the current task or thread.

Arguments
code
A code handle filled in by a previous call to LoadCode().
argc
A value that is passed directly as the argc parameter to the loaded code's main() entry point. This
function doesn't use the value of this argument, it is simply passed through to the loaded code.
argv
A value that is passed directly as the argv parameter to the loaded code's main() entry point. This
file:///C|/%23%23DDOC/spr/02spr009.html (1 of 2) [4/16/2002 11:13:52 PM]

ExecuteAsThread

function doesn't use the value of this argument; it is simply passed through to the loaded code.
threadName
The name of the thread. Should be a descriptive string that identifies this thread.
priority
The priority for the new thread. Supply a negative value to have the thread inherit the priority of
the current task or thread. Priorities for user threads can be in the range of 10 to 199.

Return Value
Returns the item number of the new thread, or a negative error code if the thread could not be created.

Implementation
Folio call implemented in file folio V21.

Associated Files
filefunctions.h

See Also
LoadCode(), UnloadCode(), ExecuteAsSubroutine()

file:///C|/%23%23DDOC/spr/02spr009.html (2 of 2) [4/16/2002 11:13:52 PM]

LoadCode

LoadCode
Loads a binary image into memory, and obtains a handle to it.

Synopsis
Err LoadCode(char *fileName, CodeHandle *code);

Description
This function loads an executable file from disk into memory. Once loaded, the code can be spawned as a
thread, or executed as a subroutine.
In order to work correctly with this and associated functions, the executable file being loaded must have
been linked with threadstartup.o or subroutinestartup.o instead of the usual cstartup.o.
Give this function the name of the executable file to load, as well as a pointer to a CodeHandle variable,
where the handle for the loaded code will be stored. Note, "code" must point to a valid CodeHandle
variable; that's where LoadCode() will put a pointer to the loaded code.
Once you finish using the loaded code, you can remove it from memory by passing the code handle to
the UnloadCode() function.
To execute the loaded code, you must call either the ExecuteAsThread() function or the
ExecuteAsSubroutine()function. Note that if the loaded code is reentrant, the same loaded code
can be spawned multiple times simultaneously as a thread.

Arguments
fileName
A NULL-terminated string indicating the executable file to load.
code
A pointer to a CodeHandle variable, where a handle to the loaded code can be put.

Return Value
Returns > = 0 if successful, or a negative error code it the file could not be loaded.

file:///C|/%23%23DDOC/spr/02spr011.html (1 of 2) [4/16/2002 11:13:52 PM]

LoadCode

Implementation
Folio call implemented in file folio V21.

Associated Files
filefunctions.h

See Also
LoadProgram(), UnloadCode(), ExecuteAsThread(), ExecuteAsSubroutine()

file:///C|/%23%23DDOC/spr/02spr011.html (2 of 2) [4/16/2002 11:13:52 PM]

LoadProgram

LoadProgram
Loads a binary image and spawns it as a task.

Synopsis
Item LoadProgram(char *cmdLine);

Description
This function loads an executable file from disk and launches a new task to execute the code.
You give this function a command line to interpret. The first component of the command line is taken as
the name of the file to load. The entirety of the command line is passed to the new task as argc and argv
in the main() function. The filename component of the command line specifies either a fully qualified
pathname, or a pathname relative to the current directory.
The priority of the new task is identical to the priority of the current task. If you wish the task to have a
different priority, you must use the LoadProgramPrio() function instead.
If a priority was given to the executable being launched using the modbin utility, then the priority that
was specified to modbin will be used for the new task, and not the current priority.

Arguments
cmdLine
A NULL-terminated string indicating the file to load as a task. The string may also contain
arguments for the task being started.

Return Value
The Item number of the newly created task, or a negative error code if the task could not be created.

Implementation
Folio call implemented in file folio V20.

Associated Files
file:///C|/%23%23DDOC/spr/02spr012.html (1 of 2) [4/16/2002 11:13:52 PM]

LoadProgram

filefunctions.h

See Also
LoadProgramPrio(), LoadCode(), ExecuteAsThread()

file:///C|/%23%23DDOC/spr/02spr012.html (2 of 2) [4/16/2002 11:13:52 PM]

LoadProgramPrio

LoadProgramPrio
Loads a binary image and spawns it as a task, with priority.

Synopsis
Item LoadProgramPrio(char *cmdLine, int32 priority);

Description
This function loads an executable file from disk and launches a new task to execute the code.
You give this function a command line to interpret. The first component of the command line is taken as
the name of the file to load. The entirety of the command line is passed to the new task as argc and argv
in the main() function. The filename component of the command line specifies either a fully qualified
pathname, or a pathname relative to the current directory.
The priority argument specifies the task priority to use for the new task. If you simply want the new task
to have the same priority as the current task, use the LoadProgram() function instead. Alternatively,
passing a negative priority to this function will also give the new task the same priority as the current
task.
If a priority was given to the executable being launched using the modbin utility, then the priority you
give to this function is ignored, and the priority that was specified to modbin will be used instead.

Arguments
cmdLine
A NULL-terminated string indicating the file to load as a task. The string may also contain
arguments for the task being started.
priority
The task priority for the new task. For user code, this can be in the range 10 to 199.

Return Value
The item number of the newly created task, or a negative error code if the task could not be created.

Implementation
file:///C|/%23%23DDOC/spr/02spr013.html (1 of 2) [4/16/2002 11:13:53 PM]

LoadProgramPrio

Folio call implemented in file folio V20.

Associated Files
filefunctions.h

See Also
LoadProgram(), LoadCode(), ExecuteAsThread()

file:///C|/%23%23DDOC/spr/02spr013.html (2 of 2) [4/16/2002 11:13:53 PM]

UnloadCode

UnloadCode
Unloads a binary image previously loaded with LoadCode().

Synopsis
Err UnloadCode(CodeHandle code);

Description
This function frees any resources allocated by LoadCode(). Once UnloadCode() has been called,
the code handle supplied becomes invalid and cannot be used again.

Arguments
code
A code handle filled in by a previous call to LoadCode().

Return Value
Returns > = 0 if successful, or a negative error code of the CodeHandle supplied is somehow invalid.

Implementation
Folio call Implemented in file folio V21.

Associated Files
filefunctions.h

See Also
LoadCode()

file:///C|/%23%23DDOC/spr/02spr022.html [4/16/2002 11:13:53 PM]

ExecuteAsSubroutine

ExecuteAsSubroutine
Executes previously loaded code as a subroutine.

Synopsis
int32 ExecuteAsSubroutine(CodeHandle code,int32 argc, char **argv);

Description
This function lets you execute a chunk of code that was previously loaded from disk using
LoadCode(). The code will run as a subroutine of the current task or thread.
In order to function correctly, code being run as a subroutine should be linked with subroutinestartup.o
instead of the usual cstartup.o.
The argc and argv parameters are passed directly to the main() entry point of the loaded code. The
return value of this function is the value returned by main() of the code being run.
The values you supply for argc and argv are irrelevant to this function. They are simply passed through
to the loaded code. Therefore, their meaning must be agreed upon by the caller of this function, and by
the loaded code.

Arguments
code
A code handle filled in by a previous call to LoadCode().
argc
A value that is passed directly as the argc parameter to the loaded code's main() entry point. This
function doesn't use the value of this argument, it is simply passed through to the loaded code.
argv
A value that is passed directly as the argv parameter to the loaded code's main() entry point. This
function doesn't use the value of this argument, it is simply passed through to the loaded code.

Return Value
Returns the value that the loaded code's main() function returns.
file:///C|/%23%23DDOC/spr/02spr008.html (1 of 2) [4/16/2002 11:13:53 PM]

ExecuteAsSubroutine

Implementation
Folio call implemented in file folio V21.

Caveats
If code being executed as a subroutine calls exit(), the parent thread or task will exit, not just the
subroutine code.

Associated Files
filefunctions.h

See Also
LoadCode(), UnloadCode(), ExecuteAsThread()

file:///C|/%23%23DDOC/spr/02spr008.html (2 of 2) [4/16/2002 11:13:53 PM]

Tuning

Tuning
An item that contains information for tuning an instrument.

Description
A tuning item contains information for converting MIDI pitch numbers to frequency for an instrument or
template. The information includes an array of frequencies, and 32-bit integer values indicating the
number of pitches, notes in an octave, and the lowest pitch for the tuning frequency. See the
CreateTuning() call in the "Audio folio Calls" chapter in this manual for more information.

Folio
audio

Item Type
AUDIO_TUNING_NODE

Create
CreateItem()
CreateTuning()

Delete
DeleteItem()
DeleteTuning()

Query
None

Modify

file:///C|/%23%23DDOC/spr/09spr021.html (1 of 2) [4/16/2002 11:13:54 PM]

Tuning

SetAudioItemInfo()

Use
TuneInsTemplate()
TuneInstrument()

Tags
AF_TAG_ADDRESS
(const ufrac16 *) Create, Modify. Array of frequencies in 16.16 Hz to be used as a lookup table.
AF_TAG_BASENOTE
(uint32) Create, Modify. MIDI note number that should be given the first frequency in the
frequency array in the range of 0..127.
AF_TAG_FRAMES
(uint32) Create, Modify. Number of frequencies in array pointed to by AF_TAG_ADDRESS.
This value must be >= NotesPerOctave.
AF_TAG_NOTESPEROCTAVE
(uint32) Create, Modify. Number of notes per octave. This is used to determine where in the
frequency array to look for notes that fall outside the range of BaseNote..BaseNote+Frames-1.
This value must be <= Frames.

file:///C|/%23%23DDOC/spr/09spr021.html (2 of 2) [4/16/2002 11:13:54 PM]

VDL

VDL
A display control object.

Description
A VDL is a collection of hardware control values which are used to manipulate the display
characteristics in strange and bizarre ways. VDLs tell the display hardware where the frame buffer is, its
geometry, what colors to use, and other characteristics.
Because of their dependency on specific underlying hardware, whose quirks may change from
manufacturer to manufacturer, the use of custom VDLs is discouraged at this time.

Folio
graphics

Item Type
VDLNODE

Create
CreateVDL()
CreateVDLVA()
CreateItem()
SubmitVDL()

Delete
DeleteItem()
DeleteVDL()
DeleteItem()

file:///C|/%23%23DDOC/spr/09spr022.html (1 of 3) [4/16/2002 11:13:54 PM]

VDL

Query
None

Modify
ModifyVDL()
ModifyVDLVA()

Use
SetVDL()

Tags
The following tags are only valid when creating a VDL item:
CREATEVDL_TAG_VDLTYPE(int32) The type of VDL you wish to create. The currently supported
types are:
●

●

VDLTYPE_FULL: Contains complete description of all display characteristics.
CREATEVDL_TAG_DISPLAYTYPE(int32) The type of display for which this VDL is intended.
This is one of the DI_TYPE_ values in graphics.h.

●

CREATEVDL_TAG_LENGTH(int32) The length of the submitted VDL, in 32-bit words.

●

CREATEVDL_TAG_HEIGHT(int32) The number of display lines this VDL will affect.

CREATEVDL_TAG_DATAPTR(void *) Pointer to array of VDL instructions you wish to be validated
and converted to a VDL item.
The following tags may be used to create or modify a VDL item:
CREATEVDL_TAG_SLIPSTREAM(Boolean)
Enables/disables slipstream (non-zero == enable). When enabled, all pixels in the display buffer
with a value of 000 are made transparent.

file:///C|/%23%23DDOC/spr/09spr022.html (2 of 3) [4/16/2002 11:13:54 PM]

VDL

CREATEVDL_TAG_HAVG(Boolean)
Enables/disables horizontal interpolation (non-zero == enable).
CREATEVDL_TAG_VAVG(Boolean)
Enables/disables vertical interpolation (non-zero == enable).
CREATEVDL_TAG_HSUB(int32)
Sets the source for horizontal subpositioning bits as follows: 0:Force to zero. 1:Force to one.
2:Take from display buffer.
CREATEVDL_TAG_VSUB(int32)
Sets the source for vertical subpositioning bits as follows: 0:Force to zero. 1:Force to one. 2:Take
from display buffer.
CREATEVDL_TAG_SWAPHV(Boolean)
Enables/disables swapping of the horizontal and vertical subpositioning bits: 0:Bit 0 == HSub; bit
15 == VSub (default) non-0:Bit 0 == VSub; bit 15 == HSub
CREATEVDL_TAG_CLUTBYPASS(Boolean)
Enables/disables the availability of CLUT bypass mode for pixels where bit 15 is set (non-zero ==
enable).
CREATEVDL_TAG_WINHAVG(Boolean)
Enables/disables horizontal interpolation for pixels making use of CLUT bypass mode (non-zero
== enable).
CREATEVDL_TAG_WINVAVG(Boolean)
Enables/disables vertical interpolation for pixels making use of CLUT bypass mode (non-zero ==
enable).
CREATEVDL_TAG_WINHSUB(int32)
Sets the source for horizontal subpositioning bits for pixels making use of CLUT bypass mode as
follows: 0:Force to zero. 1:Force to one. 2:Take from display buffer.
CREATEVDL_TAG_WINVSUB(int32)
Sets the source for vertical subpositioning bits for pixels making use of CLUT bypass mode as
follows: 0:Force to zero. 1:Force to one. 2:Take from display buffer.
CREATEVDL_TAG_WINSWAPHV(Boolean)
Enables/disables swapping of the horizontal and vertical subpositioning bits for pixels making use
of CLUT bypass mode: 0:Bit 0 == HSub; bit 15 == VSub (default) non-0:Bit 0 == VSub; bit 15
== HSub
file:///C|/%23%23DDOC/spr/09spr022.html (3 of 3) [4/16/2002 11:13:54 PM]

Using an Item

Using an Item
Once an item is created or opened, you can manage it with the kernel item calls, which are described
here.

Finding an Item
To find an item by specifying its item type and a set of tag arguments or a name, use these calls.
Item FindItem( int32 cType, const TagArg *tp )
Item FindItemVA( int32 cType, uint32 tags, ...)
Item FindNamedItem( int32 cType, const char *name )
Item FindVersionedItem( int32 cType, const char *name, uint8
vers, uint8 rev )
FindItem() accepts an item type value, which is created by MkNodeID() as it is for the
CreateItem() call. This value specifies the type of the item for which the call should search. The
second argument, tp, is a pointer to an array of tag arguments the call should try to match. When the call
is executed, it looks through the list of items and, if it finds an item of the specified item type whose tag
arguments match those set in the tag argument array, it returns the item number of that item.
FindNamedItem() calls FindItem() after creating a TagArg for the name. When it searches
through the item list, it checks names of all items of the specified type. If it finds a match, it returns the
item number of that item.
FindVersionedItem() accepts cType as its first argument, which is the same type of value as
itemType in the other find calls. It also accepts a name, a version number, and a revision number. It
searches to find the item that matches these specifications, then returns the item number of that item.
All of the item finding calls return a negative number if an error occurred in the search.

Getting a Pointer to an Item
To find the absolute address of an item, use this call:
void *LookupItem( Item i )
LookupItem() takes the item number of the item to locate as its only argument. If it finds the item, it
file:///C|/%23%23DDOC/spg/06spg003.html (1 of 3) [4/16/2002 11:13:55 PM]

Using an Item

returns a pointer to the item's ItemNode structure; if it doesn't find the item, it returns NULL. Once you
have a pointer to the item, you can use it to read the values in the fields of the data structure. The
ItemNode structure is protected by the system, so a user task can't write to it.

Checking If an Item Exists
To see if an item exists, use this call:
void *CheckItem( Item i, uint8 ftype, uint8 ntype )
CheckItem() accepts the item number of the item you want to check, followed by the folio type and
the node type of the item. (ftype and ntype are the same as the arguments accepted by
MkNodeID(), and are supplied with constants defined in appropriate header files.) When executed, the
call returns a NULL if it can't find an item with the specified item number, or if it found an item but it
didn't have the specified folio and node types. If the call finds an item that matches in all respects, it
returns a pointer to that item.

Changing Item Ownership
To change the ownership of an item from one task to another, use this call:
Err SetItemOwner( Item i, Item newOwner )
The first argument of SetItemOwner() is the item number of the item for which to change
ownership; its second argument is the item number of the task that is to be the new owner. The task that
makes this call must be the owner of the item. If ownership transfer fails, the call returns a negative
number (an error code).
When ownership of an item changes, the item is removed from the former owner's resource table and
placed in the new owner's resource table. This allows an item to remain in the system after the original
owner dies; all items owned by a task are removed from the system when the task dies.

Changing an Item's Priority
To change the priority of an item, a task should call:
int32 SetItemPri( Item i, uint8 newpri )
Item priority determines how frequently system resources are allocated to an item. The higher its priority,
file:///C|/%23%23DDOC/spg/06spg003.html (2 of 3) [4/16/2002 11:13:55 PM]

Using an Item

the more often an item has access to the resources. The task must be the owner of the item to change its
priority.
SetItemPri() accepts the item number of the item whose priority you want to change, followed by
an unsigned 8-bit integer which specifies the new priority for the item. Priority values range from 0-255.
The call returns the former priority value of the item if successful, otherwise it returns a negative
number.

file:///C|/%23%23DDOC/spg/06spg003.html (3 of 3) [4/16/2002 11:13:55 PM]

Deleting an Item

Deleting an Item
When a task finishes with an item it owns, it should delete the item from the system to free resources for
other uses. The task can use this call:
Err DeleteItem( Item i )
DeleteItem() accepts the item number of the item to delete. It returns 0 if successful, or an error
code (a negative value) if an error occurs.
Only use DeleteItem() to delete items created with CreateItem(). If you've used a
convenience call to create an item, you must use the corresponding deletion routine. A task must own an
item to delete it.
Once an item is deleted, the kernel does not reuse the item number when it creates new items, to maintain
the integrity of items. When a task tries to use an item number for a deleted item, the kernel informs the
task that the item no longer exists.

file:///C|/%23%23DDOC/spg/06spg004.html [4/16/2002 11:13:55 PM]

Opening an Item

Opening an Item
When a task uses a system- supplied item such as a device or a folio, it opens the item instead of creating
it. To open an item, use these calls:
Item OpenItem( Item FoundItem, void *args )
Item FindAndOpenItem( int32 cType, const TagArg *tags)
Item FindAndOpenItemVA( int32 cType, uint32 tags, ...)
OpenItem() accepts the item number of the resource to be opened (which is found with
FindItem()) and a pointer. Currently, NULL should always be passed in for this argument.
FindAndOpenItem() finds an item and opens it with one call. It works just like FindItem(),
except that it automatically opens the item before returning it to you.

file:///C|/%23%23DDOC/spg/06spg005.html [4/16/2002 11:13:55 PM]

Closing an Item

Closing an Item
When a task finishes using an open item, it should close it so the kernel knows the item is no longer
required by that task. When no tasks require an opened item, the kernel can remove the item from
memory, freeing system resources.
To close an item, use this call:
Err CloseItem( Item i )
CloseItem() accepts the item number of the item to close. It returns 0 if successful or an error code (a
negative value) if an error occurs.

file:///C|/%23%23DDOC/spg/06spg006.html [4/16/2002 11:13:56 PM]

Function Calls

Function Calls
The following kernel function calls control items. See Kernel Folio Calls, in the 3DO System
Programmer's Reference for a complete description of these calls.

Creating Items
The following calls create items:
●
●
●
●
●
●
●
●
●
●

CreateBufferedMsg() Creates a buffered message.
CreateIOReq() Creates an I/O request.
CreateItem() Creates an item.
CreateMsg() Creates a standard message.
CreateMsgPort() Creates a message port.
CreateSemaphore() Creates a semaphore.
CreateSmallMsg) Creates a small message.
CreateThread() Creates a thread.
CreateUniqueMsgPort() Creates a message port with a guaranteed unique name.
CreateUniqueSemaphore() Creates a semaphore with a guaranteed unique name.

Opening Items
The following calls open items:
●
●
●
●
●
●

FindAndOpenDevice() Finds and opens a device item.
FindAndOpenFolio() Finds and opens a folio item.
FindAndOpenItem() Finds and opens an item.
FindAndOpenNamedItem() Finds an item by name and opens it.
OpenItem() Opens a system item.
OpenNamedDevice() Opens the named device.

Managing Items
The following calls manage items:

file:///C|/%23%23DDOC/spg/06spg007.html (1 of 2) [4/16/2002 11:13:56 PM]

Function Calls
●
●
●
●
●
●
●
●
●
●
●
●

CheckItem() Checks to see if an item exists.
FindDevice() Finds a device item by name.
FindFolio() Finds a folio item by name.
FindItem() Finds an item by type and tag arguments.
FindMsgPort() Finds a message port item by name.
FindNamedItem()Finds an item by name.
FindSemaphore() Finds a semaphore item by name.
FindTask()Finds a task item by name.
FindVersionedItem()Finds an item by name and version number.
LookupItem()Gets a pointer to an item.
SetItemOwner()Changes the owner of an item.
SetItemPri()Changes the priority of an item.

Closing and Deleting Items
The following calls close and delete items:
●
●
●
●
●
●
●
●

CloseItem() Closes a system item.
CloseNamedDevice() Closes a device item.
DeleteIOReq() Deletes an IOReq item.
DeleteItem() Deletes an item.
DeleteMsg()Deletes a message item.
DeleteMsgPort()Deletes a message port item.
DeleteSemaphore() Deletes a semaphore item.
DeleteThread()Deletes a thread.

file:///C|/%23%23DDOC/spg/06spg007.html (2 of 2) [4/16/2002 11:13:56 PM]

Controlling the State of a Task

Controlling the State of a Task
A task can be in one of three states at any moment:
●

Running, in which the task is the currently executing task.

●

Ready to run, in which the task is in the ready queue, awaiting execution.

●

Waiting, in which the task is in the wait queue, awaiting an external event to occur, so it becomes
the running task, or if the priority of the current running task is greater than its own, it moves to
the ready queue where it awaits execution.

Each non-privileged task has a priority that ranges from the lowest priority of 10 to the highest priority of
199. Priority determines the order of task execution for tasks that are in the ready queue. The kernel only
executes the tasks in the ready queue with the highest-priority values.
The state of a task is determined partly by its own priority, and partly by the other tasks in the system and
the interactions among them. A task can wait for other tasks to complete certain processing, at which
point it resumes its own processing. Intertask communication is essential because it enables one task to
notify another task on the waiting queue that an external event is complete.
If there are no external events, preemptive multitasking only takes place when tasks of equal priority are
the highest priority tasks in the ready queue. If only one task has the highest-priority, only that task runs,
and all other tasks wait until the task finishes or is replaced by another task with higher priority.

Yielding the CPU to Another Task
A task that executes a Yield() call cedes its CPU time immediately to another task with the same
priority. The Yield() call, which neither takes arguments nor returns anything, is:
void Yield( void )
The next task in the ready queue with equal priority takes the place of the task that executes the
Yield(). If there is no other task in the ready queue with equal priority, then the task that executes the
Yield() call immediately resumes processing.

Going to and From the Waiting Queue
file:///C|/%23%23DDOC/spg/02spg003.html (1 of 3) [4/16/2002 11:13:57 PM]

Controlling the State of a Task

A task can place itself in the waiting queue with a wait function call, where it uses no CPU time waiting
for an event to occur. A wait call defines the event or condition for which the task waits. When the
condition occurs, the task moves to the ready queue and resumes running based on its priority. The basic
wait call is:
int32 WaitSignal( uint32 sigMask )
Many other functions in Portfolio can make your task wait. Internally, all of these other functions
eventually end up calling WaitSignal() to put your task to sleep.
WaitSignal() is the basic wait call that a task uses to wait for a signal. The wait calls WaitIO()
and WaitPort() are built on WaitSignal(). Each of these calls puts a task on the waiting queue
to await a signal, an I/O request return, or a message. Once the signal, I/O request, or message is
received, the task returns to the ready queue.

Changing a Task's Parent
Normally, a task created by another task ends when the parent task ends. However, by passing ownership
of the child task to another parent task, the child task can live on after the parent task ends. To change
ownership, use this call:
Err SetItemOwner( Item i, Item newOwner )
The SetItemOwner() call takes two arguments, the item number of the task whose ownership you
wish to change (Item), and the item number of the task that is to become the new parent (newOwner).
This routine returns an error code if an error occurs.
A task must be the parent of a child task to change its ownership. If this call is successful, the child task's
TCB is removed from the current task's resource table and placed in the parent task's resource table.

Changing Task Priorities
When a task first runs, its priority is set based on a field defined in its TCB data structure. You can
change the priority (in the range of 10 through 199) of a task after it has been created by using this call:
int32 SetItemPri( Item i, uint8 newpri )
The call changes the priority of an existing task. The first argument, i, is the item number of the task
whose priority you want to change. The second argument, newpri, is the new priority value that you
want the task to have. The call returns the old or former priority of the task or an error code (a negative
file:///C|/%23%23DDOC/spg/02spg003.html (2 of 3) [4/16/2002 11:13:57 PM]

Controlling the State of a Task

number) if an error occurred.
A task can change its own priority by calling:
SetItemPri(CURRENTTASK->t.n_Item, newPriority);
Keep in mind that changing a task's priority affects its status in the ready queue. If you drop the priority
below other tasks in the queue, the task can stop executing. If you raise the priority above other tasks in
the queue, the task can run alone while the other tasks wait.

file:///C|/%23%23DDOC/spg/02spg003.html (3 of 3) [4/16/2002 11:13:57 PM]

Starting and Ending Threads

Starting and Ending Threads
Threads, as you recall, differ from child tasks in that they are more tightly bound to their parent task.
They share the parent task's memory and can't transfer their ownership. However, they still need to be
started and ended just as tasks do. This section describes the calls used to start and end threads.

Creating a Thread
The CreateThread() function creates a thread:
Item CreateThread ( cconst char *name, uint8 pri, void (*code)
(), int32 stacksize )
The first argument, name, is the name of the thread to create. The second argument, pri, is the priority
that the thread will have. The third argument, code, is a pointer to the code that the thread will execute.
The last argument, stacksize, specifies the size in bytes of the thread's stack. If successful, the call
returns the item number of the thread. If unsuccessful, it returns an error code.
Before calling CreateThread(), you must determine what stack size to use for the thread. There is
no default size for the stacksize argument; however, it's important to make the size large enough so
that stack overflow errors do not occur. Stack overflow errors are characterized by random crashes that
defy logical analysis, so it's a good approach to start with a large stack size and reduce it until a crash
occurs, then double the stack size. In the sample code later in this chapter, the stack size is set to 10000.
A good size to start with is 2048.
Example 1 shows the process of creating a thread:
Example 1: Starting a task.
#define STACKSIZE (10000)
...
int main(int argc, char *argv[])
{
uint8 Priority;
Item T1;
...
Priority = CURRENTTASK->t.n_Priority;
T1 = CreateThread("Thread1", Priority, Thread1Proc, STACKSIZE);
...
file:///C|/%23%23DDOC/spg/02spg004.html (1 of 3) [4/16/2002 11:13:58 PM]

Starting and Ending Threads

}
int Thread1Proc()
{
/* This is the code for Thread1Proc */
}

Communication
Because threads share memory with the parent task, global variables can pass information among threads
and tasks. In the sample code later in this chapter a number of global variables are declared at the start of
the program, prior to the code for the threads and the parent task code. As global variables, they are
accessible to the main routine and to the threads-an example of threads sharing the same memory as the
parent task.
The code example given at the end of this chapter is a good illustration of using CreateThread() to
start two threads. It shows the use of global variables that are shared by all threads, which signal among
threads and the parent task. Signals for both threads are first allocated with AllocSignal(). The
parent task then uses WaitSignal() to wait for an event from either of the threads.

Opening Folios
Whenever you make folio calls from a thread, be sure to open the appropriate folios first. It's tempting to
think that because a folio has been opened by the parent task, the thread can make calls from the same
folio without opening it. Not true-and potentially fatal to the thread. Each thread must open all folios it
intends to use.

Ending a Thread
Use DeleteThread() to end a thread when a parent task finishes with it:
Err DeleteThread( Item thread )
This function takes the item number of the thread to delete as its only argument, and returns a negative
error code if an error occurs. Although all threads terminate automatically when the parent task ceases,
it's good programming practice to kill a thread as soon as the parent task finishes using it. Note that when
you terminate a thread, the thread's memory (which is shared with the parent task) is not freed, and
remains the property of the parent task. A thread can also terminate itself by calling exit() or just
returning.

Advanced Thread Usage
file:///C|/%23%23DDOC/spg/02spg004.html (2 of 3) [4/16/2002 11:13:58 PM]

Starting and Ending Threads

The CreateThread() and DeleteThread() functions are convenience routines, which make it
easy to create and delete threads for the most common uses. It is sometimes necessary to have better
control over thread creation. This requires allocating resources yourself and creating the thread item
using CreateItem() or CreateItemVA().
Creating a thread involves allocating memory for the stack that the thread will use, and constructing a tag
argument list that describes how the thread should be created. The tags you supply are:
●

●

●

●

●

●

●

●

●

TAG_ITEM_NAME, Provides a pointer to the name of the thread.
TAG_ITEM_PRI, Provides a priority for the thread in the range 10 to 199. If this tag is not
given, the thread inherits the priority of the current context.
CREATETASK_TAG_PC, Provides a pointer to the code to be executed as a thread.
CREATETASK_TAG_SP, Provides a pointer to the memory buffer to use as stack for the
thread.
CREATETASK_TAG_STACKSIZE, Specifies the size, in bytes, of the memory buffer
reserved for the thread's stack.
CREATETASK_TAG_ARGC, A 32-bit value that is passed as a first argument to the thread
being created. If this value is omitted, the first argument is 0.
CREATETASK_TAG_ARGP, A 32-bit value that is passed as a second argument to the thread
being created. If this is omitted, the second argument is 0.
CREATETASK_TAG_MSGFROMCHILD, Provides the item number of a message port. The
kernel sends a status message to this port whenever the thread or task being created exits. The
message is sent by the kernel after the task has been deleted. The msg_Result field of the
message contains the exit status of the task. This is the value the task provided to exit(), or the
value returned by the task's primary function. The msg_DataPtr field of the message contains
the item number of the task that just terminated. If a task exited on its own, this is the item
number of the task itself. It is the responsibility of the task that receives the status message to
delete it when the message is no longer needed by using DeleteMsg().
CREATETASK_TAG_ALLOCDTHREADSP, Tells the kernel that if this thread dies by itself,
by either returning to the kernel or by calling exit(); the memory used for its stack must be
freed automatically. When this tag is not provided, you are responsible for freeing the stack
whenever the thread terminates.

file:///C|/%23%23DDOC/spg/02spg004.html (3 of 3) [4/16/2002 11:13:58 PM]

Loading and Executing Separate Code Modules

Loading and Executing Separate Code
Modules
Using the LoadProgram() and LoadProgramPrio() calls mentioned previously, you can load an
executable file from external storage, and launch it as a totally independent task. This gives the code its
own memory pages and resource tracking. It also means that even if the program being loaded is only 4
KB big, it will still consume an entire page of RAM, which is normally 32 KB or 16 KB. Loading such
programs can waste a lot of memory if you launch many of them.
Instead of launching separate tasks, it is generally better for an application to launch separate threads. As
described above, you can use CreateThread() to do this with functions that are within your
program.
In many cases, it is desirable to split up a program into multiple pieces, only one of which needs to be in
memory at any given time. For example, the code to control the high score table of your game doesn't
need to reside in memory when playing the game. It only needs to be loaded when the time comes to
display the high score table.
Portfolio supports the partitioning of a game into multiple executable files with the LoadCode()
function. Using LoadCode(), you can load the data for an executable file in memory, and then launch
the code as a thread using ExecuteAsThread() or ExecuteAsSubroutine(). Once you finish
with the code module, you can unload it from memory using the UnloadCode() function.
LoadCode() is defined as:
Err LoadCode( char *fileName, CodeHandle *code )
The fileName argument specifies the name of the executable file to load. This is a regular executable
file as generated by the ARM linker, except that it must be linked with different startup code. If you plan
on executing this file as a thread, then you must link the file with threadstartup.o instead of cstartup.o.
If you plan on executing the file as a subroutine, it must be linked with subroutinestartup.o. The code
argument is a pointer to a variable where a handle to the loaded code is stored.
LoadCode() reads the file and allocates memory to hold its contents. The allocated memory is within
the address space of the current task. If the current task exits, the memory is automatically freed.
Once code has been loaded, it can be executed using either ExecuteAsThread() or
ExecuteAsSubroutine().

file:///C|/%23%23DDOC/spg/02spg005.html (1 of 2) [4/16/2002 11:13:58 PM]

Loading and Executing Separate Code Modules

Err ExecuteAsThread( CodeHandle code, uint32 argc, char **argv,
char *threadName, int32 priority )
Err ExecuteAsSubroutine( CodeHandle code, uint32 argc, char
**argv )
The code argument specifies the loaded code to run. This is the value stored by LoadCode() in the
CodeHandle variable passed to it. argc and argv are two 32-bit values Portfolio does not use, and
are just passed through to the code being executed. These are the values that the main() routine in the
loaded code receives for its argc and argv parameters. Finally, when executing a thread, you must
specify a thread name, and priority, just like when using CreateThread().
Once the code completes execution, call UnloadCode():
Err UnloadCode( CodeHandle code )
This removes the loaded code and frees its memory.
When you load external code and execute it using the above function, it is important to understand that
the code is actually a separate executable file. This means that global variables in one code module
cannot be accessed by a different code module.
When you execute loaded code as a thread, any memory this thread allocates does not get freed when the
thread exits or when the code is unloaded. The thread must clean up after itself, just like a thread created
using CreateThread().
If loaded code is being executed as a subroutine and calls exit(), this call causes the entire program,
not just the subroutine, to exit.

file:///C|/%23%23DDOC/spg/02spg005.html (2 of 2) [4/16/2002 11:13:58 PM]

Example

Example
Example 1 contains sample code for using threads and signals.
The main() routine launches two threads. These threads simply sit in a loop and count. After a given number of
iterations through their loop, they send a signal to the parent task.
When the parent task gets a signal, it wakes up and prints the current counters of the threads to show how much they
were able to count.
Example 1: Using Threads (signals.c).
#include
#include
#include
#include
#include

"types.h"
"task.h"
"kernel.h"
"stdio.h"
"operror.h"

/*****************************************************************************/
/* Global variables shared by all threads. */
static int32 thread1Sig;
static int32 thread2Sig;
static Item
parentItem;
static uint32 thread1Cnt;
static uint32 thread2Cnt;
/*****************************************************************************/
/* This routine shared by both threads */
static void DoThread(int32 signal, uint32 amount, uint32 *counter)
{
uint32 i;
while (TRUE)
{
for (i = 0; i < amount; i++)
{
(*counter)++;
SendSignal(parentItem,signal);
}
}
}
file:///C|/%23%23DDOC/spg/02spg006.html (1 of 3) [4/16/2002 11:13:59 PM]

Example

/*****************************************************************************/
static void Thread1Func(void)
{
DoThread(thread1Sig, 100000, &thread1Cnt);
}
/*****************************************************************************/
static void Thread2Func(void)
{
DoThread(thread2Sig, 200000,&thread2Cnt);
}
/*****************************************************************************/
int main(int32 argc, char **argv)
{
uint8 parentPri;
Item
thread1Item;
Item
thread2Item;
uint32 count;
int32 sigs;
/* get the priority of the parent task */
parentPri = CURRENTTASK->t.n_Priority;
/* get the item number of the parent task */
parentItem = CURRENTTASK->t.n_Item;
/* allocate one signal bits for each thread */
thread1Sig = AllocSignal(0);
thread2Sig = AllocSignal(0);
/* spawn two threads that will run in parallel */
thread1Item = CreateThread("Thread1", parentPri, Thread1Func, 2048);
thread2Item = CreateThread("Thread2", parentPri, Thread2Func, 2048);
/* enter a loop until we receive 10 signals */
count = 0;
while (count < 10)
{
sigs = WaitSignal(thread1Sig | thread2Sig);

file:///C|/%23%23DDOC/spg/02spg006.html (2 of 3) [4/16/2002 11:13:59 PM]

Example

printf("Thread 1 at %d, thread 2 at
%d\n",thread1Cnt,thread2Cnt);
if (sigs & thread1Sig)
printf("Signal from thread 1\n");
if (sigs & thread2Sig)
printf("Signal from thread 2\n");
count++;
}
/* nuke both threads */
DeleteThread(thread1Item);
DeleteThread(thread2Item);
}

file:///C|/%23%23DDOC/spg/02spg006.html (3 of 3) [4/16/2002 11:13:59 PM]

Function Calls

Function Calls
The following calls control tasks and threads. See Kernel Folio Calls, for more information on these
calls.

Starting Tasks
The following calls start tasks:
●
●
●

CreateItem() Creates an item.
LoadProgram() Launches a program.
LoadProgramPrio() Launches a program and gives it a priority.

Ending Tasks
The following calls delete or exit a task:
●
●

DeleteItem() Deletes an item.
exit() Exits from a task or thread.

Loading and Unloading Code
The following calls load or unload code:
●
●

LoadCode() Loads a binary image into memory, and obtains a handle to it.
UnloadCode() Unloads a binary image previously loaded with LoadCode().

Starting Threads
The following calls create a thread:
●
●

CreateThread() Creates a thread.
ExecuteAsThread() Executes previously loaded code as a thread.

Ending Threads
file:///C|/%23%23DDOC/spg/02spg007.html (1 of 2) [4/16/2002 11:13:59 PM]

Function Calls

The following calls delete and exit from a thread:
●
●

DeleteThread() Deletes a thread.
exit() Exits from a task or thread.

Controlling Tasks
The following calls control tasks and threads.
●
●
●
●
●

SendSignal() Sends one or more signals to another task.
SetItemOwner() Changes the owner of an item.
SetItemPri() Changes the priority of an item.
WaitSignal() Waits until a signal is sent.
Yield() Gives up the CPU to a task of equal priority.

file:///C|/%23%23DDOC/spg/02spg007.html (2 of 2) [4/16/2002 11:13:59 PM]

Using Tags and TagArgs

Using Tags and TagArgs
This chapter provides information on tags and TagArgs. It contains the following sections:
●
●
●
●
●
●

About Tags and TagArgs
Using Tags and TagArgs
Special Tag Commands
Tags and VarArgs
Parsing Tags
TagArg Function Calls

file:///C|/%23%23DDOC/spg/03spg.html [4/16/2002 11:13:59 PM]

About Tags and TagArgs

About Tags and TagArgs
A TagArg is a data structure that is used throughout Portfolio. The structure provides potentially long
and variable lists of parameters to system function calls. TagArgs, also referred to simply as tags, provide
a very flexible and expandable mechanism that allows Portfolio to evolve with minimal impact on
application code.

file:///C|/%23%23DDOC/spg/03spg001.html [4/16/2002 11:14:00 PM]

Tags and TagArgs

Tags and TagArgs
A TagArg is a simple data structure that contains a command or attribute, and an argument for that
command or attribute. The TagArg structure looks like:
typedef struct TagArg
{
uint32 ta_Tag;
TagData ta_Arg;
} TagArg;
TagArg structures are generally used in array form. Many Portfolio function calls take an array of
TagArg structures as a parameter. Each function call that uses TagArg arrays defines which commands
or attributes can be used with the call.
Arrays of TagArg structures are scanned from start to finish by the function calls that use them. Each
element in the array specifies an individual command or attribute pertinent to that function. If a given
command appears more than once in a TagArg array, the last occurrence within the array takes
precedence. If an unknown command appears in a TagArg, the whole function call fails and returns an
appropriate error.

file:///C|/%23%23DDOC/spg/03spg002.html [4/16/2002 11:14:00 PM]

Special Tag Commands

Special Tag Commands
Portfolio provides three special tag commands that have universal meanings in all system calls:
TAG_END, TAG_NOP, and TAG_JUMP. By setting the ta_Tag field to these commands, you can
control how TagArg arrays are processed by the system.

TAG_END
The TAG_END command tells the system that this structure marks the end of an array of TagArg
structures. The system stops scanning the array and goes no further.

TAG_NOP
The TAG_NOP command tells the system to ignore the particular TagArg structure. The system just skips
ahead and continues processing with the next TagArg structure.

TAG_JUMP
The TAG_JUMP command links arrays of TagArg structures together. The ta_Arg field for this
command must point to another array of TagArg structures. When the system encounters such a TagArg
structure, it stops scanning the current array, and resumes scanning at the address specified by ta_Arg.

file:///C|/%23%23DDOC/spg/03spg003.html [4/16/2002 11:14:00 PM]

Tags and VarArgs

Tags and VarArgs
Although Portfolio TagArg calls traditionally use static arrays of TagArg structures to define their
parameters, a much superior approach is possible by using the C VarArgs capability.
VarArgs lets C routines like printf() accept a variable number of parameters. You can use VarArgs
to construct arrays of TagArg structures on the fly within a function call you are making. This is
generally easier to write, understand, and maintain than static arrays.
Most Portfolio functions that accept TagArg arrays as parameters also have VarArgs counterparts. These
counterparts have the same names as the regular functions, with the addition of a VA suffix to identify
them as VarArgs.
For example, the CreateItem() kernel function accepts an array of TagArg structures as a parameter.
The CreateItemVA() function is identical in purpose and function, except that it uses a VarArgs list
of tags instead of a pointer to an array.
To build up a tag list on the stack, you enumerate all commands and their arguments in sequence,
separated by commas, and terminate them with a TAG_END tag command. Here are examples of using
CreateItem() and CreateItemVA() to create a message port.
Example 1: Creating a message port
static TagArgs tags[] =
{
{CREATEPORT_TAG_SIGNAL,
0},
{CREATEPORT_TAG_USERDATA, 0},
{TAG_END,
0}
};
{
Item mp;
tags[0].ta_Arg = (void *)sigMask;
tags[1].ta_Arg = (void *)userData;
mp = CreateItem(MKNODEID(KERNELNODE,MSGPORTNODE),tags);
}
{
Item mp;

file:///C|/%23%23DDOC/spg/03spg004.html (1 of 2) [4/16/2002 11:14:00 PM]

Tags and VarArgs

mp = CreateItemVA(MKNODEID(KERNELNODE,MSGPORTNODE),
CREATEPORT_TAG_SIGNAL,
sigMask,
CREATEPORT_TAG_USERDATA, userData,
TAG_END);
}
As you can see, the version using CreateItemVA() is easier to understand. All the definitions
pertaining to the tags can be kept within the function call itself, instead of requiring a separate array.

file:///C|/%23%23DDOC/spg/03spg004.html (2 of 2) [4/16/2002 11:14:00 PM]

Parsing Tags

Parsing Tags
If you write utility routines to be shared by many programmers, it is often useful to implement functions
that take TagArg arrays in a manner similar to the system functions.
The NextTagArg() function lets you easily go through all the TagArg structures in an array. The
function automatically handles all system tag commands like TAG_NOP and TAG_JUMP, and only
returns TagArg structures that do not contain system tag commands. You give NextTagArg() a
pointer to a variable that points to the tag array to process. It returns a pointer to the first TagArg
structure within the array. You then call the function repeatedly until it returns NULL. Every time you
call it, it returns the next TagArg structure in the array.
The FindTagArg() function takes a pointer to an array of TagArg structures and to a particular tag
command. The function scans the supplied array looking for a TagArg structure that has the requested
command. It returns a pointer to the TagArg structure, or NULL if no structure with that command is
found.
The GetTagArg() function works much as FindTagArg() does, except that instead of returning a
pointer to a TagArg structure, it returns the value stored in the ta_Arg field of the TagArg structure.
You also give the function a default data value. If the desired TagArg can't be found, the function returns
the default data value to you.
Finally, the DumpTagList() function displays all the tag commands and arguments in a TagArg array
to the debugging terminal. This is very useful when you need to see every tag value being passed to a
function call.

file:///C|/%23%23DDOC/spg/03spg005.html [4/16/2002 11:14:01 PM]

TagArg Function Calls

TagArg Function Calls
These functions help you parse arrays of TagArg structures:
●

●
●

●

DumpTagList Displays all of the TagArg structures within a TagArg array to the debugging
terminal.
FindTagArg Finds a TagArg that contains a given command within a TagArg array.
GetTagArg Returns the argument for a TagArg that contains a given command within a
TagArg array.
NextTagArg Iterates through all the structures in a TagArg array.

file:///C|/%23%23DDOC/spg/03spg006.html [4/16/2002 11:14:01 PM]

Managing Linked Lists

Managing Linked Lists
This chapter explains how to manage linked lists. For details about the functions described here, see
Kernel Folio Calls, in the 3DO System Programmer's Reference.
This chapter contains the following topics:
●
●
●
●
●
●
●
●
●
●
●
●
●
●

About Linked Lists
Creating and Initializing a List
Adding a Node to a List
Changing the Priority of a Node
Removing a Node From a List
Finding out If a List Is Empty
Traversing a List
Finding a Node by Name
Finding a Node by Its Ordinal Position
Determining the Ordinal Position of a Node
Counting the Number of Nodes in a List
Example
Primary Data Structures
Function Calls

file:///C|/%23%23DDOC/spg/04spg.html [4/16/2002 11:14:01 PM]

About Linked Lists

About Linked Lists
Linked lists are used throughout Portfolio and in applications you create with it. To make using lists
easier (and to meet the needs of system software and its lists), the kernel defines a special type of linked
list, known as a Portfolio list. The kernel also provides a variety of functions for creating and managing
Portfolio lists.
Like all linked lists, Portfolio lists are dynamic; they can expand and contract as needed. Their contents,
known as nodes, are ordered (there is a first node, a second node, and so on), and you can add a new
node at any position in a list. The following sections explain how Portfolio lists are different from other
linked lists.

Characteristics of Portfolio Lists
Unlike ordinary linked lists, which contain only nodes, Portfolio lists also contain a special component
known as an anchor, which marks both ends of the list. The anchor (which is implemented as a C union)
serves as both the beginning-of-list marker (known as the head anchor) and the end-of-list marker
(known as the tail anchor). Figure 1 illustrates an anchored list.

Figure 1: Anchored list.
When a task traverses a Portfolio list, it determines whether it's at the beginning or end of the list by
testing to see if the subsequent node is an anchor.
As the previous illustration shows, Portfolio lists are doubly linked: Each node contains two pointers, one
to point to the following node or anchor and one to the previous node or anchor. As a result, back-tofront list traversals are as efficient as front-to-back traversals.

file:///C|/%23%23DDOC/spg/04spg001.html (1 of 2) [4/16/2002 11:14:02 PM]

About Linked Lists

Characteristics of Nodes
In Portfolio lists, there are special data structures that contain only information needed for list
management. This information includes the necessary forward and backward pointers, a priority value
(described later in this section), and other fields that are used primarily by the operating system. A node
can also have a name. Use the FindNamedNode() call to find a node by name.
To create a list component, you define a data structure whose first field is a node. An example is the
NoteTracker structure defined in the music library:
Example 1: The Note Tracker structure in the music library.
typedef struct NoteTracker
{
Node
nttr_Node;
int8
nttr_Note;
int8
nttr_MixerChannel;
uint8
nttr_Flags;
int8
nttr_Channel; /* MIDI */
Item
nttr_Instrument;
} NoteTracker;
To pass such a component to one of the many list-manipulation functions that takes a Node structure as
an argument, you simply cast the argument to type Node. Here's an example:
AddTail( &DSPPData.dspp_ExternalList, (Node *) dext );
Every node in a list has a priority (a value from 0-255 that is stored in the n_Priority field of the
Node structure). When you use a list, you have the option of keeping its nodes sorted by priority (done
automatically by the kernel if you use InsertNodeFromHead() or InsertNodeFromTail()),
or you can specify other ways to arrange the contents (by using the UniversalInsertNode()
function). You can also change the priority of a node in a list with the SetNodePri() function,
whereupon the kernel automatically repositions the node in the list to reflect its new priority value.
A node can be in only one list at a time.

file:///C|/%23%23DDOC/spg/04spg001.html (2 of 2) [4/16/2002 11:14:02 PM]

Creating and Initializing a List

Creating and Initializing a List
To create an empty linked list, you first create a variable of type List. You then initialize the list, which
gives the list a name and initializes its head and tail anchors, by calling the InitList() function:
void InitList( List *l, const char *name )
The l argument is a pointer to the list to be initialized. The name argument is the name of the list.
Another way to initialize a list is by using the INITLIST() macro. This macro lets you define a fully
initialized List as a variable. By using the macro, you avoid the need to call the InitList()
function. Here is an example of using the INITLIST macro to create a variable called listOfStuff:
static List listOfStuff = INITLIST(listOfStuff,"List Name");

file:///C|/%23%23DDOC/spg/04spg002.html [4/16/2002 11:14:02 PM]

Adding a Node to a List

Adding a Node to a List
You can add a node to a list in any of the following ways:
●

The beginning or end of a list.

●

A position in the list that corresponds to the node's priority.

●

A position in the list determined by comparing one or more values contained in the node to values
of nodes currently in the list, or relative to another node already in the list.

The following sections describe each of these cases.

Adding a Node to the Head of a List
To add a node to the head of a list, use the AddHead() function:
void AddHead( List *l, Node *n )
The l argument is a pointer to the list to which to add the node, while the n argument is a pointer to the
node to add.

Adding a Node to the Tail of a List
To add a node to the tail of a list, use the AddTail() function:
void AddTail( List *l, Node *n )
The l argument is a pointer to the list to which to add the node, while the n argument is a pointer to the
node to add.

Adding a Node After Another Node in a List
To add a node to a list and position it after another node already in the list, use the
InsertNodeAfter() function:
void InsertNodeAfter( Node *oldNode, Node *newNode )
file:///C|/%23%23DDOC/spg/04spg003.html (1 of 3) [4/16/2002 11:14:03 PM]

Adding a Node to a List

The oldNode argument is a pointer to a node already in the list, while the newNode argument is a
pointer to the new node to insert.

Adding a Node Before Another Node in a List
To add a node to a list and position it before another node already in the list, use the
InsertNodeBefore() function:
void InsertNodeBefore( Node *oldNode, Node *newNode )
The oldNode argument is a pointer to a node already in the list, while the newNode argument is a
pointer to the new node to insert.

Adding a Node According to Its Priority
The nodes in a list are often arranged by priority. To insert a new node immediately before any other
nodes of the same priority, use the InsertNodeFromHead() function:
void InsertNodeFromHead( List *l, Node *n )
As in the other functions for adding nodes, the l argument is a pointer to the list to which to add the
node, while the n argument is a pointer to the node to add.
The name InsertNodeFromHead() refers to the way the kernel traverses the list to find the correct
position for a new node: it compares the priority of the new node to the priorities of nodes already in the
list, beginning at the head of the list, and inserts the new node immediately after nodes with higher
priorities. If the priorities of all the nodes in the list are higher than the priority of the new node, the node
is added to the end of the list.
To insert a new node immediately after all other nodes of the same priority, you use the
InsertNodeFromTail() function:
void InsertNodeFromTail( List *l, Node *n )
Again, the l argument is a pointer to the list to which to add the node, while the n argument is a pointer
to the node to add. As with InsertNodeFromHead(), the name InsertNodeFromTail()
refers to the way the kernel traverses the list to find the correct position for the new node: it compares the
priority of the new node to the priorities of nodes already in the list, beginning at the tail of the list, and
inserts the new node immediately before nodes with lower priorities. If the priorities of all the nodes in
file:///C|/%23%23DDOC/spg/04spg003.html (2 of 3) [4/16/2002 11:14:03 PM]

Adding a Node to a List

the list are lower, the node is added to the head of the list.

Adding a Node According to Other Node Values
Arranging list nodes by priority is only one way to order a list. You can arrange the nodes in a list by
node values other than priority by using the UniversalInsertNode() function to insert new nodes:
void UniversalInsertNode( List *l, Node *n, bool (*f)(Node *n,
Node *m) )
The l argument is a pointer to the list to which to add the node, while the n argument is a pointer to the
node to add. Like InsertNodeFromHead(), UniversalInsertNode() compares the node to
be inserted with nodes already in the list, beginning with the first node. The difference is that it uses the
comparison function f provided by your task to compare the new node to existing nodes. If the
comparison function returns TRUE, the new node is inserted immediately before the node to which it
was compared. If the comparison function always returns FALSE, the new node becomes the last node in
the list. The comparison function, whose arguments are pointers to two nodes, can use any data in the
nodes for the comparison.

file:///C|/%23%23DDOC/spg/04spg003.html (3 of 3) [4/16/2002 11:14:03 PM]

Changing the Priority of a Node

Changing the Priority of a Node
List nodes are often ordered by priority. You can change the priority of a list node (and thereby change
its position in the list) by using the SetNodePri() function:
uint8 SetNodePri( Node *n, uint8 newpri )
The n argument is a pointer to the list node whose priority you want to change. The newpri argument
specifies the new priority for the node (a value from 0 to 255). The function returns the previous priority
of the node. When you change the priority of a node, the kernel automatically moves the node
immediately.

file:///C|/%23%23DDOC/spg/04spg004.html [4/16/2002 11:14:03 PM]

Removing a Node From a List

Removing a Node From a List
You can remove the first node, the last node, or a specific node from a list. The following sections
explain how to do it.

Removing the First Node
To remove the first node from a list, use the RemHead() function:
Node *RemHead( List *l )
The l argument is a pointer to the list from which you want to remove the node. The function returns a
pointer to the node that was removed from the list or NULL if the list was empty.

Removing the Last Node
To remove the last node from a list, use the RemTail() function:
Node *RemTail( List *l )
The l argument is a pointer to the list from which you want to remove the node. The function returns a
pointer to the node that was removed from the list or NULL if the list was empty.

Removing a Specific Node
To remove a specific node from a list, use the RemNode() function:
void RemNode( Node *n )
The n argument is a pointer to the node you want to remove. Because a node can be only in one list, the
node is automatically removed from the correct list.

file:///C|/%23%23DDOC/spg/04spg005.html [4/16/2002 11:14:03 PM]

Finding out If a List Is Empty

Finding out If a List Is Empty
To find out if a list is empty, use IsListEmpty():
bool IsListEmpty( const List *l )
The l argument is a pointer to the list to check. The macro returns TRUE if the list is empty or FALSE if
it isn't.

file:///C|/%23%23DDOC/spg/04spg006.html [4/16/2002 11:14:03 PM]

Traversing a List

Traversing a List
You can traverse a list equally quickly from front to back or from back to front. The following sections
explain how.

Traversing a List From Front to Back
To traverse a list from front to back, use ScanList(). It iterates through all of the elements in the list.
Example 1: Traversing a list front to back.
ScanList(list,n,DataType)
{
/* here you can dereference "n" */
}
ScanList() is a macro made up of the simpler macros FirstNode(), IsNode(), and
NextNode().
Use FirstNode() to get the first node in a list:
Node *FirstNode( const List *l )
The l argument is a pointer to the list the node is in. The macro returns a pointer to the first node in the
list or, if the list is empty, a pointer to the tail anchor.
To check to see if a node is an actual node rather than the tail anchor, use IsNode():
bool IsNode( const List *l, const Node *n )
The l argument is a pointer to the list containing the node; the n argument is a pointer to the node to
check. The macro returns FALSE if it is the tail anchor or TRUE for any other node. (IsNode()returns
TRUE for any node that is not the tail anchor, no matter if the node is in the specified list.)
To go from one node to its successor in the same list, use NextNode():
Node *NextNode( const Node *n )

file:///C|/%23%23DDOC/spg/04spg007.html (1 of 2) [4/16/2002 11:14:04 PM]

Traversing a List

The n argument is a pointer to the current node. (This node must be in a list.) The macro returns a pointer
to the next node in the list or, if the current node is the last node in the list, to the tail anchor.

Traversing a List From Back to Front
To traverse a list from front to back, use the ScanListB() macro. It iterates through all the elements
in the list.
Example 2: Traversing a list back to front.
ScanListB(list,n,DataType)
{
/* here you can dereference "n" */
}
ScanListB() is a macro made up of the simpler macros LastNode(), IsNodeB(), and
PrevNode().
Use LastNode() to get the last node in a list:
Node *LastNode( const List *l )
The l argument is a pointer to the list the node is in. The macro returns a pointer to the last node in the
list or, if the list is empty, a pointer to the head anchor.
To check to see if a node is an actual node rather than the head anchor, use IsNodeB():
bool IsNodeB( const List *l, const Node *n )
The l argument is a pointer to the list containing the node to check; the n argument is a pointer to the
node to check. The macro returns FALSE if it is the head anchor or TRUE for any other node. (The
macro returns TRUE for any node that is not the head anchor, whether or not the node is in the specified
list.)
To go from one node to its predeccessor in the list, use the PrevNode() macro:
Node *PrevNode( const Node *n )
The n argument is a pointer to the current node. (This node must be in a list.) The macro returns a pointer
to the previous node in the list or, if the current node is the first node in the list, to the head anchor.

file:///C|/%23%23DDOC/spg/04spg007.html (2 of 2) [4/16/2002 11:14:04 PM]

Finding a Node by Name

Finding a Node by Name
Because list nodes can have names, you can search for a node with a particular name with the
FindNamedNode() function:
Node *FindNamedNode( const List *l, const char *name )
The l argument is a pointer to the list to search; the name argument is the name of the node for which
to search. The function returns a pointer to the Node structure or NULL if the named node is not found.
The search is not case-sensitive; that is, the kernel does not distinguish uppercase and lowercase letters in
the node names.

file:///C|/%23%23DDOC/spg/04spg008.html [4/16/2002 11:14:04 PM]

Finding a Node by Its Ordinal Position

Finding a Node by Its Ordinal Position
You can find a node that appears in a given position from the beginning or end of a list. To find a node
from the beginning of a list, use the FindNodeFromHead() function:
Node *FindNodeFromHead( const List *l, uint32 position )
The l argument is a pointer to the list to search; the position argument is the position of the node
sought within the list, counting from the head of the list. The first node in the list has position 0. The
function returns a pointer to the node, or NULL if there are not enough nodes in the list for the requested
position.
To find a node from the end of a list, use the FindNodeFromTail() function:
Node *FindNodeFromTail( const List *l, uint32 position )
The l argument is a pointer to the list to search; the position argument is the position of the node
sought within the list, counting from the tail of the list. The last node in the list has position 0. The
function returns a pointer to the node, or NULL if there are not enough nodes in the list for the requested
position.

file:///C|/%23%23DDOC/spg/04spg009.html [4/16/2002 11:14:04 PM]

Determining the Ordinal Position of a Node

Determining the Ordinal Position of a
Node
Given a list and a node, you can determine the position of the node within the list, counting from the
beginning or the end of the list. To determine the position of a node relative to the beginning of a list, use
the GetNodePosFromHead() function:
int32 GetNodePosFromHead( const List *l, const Node *n );
The l argument is a pointer to the list in which the node is located; the n argument is the node to find in
the list. The function scans the list looking for the node, and returns the position of the node within the
list. The first node in the list has position 0. If the node cannot be located in the list, the function returns 1.
To determine the position of a node relative to the end of a list, use the GetNodePosFromTail()
function:
int32 GetNodePosFromTail( const List *l, const Node *n );
The l argument is a pointer to the list in which the node is located; the n argument is the node to find in
the list. The function scans the list looking for the node, and returns the position of the node relative to
the end of the list. The last node in the list has position 0. If the node cannot be located in the list, the
function returns -1.

file:///C|/%23%23DDOC/spg/04spg010.html [4/16/2002 11:14:05 PM]

Counting the Number of Nodes in a List

Counting the Number of Nodes in a List
To count the number of nodes in a list, use the GetNodeCount() function:
uint32 GetNodeCount( const List *l );
The l argument is a pointer to the list of which you want count the nodes. The function returns the
number of nodes currently in the list.

file:///C|/%23%23DDOC/spg/04spg011.html [4/16/2002 11:14:05 PM]

Example

Example
Example 4 illustrates how to traverse a list.
Example 1: List traversal.
void DumpList ( const List *theList )
{
Node *n;
ScanList(theList,n,Node)
{
printf("Node = 0x%lx\n", n);
}
}

file:///C|/%23%23DDOC/spg/04spg012.html [4/16/2002 11:14:05 PM]

Primary Data Structures

Primary Data Structures
The following sections describe the most important data structures that use linked lists. With the exception of the
n_Name field in a Node structure (which you use to name a node), tasks perform all normal operations involving lists
by using the function calls described in this chapter.

The Node Structure
The Node data structure is the standard structure for any named node in a linked list. The n_Name field lets you easily
locate any node in a linked list.
Example 1: The Node data structure.
typedef struct Node
{
struct Node
*n_Next;
/* pointer to next node in list */
struct Node
*n_Prev;
/* pointer to previous node in list */
uint8
n_SubsysType; /* what folio manages this node */
uint8
n_Type;
/* what type of node for the folio */
uint8
n_Priority;
/* queueing priority */
uint8
n_Flags;
/* flags used by the system */
int32
n_Size;
/* total size of node including hdr */
char
*n_Name;
/* ptr to null terminated string or
NULL */
} Node, *NodeP;
/* n_Flag bits */
/* bits 4-7 are reserved for the system */
/* bits 0-3 are available for node specific use by the system */
#define NODE_RSRV1
0x40
#define NODE_SIZELOCKED 0x20
/* The size of this item has been

#define NODE_ITEMVALID
#define NODE_NAMEVALID

0x10
0x80

/* locked down */
/* This is an ItemNode */
/* This node's namefield is valid */

MinNode and NamelessNode Structures
In addition to the regular Node structure, Portfolio also defines the MinNode and NamelessNode structures. These
structures can be used in place of the full Node structure when defining your own lists. These structures have much
less overhead than the Node structure, so your lists use less memory.
The NamelessNode structure is identical to the Node structure, except that it doesn't have the n_Name field. You
can use the NamelessNode structure in place of a Node structure for all the functions and macros explained in this
chapter, except for the FindNamedNode() and DumpNode() functions. Since these functions use the n_Name
file:///C|/%23%23DDOC/spg/04spg013.html (1 of 3) [4/16/2002 11:14:06 PM]

Primary Data Structures

field, they cannot handle the NamelessNode.
Example 2: The NamelessNode structure.
/* Node structure used when the Name is not needed */
typedef struct NamelessNode
{
struct NamelessNode *n_Next;
struct NamelessNode *n_Prev;
uint8 n_SubsysType;
uint8 n_Type;
uint8 n_Priority;
uint8 n_Flags;
int32 n_Size;
} NamelessNode, *NamelessNodeP;
The MinNode structure is very small, and provides just enough information to link within lists. It can be used with
most functions and macros explained in this chapter, except for SetNodePri(), InsertNodeFromTail(),
InsertNodeFromHead(), FindNamedNode(), and DumpNode(). These functions use the extra fields found
in the Node structure, and cannot work with the simple MinNode structure.
Example 3: The MinNode structure.
/* Node structure used for linking only */
typedef struct MinNode
{
struct MinNode *n_Next;
struct MinNode *n_Prev;
} MinNode;

The List Data Structure
The List data structure is the means by which nodes are linked together.
Example 4: The List data structure.
typedef struct List
{
Node l;
ListAnchor ListAnchor;
} List, *ListP;

/* A list is a node itself */
/* Anchor point for list of nodes */

The ListAnchor Union
The ListAnchor union contains the forward and backward pointers for the first and last node of any linked list.

file:///C|/%23%23DDOC/spg/04spg013.html (2 of 3) [4/16/2002 11:14:06 PM]

Primary Data Structures

Example 5: The ListAnchor union.
typedef union ListAnchor
{
struct
/* ptr to first node */
{
/* anchor for lastnode */
Link links;
Link *filler;
} head;
struct
{
Link *filler;
Link links;
/* ptr to lastnode */
} tail;
/* anchore for firstnode */
} ListAnchor;

The Link Data Structure
The Link data structure contains the forward and backward pointers for a linked list.
Example 6: The Link data structure.
typedef struct Link
{
struct Link *flink;
struct Link *blink;
} Link;

/* forward (next) link */
/* backward (prev) link */

file:///C|/%23%23DDOC/spg/04spg013.html (3 of 3) [4/16/2002 11:14:06 PM]

Function Calls

Function Calls
The following list contains the function calls that handle linked lists. See Kernel Folio Calls, in the 3DO
System Programmer's Reference for more information on these calls.

Initializing a List
The following calls initialize a list:
●
●

InitList() Initializes a list.
INITLIST() Statically initializes a list.

Adding Nodes to a List
The following calls handle nodes:
●
●
●
●
●
●
●

AddHead() Adds a node to the head of a list.
AddTail() Adds a node to the tail of a list.
InsertNodeAfter() Inserts a node after another node already in a list.
InsertNodeBefore() Inserts a node before another node already in a list.
InsertNodeFromHead()Inserts a node into a list.
InsertNodeFromTail() Inserts a node into a list.
UniversalInsertNode() Inserts a node into a list.

Changing the Priority of a List Node
The following call changes the priority of a node:
●

SetNodePri() Changes the priority of a list node.

Removing Nodes From a List
The following calls remove nodes from a list:
●

RemHead() Removes the first node from a list.

file:///C|/%23%23DDOC/spg/04spg014.html (1 of 3) [4/16/2002 11:14:06 PM]

Function Calls
●
●

RemNode() Removes a specified node from a list.
RemTail() Removes the last node from a list.

Checking to See If a List Is Empty
The following call checks if a list is empty:
●

IsListEmpty() Checks whether a list is empty.

Testing Nodes and Lists
The following calls are used to test nodes and lists:
●
●

IsNode() Checks whether a node is an actual node or the tail (end-of-list) anchor.
IsNodeB() Tests whether the node is an actual node or the head (beginning-of-list) anchor.

Traversing a Linked List
The following calls are used to traverse a list:
●
●
●
●
●
●

FirstNode() Gets the first node in a list.
LastNode() Gets the last node in a list.
NextNode() Gets the next node in a list.
PrevNode() Gets the previous node in a list.
ScanList()Walks through all the nodes in a list.
ScanListB() Walks through all the nodes in a list backwards.

Finding a Node by Name
The following call finds a node by name.
●

FindNamedNode() Finds a node by specifying its name.

Ordinal Node Position Functions
The following functions deal with nodes using their ordinal position in a list.
file:///C|/%23%23DDOC/spg/04spg014.html (2 of 3) [4/16/2002 11:14:06 PM]

Function Calls

●
●
●

●

FindNodeFromHead() Finds a node in a list by counting from the head of the list.
FindNodeFromTail() Finds a node in a list by counting from the tail of the list.
GetNodePosFromHead() Determines the position of a node within a list, counting from the
head of the list.
GetNodePosFromTail() Determines the position of a node within a list, counting from the
tail of the list.

Counting the Nodes in a List
●
●

GetNodeCount() Counts the number of nodes in a list.
DumpNode() Prints contents of a node to the debugging terminal.

file:///C|/%23%23DDOC/spg/04spg014.html (3 of 3) [4/16/2002 11:14:06 PM]

Managing Memory

Managing Memory
All tasks need memory. This chapter explains how to allocate memory, how to share it with other tasks,
how to get information about it, and how to free it. For details of the functions described here, see Kernel
Folio Calls, in the 3DO System Programmer's Reference.
This chapter contains the following topics:
●
●
●
●
●
●
●
●
●
●
●
●

About Memory
Allocating Memory
Getting Information About Memory
Reclaiming Memory for Other Tasks
Allowing Other Tasks to Write to Your Memory
Transferring Memory to Other Tasks
Using Private Memory Lists
Using Private Memory Pools
Getting Memory From the System-Wide Free Memory Pool
Debugging Memory Usage
Example
Function Calls

file:///C|/%23%23DDOC/spg/05spg.html [4/16/2002 11:14:07 PM]

About Memory

About Memory
This section explains the fundamentals of memory and memory usage for 3DO software.

Types of Memory
Current 3DO systems include three types of memory: dynamic random access memory (DRAM), video
random access memory (VRAM), and nonvolatile random access memory (NVRAM). Future systems may
include additional types of memory.

DRAM
Dynamic random access memory (DRAM) is generic memory for operations that don't involve special
interactions with 3DO hardware, such as the SPORT bus transfers. Current 3DO systems include 2 MB of
DRAM, which can be expanded to either 15 MB (in systems with 1 MB of VRAM) or 14 MB (in systems
with 2 MB of VRAM). Future systems may have larger memory capacities.

VRAM
Not all memory is created equal. VRAM is one kind of special purpose memory, that is, memory primarily
or exclusively used with particular parts of the 3DO hardware (in this case, the SPORT bus). Video random
access memory (VRAM) is RAM for video and graphics operations that involve the SPORT bus. (For
information about the SPORT bus, see the Understanding the Cel Engine and SPORT in the 3DO Graphics
Programmer's Guide.) Because VRAM is connected to the standard memory bus as well as the SPORT bus,
you can also use it for generic operations.
Current systems include 1 MB of VRAM, which can be expanded to 2 MB. Future systems may have larger
memory capacities.
In systems with 2 MB of VRAM, VRAM is divided into two 1 MB banks. The SPORT bus can only transfer
data between locations in the same bank, never between banks. When blocks of VRAM are allocated, each
block must come from the same bank.
Note: Future 3DO systems may have other kinds of special purpose memory, including memory for direct
memory access (DMA), for the cel engine, for audio, and for the digital signal processor (DSP). See
Allocating Memory for information about when to specify these future memory types in current software.

NVRAM

file:///C|/%23%23DDOC/spg/05spg001.html (1 of 10) [4/16/2002 11:14:09 PM]

About Memory

Every 3DO system includes at least 32 KB of nonvolatile random access memory (NVRAM) that can
preserve information when the system is turned off or rebooted. Applications can use NVRAM to store
small amounts of information, such as application configuration information, user preferences, and high
scores for games.
Unlike other types of memory, access to NVRAM is through the Portfolio file system, where it is treated as
a separate volume. For more information about NVRAM, see The Filesystem and the File Folio.

Organization of Memory
The following sections explain how memory is arranged (in fixed-size units known as pages), how it is
divided up when allocated (into contiguous arrays of bytes known as blocks), how the kernel keeps track of
memory available for allocation (in special lists known as free memory lists), and where allocated memory
comes from (from lists of free memory lists known as free memory pools).

Memory Pages
In 3DO system the hardware divides memory into pages. Currently, the number of pages in the system, also
called system pages, is fixed (64 pages of DRAM and 64 pages of VRAM); the size of each page depends on
the amount of each type of memory in the system. For example, in current systems with 2 MB of DRAM
and 1 MB of VRAM, DRAM pages are 32 KB (2 MB divided by 64) and VRAM pages are 16K (1 MB
divided by 64). In a loaded system with 14 MB of DRAM, 2 MB of VRAM, and cruise control, DRAM
pages are 256 KB and VRAM pages are 32 KB.
Each page of memory has an owner. Although any task can read any memory location in RAM, only the
task that owns a page (or a task that the owner designates) can write to the page. How tasks become owners
of memory is explained in How Memory Allocation Works. How tasks can transfer ownership of memory to
other tasks is explained in the section Transferring Memory to Other Tasks.
When a task needs memory, it allocates a block of memory from the memory pages it owns. It specifies the
size of the block in a call to a memory allocation function. The bytes in a memory block are always
contiguous, even when the block crosses page boundaries.

VRAM Memory Pages
As described in the previous section, VRAM is divided by the hardware into 64 pages. These pages are part
of the memory protection scheme. VRAM has a secondary page size imposed by the SPORT hardware, and
is used for graphics operations. This secondary page size is currently fixed at 2K. SPORT operation can only
be performed in increments of 2K with blocks aligned on a 2K boundary. You can find more information
about the SPORT device and its restrictions in the 3DO Portfolio Graphics Programmer's Guide.
For the remainder of this chapter, unless otherwise indicated, the term "pages" refers to the memory
file:///C|/%23%23DDOC/spg/05spg001.html (2 of 10) [4/16/2002 11:14:09 PM]

About Memory

protection pages, and not to the SPORT hardware pages.

Free Memory Lists
The kernel uses linked lists to keep track of memory that is available for allocation. These lists, known as
free memory lists, contain entries for all currently free blocks.
Most tasks let the kernel take care of memory allocation and free memory lists. However, tasks that need
additional control over memory allocation can create their own memory lists and allocate memory to
themselves from those lists.

Free Memory Pools
The kernel keeps a list of free memory lists for each owner of memory. For example, it creates a list
containing two free memory lists, one for DRAM and one for VRAM, for each new task that is created. This
list of memory lists-which contains all the unused memory that a task owns -is the task's free memory pool.
When a task allocates memory, it must allocate it from its own free memory pool.
Note: Threads share the free memory lists with their parent and sibling threads. Access to these lists is
controlled by a semaphore.
In addition to the free memory pools for tasks, there is a system-wide free memory pool that contains the
unused memory that the kernel owns. The next section explains how memory is transferred from the systemwide free memory pool to the free memory pools for specific tasks.

How Memory Allocation Works
The following sections take you step-by-step through the process of memory allocation and illustrates what
happens to memory pools, lists, and blocks at each step.

The Beginning: The System-Wide Free Memory Pool
In the beginning, after the system is started and before any user tasks are launched, there is a system-wide
free memory pool with DRAM and VRAM. Figure 1 shows this memory pool.

file:///C|/%23%23DDOC/spg/05spg001.html (3 of 10) [4/16/2002 11:14:09 PM]

About Memory

Figure 1: System-wide free memory pool on bootup.
Figure 1 illustrates that the system software allocates a number of pages for itself (currently 19 pages of
DRAM and 1 page of VRAM for a system with 2 MB DRAM and 1 MB VRAM). On current 3DO systems
with 2 MB of DRAM and 1 MB of VRAM, this leaves at least 1440 KB of DRAM and 1008 KB of VRAM
for applications. In certain cases, the operating system can free additional memory for applications.

A Task Gets a Free Memory Pool
Next, the first user task is launched. The kernel creates a free memory pool for each new task. The pool
consists of two free memory lists: one for DRAM and one for VRAM. The kernel then gives the task the
memory it needs to get started (the amount needed for the task's code, global variables, and stack) by
transferring the necessary pages of DRAM and VRAM from the system-wide free memory pool to the task's
pool, thereby making the task the owner of the memory. Figure 2 shows the result.
Note: A task's VRAM pool is usually empty when the task first starts up.

Figure 2: A task receives necessary memory for its own free memory pool.
When memory moves from one free memory pool to another, only full pages of memory are moved. All the
memory in a page belongs to the same owner, so a page is the smallest amount of memory that can be
transferred from one owner to another.

file:///C|/%23%23DDOC/spg/05spg001.html (4 of 10) [4/16/2002 11:14:09 PM]

About Memory

The Task Allocates Its First Memory Block
The new task allocates its first memory block, a block of VRAM for its frame buffer. Figure 3 shows this
VRAM allocation.

Figure 3: A task allocates a block of VRAM for its frame buffer.

The Task Allocates More Blocks
The task allocates several blocks of DRAM, as shown in Figure 4.

Figure 4: A task allocates blocks of DRAM.
file:///C|/%23%23DDOC/spg/05spg001.html (5 of 10) [4/16/2002 11:14:09 PM]

About Memory

The Task Frees Memory
When the task finishes with a particular block of memory, it returns the block to its free memory pool, as
shown in Figure 5. The kernel automatically coalesces any free blocks in an adjacent free memory list. To
make it easy to find adjacent blocks, the kernel sorts memory lists by memory address; adjacent blocks are
thus next to each other in a list.

Figure 5: A task frees a block of memory.

The Task Needs More Memory
When the amount of memory a task requests in an allocation is more than the amount of contiguous DRAM
remaining in the task's free memory pool, the kernel transfers pages from the system free pool to the task,
thereby replenishing the task's pool.

file:///C|/%23%23DDOC/spg/05spg001.html (6 of 10) [4/16/2002 11:14:09 PM]

About Memory

Figure 6: The kernel transfers pages of DRAM to satisfy a memory request.

Another Task Gets a Free Memory Pool
A second task is now launched. Like all new tasks, it gets its own free memory pool as shown in Figure 7.

Figure 7: A second task receives its own free memory pool.

The System-Wide Free Memory Pool Is Drained
file:///C|/%23%23DDOC/spg/05spg001.html (7 of 10) [4/16/2002 11:14:09 PM]

About Memory

The two tasks keep allocating memory blocks from their free memory pools, and the kernel continues to
replenish the task pools from the system-wide free memory pool when necessary. Finally, the system-wide
free memory pool gets low on memory, as shown in Figure 8.

Figure 8: The system wide free memory pool runs low on memory.

Tasks Reclaim Memory and Return It to the Kernel
When the tasks try to allocate more memory, the system calls ScavengeMem() on the tasks behalf, as
shown Figure 9.
ScavengeMem()returns any completely unused pages of memory in a task's free memory pool to the
system-wide free memory pool, thereby making the pages available to other tasks.

file:///C|/%23%23DDOC/spg/05spg001.html (8 of 10) [4/16/2002 11:14:09 PM]

About Memory

Figure 9: Tasks scavenge memory in response to the kernel's signal.

Guidelines for Using Memory
Remember the following guidelines when using memory:
●

For each memory allocation function, there is a corresponding function to free the memory that was
allocated and return it to the free memory list it came from. You must use this corresponding function
to free memory. Table 1 lists the corresponding functions:
Table 1:
Corresponding memory allocation and memory freeing calls.
-------------------------------------------------Allocate Function
|Corresponding Free Function
-------------------------------------------------AllocMem()
|FreeMem()
-------------------------------------------------malloc()
|free()
-------------------------------------------------AllocMemList()
|FreeMemList()
-------------------------------------------------AllocMemFromMemList() |FreeMemToMemList()
-------------------------------------------------AllocMemFromMemLists()|FreeMemToMemLists()

file:///C|/%23%23DDOC/spg/05spg001.html (9 of 10) [4/16/2002 11:14:09 PM]

About Memory

-------------------------------------------------AllocMemBlocks()
|ControlMem()
-------------------------------------------------●

●

●

●

●

Use 32-bit addressing for all memory. Future 3DO systems may have enough memory to need it.
Don't tamper with the system structures (such as free memory lists) that control memory allocation,
ownership, and write access. The ways these work are subject to change in future versions of
Portfolio.
Although tasks can write to each other's memory, tasks should normally use intertask communication
to share information. Intertask communications are described in Communicating Among Tasks.
Certain regions of the address space must not be accessed. Memory references must be restricted to
addresses that have valid RAM. In addition, the lower page of RAM should never be accessed by
applications.
Use memdebug to identify problems with your memory usage. See Debugging Memory Usage for
more information.

file:///C|/%23%23DDOC/spg/05spg001.html (10 of 10) [4/16/2002 11:14:09 PM]

Allocating Memory

Allocating Memory
The following sections explain the easy way to allocate memory: by asking the kernel to do it. To learn
how tasks can allocate their own memory from private memory lists, see Using Private Memory Lists.

Allocating a Memory Block
The normal way to allocate memory is with the AllocMem() macro:
void *AllocMem( int32 s, uint32 t )
The s argument specifies the size of the memory block to allocate, in bytes. The t argument contains
memory allocation flags that specify the type of memory to allocate. You can include optional flags in
the t argument that specify other characteristics of the block. The macro returns a pointer to the allocated
block or NULL if the block couldn't be allocated.

Memory Block Flags
In the t argument, you must include one of the following flags to specify the type of memory to allocate:
●
●
●

MEMTYPE_ANY. Allocates any memory that is available.
MEMTYPE_VRAM. Allocates only video random-access memory (VRAM).
MEMTYPE_DRAM. Allocates only dynamic random-access memory (DRAM).

If a block of VRAM must come from a specific VRAM bank, you must include the following flag to
specify that bank:
●

MEMTYPE_BANKSELECT, Allocates VRAM from a specific VRAM bank.

You must also include one of the following two VRAM bank selection flags:
●
●

MEMTYPE_BANK1. Allocates only memory from VRAM bank 1.
MEMTYPE_BANK2. Allocates only memory from VRAM bank 2.

The following flags are for compatibility with future hardware. You can set them in addition to the
preceding flags.
●

MEMTYPE_DMA. Allocates only the memory that is accessible via direct memory access

file:///C|/%23%23DDOC/spg/05spg002.html (1 of 4) [4/16/2002 11:14:10 PM]

Allocating Memory

(DMA). Currently, all memory is accessible via DMA, but this may not be true in future
hardware. Include this flag if you know the memory must be accessible via DMA.
●

●

●

MEMTYPE_CEL. Allocates memory that is accessible only to the cel engine. Currently, all
memory is accessible to the cel engine, but this may not be true in future hardware. Include this
flag if you know the memory will be used for graphics.
MEMTYPE_AUDIO. Allocates only memory that is used only for audio data (such as digitized
sound). Currently, all memory can be used for audio, but this may not be true in future hardware.
Include this flag if you know the memory will be used for audio data.
MEMTYPE_DSP. Allocates only memory that is accessible to the digital signal processor
(DSP). Currently, all memory is accessible to the DSP, but this may not be true in future
hardware. Include this flag if you know the memory must be accessible to the DSP.

You can use the following optional flags to specify alignment (where the block is in relation to page
boundaries), fill (the initial value of all memory locations in the block), and other allocation
characteristics:
●

●

●

●

●

●

MEMTYPE_FILL. Sets every byte in the memory block to the value of the lower-8 bits of the
flags. If this flag is not set, the previous contents of the memory block are not changed. Using this
flag is slower than not using it, so don't set this flag if you plan to initialize memory with your
own data.
MEMTYPE_INPAGE. Allocates a memory block that does not cross page boundaries.
MEMTYPE_SYSTEMPAGESIZE. Allocates a memory block that starts on a memory
protection page boundary as opposed to a SPORT page boundary.
MEMTYPE_STARTPAGE. Allocates a memory block that starts on a page boundary. When
allocating VRAM, this flag tells the system to allocate memory at the start of a SPORT page (2
KB boundaries) as opposed to a memory protection page. To always use the memory protection
page size, you must also set the MEMTYPE_SYSTEMPAGESIZE flag.
MEMTYPE_MYPOOL. Allocates a memory block from memory that is already in your task's
free memory pool. This means that if there is not sufficient memory in the task's pool, the kernel
will not allocate additional memory from the system-wide free memory pool.
MEMTYPE_FROMTOP. Causes the allocation to come from the top of the task's free pool
instead of from the bottom.

If there is insufficient memory in a task's free memory pool to allocate the requested memory, the kernel
file:///C|/%23%23DDOC/spg/05spg002.html (2 of 4) [4/16/2002 11:14:10 PM]

Allocating Memory

automatically transfers the necessary pages of additional memory from the system-wide free memory
pool to the task's free memory pool. The only exceptions are when there is not enough memory in both
pools together to satisfy the request, or when the MEMTYPE_MYPOOL memory flag-which specifies that
the memory block must be allocated only from the task's current free memory pool-is set.

Freeing a Memory Block
To free a memory block allocated with AllocMem(), use FreeMem():
void FreeMem( void *p, int32 size )
The p argument points to the memory block to free. The size argument specifies the size of the block
to free, in bytes. The size you specify must always be the same as the size specified when you allocated
the block.

Allocating Memory in Programs Ported From Other
Platforms
If you're porting a program from another platform that uses the malloc() function from the standard C
library to allocate memory, you can continue to use malloc():
void *malloc( int32 size )
The size argument specifies the size of block to allocate, in bytes. It returns a pointer to the block that
was allocated, or NULL if the memory couldn't be allocated.
Because malloc() does not accept memory allocation flags, you cannot use it to specify a particular
kind of memory or any other memory characteristics. If you are writing programs specifically for 3DO
systems, you should use AllocMem() in place of malloc().
You must only use free() to free memory that you've allocated with malloc(). Each memory
allocation function has a corresponding deallocation function; if you use a different memory allocation
function, you must use its corresponding deallocation function. (See .)

Freeing Memory in Programs Ported From Other
Platforms
To free a memory block you have allocated with malloc(), use free():
file:///C|/%23%23DDOC/spg/05spg002.html (3 of 4) [4/16/2002 11:14:10 PM]

Allocating Memory

void free( void *p )
The p argument points to the memory block to free. The entire block is freed automatically; unlike
FreeMem(), you do not need to specify the amount of memory to free.

file:///C|/%23%23DDOC/spg/05spg002.html (4 of 4) [4/16/2002 11:14:10 PM]

Using Private Memory Lists

Using Private Memory Lists
If you have dynamic components running and allocating memory, it may be necessary to limit the
amount of memory certain threads can use. You can create a private memory for those threads, memory
list. Those threads would only allocate memory from this list and since you can control the total amount
of memory in the private memory list, you can control the maximum amount of memory that certain
threads can allocate.

Creating a Private Memory List
You can create a private memory list by calling the AllocMemList() function:
MemList *AllocMemList( const void *p, const char *name )
The p argument is a pointer to a memory address of the type of memory (either DRAM or VRAM) you
want to store in the list. A single memory list can store either DRAM or VRAM, but not both. You use
the name argument to name the memory list. The return value is a pointer to the resulting MemList
structure, or NULL if an error occurred.

Adding Memory to a Private Memory List
Initially, the memory list you create with AllocMemList() is empty. To add memory to the list, use
the FreeMemToMemList() function:
void FreeMemToMemList( MemList *ml, void *p, int32 size )
The ml argument is a pointer to the memory list from which to free the memory. The p argument is a
pointer to the memory to free. The memory block must be properly aligned in position and size for the
type of memory being manipulated. The alignment granularity can be determined with
GetMemAllocAlignment(). The number returned by this function indicates the alignment needed
for the pointer; the size of the memory block being freed must also be a multiple of this value. Your task
must already own this memory. The type of the memory to free must be the same as the type specified in
the p argument of AllocMemList(). The size argument specifies the amount of memory to move
the free list, in bytes. You can move a block of any size to the free list.

Allocating Memory From a Private Memory List
file:///C|/%23%23DDOC/spg/05spg007.html (1 of 3) [4/16/2002 11:14:10 PM]

Using Private Memory Lists

Once you've created a private memory list and put memory into it, you can allocate memory from the list
with the AllocMemFromMemList() function:
void *AllocMemFromMemList( MemList *ml, int32 size, uint32
memFlags )
The ml argument is a pointer to the memory list from which to allocate the memory. The size
argument specifies the size of the block to allocate, in bytes. The memtype argument contains flags that
specify the type of memory to allocate, the alignment of the block with respect to the page, and so on;
these flags can include MEMTYPE_ANY, MEMTYPE_VRAM, MEMTYPE_DRAM,
MEMTYPE_BANKSELECT, MEMTYPE_BANK1, MEMTYPE_BANK2, MEMTYPE_DMA, MEMTYPE_CEL,
MEMTYPE_AUDIO, MEMTYPE_DSP, MEMTYPE_FILL, MEMTYPE_INPAGE,
MEMTYPE_STARTPAGE, MEMTYPE_SYSTEMPAGESIZE, and MEMTYPE_MYPOOL. Note that the
flags that specify the actual memory type (such as MEMTYPE_DRAM) must match the type of the memory
contained in the list. For complete descriptions of these flags, see Allocating a Memory Block. The
function returns a pointer to the block that was allocated or NULL if there was not enough memory in the
list to satisfy the request.
To free memory that you've allocated with AllocMemFromMemList(), you must use only
FreeMemToMemList() (described in the next section). Each memory allocation function has a
corresponding deallocation function; if you use another memory allocation function, you must use its
corresponding deallocation function.

Freeing Memory to a Private Memory List
To free a block of memory that you've allocated from a private memory list and return it to the list, you
use the FreeMemToMemList() function:
void FreeMemToMemList( MemList *ml, void *p, int32 size )
The ml argument is a pointer to the memory list from which the block was allocated. The p argument is
a pointer to the block to free. The size argument specifies the size of the block to free, in bytes.

Deallocating a Private Memory List
To deallocate a private memory list, you first empty it (using ControlMem() to return the memory
pages to the kernel, as described in Transferring Memory to Other Tasks) and then use the
FreeMemList() function:
void FreeMemList( MemList *ml )
file:///C|/%23%23DDOC/spg/05spg007.html (2 of 3) [4/16/2002 11:14:10 PM]

Using Private Memory Lists

The ml argument is a pointer to the memory list to deallocate. If the list is not empty, any memory it
contains is lost.

Sharing Private Memory Lists Among Threads
To use a single memory list from multiple independent threads, there must be extra protection so the
threads don't corrupt the shared data structure. To share a memory list, you must attach a semaphore item
to the MemList structure. This is done by creating a semaphore item and putting its Item number in the
meml_Sema4 field of the MemList structure.

file:///C|/%23%23DDOC/spg/05spg007.html (3 of 3) [4/16/2002 11:14:10 PM]

Transferring Memory to Other Tasks

Transferring Memory to Other Tasks
The previous section explained how to use ControlMem() to grant and revoke write access to memory
pages. You can also use ControlMem() to transfer ownership of memory pages to other tasks:
Err ControlMem( void *p, int32 size, int32 cmd, Item task )
If the value of the cmd argument is MEMC_GIVE, the call gives the memory pages to the task specified
by the task argument. In this case, the p argument, a pointer to a memory location, and the size
argument, the amount of the contiguous memory, in bytes, beginning at the memory location specified by
the p argument, together specify the memory to give away. If these two arguments specify any part of a
page, the entire page is given away.
You can also give memory pages back to the kernel-and thereby return them to the system-wide free
memory pool-by calling ControlMem() as described here, but with 0 as the value of the task
argument. Memory pages can be returned to the kernel automatically when a task calls the
ScavengeMem() function described in Reclaiming Memory for Other Tasks.

file:///C|/%23%23DDOC/spg/05spg006.html [4/16/2002 11:14:11 PM]

Reclaiming Memory for Other Tasks

Reclaiming Memory for Other Tasks
When you free a large chunk of memory, it is good practice to return the pages to the system-wide free
memory pool with ScavengeMem(), so other tasks can use them:
int32 ScavengeMem( void )
This function finds pages of memory from which no memory is allocated in the task's free memory pool
and gives those pages back to the system-wide free memory pool. The function returns the amount of
memory that was returned to the system-wide memory pool, in bytes, or it returns 0 if no memory was
returned.

file:///C|/%23%23DDOC/spg/05spg004.html [4/16/2002 11:14:11 PM]

The Filesystem and the File Folio

The Filesystem and the File Folio
This chapter describes the 3DO file system. It includes sample code that illustrates how to use File folio
calls. This chapter contains the following topics:
●
●
●
●
●
●
●
●
●

3DO File System Interface
Pathnames and Filenames
Byte-Stream File Access
Accessing Directories
The Current Directory
Loading and Executing an Application
Working With NVRAM
File System Folio Function Calls
Examples

file:///C|/%23%23DDOC/spg/11spg.html [4/16/2002 11:14:11 PM]

3DO File System Interface

3DO File System Interface
The 3DO file system is, in essence, a high-level device driver that interposes itself between an application
and the "raw" disk device. The application can issue a call to open a specific disk file and will receive in
return an item for a device node. This device item (referred to internally as an "open file") can be treated
like most other device items-you can create one or more IOReq items for the device item, and send these
IOReqs to the device to read data from the file.
The file system architecture is implemented as a combination of the following elements:
●
●
●

The File folio that provides high-level functions to interface to the lower-level components.
The driver that manages the file system and open file devices.
The daemon task that manages I/O scheduling.

The 3DO filesystem is an intrinsic part of Portfolio and starts automatically during system start up.

Design Philosophy
The 3DO filesystem structures were designed with a number of factors:
●

●

●

Most 3DO file systems reside on CD-ROM devices.
CD-ROM drives are slow, with seek times measured in hundreds of milliseconds. Minimizing the
amount of head-seeking required during game play is critical to the responsiveness of the system.
3DO CD-ROMs tend to be handled and stored under less-than-ideal conditions. They can be
subject to accidental damage during or between uses.

For these reasons, the 3DO file system supports data replication, in a way that is transparent to the
application and to the user (except for a possible delay, if one copy of the data cannot be read and the CDROM mechanism must seek another copy). The file driver prioritizes, sorts, and optimizes I/O requests to
the file system device to minimize the total seek-and-read time for individual requests and for groups of
requests.

Files
Files are collections of blocks, each block containing a fixed number of bytes. The block size of a file is
determined generally by the block or sector size of the device on which it resides. For example, on a CDfile:///C|/%23%23DDOC/spg/11spg001.html (1 of 3) [4/16/2002 11:14:12 PM]

3DO File System Interface

ROM file system, most files have a block size of 2,048 bytes.
The file system deals with files exclusively in terms of blocks. However, it does maintain a logical size in
bytes for each file. This logical size indicates the number of bytes actually used within the blocks
allocated for the file.
The File folio provides a number of FileStream functions that offer a stream-oriented interface to the file
system. Using these functions, you can read and seek in files in a manner that is similar to the C stdio
routines. These functions are described in Byte-Stream File Access.

Directories
The 3DO-native file system implements directories as ordinary disk files that are flagged as a specific
type. The directories can be opened as normal files using the OpenDiskFile() function. To read the
contents of a directory, you must use the OpenDirectory() and ReadDirectory() functions.

Avatars
The 3DO CD-ROM file system supports the unique concept of avatars. Each file consists of one or more
avatars, placed in various locations across the disk. Each avatar is an exact, coequal image of the data in
the file.

How Avatars Work
The file driver keeps track of the current position of the device's read head. When asked to read data, it
automatically chooses the "closest avatar in good condition" of each block of data it is asked to read. If it
must perform more than one read, the driver sorts the read requests to minimize the amount of headseeking. It honors the I/O request priorities during this process-completing all requests of one priority
before scheduling any requests of a lower priority.
If the device has trouble reading a data block contained within one avatar of a file, the file driver marks
that avatar as flawed and reissues the read request-thus searching out another avatar on the disk, if one
exists.
It is not necessary, nor is it desirable, for all files in a 3DO file system to have the same number of
avatars. Critical directories, or files accessed frequently throughout the execution of the application, can
have as many as a dozen avatars scattered across the disk. Large files, or those containing noncritical
data, may have only one avatar.

Placement of a File's Avatars
file:///C|/%23%23DDOC/spg/11spg001.html (2 of 3) [4/16/2002 11:14:12 PM]

3DO File System Interface

The placement of a file's avatars can have a great effect on the performance of a Portfolio game
application. If your application opens and reads several files in sequence, and the avatars lie some
distance away from one another on the CD-ROM, the CD-ROM drive must seek from one file to another;
your program must wait while it does so. However, if the avatars are located close together, ideally, right
next to one another, the CD-ROM drive needs to seek less, and perhaps not at all. Every seek on a CDROM drive takes tens to hundreds of milliseconds; it's important to minimize the number of seeks for
your application to perform well.
The software tool that lays out a Portfolio CD-ROM can optimize the avatar locations on your files in an
effective, semiautomatic fashion. It can create two or more avatars of frequently used files, to reduce the
distance needed to seek to the file. It can even weave portions of different files together into a single
accelerated-access file called Catapult, eliminating most of the seeks that occur during the system startup
process.
The layout optimization and multiple-avatar speedups, and the Catapult acceleration, are completely
transparent to your application. You do not need to change any application code to take advantage of
them. They do not change the functionality of the filesystem, they simply improve its performance.
Instructions on doing an optimized CD-ROM layout with Catapult acceleration can be found in the 3DO
CD-ROM Mastering Guide. You should do an optimized and Catapult-accelerated layout of your
application before you submit it to The 3DO Company for encryption. If you submit a nonoptimized CDROM image for encryption, the company may ask you to optimize and resubmit it.

file:///C|/%23%23DDOC/spg/11spg001.html (3 of 3) [4/16/2002 11:14:12 PM]

Byte-Stream File Access

Byte-Stream File Access
A set of function calls in the File folio eases the job of accessing the contents of a file in a byte-by-byte
fashion, rather than in the block-by-block mode supported by the file driver interface. These functions
include:
●
●
●
●

OpenDiskStream()
SeekDiskStream()
ReadDiskStream()
CloseDiskStream()

With these functions, a program can read an arbitrary number of bytes
from anywhere within a file, without worrying about block boundaries.

Opening a File
Before you can read a file's data using the streaming routines, you must open the file:
Stream *OpenDiskStream( char *theName, int32 bSize )
OpenDiskStream() opens the file identified by an absolute or relative pathname, allocates the
specified amount of buffer space, and initiates an asynchronous read to fill the buffer with the first
portion of the file's data. It returns NULL if any of these functions cannot be performed for any reason.

Reading the Data
To read data from a stream file, you must call ReadDiskStream()
int32 ReadDiskStream( Stream *theStream, char *buffer, int32
nBytes )
ReadDiskStream() reads data from the given stream file starting at the current position within the
file. The data is put into the supplied buffer. The number of bytes actually read from the file is returned.
The position within the file is advanced by the number of bytes read, so that the next time
ReadDiskStream() is called, the data that follows is read.

Setting Up the Read Position
file:///C|/%23%23DDOC/spg/11spg003.html (1 of 2) [4/16/2002 11:14:12 PM]

Byte-Stream File Access

To change the current position within a stream file, you must call:
SeekDiskStream( Stream *thream, int32 offset, enum SeekOrigin
whence )
After you call SeekDiskStream(), data transfers start with the first byte at the new file position. The
whence argument specifies whether the operation is relative to either the beginning or end of the file, or
to the current position in the file. The offset argument specifies the number of bytes offset relative to
the whence position. It returns the actual absolute file position that results from the seek position or a
negative error code if unsuccessful.
The offset can be specified in any of three ways: absolute (positive) byte offset from the beginning of file
(SEEK_SET), relative byte offset from the current position in the file (SEEK_CUR), or absolute
(negative) byte offset from the end of the file (SEEK_END).

Cleaning Up
CloseDiskStream() closes the stream's file, deallocates the buffer memory, and releases the stream
structure.
void CloseDiskStream(Stream *theStream);

file:///C|/%23%23DDOC/spg/11spg003.html (2 of 2) [4/16/2002 11:14:12 PM]

Pathnames and Filenames

Pathnames and Filenames
Gaining access to files is done by describing the files using pathnames. Pathnames provide a description
of the location of files within a file system hiearchy. The 3DO file system uses pathnames akin to those
used in UNIX. An absolute pathname is of the form:
/file system/dir1/dir2/dir3/(more)/dirN/filename
Each task in Portfolio has a current directory associated with it. Relative pathnames describe a location
relative to a known directory. An absolute pathname always starts with a backslash ( /), while a relative
pathname never does.
A relative pathname can be in one of three forms:
filename dir/filename dir1/dir2/(more)/dirN/filename
Relative pathnames can be used in either of two ways:
●

●

In the OpenDiskFile() call, pathnames specify a path relative to the current task's current
directory.
In the OpenDiskFileInDir() call, pathnames specify a path relative to a directory whose
item is specified in the call.

In addition, three special conventions are used to further describe the 3DO directory structure. A path
component of a full stop (.) indicates the current directory. A path component of two full stops (..)
indicates the parent directory. Finally, a caret (^) indicates the root of the file system.
Each pathname component should not be longer than 31 characters. In addition, certain characters are not
allowed in component names. These illegal characters are backslash (/), dollar sign ($), left bracket ( { ),
right bracket ( } ), and a pipe (|).

file:///C|/%23%23DDOC/spg/11spg002.html [4/16/2002 11:14:13 PM]

Accessing Directories

Accessing Directories
Four functions in the File folio provide access to directories and their contents. These functions can
enumerate the contents of directories or obtain information about all the currently mounted file systems.
●
●
●
●

OpenDirectoryPath()
OpenDirectoryItem()
ReadDirectory()
CloseDirectory()

Opening the Directory
You can open a directory to read by specifying the directory's pathname or the directory's item number.
OpenDirectoryPathName() opens a directory by specifying its pathname.
Directory *OpenDirectoryPathName( char *thePath )
This function opens a directory, allocates a new Directory structure, and prepares for a traversal of the
contents of the directory. It returns a pointer to a Directory structure that or NULL if an error occurs.
OpenDirectoryItem() opens a directory by referencing its item number.
Directory *OpenDirectoryItem( Item openFileItem )
It allocates a new Directory structure, opens the directory, and prepares for a traversal of the contents of
the directory. OpenDirectoryItem() returns a pointer to the Directory structure, or NULL if an
error occurs. Typically, you obtain the item number of a directory by calling OpenDiskFile() on the
directory, or by calling GetDirectory().

Reading the Directory
ReadDirectory() reads the next entry from the specified directory.
int32 ReadDirectory( Directory *dir, DirectoryEntry *de )
This function gets information about the next directory entry, and deposits this information in the
supplied DirectoryEntry structure. The contents of this structure can then be examined to get details
about the entry. The function returns an error code if all entries in the directory have been processed.
file:///C|/%23%23DDOC/spg/11spg004.html (1 of 2) [4/16/2002 11:14:13 PM]

Accessing Directories

Cleaning Up
CloseDirectory() closes a directory that was previously opened using OpenDirectoryItem()
or OpenDirectoryPath().
void CloseDirectory( Directory *dir )
All resources get released.

Finding Mounted File Systems
You can obtain a list of the mounted file systems by scanning the "/" directory. If you open this directory
and call ReadDirectory() on it, you iterate through all of the currently mounted file system. The
DirectoryEntry structure will then hold information about the file system.

file:///C|/%23%23DDOC/spg/11spg004.html (2 of 2) [4/16/2002 11:14:13 PM]

The Current Directory

The Current Directory
Each task in the Portfolio environment has a current directory associated with it. The current directory is
the starting location for relative pathnames that are used with various File folio calls which take a
pathname as an argument.
When an application is loaded from a file, it automatically gets its current directory set to where the
program file is located. This makes it easier for the new task to find any files it needs.
The File folio provides two calls, GetDirectory() and ChangeDirectory(), to determine and
change the location of the current directory of the current task.

Finding the Current Directory
GetDirectory() returns the item number of the current directory of the calling task.
Item GetDirectory( char *pathBuf, int32 pathBufLen )
If pathBuf is non-NULL, it points to a buffer of writable memory whose length is given in
pathBufLen; the absolute pathname of the current working directory is stored into this buffer.

Changing the Current Directory
ChangeDirectory() changes the current directory of the current task to the absolute or relative
location specified by the path.
Item ChangeDirectory( char *path )
The function returns the item number of the new directory, or a negative error code if an error occurs.

file:///C|/%23%23DDOC/spg/11spg005.html [4/16/2002 11:14:13 PM]

Loading and Executing an Application

Loading and Executing an Application
The File folio provides six functions to load and run executable code:
●
●
●
●
●
●

LoadProgram()
LoadProgramPrio()
LoadCode()
UnloadCode()
ExecuteAsSubroutine()
ExecuteAsThread()

Loading and Launching a Task
LoadProgram() loads an executable file from disk and launches a new task which executes the code
in the file.
Item LoadProgram(char *cmdLine);
The only argument of this function is a command line to interpret. The first component of the command
line is taken as the name of the file to load. The entire command line is passed to the new task as argc
and argv in the main() function. The file name component of the command line specifies either a
fully qualified pathname, or a pathname relative to the current directory.
The priority of the new task is the same as the priority of the current task. If the task should have a
different priority, use the LoadProgramPrio() function.
LoadProgramPrio() is identical to LoadProgram() except that it specifies a task priority for the
new task.
Item LoadProgramPrio(char *cmdLine, int32 priority);
You give this function a command line to interpret. The first component of the command line is taken as
the name of the file to load. Like LoadProgram(), the entire command line is passed to the new task
as argc and argv in the main() function. The file name component of the command line specifies
either a fully qualified pathname, or a pathname relative to the current directory.
The priority argument specifies the task priority for the new task. If you simply want the new task to
have the same priority as the current task, use the LoadProgram() function instead. Alternatively,
passing a negative priority to this function will also give the new task the same priority as the current
file:///C|/%23%23DDOC/spg/11spg006.html (1 of 3) [4/16/2002 11:14:14 PM]

Loading and Executing an Application

task. LoadProgram() and LoadProgramPrio() will set the current directory of the newly created
task to the directory from which the executable was loaded.

Loading a Code Module
LoadCode() loads an executable file from disk into memory. Once loaded, the code can be spawned as
a thread, or executed as a subroutine.
Err LoadCode(char *fileName, CodeHandle *code);
In order to work correctly with this and associated functions, the executable file being loaded must have
been linked with threadstartup.o or subroutinestartup.o instead of cstartup.o
This function requires the name of the executable file to load, as well as a pointer to a CodeHandle
variable, where the handle for the loaded code will be stored.
Note: code must point to a valid CodeHandle variable, because LoadCode() uses this location to
put a pointer to the loaded code.

Executing a Loaded Code Module
To execute the loaded code, you must call either the ExecuteAsThread() function or the
ExecuteAsSubroutine() function. If the loaded code is reentrant, the same loaded code can be
spawned multiple times simultaneously as a thread.
ExecuteAsSubroutine() executes a chunk of code that was previously loaded from disk using
LoadCode().
int32 ExecuteAsSubroutine(CodeHandle code, int32 argc, char
**argv);
This function runs the code as a subroutine of the current task or thread.To work correctly, code that is
run as a subroutine should be linked with subroutinestartup.o instead of the usual cstartup.o
The parameters in argc and argv are passed directly to the main() entry point of the loaded code.
The return value of this function is the value returned by main() of the code being run.
The values you supply for argc and argv are irrelevant to this function. They are simply passed
through to the loaded code. Therefore, their meaning must be agreed upon by the caller of this function,
and by the loaded code.
file:///C|/%23%23DDOC/spg/11spg006.html (2 of 3) [4/16/2002 11:14:14 PM]

Loading and Executing an Application

ExecuteAsThread() executes a chunk of code that was previously loaded from disk using
LoadCode(). This function executes code that will execute as a thread of the current task.
Item ExecuteAsThread(CodeHandle code, int32 argc, char **argv,
char *threadName, int32 priority);
To work correctly, code being run as a thread should be linked with threadstartup.o instead of the usual
cstartup.o
The argc and argv parameters are passed directly to the main() entry point of the loaded code.The
values you supply for argc and argv are irrelevant to this function. They are simply passed through to
the loaded code. Therefore, their meaning must be agreed upon by the caller of this function, and by the
loaded code. threadName specifies the name of the thread. priority specifies the priority the new
thread should have. Providing a negative priority makes the thread inherit the priority of the current task
or thread.

Unloading a Code Module
Once you are done using the loaded code, you can remove it from memory by passing the code handle to
the UnloadCode() function. UnloadCode() frees any resources allocated by LoadCode(). Once
UnloadCode() has been called, the code handle supplied becomes invalid and cannot be used again.

file:///C|/%23%23DDOC/spg/11spg006.html (3 of 3) [4/16/2002 11:14:14 PM]

Working With NVRAM

Working With NVRAM
The Portfolio operating system treats NVRAM-nonvolatile random access memory-as a file system
volume. This maintains consistency for I/O operations; you use the same steps for accessing NVRAM as
you do for all other files. Portfolio also provides an NVRAM maintenance utility called lmadm. See the
3DO Debugger Programmer's Guide, "Terminal Window Commands," for full details.
A minimally configured 3DO system has at least 32 KB of NVRAM. Application developers can use this
facility for persistent storage of small pieces of data. Practical uses include providing a game saving
feature, to save user preference settings, or to store application configuration information. There is no
way to query the operating system for the amount of available NVRAM memory prior to creating an
NVRAM file, because NVRAM is not confined to one contiguous area. The correct procedure is to try to
create and allocate the NVRAM file using the OpenDiskFile() call. If the call is successful, then
sufficient memory was available. If the call fails for lack of memory, then it returns an error code
indicating insufficient space.
The following sections explain how to access NVRAM. They include descriptions of high-level
NVRAM access routines.

How Not to Manage NVRAM
When NVRAM is full, some titles cannot manage VRAM appropriately. Some titles fail silently,
discarding information the user wants to save. Other titles overwrite information saved by other titles.
This can be annoying if a user reached a relatively high level in another title.
Caution: Developers should avoid managing NVRAM in the ways mentioned above.

How to Manage NVRAM
A title should do the following to manage NVRAM properly:
●

Remove obsolete files. For example, files for a previous version of the same title can probably be
removed.

●

If possible, save files as compressed files.

●

Never delete information about a different title without prompting the user.

file:///C|/%23%23DDOC/spg/11spg007.html (1 of 5) [4/16/2002 11:14:15 PM]

Working With NVRAM
●

Prompt the user to delete information currently in NVRAM if a title attempts to write to NVRAM
but fails because it is full. This can be done using Access, discussed in Access: A Simple User
Interface. Some guidelines are discussed in the next section.

How a Title Should Save Its Status
Every title should go through the same set of steps to save its status. This section lists the steps in
sequence. Commented sample code for parts of this sequence is provided in the 3DO Toolkit 1.3.1.
1. Bring up the Save Title display. This display differs from title to title. Users can usually choose to
overwrite files or add to a list of existing files.
2. If the user cancels, exit with no error.
3. Otherwise, attempt to write file.
4. If writing file works, exit with no error.
5. Otherwise, delete the file that was just saved. (This is important in order to remove any parts of
the file that might have made it to NVRAM.) Then inform the user that there is not enough room
to save the game, and bring up the Delete File display.
6. If the user chooses a file to delete, remove the file and go back to step 3 above.
Otherwise, if the user cancels-return to Save Title display and go back to step 1.
Note: A sample program that brings up a Delete File display is included in this release.

Working With NVRAM Files
Portfolio supports NVRAM access through file system function calls. Your title can use I/O requests to
work with an open NVRAM file as a device, as it would any other file. You can use the functions in the
section Using NVRAM to create (and allocate) blocks, and to read from, write to, get the block size of a
file, and set the end of a file.
This section first provides information on how to choose appropriate filenames, then provides some
information about how to look at NVRAM using the 3DO Debugger.

Choosing Appropriate Filenames
file:///C|/%23%23DDOC/spg/11spg007.html (2 of 5) [4/16/2002 11:14:15 PM]

Working With NVRAM

The NVRAM volume is a flat file system; it cannot contain subdirectories. Choose filenames wisely to
avoid conflicts with other title developers. To avoid name conflicts while still providing readable
filenames to end users, 3DO recommends the following file-naming standard. Filenames in NVRAM
have a limit of 31 characters. Filenames that follow this standard consist of two parts:
 [<user/level name>]
●

●

The first part is the name of the title itself. If space allows you should use the full name of your
title, with no abbreviations.
The second part of the filename uniquely identifies the file to the user. This part is flexible
depending on the purpose of the file. For example, if the file is a game and users are prompted for
their name as part of the game, the users' name or the name of the game level could be part of the
filename.

Note: When a title displays a Load Game or a Save Game display, it should only show its own files
within the list. That is, when loading a saved game from Total Eclipse, for example, a player shouldn't be
able to see games from Monster Manor in the file list. In addition, the entries displayed in that list should
not include the title's name.
Following this standard reduces the chance of filename conflicts in NVRAM. However, it still does not
completely eliminate the possibility of confusion between titles that create files with similar or identical
names. Therefore, it is recommended that you store a unique identifier in the first two bytes of every file
that your title creates in NVRAM. To guarantee uniqueness, this identifier should be the licensee number
assigned to you by 3DO.

Working With NVRAM via the 3DO Debugger
As with any other volume, NVRAM must be formatted properly before the file system can access it. If
you're working from the debugger, type the following command, followed by the Enter key, in the
debugger Terminal window:
format RAM 3 0 NVRAM
After issuing this command, reset the target. You should see the /NVRAM volume mount during file
system start-up. Thereafter, you can refer to this volume as /NVRAM. You will not need to perform this
format ritual again, since the contents of NVRAM are preserved across restarts and shutdowns. On a
production player NVRAM is preformatted.
If you're working from a CD-ROM image, the volume is formatted automatically.

file:///C|/%23%23DDOC/spg/11spg007.html (3 of 5) [4/16/2002 11:14:15 PM]

Working With NVRAM

Working With NVRAM Files From the Debugger
You can work with files in NVRAM the same way you'd work with other files. Copy them using the
Copy command. To view them, type into the Terminal window:
$c/ls /nvram
A list of all files appears in NVRAM. To see a more detailed list, type:
$c/lmdump RAM 3 0

NVRAM Chunk Definition
This section describes a format for files in NVRAM. The format lets you embed information about a file
inside the file itself. As a result, the Storage Manager or other software can present users with
information about the files in NVRAM.
This section first lists file type and chunk information, then presents a new chunk, the comment chunk,
and an example.

File type and chunk information
The files must have a special type, 3DOF, which stands for 3DO file format. This must be set for
applications to know that the file is in the correct format.
A file which is in the 3DO file format consists of one or more chunks. Each chunk contains a chunk ID,
chunk size, and chunk data. For more information about the 3DO file format see the 3DO CD-ROM
Mastering Guide.

The comment chunk
The comment chunk contains information about the file in NVRAM.
Table 1: Components of comment chunk.
----------------------------------------------------Name
|Descriptions
----------------------------------------------------ID
|NVRT
----------------------------------------------------size
|Length of the language data + 4
file:///C|/%23%23DDOC/spg/11spg007.html (4 of 5) [4/16/2002 11:14:15 PM]

Working With NVRAM

|bytes for the language code
----------------------------------------------------chunk data
|Language code and the comment
|with a null at the end
----------------------------------------------------language code
|0 for English
----------------------------------------------------For example, a comment chunk might look like this:
`NVRT',

20,

0,

"The 3DO Company"

file:///C|/%23%23DDOC/spg/11spg007.html (5 of 5) [4/16/2002 11:14:15 PM]

Access: A Simple User Interface

Access: A Simple User Interface
This chapter shows how a task uses Access to ask for and retrieve input from a 3DO user. This chapter
contains the following topics:
●
●
●
●

How Access Works
How to Use Access
Example
Access Message Tag Arguments

file:///C|/%23%23DDOC/spg/16spg.html [4/16/2002 11:14:15 PM]

How Access Works

How Access Works
Many times a task needs to present information to or ask for input from the user. For example, a task may
need the file name of a file to load, save, or delete, or ask the user which of two choices to make.
Access is a Portfolio system task that provides a mechanism for displaying this type of information to the
user and accepting user input. Access can create transaction boxes, display specified text, read controller
input, and perform all the other user input activities.
To use Access, a task communicates its user interface needs by sending messages to the Access message
port. The calling task receives results by receiving reply messages from Access. For example, a task
sends a message to Access requesting it to ask the user to load a file. Access presents the appropriate
transaction box, accepts the user's input (via the control pad), and sends the name of the file back to the
task.
Access provides two benefits to calling tasks:
●

●

First, the task doesn't have to create a user interface from scratch. Access creates the transaction
boxes for user input and monitors controllers to get the response to the transaction boxes, all
according to simple requests from the calling task.
Second, Access provides a consistent user interface for common activities found in many tasks.
For example, once a user learns how to load a file in one program that uses Access, he or she
doesn't have to learn a different process to load a file in another program that uses Access.

file:///C|/%23%23DDOC/spg/16spg001.html [4/16/2002 11:14:15 PM]

How to Use Access

How to Use Access
Using Access is simple. The calling task must follow these steps, which are explained in detail in the
sections that follow:
1. Create a message to send to Access and a reply port to receive a reply to the message.
2. Find the Access message port.
3. Create a list of tag arguments that request a specific user-interface transaction and describe the
properties of the transaction box that carries out the request.
4. Send a message to Access that points to the tag argument list.
5. Enter the wait state and wait for a reply from access.
6. Read the returned user input from Access's reply message.
The trick is in setting up the tag arguments to specify the interface transaction with the desired
transaction box layout.

Setting Up Message Communication With Access
Before a task can send tag argument lists to Access, it must first create a message item and a message
port as described in Communicating Among Tasks. Then, it must then find Access's message port,
"access," using the FindMsgPort() call. The following code segment returns the item number of
Access's message port:
FindMsgPort("access");

Creating a Tag Argument List
Once a task is set up to communicate with Access, it must create a tag argument list to carry tag
arguments to Access. The tag arguments that Access reads are the same tag argument data types used to
specify item attributes with the CreateItem() call. For a list of the tag argument data types, see
Managing Items. Each tag argument has two fields: the tag and the argument value. You need only
provide tag arguments for the attributes you wish to specify; all nonspecified attributes are set to default
values. Two tag arguments are mandatory: ACCTAG_REQUEST and ACCTAG_SCREEN. The final tag
file:///C|/%23%23DDOC/spg/16spg002.html (1 of 5) [4/16/2002 11:14:17 PM]

How to Use Access

argument in the list must be set to TAG_END to terminate the list.
All Access tags and the constants used to set their argument values are found in the include file access.h.

Specifying a Request
The first order of business is to request the type of user-input transaction the task wants Access to
perform. To specify, the task uses the tag ACCTAG_REQUEST, which can accept any one of the
following arguments:
●

●

●

●

●

●

●

ACCREQ_LOAD displays a transaction box that asks the user to specify a file to be loaded. The
transaction returns the pathname of a file to be loaded.
ACCREQ_SAVE displays a transaction box that asks the user to specify a file to save. The
transaction returns the pathname of a file to save.
ACCREQ_DELETE displays a transaction box that asks the user to specify a file to delete. The
transaction returns the pathname of a file to delete.
ACCREQ_OK displays a transaction box with text supplied by the calling task to inform the user
of a fact. The transaction box contains a single OK button, which the user can click to continue.
The transaction returns a 0.
ACCREQ_OKCANCEL displays a transaction box with text supplied by the calling task to inform
the user of a proposed action. The transaction box contains two buttons, OK and Cancel, which
the user can click on either to confirm the action or cancel it. The transaction returns a 0 for the
OK button or a 1 for the Cancel button.
ACCREQ_ONEBUTTON displays a transaction box with text supplied by the calling task to
inform the user. The transaction box has a single button with text also supplied by the calling task.
The user can click on it to continue. The transaction returns a 0.
ACCREQ_TWOBUTTON displays a transaction box with text supplied by the calling task to
inform the user. The transaction box has two buttons, each with text supplied by the calling task.
The user can click on either button to choose between the two choices. The transaction returns a 0
for the left button or a 1 for the right button.

When the calling task requests a specific user interface transaction, it must supply the necessary
information for carrying out the transaction. For example, if it specifies ACCREQ_TWOBUTTON, it must
supply text for both of the buttons in the transaction box and background text to explain the context of
the buttons.

file:///C|/%23%23DDOC/spg/16spg002.html (2 of 5) [4/16/2002 11:14:17 PM]

How to Use Access

Specifying a Screen
When a task requests a user interface transaction through Access, it must specify a screen where the
transaction box appears. To do so, the task provides the tag argument ACCTAG_SCREEN, which takes
the item number of the screen as its argument.
Note: Before you call Access, you must call ControlMem() so that Access can write to the screen's
memory.

Specifying Transaction Box Text
When Access puts a transaction box up on a screen, it can give the box a title that appears in its upperleft corner, fill the center of the box with explanatory text, and specify text for custom buttons as shown
in Figure 1.

Figure 1: An Access transaction box.
To specify a title for the transaction box, a task uses the tag argument ACCTAG_TITLE, which takes as
its argument a pointer to a NULL-terminated text string to be used as the title.
To specify text for the center of the transaction box, a task uses the tag argument ACCTAG_TEXT, which
takes as its argument a pointer to a NULL-terminated text string to be used as explanatory text. Access
automatically wraps text within the transaction box.
To specify text for the first button (the left button), a task uses the tag argument
ACCTAG_BUTTON_ONE; to specify text for the second button (the right button), it uses the tag
ACCTAG_BUTTON_TWO. Both tag arguments accept a pointer to a NULL-terminated text strings
containing the text to be inserted in the button.
file:///C|/%23%23DDOC/spg/16spg002.html (3 of 5) [4/16/2002 11:14:17 PM]

How to Use Access

Keep in mind that if you supply too much text for a button or the title, you may overflow the display.

Preserving the Screen Background
When Access presents a transaction box in a screen, it can overwrite the pixels beneath the transaction
box without restoring them (which leaves a big blank rectangle when the transaction box closes), or it
can save the pixels and restore them after closing the transaction box. To choose screen background
preservation, a task sends the tag ACCTAG_SAVE_BACK with the argument 0.
Preserving the screen background requires a fair amount of memory. To be memory efficient, you can
choose not to preserve the screen background by not sending the ACCTAG_SAVE_BACK tag argument at
all.

Creating a String Buffer for User Input Return
When an Access transaction box returns user input in the form of a text string, Access returns the string
by storing it in a buffer and then pointing to the buffer in its reply message. The task requesting the
transaction must supply the string buffer, allocating memory if necessary and then pointing to it and
giving its size. To point to a buffer, a task uses the tag argument ACCTAG_STRINGBUF, which takes a
pointer to the beginning address of the string buffer as its argument. It must also supply the tag argument
ACCTAG_STRINGBUF_SIZE, which takes the size in bytes of the string buffer as its argument.
Note: Before you call Access, you must call ControlMem() so that Access can write to the buffers.

Setting Transaction Box Colors
When Access presents a transaction box, it uses four colors:
●
●
●
●

The background color fills the interior of the box and the interior of any unselected buttons.
The foreground color forms the characters in all text within the transaction box.
The highlight color fills the interior of any selected button.
The shadow color forms the outline of buttons in the transaction box.

To set those colors, a task uses these four tag arguments:
●
●
●
●

ACCTAG_FG_PEN sets the foreground color.
ACCTAG_BG_PEN sets the background color.
ACCTAG_HILITE_PEN sets the highlight color.
ACCTAG_SHADOW_PEN sets the shadow color.

file:///C|/%23%23DDOC/spg/16spg002.html (4 of 5) [4/16/2002 11:14:17 PM]

How to Use Access

Each of these tags takes as an argument a pen color value, which is a 15-bit 3DO RGB value stored in the
low 15-bits of a 32-bit unsigned integer. (The upper 17 bits are set to 0.)

Sending a Message to Access and Waiting for a
Reply
Once the tag argument list for a transaction is created, the task requesting the transaction sends a message
to Access. The message points to the first tag argument in the list and gives the size of the buffer used to
store the tag arguments in bytes. Access receives the message, reads the tag arguments to define a
transaction, and puts up the appropriate transaction box to query the user.
In the meantime, the task that requested the transaction should entering the wait state to wait for a reply
message from Access. It can do so using the WaitPort() call. When Access is finished with the
transaction, it sends a reply to the task's reply port, which wakes up the task. The task can then read the
contents of Access's reply message.

Reading a Reply Message
Access's reply message to a task requesting a transaction contains the field msg_Result, which
contains the results of the transaction. If an error occurs, it contains a negative value (an error code
defined in access.h). If the transaction was successful, msg_Result contains a 0 or a 1. These values
can be interpreted in different ways depending on the button content of the transaction box. If the box
contains a single button, msg_Result contains 0 if the button was clicked. If the box contains a Cancel
and an OK button, it contains 0 for OK and 1 for Cancel. If the box contains two task-labeled buttons, it
contains 0 for the left button and 1 for the right button.

file:///C|/%23%23DDOC/spg/16spg002.html (5 of 5) [4/16/2002 11:14:17 PM]

Communicating Among Tasks

Communicating Among Tasks
This chapter gives you the background and necessary programming details to perform intertask
communication. Kernel Folio Calls in the 3DO System Programmer's Reference contains more specific
information about the calls used in this chapter.
This chapter contains the following topics:
●
●
●
●

About Intertask Communication
Using Signals
Passing Messages
Function Calls

file:///C|/%23%23DDOC/spg/08spg.html [4/16/2002 11:14:17 PM]

About Intertask Communication

About Intertask Communication
Two mechanisms can be used for intertask communication: signals and messages. Signals are used as an
intertask flag with which one task can notify another that something has occurred. Messages not only
allow one task to notify another, but also carry data from the sending task to the receiving task.
Signals and a task's ability to wait for a signal are the basis for all intertask communication. The message
mechanism, which passes more detailed information, is built on top of the signal mechanism. Sending
and receiving a message is based on a signal sent to the receiving task, informing it that a message is
waiting.

file:///C|/%23%23DDOC/spg/08spg001.html [4/16/2002 11:14:17 PM]

Using Signals

Using Signals
The procedure for using a signal involves several steps:
●

●

●

●

Task A uses AllocSignal() to allocate a signal bit (1 bit within a 32-bit word) for a signal.
Task A communicates the allocated signal bit to Task B so that it knows which signal to send (using the
allocated signal bit) back to Task A.
Task A uses WaitSignal() to enter a wait state until it receives a signal on the bit it allocated.
Task B uses SendSignal() to send a signal to Task A. Task B must provide SendSignal() with the
item of that task to signal, and the signals to send the task.

●

Task A receives the signal and returns from the wait state.

●

Task A uses FreeSignal() to free the signal bit when it's no longer needed.

Allocating a Signal Bit
To allocate a signal bit for a task, use this call:
int32 AllocSignal( uint32 sigMask )
AllocSignal() accepts as its sole argument a 32-bit word (sigMask) which specifies which signal bits to
allocate. There are 31 signal bits for each task. The lower-8 bits (bits 0-7) are reserved for system use and cannot be
allocated. Bits 8-30 can be allocated for task use. To specify a particular signal bit to allocate, just set the
corresponding bit in the sigMask parameter. For example, to allocate bit 21, you set sigMask to 0x00200000. If
you don't care which signal bit you get, you can use AllocSignal(0), in which case the kernel chooses a free bit
and allocates it for you. It is most common to simply use AllocSignal(0) instead of requesting specific signal
bits.
AllocSignal() returns a signal mask with bits set to 1 where signals were successfully allocated. If no bits were
available for allocation, the call returns 0. If there was an error in allocation, the call returns an error code (a negative
number).
The code fragment in example 8-1 demonstrates using AllocSignal() to allocate a signal bit. In this program, a
parent task creates two threads, and it uses the signal mechanisms for the threads to communicate with the parent task.
Here, the parent task allocates two of its signal bits, one for each thread. First, it declares two global variables,
threadSig1 and threadSig2, to use as signal mask variables for each of the threads:
Example 1: Allocating a signal bit.
/* Global variables shared by all threads. */
file:///C|/%23%23DDOC/spg/08spg002.html (1 of 6) [4/16/2002 11:14:18 PM]

Using Signals

static int32
static int32
...
...

thread1Sig;
thread2Sig;

/* allocate one signal bit for each thread */
thread1Sig = AllocSignal(0);
thread2Sig = AllocSignal(0);
if ((thread1Sig == 0) || (thread2Sig == 0))
{
/* could not allocate the needed signal bits */
}
The two calls to AllocSignal() allocate 2 available signal bits. If successful, the variables threadSig1 and
threadSig2 each contain a signal mask with a specially allocated bit for each thread to use.

Receiving a Signal
To receive a signal, a task enters wait state using this call:
int32 WaitSignal( uint32 sigMask )
WaitSignal() accepts a signal mask that specifies which of the task's allocated signal bits to wait for. It can
specify more than one bit to wait for, but it can't specify any bits that haven't already been allocated. If unallocated
bits are specified, the call returns a negative value (an error code) when it executes. Before returning,
WaitSignal() clears the signal bits.
When the allocated bits are specified and the call executes, the task enters the wait state until a signal is sent to one of
the signal bits it specified in WaitSignal(). The task then exits the wait state and returns to the ready queue. The
call returns a signal mask with 1 set in each bit where a signal was received.
A task can receive signals before it enters a wait state, in which case they're kept as pending signals in a pending
signals mask maintained in the task's control block (TCB). There is no signal queue-that is, no more than one signal
can be kept pending for each allocated signal bit. When a task calls WaitSignal(), any pending signals that match
the signal mask given to WaitSignal() cause the call to return immediately, and the task never enters the wait
state. The signal bits that the task was waiting for are cleared before returning.

Sampling and Changing the Current Signal Bits
It is sometimes necessary for a task to look at the current state of the signal bits to determine whether a given signal
was received. To do this, use GetCurrentSignals():
int32 GetCurrentSignals(void);
The macro returns a signal mask with bits on for every signal bit that has been received. This provides a sample or the
file:///C|/%23%23DDOC/spg/08spg002.html (2 of 6) [4/16/2002 11:14:18 PM]

Using Signals

current signal bits without entering the wait state.
You can forcibly set the signal bits of your task by using SendSignal() with 0 for the task item. This is sometimes
useful to set the initial state of the task's signals.
You can also forcibly clear signal bits of a task by using the ClearCurrentSignals() macro.
Err ClearCurrentSignals(int32 signalMask);
This macro takes a signal mask that describes the signal bits to clear. The macro returns a negative value if reserved
signal bits (bits 0-7) are specified.

Sending a Signal
A task sends one or more signals to another task with this call:
Err SendSignal( Item task, uint32 sigMask )
The call accepts the item number of the task to which the signal or signals should be sent, and a signal mask with a 1
in each bit to which a signal is sent. When it executes, the kernel checks that each specified signal bit in
SendSignal() is allocated by the receiving task. If it's not, then the call returns a negative number (an error code).
If all specified bits are allocated by the receiving task, then the kernel performs a logical OR between the
SendSignal() signal mask and the pending signals mask maintained in the receiving task's TCB. This is how the
pending signals mask maintains a record of pending signals. When the receiving task uses WaitSignal(), the
kernel checks the pending signals mask, and if any bits are set to 1, the task immediately returns to execution.

Freeing Signal Bits
When a task no longer needs an allocated signal bit, it uses this call:
Err FreeSignal( uint32 sigMask )
The call accepts a signal mask with a 1 set in each bit that is to be freed, and a 0 set in each bit where allocation status
should be unchanged. For example, if bits 8 and 9 are currently allocated and you wish to free only bit 8, then you
need to create a signal mask with the binary value 1<<8 (which equals a 256 decimal value).
FreeSignal(), frees the specified bits when executed. It returns 0 if it was successful, and a negative number (an
error code) if unsuccessful.

Sample Code for Signals
Example 2 is a full code sample on which the previous code sample is based. The variables declared at the beginning
of the example are global to the main routine (the parent task) and the two threads. These global variables pass signal
file:///C|/%23%23DDOC/spg/08spg002.html (3 of 6) [4/16/2002 11:14:18 PM]

Using Signals

masks between the threads and the task. The main routine, which appears at the end of the example, allocates signals
for the two threads it will create.
The main() routine uses WaitSignal() to wait for signals from the two threads. The threads use
SendSignal() to send their signals to the parent task.
Example 2: Complete code sample for signals.
#include
#include
#include
#include
#include

"types.h"
"task.h"
"kernel.h"
"stdio.h"
"operror.h"

/*****************************************************************************/
/* Global variables shared by all threads. */
static int32 thread1Sig;
static int32 thread2Sig;
static Item
parentItem;
static uint32 thread1Cnt;
static uint32 thread2Cnt;
/*****************************************************************************/
/* This routine shared by both threads */
static void DoThread(int32 signal, uint32 amount, uint32 *counter)
{
uint32 i;
while (TRUE)
{
for (i = 0; i < amount; i++)
{
(*counter)++;
SendSignal(parentItem,signal);
}
}
}
/*****************************************************************************/
static void Thread1Func(void)
{
file:///C|/%23%23DDOC/spg/08spg002.html (4 of 6) [4/16/2002 11:14:18 PM]

Using Signals

DoThread(thread1Sig, 100000, &thread1Cnt);
}
/*****************************************************************************/
static void Thread2Func(void)
{
DoThread(thread2Sig, 200000,&thread2Cnt);
}
/*****************************************************************************/
int main(int32 argc, char **argv)
{
uint8 parentPri;
Item
thread1Item;
Item
thread2Item;
uint32 count;
int32 sigs;
/* get the priority of the parent task */
parentPri = CURRENTTASK->t.n_Priority;
/* get the item number of the parent task */
parentItem = CURRENTTASK->t.n_Item;
/* allocate one signal bits for each thread */
thread1Sig = AllocSignal(0);
thread2Sig = AllocSignal(0);
/* spawn two threads that will run in parallel */
thread1Item = CreateThread("Thread1", parentPri, Thread1Func, 2048);
thread2Item = CreateThread("Thread2", parentPri, Thread2Func, 2048);
/* enter a loop until we receive 10 signals */
count = 0;
while (count < 10)
{
sigs = WaitSignal(thread1Sig | thread2Sig);
printf("Thread 1 at %d, thread 2 at %d\n",thread1Cnt,thread2Cnt);
if (sigs & thread1Sig)
printf("Signal from thread 1\n");
if (sigs & thread2Sig)
printf("Signal from thread 2\n");
file:///C|/%23%23DDOC/spg/08spg002.html (5 of 6) [4/16/2002 11:14:18 PM]

Using Signals

count++;
}
/* nuke both threads */
DeleteThread(thread1Item);
DeleteThread(thread2Item);
}

file:///C|/%23%23DDOC/spg/08spg002.html (6 of 6) [4/16/2002 11:14:18 PM]

Passing Messages

Passing Messages
The message system allows tasks to send data to one another, providing information flow from task to task. Tasks must
create the following elements for the message system to work:
●
●
●

The sending task must create a message port.
The receiving task must create a message port.
The sending task must create a message.

Once the elements are in place, the sending task follows these procedures:
●
●

It specifies a message to send and a destination message port to which to send the message.
It specifies the data to go with the message.

The receiving task does one of the following procedures:
●
●

It enters the wait state to wait for a message on a specified message port.
It checks one of its message ports to see if a message has arrived there.

Once a message arrives at a task's message port, the task follows these procedures:
●

●

●

●

It removes the message from its message port.
It gets a pointer to the message, and reads data directly from the message, or finds the data block pointer and size
and reads from the data block.
If the message needs a reply, the task writes new data directly into the message or sets a pointer and size in the
message for a new data block.
It sends the reply back to the message.

The message system is very flexible, and allows a single task to create multiple message ports and multiple messages. A
single message port can receive many messages; they're queued up and retrieved one at a time by the receiving task. A
message port allows a single task to receive, in serial order, messages from many other tasks.
Messages, like all other items, are assigned priority numbers. These priority numbers determine the order of messages
within a message queue: higher- priority messages go to the front of the queue. Messages with the same priority are
arranged in arrival order: earlier messages come first.

Creating a Message Port
Before a task can send or receive a message, it must have at least created one message port. To create a message port, use
this call:
Item CreateMsgPort( const char *name, uint8 pri, uint32 signal )

file:///C|/%23%23DDOC/spg/08spg003.html (1 of 11) [4/16/2002 11:14:21 PM]

Passing Messages

The call accepts three arguments: a name string, name, which it uses to name the message port; a 1-byte priority value,
pri, which assigns a priority to the message port; and a 32-bit signal mask, signal, which assigns an allocated signal
bit to the message port.
The message port's name and priority don't change the way the message port operates, but are useful when another task
tries to find the message port.
The signal mask specifies a signal to associate with the message port. The signal mask must contain only allocated signal
bits. If you specify a signal mask of 0, then CreateMsgPort() allocates a signal bit automatically. When the port is
later deleted using DeleteMsgPort(), the signal bit is automatically freed.
CreateMsgPort() returns the item number of the newly created message port if successful, or returns a negative
number (an error code) if unsuccessful. The message port now exists as an item in system memory, owned by the creating
task.
The message port uses its assigned signal bit to signal its owner task whenever a message arrives at the port. The signal bit
should not be freed until the message port is freed.
The item number returned by CreateMsgPort() is a handle to the new port. The owner task should give it out to any
task that may want to send a message to it. Sending a message requires specifying the item number of the message port to
which the message is sent.

Creating a Message
To create a message to send to a specific message port, a task must first create its own message port to use as a reply port.
Then, it must specify which of three message types to create:
●
●
●

A standard message, which has a pointer to a block of data and the size of that data.
A small message, which has two 32-bit words of data.
A buffered message, which has a built-in data block.

If the task sends 8 or fewer bytes of data within the message itself, it should create a small message.
If the task sends more than 8 bytes of data and only points to the data in a data block that isn't carried with the message, it
should create a standard message.
And if the task sends more than 8 bytes of data within the message, it should create a buffered message.

Standard Messages
To create a standard message, use this call:
Item CreateMsg( const char *name, uint8 pri, Item mp )
The first argument, name, is the name for the message, which is useful for finding the message later. The second
argument, pri, sets the message's priority, which determines how it is sorted in a receiving task's message queue. It can
be a value from 0 to 255. The third argument, mp, is the item number of a message port that belongs to the creating task.
file:///C|/%23%23DDOC/spg/08spg003.html (2 of 11) [4/16/2002 11:14:21 PM]

Passing Messages

This is the message's reply port, where it returns if the receiving task sends it back with a reply call.
A standard message carries with it a pointer to a data block, and the size of the data block. The task that receives the
message can obtain the pointer to the data block and access the data. If the receiving task has write permission to the pages
of memory where the data block is located, it can even write to the data block directly. Because of the fact you pass a
pointer to a data block, standard messages are often referred to as "pass-by-reference" messages.
The reply to a standard message can contain 4 bytes of data.
When executed, CreateMsg() creates a standard message and returns the message's item number. If unsuccessful, it
returns a negative number (an error code). Example 1 uses CreateMsg():
Example 1: Sample using CreateMsg( ).
static Item myMsg;
static Item mpItem;
/* Create a message */
myMsg = CreateMsg("Message1", 0, mpItem);
if (myMsg < 0)
{
printf("error creating Message\n");
return (-2);
}

Small Messages
Both standard and buffered messages have message structure fields with pointers to a data block and the size of the data
block. A small message uses those same fields to store up to 8 bytes of data instead of storing a pointer and a block size
value.
To create a small message, use CreateSmallMsg():
Item CreateSmallMsg( const char *name, uint8 pri, Item mp )
The arguments are identical to those for CreateMsg(). You'll see the difference when you call SendSmallMsg()
(described later).

Buffered Messages
Some applications require a message that can carry data within the message itself. This lets the sender copy data into the
message, send the message, and not have to keep around its original data buffer. The buffer is no longer needed because
the data is now in the message itself. In addition, when the destination task returns a buffered message, it can also write
data to the message's buffer, allowing a great deal of information to be returned.
Because buffered messages require data to be copied into them before being sent, they are often referred to as "pass-byvalue" messages.

file:///C|/%23%23DDOC/spg/08spg003.html (3 of 11) [4/16/2002 11:14:21 PM]

Passing Messages

With buffered messages, a sending task can send large amounts of read/write data to another task. The receiving task can
modify this data and return it to the caller. This avoids granting the receiving task write permission to memory buffers in
the sending task's address space.
To create a buffered message, use this call:
Item CreateBufferedMsg( const char *name, uint8 pri, Item mp, uint32 datasize
)
Like CreateMsg(), this call accepts arguments that point to a name, supply a priority, and give the item number of a
reply port for the message. The additional argument, datasize, specifies the size, in bytes, of the data buffer to create.
When the call executes, it creates a buffered message with its accompanying buffer. If successful, the call returns the item
number of the message. If unsuccessful, it returns a negative number (an error code).

Sending a Message
A task can send all three types of messages, but each requires different handling.

Small Messages
To send a small message, use this call:
Err SendSmallMsg( Item mp, Item msg, uint32 val1, uint32 val2 )
The first argument, mp, is the item number of the message port to which the message is sent. The second argument, msg,
is the item number of the small message to send. The third argument, val1, is the first 4 bytes of data to send in the
message; the fourth argument, val2, is the second 4 bytes of data to send in the message. (If you don't know the item
number of the message port, but you know its name, you can use FindMsgPort() to get the item number.)
When SendSmallMsg() executes, it writes the first value into the msg_DataPtr field of the message's data structure
and the second value into the msg_DataSize field of the structure. It then sends the message to the specified message
port. It returns a 0 if the message is successfully sent, or a negative number (an error code) if unsuccessful.
You should not send a standard or buffered message with this call, because the values you supply can be read as an
erroneous pointer and data size.

Standard and Buffered Messages
To send a standard or buffered message, use this call:
Err SendMsg( Item mp, Item msg, const void *dataptr, int32 datasize )
Like SendSmallMsg(), this call accepts the item number of a message port to which to send the message, mp, and the
item number of the message to send, msg. Instead of accepting values to store with the message, SendMsg() accepts a
pointer to a data block in the dataptr argument and the size, in bytes, of the data block in the datasize argument.

file:///C|/%23%23DDOC/spg/08spg003.html (4 of 11) [4/16/2002 11:14:21 PM]

Passing Messages

When SendMsg() executes, it sends the message, returning a 0 if successful, or a negative number (an error code) if
unsuccessful. Its effect on the message depends on whether the message is standard or buffered.
A standard message stores the data block pointer and the data size value in the message. The data block remains where it
is, and the receiving task reads it there, using the pointer and size value to find it and know how far it extends.
With a buffered message, SendMsg() checks the size of the data block to see if it will fit in the message's buffer. If it
won't, the call returns an error. If it does fit, SendMsg() copies the contents of the data block into the message's buffer.
The receiving task can then read the data directly out of the message's buffer.
The advantage of a buffered message is that it carries the full data block within its buffer, so the sending task can
immediately use the original data block's memory for something else. The task doesn't need to maintain the data block
until it's sure that the receiving task has read the block. The data block is handled by the system, and is carried within the
message in protected system memory.

Receiving a Message
Once a message is sent to a message port, it is held in the message port's message queue until the receiving task retrieves
the message, or the sending task decides to pull it back. The messages within the queue are put in order first by priority,
and then by order received.
To receive a message, a task can wait until it receives notification of a message at a message port, or it can check a
message port directly to see if a message is there.

Waiting for a Message
To enter the wait state until a message arrives on a specific message port, a task uses this call:
Item WaitPort( Item mp, Item msg )
WaitPort() accepts the required argument, mp, which contains the item number of the message port where the task
receives messages. The call also accepts an optional argument, msg, which contains the item number of a specific
message the task expects to receive at the message port. (To wait for any incoming message, use 0 as the value of msg.)
Note: If the message arrived before WaitPort() is called, the task never enters the wait state.
When WaitPort() executes, the task enters the wait state until it detects a message on the message port's message
queue. At that point, if the call doesn't specify a specific message, the task exits the wait state, and the call returns the item
number of the first message in the port's queue. The message is removed from the message queue, and the task can use its
item number to find and read the message.
If a specific message was given to WaitPort() in addition to a message port, the task waits until that message arrives at
the message port. When it arrives, the task exits the wait state and the message is removed from the message queue.

Checking for a Message
To check for a message at a message port without entering the wait state, a task uses this call:
file:///C|/%23%23DDOC/spg/08spg003.html (5 of 11) [4/16/2002 11:14:21 PM]

Passing Messages

Item GetMsg( Item mp )
GetMsg() accepts a single argument: the item number of the message port where it wants to check for messages. When
it executes, it checks the message port to see if there are any messages in the port's queue. If there are, it returns the item
number of the first message in the queue and removes it from the queue. If there is no message at the message port, the
call returns 0. If there is an error, the call returns an error code (a negative number).

Working With a Message
Once a task receives a message, it interprets the contents of the message to determine what the message means. To do this,
the task must obtain a pointer to the Message structure associated with the message's item number:
Message *msg;
Item
msgItem;
msg = (Message *)LookupItem(msgItem);
Once the task has the pointer, it can determine the type of message it has received by inspecting the contents of the
msg.n_Flags field of the message structure. If the MESSAGE_SMALL bit is set in this field, it means it is a small
message. If the MESSAGE_PASS_BY_VALUE bit is set, it means it is a buffered message. If neither of these bits is set, it
means that it is a standard message.
When you set up communication channels among your tasks or threads using message ports, you should know what type
of messages will be sent around to these ports, so that you don't always need to check the types.

Small Messages
When you receive a small message, the only information you can get from the message is contained in the
msg_DataPtr and msg_DataSize fields. The information corresponds directly to the val1 and val2 arguments the
sending task specified when it called SendSmallMsg(). When you return such a message, you supply a 4-byte result
code, and two new 32-bit values to put into msg_DataPtr and msg_DataSize.

Standard Messages
When you receive a standard message, the msg_DataPtr field of the message contains the address of a data area which
you can access. The size of the data area is contained in msg_DataSize. Typically, the data area points to a data
structure belonging to the task that sent the message.
If the standard message comes from another task, as opposed to a sibling thread, the data area likely will only be readable
by the receiving task, unless the sending task takes the extra steps to grant write permission to that data area. To determine
whether your task can write to a data area pointed to in a standard message, use the IsMemWritable() function.
If you send messages between threads and tasks of the same application, it is often not necessary to go through the extra
trouble of checking whether the data area is writable before writing to it, since this can be part of the protocol setup within
your application.
When a task replies to a standard message, it provides a 4-byte result code, and new values for msg_DataPtr and
file:///C|/%23%23DDOC/spg/08spg003.html (6 of 11) [4/16/2002 11:14:21 PM]

Passing Messages

msg_DataSize. When a task calls ReplyMsg(), it can leave the values to what they were by simply using
msg_DataPtr and msg_DataSize as parameters to ReplyMsg().

Buffered Messages
When a task receives a buffered message, the msg_DataPtr field of the message contains the address of a read-only
data area, and msg_DataSize specifies the number of useful bytes within this buffer. The task can read this data at will.
When a task replies a buffered message, it supplies a 4-byte result code, and can optionally supply new data to be copied
into the message's buffer. The task can determine the size available in the message's buffer by looking at the
msg_DataPtrSize field of the message structure.

Pulling Back a Message
When a sending task sends a message, the task can pull the message out of a message queue before the message has been
received. To do so, it uses the GetThisMsg() call:
Item GetThisMsg( Item msg )
The single argument, msg, specifies the message to rescind. If the message is still on the message port it was sent to, it is
removed and its item number returned. If the message was already removed from the port by the receiving task, then the
function returns 0.

Replying to a Message
Once a message is received, the receiving task can reply, which returns a message to its reply port. The message contains
4 bytes that are set aside for a reply code; the replying task assigns an arbitrary value for storage there, often a value that
reports the success or failure of message handling.
Once again, the three different message types require different handling when replying to a message.

Small Messages
To send back a small message in reply to the sending task, use this call:
Err ReplySmallMsg( Item msg, int32 result, uint32 val1, uint32 val2 )
ReplySmallMsg() accepts four arguments. The first argument, msg, is the item number of the message being returned
in reply. The second argument, result, is a 32-bit value written into the reply field of the message data structure. The
third and fourth arguments, val1 and val2, are data values written into the pointer and size fields of the message data
structure (just as they are in SendSmallMsg()). Note that no destination message port is specified because the message
returns to its reply port, which is specified within the message data structure.
When ReplySmallMsg() executes, it sends a message back in reply and returns a 0 if successful, or an error code (a
negative number) if unsuccessful.

file:///C|/%23%23DDOC/spg/08spg003.html (7 of 11) [4/16/2002 11:14:21 PM]

Passing Messages

Standard and Buffered Messages
To send back a standard or buffered message in reply, use this call:
Err ReplyMsg( Item msg, int32 result, const void *dataptr, int32 datasize)
ReplyMsg() accepts four arguments. The first two, msg and result, are the same as those accepted by
ReplySmallMsg(). The third, dataptr, is a pointer to a data block in memory. The fourth, datasize, is the size in
bytes of that data block.
When ReplyMsg() executes, it sends the message in reply and returns a 0 if successful, or an error code (a negative
number) if unsuccessful. The effect the reply has on the message depends on whether the message is standard or buffered,
just as it does in SendMsg().
If the message is standard, the data block pointer and the data size value are stored in the message, and are read as such by
the task getting the reply. If the message is buffered, ReplyMsg() checks the size of the data block to see if it will fit in
the message's buffer. If it doesn't fit, the call returns an error. If it does fit, ReplyMsg() copies the contents of the data
block into the message's buffer and sends the message.

Finding a Message Port
When a task sends a message to message a port, it needs to know the item number of the port. To get the item number of
the port, it is often necessary to use the FindMsgPort() call:
Item FindMsgPort( const char *name )
When you provide FindMsgPort() the name of the message port to find, it returns the item number of that port. If the
port doesn't exist, it returns a negative error code. If multiple ports of the same name exist, it returns the item number of
the port with the highest priority.

Example Code for Messages
The code in Example 2 demonstrates how to send messages among threads or tasks.
The main() routine of the program creates a message port where it can receive messages. It then spawns a thread. This
thread creates its own message port and message. The thread then sends the message to the parent's message port. Once
the parent receives the message, it sends it back to the thread.
Example 2: Samples using the message passing routines (msgpassing.c).
#include
#include
#include
#include
#include
#include
#include

"types.h"
"item.h"
"kernel.h"
"task.h"
"msgport.h"
"operror.h"
"stdio.h"

file:///C|/%23%23DDOC/spg/08spg003.html (8 of 11) [4/16/2002 11:14:21 PM]

Passing Messages

/*****************************************************************************/
/* A signal mask used to sync the thread with the parent */
int32 parentSig;
/*****************************************************************************/
static void ThreadFunction(void)
{
Item childPortItem;
Item childMsgItem;
Item parentPortItem;
Err
err;
Msg *msg;
printf("Child thread is running\n");
childPortItem = CreateMsgPort("ChildPort",0,0);
if (childPortItem >= 0)
{
childMsgItem = CreateSmallMsg("ChildMsg",0,childPortItem);
if (childMsgItem >= 0)
{
parentPortItem = FindMsgPort("ParentPort");
if (parentPortItem >= 0)
{
/* tell the paren't we're done initializing */
SendSignal(CURRENTTASK->t_ThreadTask->t.n_Item,parentSig);
err = SendSmallMsg(parentPortItem,childMsgItem,12,34);
if (err >= 0)
{
err = WaitPort(childPortItem,childMsgItem);
if (err >= 0)
{
msg = (Msg *)LookupItem(childMsgItem);
printf("Child received reply from parent: ");
printf("msg_Result %d, msg_DataPtr %d, msg_DataSize %d\n",
msg->msg_Result, msg->msg_DataPtr, msg>msg_DataSize);
}
else
{
printf("WaitPort() failed: ");
PrintfSysErr(err);
}
}
else
{
file:///C|/%23%23DDOC/spg/08spg003.html (9 of 11) [4/16/2002 11:14:21 PM]

Passing Messages

printf("SendSmallMsg() failed: ");
PrintfSysErr(err);
}
SendSignal(CURRENTTASK->t_ThreadTask->t.n_Item,parentSig);
}
else
{
printf("Could not find parent message port: ");
PrintfSysErr(parentPortItem);
}
DeleteMsg(childMsgItem);
}
else
{
printf("CreateSmallMsg() failed: ");
PrintfSysErr(childMsgItem);
}
DeleteMsgPort(childPortItem);
}
else
{
printf("CreateMsgPort() failed: ");
PrintfSysErr(childPortItem);
}
}
/*****************************************************************************/
int main(int32 argc, char **argv)
{
Item portItem;
Item threadItem;
Item msgItem;
Msg *msg;
parentSig = AllocSignal(0);
if (parentSig > 0)
{
portItem = CreateMsgPort("ParentPort",0,0);
if (portItem >= 0)
{
threadItem = CreateThread("Child",10,ThreadFunction,2048);
if (threadItem >= 0)
{
/* wait for the child to be ready */
WaitSignal(parentSig);
/* confirm that the child initialized correctly */

file:///C|/%23%23DDOC/spg/08spg003.html (10 of 11) [4/16/2002 11:14:21 PM]

Passing Messages

if (FindMsgPort("ChildPort") >= 0)
{
printf("Parent waiting for message from child\n");
msgItem = WaitPort(portItem,0);
if (msgItem >= 0)
{
msg = (Msg *)LookupItem(msgItem);
printf("Parent got child's message: ");
printf("msg_DataPtr %d, msg_DataSize %d\n",
msg->msg_DataPtr, msg->msg_DataSize);
ReplySmallMsg(msgItem,56,78,90);
}
else
{
printf("WaitPort() failed: ");
PrintfSysErr(msgItem);
}
}
/* wait for the thread to tell us it's done before we zap it */
WaitSignal(parentSig);
DeleteThread(threadItem);
}
else
{
printf("CreateThread() failed: ");
PrintfSysErr(threadItem);
}
DeleteMsgPort(portItem);
}
else
{
printf("CreateMsgPort() failed: ");
PrintfSysErr(portItem);
}
FreeSignal(parentSig);
}
else
{
printf("AllocSignal() failed");
}
return 0;
}

file:///C|/%23%23DDOC/spg/08spg003.html (11 of 11) [4/16/2002 11:14:21 PM]

Function Calls

Function Calls
The following are the calls related to signals and messages.

Allocating Signals
The following calls work with signal bits.
●
●
●
●
●
●

AllocSignal() Allocates one or more signals for intertask communication.
ClearCurrentSignals() Clears specified signals bits of the current task.
FreeSignal() Frees signal bits.
GetCurrentSignals() Returns the state of the current task's signal bits.
SendSignal() Sends one or more signals to another task or thread.
WaitSignal() Waits for one or more signals to arrive.

Creating Messages and Message Ports
The following calls create messages and ports.
●
●
●
●
●

CreateBufferedMsg() Creates a buffered message.
CreateMsg() Creates a standard message.
CreateMsgPort()Creates a message port.
CreateSmallMsg()Creates a small message.
CreateUniqueMsgPort()Creates a message port with a guaranteed unique name.

Deleting Messages and Message Ports
The following calls delete messages and ports.
●
●

DeleteMsg() Deletes a message of any type.
DeleteMsgPort()Deletes a message port.

Finding a Message Port
The following call finds a message port by name.
file:///C|/%23%23DDOC/spg/08spg004.html (1 of 2) [4/16/2002 11:14:22 PM]

Function Calls

●

FindMsgPort() Returns the item number of the message port having the specified name.

Sending Messages
The following calls send different types of messages:
●
●

SendMsg() Sends a message.
SendSmallMsg()Sends a small message.

Receiving Messages
The following calls retrieve messages:
●
●
●

GetMsg() Gets a message from a message port.
GetThisMsg() Gets a specific message.
WaitPort()Waits for a message to arrive.

Replying to Messages
The following calls reply to messages:
●
●

ReplyMsg() Sends a reply to a message.
ReplySmallMsg() Sends a reply to a small message.

file:///C|/%23%23DDOC/spg/08spg004.html (2 of 2) [4/16/2002 11:14:22 PM]

Example

Example
Example 1 uses Access to display eight different transaction boxes, one for each type of transaction. Tag argument's supply
explanatory text and two labeled choice buttons for transaction boxes that need them. The task enters the wait state after it
requests each transaction and awaits the user choice in a reply message from Access. When the task receives the reply, it
leaves the wait state.
Example 1: Using Access to put up transaction boxes.
#include
#include
#include
#include
#include
#include
#include

"types.h"
"mem.h"
"msgport.h"
"graphics.h"
"access.h"
"stdio.h"
"string.h"

/****************************************************************************/
#define ERROR(x,y) {printf(x); PrintfSysErr(y); result = y;}
#define NUM_SCREENS 1
/****************************************************************************/
static
static
static
static
static
static
static

Item accessPortItem;
Item accessItem;
Item replyPortItem;
Item msgItem;
Msg *msg;
Item screenGroupItem;
Item screenItems[NUM_SCREENS];

/****************************************************************************/
static void ClearScreenPages(Item *screenItems)
{
uint32 i;
Screen *screen;
Bitmap *bitmap;
uint32 numBytes;
Item
sport;
uint32 vramPageSize;
/* If this call fails, SetVRAMPages() will also fail, and nothing bad
* will happen. So we don't bother to check the error return.
file:///C|/%23%23DDOC/spg/16spg003.html (1 of 6) [4/16/2002 11:14:23 PM]

Example

*/
sport = GetVRAMIOReq();
for (i = 0; i < NUM_SCREENS; i++)
{
screen
= (Screen *)LookupItem(screenItems[i]);
bitmap
= screen->scr_TempBitmap;
numBytes = bitmap->bm_Width * bitmap->bm_Height * 2;
vramPageSize = GetPageSize(MEMTYPE_VRAM);
SetVRAMPages(sport,bitmap->bm_Buffer, 0,(numBytes + vramPageSize - 1) /
vramPageSize,-1);
}
DeleteItem(sport);
}
/****************************************************************************/
static void TransferScreenPages(Item *screenItems, bool toAccess)
{
uint32 i;
Screen *screen;
Bitmap *bitmap;
uint32 numBytes;
for (i = 0; i < NUM_SCREENS; i++)
{
screen
= (Screen *)LookupItem(screenItems[i]);
bitmap
= screen->scr_TempBitmap;
numBytes = bitmap->bm_Width * bitmap->bm_Height * 2;
if (toAccess)
ControlMem((void *)bitmap->bm_Buffer,numBytes,MEMC_OKWRITE,accessItem);
else
ControlMem((void *)bitmap->bm_Buffer,numBytes,MEMC_NOWRITE,accessItem);
}
}
/****************************************************************************/
static void SendAccessMsg(uint32 callNumber, char *buffer,
uint32 tags, ...)
{
Err err;
err = SendMsg(accessPortItem, msgItem, &tags, 0);
if (err >= 0)
{
file:///C|/%23%23DDOC/spg/16spg003.html (2 of 6) [4/16/2002 11:14:23 PM]

Example

WaitPort(replyPortItem,0);
printf("Call #%ld returned %ld, buffer = '%s'\n",callNumber,msg>msg_Result,buffer);
}
else
{
printf("SendAccessMsg() #%ld failed with %ld\n",callNumber,err);
}
ClearScreenPages(screenItems);
}
/****************************************************************************/
static void CallThemAll(void)
{
char buf[256];
buf[0] = 0;
SendAccessMsg(1, buf, ACCTAG_REQUEST,
ACCTAG_SCREEN,
ACCTAG_TITLE,
ACCTAG_TEXT,
ACCTAG_BUTTON_ONE,
ACCTAG_FG_PEN,
TAG_END);

ACCREQ_ONEBUTTON,
screenItems[0],
"Hi ho",
"Isn't this a great example?",
"I agree",
0x7000,

SendAccessMsg(2, buf, ACCTAG_REQUEST,
ACCTAG_SCREEN,
ACCTAG_TITLE,
ACCTAG_TEXT,
ACCTAG_BUTTON_ONE,
ACCTAG_BUTTON_TWO,
ACCTAG_FG_PEN,
TAG_END);

ACCREQ_TWOBUTTON,
screenItems[0],
"Space Zappers",
"Wanna play more Space Zappers?",
"Yep",
"Nope",
0x0700,

ControlMem(buf,sizeof(buf),MEMC_OKWRITE,accessItem);
strcpy(buf,"Gee");
SendAccessMsg(3, buf, ACCTAG_REQUEST,
ACCTAG_SCREEN,
ACCTAG_TITLE,
ACCTAG_STRINGBUF,
ACCTAG_STRINGBUF_SIZE,
TAG_END);
strcpy(buf,"Wow");
SendAccessMsg(4, buf, ACCTAG_REQUEST,
ACCTAG_SCREEN,
ACCTAG_TITLE,
file:///C|/%23%23DDOC/spg/16spg003.html (3 of 6) [4/16/2002 11:14:23 PM]

ACCREQ_LOAD,
screenItems[0],
"Space Zappers",
buf,
sizeof(buf),

ACCREQ_SAVE,
screenItems[0],
"Space Zappers",

Example

ACCTAG_STRINGBUF,
buf,
ACCTAG_STRINGBUF_SIZE, sizeof(buf),
TAG_END);
strcpy(buf,"Zawee");
SendAccessMsg(5, buf, ACCTAG_REQUEST,
ACCTAG_SCREEN,
ACCTAG_TITLE,
ACCTAG_STRINGBUF,
ACCTAG_STRINGBUF_SIZE,
TAG_END);

ACCREQ_DELETE,
screenItems[0],
"Space Zappers",
buf,
sizeof(buf),

ControlMem(buf,sizeof(buf),MEMC_NOWRITE,accessItem);
}
/****************************************************************************/
int main(uint32 argc, char *argv[])
{
MsgPort *accessPort;
Err
result;
Err
err;
err = OpenGraphicsFolio();
if (err >= 0)
{
screenGroupItem = CreateScreenGroupVA(screenItems,
CSG_TAG_SCREENCOUNT, (void *)NUM_SCREENS,
CSG_TAG_DONE);
if (screenGroupItem >= 0)
{
ClearScreenPages(screenItems);
AddScreenGroup(screenGroupItem, NULL);
err = DisplayScreen(screenItems[0], 0);
if (err >= 0)
{
accessPortItem = FindMsgPort("access");
if (accessPortItem >= 0)
{
accessPort = (MsgPort *)LookupItem(accessPortItem);
if (accessPort)
{
accessItem = accessPort->mp.n_Owner;
replyPortItem = CreateMsgPort("accessexample",0,0);
if (replyPortItem >= 0)
{
msgItem = CreateMsg("accessmsg",0,replyPortItem);
if (msgItem >= 0)
{
file:///C|/%23%23DDOC/spg/16spg003.html (4 of 6) [4/16/2002 11:14:23 PM]

Example

msg = (Msg *)LookupItem(msgItem);
if (msg)
{
TransferScreenPages(screenItems, TRUE);
CallThemAll();
result = 0;
TransferScreenPages(screenItems, FALSE);
}
else
{
ERROR("Could not lookup message\n",0);
}
DeleteItem(msgItem);
}
else
{
ERROR("Could not create message\n",msgItem);
}
DeleteMsgPort(replyPortItem);
}
else
{
ERROR("Could not create reply message
port\n",replyPortItem);
}
}
else
{
ERROR("Could not lookup the Access message port\n",-1);
}
}
else
{
ERROR("Could not find the Access message
port\n",accessPortItem);
}
RemoveScreenGroup(screenGroupItem);
}
else
{
ERROR("Could not display screen group\n",err);
}
DeleteScreenGroup(screenGroupItem);
}
else
{
ERROR("Couldn't create screen group\n",screenGroupItem);
}
file:///C|/%23%23DDOC/spg/16spg003.html (5 of 6) [4/16/2002 11:14:23 PM]

Example

CloseGraphicsFolio();
}
else
{
ERROR("Could not open the graphics folio\n",err);
}
return ((int)result);
}

file:///C|/%23%23DDOC/spg/16spg003.html (6 of 6) [4/16/2002 11:14:23 PM]

Access Message Tag Arguments

Access Message Tag Arguments
These tags define an Access transaction:
●

ACCTAG_REQUEST requests a type of transaction. It takes as an argument one of the constants
listed below:
❍
❍
❍
❍
❍
❍
❍

●

ACCREQ_LOAD
ACCREQ_SAVE
ACCREQ_DELETE
ACCREQ_OK
ACCREQ_OKCANCEL
ACCREQ_ONEBUTTON
ACCREQ_TWOBUTTON

ACCTAG_SCREEN specifies a screen on which to display the transaction box. It takes the item
number of an existing screen as an argument.

●

ACCTAG_BUFFER is reserved for future use.

●

ACCTAG_BUFFERSIZE is reserved for future use.

●

●

●

●

●

●

ACCTAG_TITLE takes as its argument a pointer to a NULL-terminated text string to be used as
the transaction box for the title.
ACCTAG_TEXT takes as its argument a pointer to a NULL-terminated text string to be used as the
explanatory text for the transaction box.
ACCTAG_BUTTON_ONE takes as its argument a pointer to a NULL- terminated text string to be
used as the text for the left button in the transaction box.
ACCTAG_BUTTON_TWO takes as its argument a pointer to a NULL- terminated text string to be
used as the text for the right button in the transaction box.
ACCTAG_SAVE_BACK specifies that pixels beneath the transaction box be saved and restored
when the transaction box is closed. It takes zero as its argument. If this tag argument isn't used,
background pixels aren't saved and restored.
ACCTAG_STRINGBUF points to a string buffer that receives user input text from Access. It takes

file:///C|/%23%23DDOC/spg/16spg004.html (1 of 2) [4/16/2002 11:14:24 PM]

Access Message Tag Arguments

a pointer to a memory location as its argument.
●

●

●

●

●

ACCTAG_STRINGBUF_SIZE gives the size of a string buffer that receives user input text from
Access. It takes the size of the buffers in byte as its arguments.
ACCTAG_FG_PEN provides the color used for text in the transaction box. It takes a pen color
value as its argument.
ACCTAG_BG_PEN provides the color used for the transaction box background. It takes a pen
color value as its argument.
ACCTAG_HILITE_PEN provides the color used for the background of a highlighted button in
the transaction box. It takes a pen color value as its argument.
ACCTAG_SHADOW_PEN provides the color used for the button outline in the transaction box. It
takes a pen color value as its argument.

file:///C|/%23%23DDOC/spg/16spg004.html (2 of 2) [4/16/2002 11:14:24 PM]

Examples

Examples
This section provides code listings of programs that use the File folio and the file system.

Using NVRAM
Example 1 is a program listing that demonstrates how to save data to a file in NVRAM or to any other writable device.
The SaveDataFile() function takes a name, a data pointer, and a size indicator, and creates a file with that name and
size, containing the supplied data.
Writing data to a file requires a bit of finesse. Data can only be written in blocks, not bytes. So if the data being written
out is not a multiple of the target device's block size, the last chunk of data must be copied to a buffer which is the size of
a block, and the block can then be written out.
Example 1: Saving data to a file in NVRAM (nvram.c).
#include
#include
#include
#include
#include
#include
#include
#include

"types.h"
"filesystem.h"
"filefunctions.h"
"io.h"
"string.h"
"mem.h"
"stdio.h"
"operror.h"

/*****************************************************************************/
Err SaveDataFile(const char *name, void *data, uint32 dataSize)
{
Item
fileItem;
Item
ioReqItem;
IOInfo
ioInfo;
void
*temp;
Err
result;
uint32
numBlocks;
uint32
blockSize;
uint32
roundedSize;
FileStatus status;
/* get rid of the file if it was already there */
DeleteFile((char *)name);
/* create the file again... */
result = CreateFile((char *)name);
file:///C|/%23%23DDOC/spg/11spg009.html (1 of 11) [4/16/2002 11:14:26 PM]

Examples

if (result >= 0)
{
/* open the file for access */
fileItem = OpenDiskFile((char *)name);
if (fileItem >= 0)
{
/* create an IOReq to communicate with the file */
ioReqItem = CreateIOReq(NULL, 0, fileItem, 0);
if (ioReqItem >= 0)
{
/* get the block size of the file */
memset(&ioInfo, 0, sizeof(IOInfo));
ioInfo.ioi_Command
= CMD_STATUS;
ioInfo.ioi_Recv.iob_Buffer = &status;
ioInfo.ioi_Recv.iob_Len
= sizeof(FileStatus);
result = DoIO(ioReqItem, &ioInfo);
if (result >= 0)
{
blockSize = status.fs.ds_DeviceBlockSize;
numBlocks = (dataSize + blockSize - 1) / blockSize;
/* allocate the blocks we need for this file */
ioInfo.ioi_Command
= FILECMD_ALLOCBLOCKS;
ioInfo.ioi_Recv.iob_Buffer = NULL;
ioInfo.ioi_Recv.iob_Len
= 0;
ioInfo.ioi_Offset
= numBlocks;
result = DoIO(ioReqItem, &ioInfo);
if (result >= 0)
{
/* tell the system how many bytes for this file */
memset(&ioInfo,0,sizeof(IOInfo));
ioInfo.ioi_Command
= FILECMD_SETEOF;
ioInfo.ioi_Offset
= dataSize;
result = DoIO(ioReqItem, &ioInfo);
if (result >= 0)
{
roundedSize = 0;
if (dataSize >= blockSize)
{
/* If we have more than one block's worth of
* data, write as much of it as possible.
*/
roundedSize = (dataSize / blockSize) * blockSize;
ioInfo.ioi_Command
= CMD_WRITE;
ioInfo.ioi_Send.iob_Buffer = (void *)data;
ioInfo.ioi_Send.iob_Len
= roundedSize;
ioInfo.ioi_Offset
= 0;
result = DoIO(ioReqItem, &ioInfo);

file:///C|/%23%23DDOC/spg/11spg009.html (2 of 11) [4/16/2002 11:14:26 PM]

Examples

data
= (void *)((uint32)data + roundedSize);
dataSize -= roundedSize;
}
if ((result >= 0) && dataSize)
{
/* If the amount of data left isn't as large
* as a whole block, we must allocate a memory
* buffer of the size of the block, copy the
* rest of the data into it, and write the
* buffer to disk.
*/
temp = AllocMem(blockSize,MEMTYPE_DMA |
MEMTYPE_FILL);
if (temp)
{
memcpy(temp,data,dataSize);
ioInfo.ioi_Command
= CMD_WRITE;
ioInfo.ioi_Send.iob_Buffer = temp;
ioInfo.ioi_Send.iob_Len
= blockSize;
ioInfo.ioi_Offset
= roundedSize;
result = DoIO(ioReqItem, &ioInfo);
FreeMem(temp,blockSize);
}
else
{
result = NOMEM;
}
}
}
}
}
DeleteIOReq(ioReqItem);
}
else
{
result = ioReqItem;
}
CloseDiskFile(fileItem);
}
else
{
result = fileItem;
}
/* don't leave a potentially corrupt file around... */
if (result < 0)

file:///C|/%23%23DDOC/spg/11spg009.html (3 of 11) [4/16/2002 11:14:26 PM]

Examples

DeleteFile((char *)name);
}
return (result);
}
/*****************************************************************************/
static char testData[] = "This is some test data to save out";
int main(int32 argc, char **argv)
{
Err err;
err = SaveDataFile("/NVRAM/test",testData,sizeof(testData));
if (err < 0)
{
printf("Could not save data: ");
PrintfSysErr(err);
}
}

Displaying Contents of a File
Example 2 is a program listing that demonstrates how to read a file using the byte stream calls, and output its contents to
the debugging terminal.
Example 2: Displaying the contents of a 3DO file (type.c)
#include
#include
#include
#include

"types.h"
"stdio.h"
"filestream.h"
"filestreamfunctions.h"

/*****************************************************************************/
#define MAXLINE 1024
static void Type(const char *path)
{
Stream *stream;
char
c;
char
line[MAXLINE];
int32
linelen;
int32
lines;
int32
endOfLine, endOfFile;

file:///C|/%23%23DDOC/spg/11spg009.html (4 of 11) [4/16/2002 11:14:26 PM]

Examples

/* Open the file as a byte-stream. A buffer size of zero is
* specified, which permits the File folio to choose an appropriate
* amount of buffer space based on the file's actual block size.
*/
stream = OpenDiskStream((char *)path, 0);
if (!stream)
{
printf("File '%s' could not be opened\n", path);
return;
}
lines
linelen
endOfLine
endOfFile

=
=
=
=

0;
0;
FALSE;
FALSE;

/* Spin through a loop, grabbing one byte each time.
*
* A more efficient implementation would grab bytes
* in larger batches (e.g. 128 bytes at a time) and parse them in a
* more reasonable fashion.
*/
while (!endOfFile)
{
if (ReadDiskStream(stream, &c, 1) < 1)
{
endOfFile = TRUE;
endOfLine = TRUE;
line[linelen] = '\0';
}
else if (c == '\r' || c == '\n')
{
endOfLine = TRUE;
line[linelen] = '\0';
}
else if (linelen < MAXLINE-1)
{
line[linelen++] = c;
}
if (endOfLine)
{
printf("%s\n", line);
linelen = 0;
lines++;
endOfLine = FALSE;
}
}
file:///C|/%23%23DDOC/spg/11spg009.html (5 of 11) [4/16/2002 11:14:26 PM]

Examples

printf("\n%d lines processed\n\n", lines);
/* close the file */
CloseDiskStream(stream);
}
/*****************************************************************************/
int main(int32 argc, char **argv)
{
int32 i;
if (argc < 2)
{
printf("Usage: type file1 [file2] [file3] [...]\n");
}
else
{
/* go through all the arguments */
for (i = 1; i < argc; i++)
Type(argv[i]);
}
return 0;
}

Scanning the File System
Example 3 is a program listing of an application that scans the file system.
Example 3: Scanning the file system (Walker.c).
#include
#include
#include
#include
#include
#include
#include
#include

"types.h"
"io.h"
"stdio.h"
"operror.h"
"filesystem.h"
"directory.h"
"directoryfunctions.h"
"filefunctions.h"

/*****************************************************************************/
static void TraverseDirectory(Item dirItem)
{

file:///C|/%23%23DDOC/spg/11spg009.html (6 of 11) [4/16/2002 11:14:26 PM]

Examples

Directory
*dir;
DirectoryEntry de;
Item
subDirItem;
int32
entry;
dir = OpenDirectoryItem(dirItem);
if (dir)
{
entry = 1;
while (ReadDirectory(dir, &de) >= 0)
{
printf("Entry #%d:\n", entry);
printf(" file '%s', type 0x%lx, ID 0x%lx",
de.de_FileName, de.de_Type,
de.de_UniqueIdentifier);
printf(", flags 0x%lx\n", de.de_Flags);
printf(" %d bytes, %d block(s) of %d byte(s) each\n",
de.de_ByteCount,
de.de_BlockCount, de.de_BlockSize);
printf(" %d avatar(s)", de.de_AvatarCount);
printf("\n\n");
if (de.de_Flags & FILE_IS_DIRECTORY)
{
subDirItem = OpenDiskFileInDir(dirItem, de.de_FileName);
if (subDirItem >= 0)
{
printf("********** RECURSE **********\n\n");
TraverseDirectory(subDirItem);
printf("******* END RECURSION *******\n\n");
}
else
{
printf("*** RECURSION FAILED ***\n\n");
}
}
entry++;
}
CloseDirectory(dir);
}
else
{
printf("OpenDirectoryItem() failed\n");
CloseDiskFile(dirItem);
}
}
/*****************************************************************************/

file:///C|/%23%23DDOC/spg/11spg009.html (7 of 11) [4/16/2002 11:14:26 PM]

Examples

static Err Walk(const char *path)
{
Item startItem;
startItem = OpenDiskFile((char *)path);
if (startItem >= 0)
{
printf("\nRecursive directory scan from %s\n\n", path);
TraverseDirectory(startItem);
printf("End of %s has been reached\n\n", path);
return 0;
}
else
{
printf("OpenDiskFile(\"%s\") failed: ",path);
PrintfSysErr(startItem);
return startItem;
}
}
/*****************************************************************************/
int main(int32 argc, char **argv)
{
int i;
if (argc <= 1)
{
/* if no directory name was given, scan the current directory */
Walk(".");
}
else
{
for (i = 1; i < argc; i++)
Walk(argv[i]);
}
return 0;
}

Listing the Contents of a Directory
Example 4 is a code listing that list the contents of a directory.
Example 4: Listing a directory (ls.c)

file:///C|/%23%23DDOC/spg/11spg009.html (8 of 11) [4/16/2002 11:14:26 PM]

Examples

**/
#include
#include
#include
#include
#include
#include
#include
#include
#include

"types.h"
"stdio.h"
"string.h"
"io.h"
"operror.h"
"filesystem.h"
"filefunctions.h"
"directory.h"
"directoryfunctions.h"

/*****************************************************************************/
static void ListDirectory(const char *path)
{
Directory
*dir;
DirectoryEntry de;
Item
ioReqItem;
int32
entry;
int32
err;
char
fullPath[FILESYSTEM_MAX_PATH_LEN];
IOInfo
ioInfo;
Item
dirItem;
/* open the directory for access */
dirItem = OpenDiskFile((char *)path);
if (dirItem >= 0)
{
/* create an IOReq for the directory */
ioReqItem = CreateIOReq(NULL, 0, dirItem, 0);
if (ioReqItem >= 0)
{
/* Ask the directory its full name. This will expand any aliases
* given on the command-line into fully qualified pathnames.
*/
memset(&ioInfo, 0, sizeof(ioInfo));
ioInfo.ioi_Command
= FILECMD_GETPATH;
ioInfo.ioi_Recv.iob_Buffer = fullPath;
ioInfo.ioi_Recv.iob_Len
= sizeof(fullPath);
err = DoIO(ioReqItem, &ioInfo);
if (err >= 0)
{
/* now open the directory for scanning */
dir = OpenDirectoryPath((char *)path);
if (dir)
{
printf("\nContents of directory %s:\n\n", fullPath);
entry = 1;
file:///C|/%23%23DDOC/spg/11spg009.html (9 of 11) [4/16/2002 11:14:26 PM]

Examples

while (ReadDirectory(dir, &de) >= 0)
{
printf("%5s", (char *) &de.de_Type);
printf(" %8d", de.de_ByteCount);
printf(" %4d*%4d", de.de_BlockCount, de.de_BlockSize);
printf(" %3d", de.de_AvatarCount);
printf(" %8x", de.de_Flags);
printf(" %s\n", de.de_FileName);
entry++;
}
CloseDirectory(dir);
printf("\nEnd of directory\n\n");
}
else
{
printf("OpenDirectory(\"%s\") failed\n",fullPath);
}
}
else
{
printf("Unable to get full path name for '%s': ",path);
PrintfSysErr(err);
}
DeleteIOReq(ioReqItem);
}
else
{
printf("CreateIOReq() failed: ");
PrintfSysErr(ioReqItem);
}
CloseDiskFile(dirItem);
}
else
{
printf("OpenDiskFile(\"%s\") failed: ",path);
PrintfSysErr(dirItem);
}
}
/*****************************************************************************/
int main(int32 argc, char **argv)
{
int32 i;
if (argc <= 1)
{
/* if no directory name was given, scan the current directory */
file:///C|/%23%23DDOC/spg/11spg009.html (10 of 11) [4/16/2002 11:14:26 PM]

Examples

ListDirectory(".");
}
else
{
/* go through all the arguments */
for (i = 1; i < argc; i++)
ListDirectory(argv[i]);
}
return 0;
}

file:///C|/%23%23DDOC/spg/11spg009.html (11 of 11) [4/16/2002 11:14:26 PM]

File System Folio Function Calls

File System Folio Function Calls
The following section lists the File folio calls. See Kernel Folio Calls in the 3DO System Programmer's
Reference for a complete description of the calls.

File Access Calls
●
●
●
●
●
●

CloseDiskFile() Closes a file.
CreateAlias() Creates an alias for a file.
CreateFile() Creates a file.
DeleteFile() Deletes a file.
OpenDiskFile()Opens a disk file.
OpenDiskFileInDir()Opens a disk file contained in a specific directory.

Program Calls
●
●
●
●
●
●

ExecuteAsSubroutine() Executes previously loaded code as a subroutine.
ExecuteAsThread() Executes previously loaded code as a thread.
LoadProgram()Launches a program.
LoadProgramPrio()Launches a program and gives it a priority.
LoadCode() Loads a binary image into memory, and obtains a handle to it.
UnloadCode() Unloads a binary image previously loaded with LoadCode().

Directory Access Calls
●
●
●
●
●
●

ChangeDirectory()Changes the current directory.
CloseDirectory()Closes a directory.
GetDirectory()Gets the item number and pathname for the current directory.
OpenDirectoryPath()Opens a directory specified by a pathname.
OpenDirectoryItem()Opens a directory.
ReadDirectory()Reads the next entry from a directory.

Byte-Stream Calls
●

OpenDiskStream()Opens a disk stream for byte stream-oriented I/O.

file:///C|/%23%23DDOC/spg/11spg008.html (1 of 2) [4/16/2002 11:14:27 PM]

File System Folio Function Calls
●
●
●

CloseDiskStream()Closes a disk stream.
ReadDiskStream() Reads from a disk stream.
SeekDiskStream()Performs a seek operation on a disk stream.

file:///C|/%23%23DDOC/spg/11spg008.html (2 of 2) [4/16/2002 11:14:27 PM]

CreateFile

CreateFile
Creates a file.

Synopsis
Item CreateFile( char *path )

Description
This function creates a new file.

Arguments
path
The pathname for the file.

Return Value
The function returns a a value greater than or equal to 0 if the file is created successfully or a negative
error code if an error occurs.

Implementation
SWI implemented in file folio V20.
Note: You do not need to delete the item returned by this function.

Associated Files
filefunctions.h

See Also
DeleteFile(), OpenDiskFile(), OpenDiskFileInDir()

file:///C|/%23%23DDOC/spr/02spr006.html [4/16/2002 11:14:27 PM]

DeleteFile

DeleteFile
Deletes a file.

Synopsis
Err DeleteFile( char *path )

Description
This function deletes a file.

Arguments
path
The pathname for the file to delete.

Return Value
The function returns zero if the file was successfully deleted or a negative error code if an error occurs.

Implementation
SWI implemented in file folio V20.

Associated Files
filefunctions.h

See Also
CreateFile(), OpenDiskFile(), OpenDiskFileInDir(), CloseDiskFile()

file:///C|/%23%23DDOC/spr/02spr007.html [4/16/2002 11:14:27 PM]

Debugging Memory Usage

Debugging Memory Usage
Problems can occur when your application allocates or manages memory if the memory is misused or
isn't freed up after use. A memory debugging module is provided to help spot memory management
problems. The module replaces the memory allocation routines in your program with a superset that
checks that the memory system is used correctly. These calls are activated when you do the following:
1. Add CreateMemDebug() as the first instruction in the main() routine of your program:
Err CreateMemDebug(uint32 controlFlags, const TagArg *args);
controlFlags is a set of bit flags that control various options of the memory debugging code;
args is a pointer to an array of tag arguments containing extra data for this function. See the
Kernel Folio Calls in the 3DO System Programmer's Reference for a description of each flag.
Currently, args must always be NULL.
2. Add DumpMemDebug() and DeleteMemDebug() as the last instructions in the main()
routine of your program.
Err DumpMemDebug(const TagArg *args);
Err DeleteMemDebug(void);
args is a pointer to an array of tag arguments containing extra data for this function. Currently
args must always be NULL.
3. Recompile your entire application with MEMDEBUG defined on the ARM compiler's command
line. For the ARM compiler, this is done by adding
-DMEMDEBUG
to the compile line.
4. Link your code with memdebug.lib
A link order is important when using memdebug.lib. The memdebug library should come before
clib.lib, but after everything else. That is, the link order should be:
[many .lib files] memdebug.lib clib.lib

file:///C|/%23%23DDOC/spg/05spg010.html (1 of 3) [4/16/2002 11:14:28 PM]

Debugging Memory Usage

Other than CreateMemDebug(), DumpMemDebug(), and DeleteMemDebug(), there is no
difference in the way your code works. When your program allocates memory, each memory allocation
is tracked and managed. In addition, the memory debugging module makes sure that illegal or dangerous
memory use is detected and flagged. When your program exits, any memory left allocated is displayed,
along with the line number and source file from where memory was allocated.
When all the control flags are turned on, the debugging code checks and reports the following problems:
●

Memory allocations of 0.

●

Memory freed with a NULL or bogus memory pointer.

●

Memory freed of a size that does not match the size of memory that was allocated.

●

NULL memory lists passed to AllocMemFromMemLists() or FreeMemToMemLists().

●

Cookies on either side of all memory allocations are checked so they are not altered from the time
a memory allocation is made to the time the memory is released. A change in the cookies
indicates that your program is writing beyond the bounds of allocated memory.

When MEMDEBUG is defined during compilation, all standard memory allocation calls are automatically
vectored through the debugging code. This includes memory allocation calls made in previously
compiled .lib files with which you might be linking. However, you can get better debugging information
if you recompile everything in your project, including .lib files, with MEMDEBUG defined.
If you call DumpMemDebug() at any time within your application, you can get a detailed listing of all
memory currently allocated, showing the source line and source file from which the allocation occurred.
This function also outputs statistics about general memory allocation patterns including: the number of
memory allocation calls that have been performed, the maximum number of bytes allocated at any one
time, current amount of allocated memory, and so on. All of this information is displayed on a per-thread
basis, as well as globally for all threads. When using link libraries that haven't been recompiled with
MEMDEBUG defined, the memory debugging subsystem will still can track the allocations, but will not
report the source file or line number where the error occurred. It reports <unknown source file> instead.
An additional call, SanityCheckMemDebug(), can find problems with memory. This call checks
outstanding memory allocations and checks all cookies to see if they have been corrupted. For example,
if you want to find the location of a chunk of memory is being corrupted, you could place
SanityCheckMemDebug() calls throughout the program. Look at the return data of each call until
you locate the place in the program where the cookies are corrupted.
After you finish using any of these calls, turn off memory debugging before you create the final version
of your program. Enabling memory debugging incurs an overhead of 32 bytes per allocation made. If you
file:///C|/%23%23DDOC/spg/05spg010.html (2 of 3) [4/16/2002 11:14:28 PM]

Debugging Memory Usage

use the MEMDEBUGF_PAD_COOKIES option, this overhead grows to 64 bytes per allocation.

file:///C|/%23%23DDOC/spg/05spg010.html (3 of 3) [4/16/2002 11:14:28 PM]

Getting Information About Memory

Getting Information About Memory
The following sections explain how to find out how much memory is available, how to find out the type
of memory you have, how to get the size of a memory page, and how to find out which VRAM bank (if
any) contains a memory location.

Finding Out How Much Memory Is Available
You can find out how much memory is available by calling AvailMem():
void AvailMem( MemInfo *minfo, uint32 memflags )
The memflags argument specifies the type of memory you want to find out about. If you want to find
out how much of all types of memory is available, use MEMTYPE_ANY as the value of the flags
argument. To find out how much DRAM is available, use MEMTYPE_DRAM; for VRAM, use
MEMTYPE_VRAM. You can also use the flag MEMTYPE_BANKSELECT together with either
MEMTYPE_BANK1 or MEMTYPE_BANK2 to get information about a specific VRAM bank. Other flags
you can include are MEMTYPE_DMA, MEMTYPE_CEL, MEMTYPE_AUDIO, and MEMTYPE_DSP. For
complete descriptions of these flags, see Allocating Memory.
Note: When you call AvailMem(), you can only request information about one memory type.
Attempting to find out about more than one memory type can produce unexpected results.
The information about available memory is returned in a MemInfo structure pointed to by the minfo
argument:
typedef struct MemInfo
{
uint32 minfo_SysFree;
uint32 minfo_SysLargest;
uint32 minfo_TaskFree;
uint32 minfo_TaskLargest;
} MemInfo;
This structure contains the following information:
●

minfo_SysFree, The amount of memory, in bytes, of the specified memory type in the systemwide free memory pool. The pool contains only full pages of memory.

file:///C|/%23%23DDOC/spg/05spg003.html (1 of 3) [4/16/2002 11:14:29 PM]

Getting Information About Memory
●

●

●

minfo_SysLargest, The size, in bytes, of the largest series of contiguous pages of the specified
memory type in the system-wide free memory pool.
minfo_TaskFree, The amount of memory, in bytes, of the specified type in the task's free
memory pool.
minfo_TaskLargest, The size, in bytes, of the largest contiguous block of the specified memory
type that can be allocated from the task's free memory pool.
Warning: Do not depend on these numbers, as they may change if other tasks on the system
allocate memory at the same time you are calling AvailMem.

Getting the Memory Type of a Memory Location
You can find out the memory type of a particular memory location by calling GetMemType():
uint32 GetMemType( void *p )
The p argument is a pointer to the memory location to identify. The function returns memory allocation
flags (such as MEMTYPE_VRAM) which describe the type of memory. For descriptions of these flags, see
Allocating a Memory Block.

Getting the Size of a Memory Page
You can get the size of a memory page by calling the GetPageSize() function:
int32 GetPageSize( uint32 memflags )
The memflags argument contains memory allocation flags for the page size of the memory type you
specify. There are currently only three page sizes: one for DRAM and two for VRAM. You can,
however, include any of the following flags: MEMTYPE_ANY, MEMTYPE_VRAM, MEMTYPE_DRAM,
MEMTYPE_BANKSELECT, MEMTYPE_BANK1, MEMTYPE_BANK2, MEMTYPE_DMA, MEMTYPE_CEL,
MEMTYPE_AUDIO, and MEMTYPE_DSP. (For complete descriptions of these flags, see Allocating a
Memory Block.) Normally, you should include just one flag which specifies the one type of memory in
which you're interested. Including more than one flag can produce an unexpected result.
The return value contains the size of the page for the specified memory type, in bytes.

Finding Out Which VRAM Bank Contains a VRAM
file:///C|/%23%23DDOC/spg/05spg003.html (2 of 3) [4/16/2002 11:14:29 PM]

Getting Information About Memory

Location
In the current 3DO hardware, 2 MB of video random access memory (VRAM) is divided into two banks,
each containing 1 MB of VRAM. Fast VRAM memory transfers using the SPORT bus can take place
only between memory locations in the same bank. You can find out which bank of VRAM-if anycontains a particular memory location by calling the GetBankBits() macro:
uint32 GetBankBits( void *a )
The a argument is a pointer to a memory location. The macro returns a set of memory flags in which the
following flags can be set:
●
●
●

MEMTYPE_BANKSELECT, Set if the memory is contained in VRAM.
MEMTYPE_BANK1, Set if the memory is in VRAM bank 1.
MEMTYPE_BANK2, Set if the memory is in VRAM bank 2.

If the memory is not in VRAM, the macro returns 0.
When a task allocates VRAM, the memory block contains memory from one VRAM bank or the other; it
never contains memory from both banks. Thus, if any memory location in a block is in one VRAM bank,
the entire block is in the same bank.

Validating Memory Pointers
When working with memory, sometimes it is necessary to verify the validity of memory pointers. This
can be extremely useful when debugging, for example, in ASSERT() macros. Portfolio validates
memory pointers that are passed to it, and rejects any corrupt ones.
The IsMemReadable() and IsMemWritable() functions let your code verify the validity of
pointers.
bool IsMemReadable(void *mem, int32 size);
bool IsMemWritable(void *mem, int32 size);
To both functions, you supply a pointer to a memory region and the size of that region. The functions
return TRUE if the current task or thread can access the complete memory region.

file:///C|/%23%23DDOC/spg/05spg003.html (3 of 3) [4/16/2002 11:14:29 PM]

Allowing Other Tasks to Write to Your Memory

Allowing Other Tasks to Write to Your
Memory
When a task owns memory, other tasks cannot write to that memory unless the task gives them
permission. To give another task permission to write to one or more of your memory pages, or to revoke
write permission that was previously granted, call ControlMem():
Err ControlMem( void *p, int32 size, int32 cmd, Item task )
Each page of memory has a control status that specifies which task owns the memory and which tasks
can write to it. Calls to ControlMem() change the control status for entire pages. The p argument, a
pointer to a memory location, and the size argument, the amount of the contiguous memory, in bytes,
beginning at the memory location specified by the p argument, specify which memory control status to
change. If p and size arguments specify any part of a page, changes are made to the entire page. The
task argument specifies which task to change the control status for. You can make multiple calls to
ControlMem() to change the control status for more than one task. The cmd argument is a constant
that specifies the change to be made to the control status. The possible values are given below:
●

●

MEMC_OKWRITE. Grants permission to write to the memory of the task specified by the
task argument. Currently, a task argument value of 0 is not supported for this operation.
MEMC_NOWRITE. Revokes permission to write to the memory from the task specified by the
task argument. A task argument value of 0 revokes the write permission for all tasks.

(One other possible value, MEMC_GIVE, is described in the next section.)
For a task to change the control status of memory pages with ControlMem(), it must own that
memory, with one exception: a task that has write access to memory it doesn't own can relinquish its
write access using MEMC_NOWRITE as the value of the cmd argument.
A task can use ControlMem() to prevent itself from writing to memory that it owns, which is useful
during debugging.

file:///C|/%23%23DDOC/spg/05spg005.html [4/16/2002 11:14:29 PM]

Using Private Memory Pools

Using Private Memory Pools
In addition to using private memory lists, a task can also use private memory pools. Each task gets a free
memory pool when it is created. Tasks can also create additional free memory pools, which, like the
pools created by the kernel, are simply lists of free memory lists. When a task creates a free memory pool
containing its private memory lists, it can use a single function call to allocate or deallocate any of the
types of memory in those lists. The functions for doing this are described in the following sections.
As with memory lists, tasks can only use memory pools that they own. This means that the system-wide
free memory pool is off-limits to tasks, as are memory pools belonging to other tasks.

Creating a Memory Pool
To create a memory pool, you must prepare a List structure using the InitList() function:
void InitList(List *l, const char *name)
Once the List structure is initialized, you can then allocate some MemList structures using the technique
described in the previous section. Every memory list you create can then be added to the memory pool by
calling the AddHead() function:
void AddHead(List *l, Node *n)

Allocating Memory From a Specific Memory Pool
To allocate memory from a specific free memory pool, you use the AllocMemFromMemLists()
function:
void *AllocMemFromMemLists( List *l, int32 size, uint32 memflags
)
The l argument is the free memory pool from which to allocate a memory block. As noted earlier, this
pool must be owned by the calling task. The size argument specifies the size of the block to allocate, in
bytes.
The memflags argument specifies the type of memory to allocate, the alignment of the block with
respect to the page, and so on; these flags can include MEMTYPE_ANY, MEMTYPE_VRAM,
MEMTYPE_DRAM, MEMTYPE_BANKSELECT, MEMTYPE_BANK1, MEMTYPE_BANK2,
file:///C|/%23%23DDOC/spg/05spg008.html (1 of 2) [4/16/2002 11:14:30 PM]

Using Private Memory Pools

MEMTYPE_DMA, MEMTYPE_CEL, MEMTYPE_AUDIO, MEMTYPE_DSP, MEMTYPE_FILL,
MEMTYPE_INPAGE, MEMTYPE_SYSTEMPAGESIZE, MEMTYPE_STARTPAGE, and
MEMTYPE_MYPOOL. For complete descriptions of these flags, see Allocating a Memory Block. The
function returns a pointer to the block that was allocated, or NULL if there was not enough memory in
the list to satisfy the request.
To free memory that you've allocated with AllocMemFromMemLists(), you can only use
FreeMemToMemLists() (described in the next section). Each memory allocation function has a
corresponding deallocation function; if you use another memory allocation function, you must use its
corresponding deallocation function.

Freeing Memory to a Specific Memory Pool
To free a block of memory allocated with AllocMemFromMemLists(), you use the
FreeMemToMemLists() function:
void FreeMemToMemLists( List *l, void *p, int32 size )
The l argument is a pointer to the memory pool from which the block was allocated. The p argument is a
pointer to the block to free. The size argument is the size of the block to free, in bytes.

file:///C|/%23%23DDOC/spg/05spg008.html (2 of 2) [4/16/2002 11:14:30 PM]

Getting Memory From the System-Wide Free Memory Pool

Getting Memory From the System-Wide
Free Memory Pool
When there is insufficient memory in a task's free memory pool to allocate a block of memory, the kernel
automatically provides additional memory pages from the system-wide free memory pool. Tasks can also
get pages directly from the system-wide free memory pool by calling the AllocMemBlocks()
function:
void *AllocMemBlocks( int32 size, uint32 typebits )
The size argument specifies the amount of memory to transfer, in bytes. If the specified size is not a
multiple of the page size for the type of memory requested, the kernel transfers enough full pages to
satisfy the request.
The first 4 bytes of the allocated block contain the actual number of bytes allocated. This isn't true when
MEMTYPE_FILL is supplied.
The typebits argument specifies the type of memory to transfer. This argument can contain any of the
following memory allocation flags: MEMTYPE_ANY, MEMTYPE_VRAM, MEMTYPE_DRAM,
MEMTYPE_BANKSELECT, MEMTYPE_BANK1, MEMTYPE_BANK2, MEMTYPE_DMA, MEMTYPE_CEL,
MEMTYPE_AUDIO, and MEMTYPE_DSP. For descriptions of these flags, see . You must always set the
MEMTYPE_TASKMEM flag when using this function.
AllocMemBlocks() returns a pointer to the memory that was transferred. When you get the memory,
you must call a function to free it, such as FreeMemToMemList() to move it to a specific memory list
or FreeMemToMemLists() to move it to a specific memory pool. For either function, use the pointer
returned by AllocMemBlocks() as the value of the p argument. Use the size value that is stored in
the first 4 bytes in the memory returned by the AllocMemBlocks() for the size argument.

file:///C|/%23%23DDOC/spg/05spg009.html [4/16/2002 11:14:30 PM]

Example

Example
Most memory allocation involves nothing more than calling AllocMem() to allocate memory and
FreeMem() to free memory. Here is a simple example.
Example 1: Allocating memory.
#include "types.h"
#include "mem.h"
#include "stdio.h"
int main(int32 argc, char **argv)
{
void *memBlock;
memBlock = AllocMem(123,MEMTYPE_ANY); /* allocate any type of
memory */
if (memBlock)
{
/* memBlock now contains the address of a block of memory
* 123 bytes in size
*/
FreeMem(memBlock,123); /* return the memory */
}
else
{
printf("Could not allocate memory!\n");
}
}

file:///C|/%23%23DDOC/spg/05spg011.html [4/16/2002 11:14:30 PM]

Function Calls

Function Calls
The following list contains the memory calls. See Kernel Folio Calls in the 3DO System Programmer's
Reference for more information on these calls.

Allocating Memory
The following calls allocate memory:
●
●

AllocMem() Allocates a specified memory block.
malloc() Allocates memory.

Freeing Memory
The following calls free memory:
●
●

FreeMem() Frees memory allocated with AllocMem().
free() Frees memory allocated with malloc().

Getting Information About Memory
The following calls get information about available memory:
●
●
●
●

AvailMem() Gets information about available memory.
GetBankBits() Finds out which VRAM bank contains a memory location.
GetMemType() Gets the type of the specified memory.
GetPageSize() Gets the number of bytes in a memory page.

Reclaiming Unused Memory
The following call reclaims unused memory:
●

ScavengeMem() Returns a task's unused memory pages to the system-wide memory pool.

Changing the Control Status of Memory
file:///C|/%23%23DDOC/spg/05spg012.html (1 of 2) [4/16/2002 11:14:31 PM]

Function Calls

The following call changes the status of memory:
●

ControlMem() Grants or revokes write permission to memory, or gives memory to another
task.

Using Private Memory Lists
The following calls deal with private lists:
●
●
●

AllocMemFromMemList() Allocates memory from a private memory pool.
FreeMemList() Frees a memory list.
FreeMemToMemList() Frees a private block of memory.

Using Memory Pools
The following calls allocate and free memory pools.
●
●
●

AllocMemBlocks() Transfers pages of memory from the system-wide free memory pool.
AllocMemFromMemLists() Allocates a memory block from a list of memory lists.
FreeMemToMemLists() Returns a block of memory to a free memory pool.

Debugging Memory Problems
The following calls find problems with memory.
●
●
●
●

CreateMemDebug() Initializes memory debugging package
DeleteMemDebug() Releases memory debugging resources
DumpMemDebug()Dumps memory allocation debugging information
SanityCheckMemDebug()Checks all current memory allocations to make sure all of the
allocation cookies are intact

file:///C|/%23%23DDOC/spg/05spg012.html (2 of 2) [4/16/2002 11:14:31 PM]

Sharing System Resources

Sharing System Resources
This chapter explains techniques for sharing system resources using semaphores. For details about the
functions described here, see Kernel Folio Calls, in the 3DO System Programmer's Reference.
This chapter contains the following topics:
●
●
●
●
●
●
●

About Semaphores
Creating a Semaphore
Locking a Semaphore
Unlocking a Semaphore
Finding a Semaphore
Deleting a Semaphore
Function Calls

file:///C|/%23%23DDOC/spg/07spg.html [4/16/2002 11:14:31 PM]

About Semaphores

About Semaphores
Tasks use special items known as semaphores to control access to shared resources. The following
sections explain how they work.

The Problem: Sharing Resources Safely
One job of a multitasking operating system like Portfolio is to provide safe, orderly ways for tasks to
share resources. A classic problem in computing is allowing multiple tasks to share the same resource.
The problem affects any resource, including memory or a disk file, whose state can be changed by the
tasks that share it. If a task changes a resource before another task finishes using it, and the change
violates an assumption the first task has about the resource's contents, then crashes and corruption can
occur.

The Solution: Locking Shared Resources When
Using Them
To share a resource safely, a task must be able to lock the resource while it's using it and unlock it when
it finishes using it. This is known as mutual exclusion: Other tasks are excluded from the resource until it
is safe for them to use it.

The Implementation: Semaphores
There are many techniques for enforcing mutual exclusion. One of the simplest and most effective
techniques uses special data structures known as semaphores. A semaphore keeps track of how many
tasks are using or waiting to use a shared resource. This approach-described in all good textbooks on
operating systems-is the one Portfolio uses. Tasks using Portfolio semaphores use the routines provided
by the kernel for creating semaphores, for deleting them, and for locking and unlocking the resources
they control.
On 3DO systems, it is up to each task to ensure that any shared resources it owns-in particular, memory
pages that other tasks can write to-are shared safely. (To learn how tasks can grant other tasks write
access to their memory, see Managing Memory.) Although tasks are not required to use semaphores, you
should always use them, or another mutual-exclusion mechanism, when your task shares any of its
memory with another task.

file:///C|/%23%23DDOC/spg/07spg001.html (1 of 2) [4/16/2002 11:14:32 PM]

About Semaphores

Using Semaphores
To control access to a shared resource it owns, a task
●

Creates a semaphore

●

Associates the semaphore with the resource

●

Tells the other tasks that share the resource there is a semaphore for controlling access to the
resource

Each task then must lock the semaphore before using the resource by calling LockSemaphore() and
unlocks it as soon as it's done using it by calling UnlockSemaphore(). Except for creating the
semaphore by calling CreateSemaphore(), sharing a resource requires the cooperation of the tasks
that are involved. The tasks must agree on a way to communicate the information about the new
semaphore, such as intertask messages or shared memory, and they need to agree on a format for this
information. They must also agree to lock the semaphore before using the resource and unlock it when
they're done.
If your task needs access to a shared resource and cannot continue without it, you can ask the kernel to
put the task into wait state until the resource becomes available. You do this by including the SEM_WAIT
flag in the flags argument of LockSemaphore() discussed below.

file:///C|/%23%23DDOC/spg/07spg001.html (2 of 2) [4/16/2002 11:14:32 PM]

Creating a Semaphore

Creating a Semaphore
To create a semaphore, use CreateSemaphore():
Item CreateSemaphore( const char *name, uint8 pri )
The name argument is the name to give to the new semaphore. You can use the FindSemaphore()
macro described later in this chapter to find the semaphore by name. To ensure that
FindSemaphore() finds the correct semaphore, you must provide a unique name for each semaphore
you create.
The pri argument determines where this semaphore will be placed within the list of all semaphores in
the system. A higher priority puts it closer to the start of the list. CreateSemaphore() returns the
item number of the new semaphore or an error code (a negative value) if an error occurred.
To delete a semaphore created with CreateSemaphore(), use the DeleteSemaphore()
function described in Deleting a Semaphore.

file:///C|/%23%23DDOC/spg/07spg002.html [4/16/2002 11:14:32 PM]

Deleting a Semaphore

Deleting a Semaphore
To delete a semaphore, use the DeleteSemaphore() function:
Err DeleteSemaphore( Item s )
The s argument is the item number of the semaphore to delete. The function returns 0 if successful or a
negative error code if an error occurred. As with all items, the item number of a deleted semaphore is not
reused.

file:///C|/%23%23DDOC/spg/07spg006.html [4/16/2002 11:14:32 PM]

Locking a Semaphore

Locking a Semaphore
To lock a semaphore, thereby preventing other tasks from accessing the associated resource until your
task is finished with it, call the LockSemaphore() function:
int32 LockSemaphore( Item s, uint32 flags )
The s argument is the item number of the semaphore for the resource you want to lock. Use the flags
argument to specify what to do if the resource is already locked: if you include the SEM_WAIT flag, your
task is put into wait state until the resource is available.
LockSemaphore() returns 1 if the resource was locked successfully. If the resource is already locked
and you did not include the SEM_WAIT flag in the flags argument, the function returns 0. If an error
occurs, the function returns a negative error code.

file:///C|/%23%23DDOC/spg/07spg003.html [4/16/2002 11:14:33 PM]

Unlocking a Semaphore

Unlocking a Semaphore
To unlock a semaphore that you've locked, use the UnlockSemaphore() function:
Err UnlockSemaphore( Item s )
The s argument is the item number of the semaphore for the resource you want to unlock. The function
returns 0 if successful or an error code (a negative value) if an error occurred. It returns the NOTOWNER
error code if your task did not call LockSemaphore() for the specified semaphore.

file:///C|/%23%23DDOC/spg/07spg004.html [4/16/2002 11:14:33 PM]

Finding a Semaphore

Finding a Semaphore
To find a semaphore by name, use the FindSemaphore() macro:
Item FindSemaphore( const char *name )
The name argument is the name of the semaphore to find. The macro returns the item number of the
semaphore or a negative error code if an error occurred.

file:///C|/%23%23DDOC/spg/07spg005.html [4/16/2002 11:14:33 PM]

Function Calls

Function Calls
The following list contains the calls used to control resources.

Creating a Semaphore
The following call creates a semaphore:
●
●

CreateSemaphore() Creates a semaphore.
CreateUniqueSemaphore() Creates a semaphore with a unique name.

Locking a Resource
The following call locks a semaphore:
●

LockSemaphore() Locks a semaphore.

Unlocking a Resource
The following call unlocks a semaphore:
●

UnlockSemaphore() Unlocks a semaphore.

Finding a Semaphore
The following finds a semaphore:
●

FindSemaphore() Finds a semaphore by name.

Deleting a Semaphore
The following deletes a semaphore:
●

DeleteSemaphore() Deletes a semaphore

file:///C|/%23%23DDOC/spg/07spg007.html [4/16/2002 11:14:33 PM]

The International Folio

The International Folio
This chapter describes the International and the JString folios for use in creating titles suitable for
international markets. For a complete description of the calls discussed in this chapter, see the
International Folio Calls in the 3DO System Programmer's Reference. This chapter contains the
following topics:
●
●
●
●
●

What Is Internationalization?
The Locale Data Structure
Using the Locale Structure
Converting Character Sets With the JString Folio
Function Calls and Macros

file:///C|/%23%23DDOC/spg/13spg.html [4/16/2002 11:14:34 PM]

International Folio Calls

International Folio Calls
This chapter describes the international folio procedure calls. The following table provides a brief
description of each call.
●
●
●
●
●
●
●
●
●

intlCloseLocale Terminate use of a locale item
intlCompareStrings Compare two character strings
intlConvertString Change attributes of a character string
intlFormatDate Format a date according to a specified format
IntlFormatNumber Format a number in a localized manner.
intlGetCharAttrs Return attributes of a specified character
intlLookupLocale Return a pointer to the locale structure for an Item
intlOpenLocale Gain access to a locale item
intlTransliterateString Convert a character string from one character set to another

file:///C|/%23%23DDOC/spr/06spr.html [4/16/2002 11:14:34 PM]

intlCompareStrings

intlCompareStrings
Compares two strings for collation purposes.

Synopsis
int32 intlCompareStrings(Item locItem,const unichar *string1,const
unichar *string2);

Description
Compares two strings according to the collation rules of the locale item's language.

Arguments
locItem
A locale item, as obtained from intlOpenLocale().
string1
The first string to compare.
string2
The second string to compare.

Return Value
-1
(string1 < string2)
0
(string1 == string2)
1
(string1>string2)
INTL_ERR_BADITEM
locItem was not an existing locale item.

Implementation
file:///C|/%23%23DDOC/spr/06spr002.html (1 of 2) [4/16/2002 11:14:34 PM]

intlCompareStrings

Folio call implemented in international folio V24.

Associated Files
intl.h

See Also
intlOpenLocale(), intlConvertString()

file:///C|/%23%23DDOC/spr/06spr002.html (2 of 2) [4/16/2002 11:14:34 PM]

intlConvertString

intlConvertString
Changes certain attributes of a string.

Synopsis
int32 intlConvertString(Item locItem,const unichar *string,unichar
*result, uint32 resultSize,uint32 flags);

Description
Converts character attributes within a string. The flags argument specifies the type of conversion to
perform.

Arguments
locItem
A locale item, as obtained from intlOpenLocale().
string
The string to convert.
result
Where the result of the conversion is put. This area must be at least as large as the number of
bytes in the string.
resultSize
The number of bytes available in the result buffer. This limits the number of bytes that are put into
the buffer.
flags
Description of the conversion process to apply:
INTL_CONVF_UPPERCASE will convert all characters to uppercase if possible.
INTL_CONVF_LOWERCASE will convert all characters to lowercase if possible.
INTL_CONVF_HALFWIDTH will convert all FullKana characters to HalfKana.
INTL_CONVF_FULLWIDTH will convert all HalfKana characters to FullKana.
INTL_CONVF_STRIPDIACRITICALS will remove diacritical marks from all characters.

file:///C|/%23%23DDOC/spr/06spr003.html (1 of 3) [4/16/2002 11:14:35 PM]

intlConvertString

You can also specify:
(INTL_CONVF_UPPERCASE|INTL_CONVF_STRIPDIACRITICALS) or
(INTL_CONVF_LOWERCASE|INTL_CONVF_STRIPDIACRITICALS) in order to perform two
conversions in one call. If flags is 0, then a straight copy occurs.

Return Value
If positive, returns the number of characters in the result buffer. If negative, returns an error code. The
string copied into the result buffer is guaranteed to be NULL-terminated.
>=0
Number of characters copied.
INTL_ERR_BADSOURCEBUFFER
The string pointer supplied was bad.
INTL_ERR_BADRESULTBUFFER
The result buffer pointer was NULL or wasn't invalid writable memory.
INTL_ERR_BUFFERTOOSMALL
There was not enough room in the result buffer.
INTL_ERR_BADITEM
locItem was not an existing locale item.

Implementation
Folio call implemented in international folio V24.

Associated Files
intl.h

Caveats
This function varies in intelligence depending on the language bound to the Locale argument.
Specifically, most of the time, all characters above 0x0ff are not affected by the routine. The exception is
with the Japanese language, where the Japanese characters are also affected by this routine.

file:///C|/%23%23DDOC/spr/06spr003.html (2 of 3) [4/16/2002 11:14:35 PM]

intlConvertString

See Also
intlOpenLocale(), intlCompareStrings()

file:///C|/%23%23DDOC/spr/06spr003.html (3 of 3) [4/16/2002 11:14:35 PM]

intlFormatDate

intlFormatDate
Formats a date in a localized manner.

Synopsis
int32 intlFormatDate(Item locItem,DateSpec spec,const GregorianDate
*date,unichar *result, uint32 resultSize);

Description
This function formats a date according to a template and to the rules specified by the locale item
provided. The formatting string works in a manner similar to the way printf() formatting strings are
handled, but uses some specialized format commands tailored to date generation. The following format
commands are supported:
%D - day of month
%H - hour using 24-hour style
%h - hour using 12-hour style
%M - minutes
%N - month name
%n - abbreviated month name
%O - month number
%P - AM or PM strings
%S - seconds
%W - weekday name
%w - abbreviated weekday name
%Y - year
file:///C|/%23%23DDOC/spr/06spr004.html (1 of 3) [4/16/2002 11:14:35 PM]

intlFormatDate

In addition to straight format commands, the formatting string can also specify a field width, a field limit,
and a field pad character. This is done in a manner identical to the way printf() formatting strings
specify these values. That is
%[flags][width][.limit]command
where flags can be "-" or "0", width is a positive numeric value, limit is a positive numeric value, and
command is one of the format commands mentioned above. Refer to documentation on the standard C
printf() function for more information on how these numbers and flags interact.
A difference with standard printf() processing is that the limit value is applied starting from the
rightmost digits, instead of the leftmost. For example;
%.2Y
Prints the rightmost two digits of the current year.

Arguments
locItem
A locale item, as obtained from intlOpenLocale().
spec
The formatting template describing the date layout. This value is typically taken from the locale
structure (loc_Date, loc_ShortDate, loc_Time, loc_ShortTime), but it can also be built up by the
title for custom formatting.
date
The date to convert into a string.
result
Where the result of the formatting is put.
resultSize
The number of bytes available in the result buffer. This limits the number of bytes that are put into
the buffer.

Return Value
If positive, then the number of characters in the result buffer. If negative, then an error code. The string
file:///C|/%23%23DDOC/spr/06spr004.html (2 of 3) [4/16/2002 11:14:35 PM]

intlFormatDate

copied into the result buffer is guaranteed to be NULL-terminated.
>=0
Number of characters copied.
INTL_ERR_BADRESULTBUFFER
The result buffer pointer was NULL or wasn't invalid writable memory.
INTL_ERR_BUFFERTOOSMALL
There was not enough room in the result buffer.
INTL_ERR_BADDATESPEC
The pointer to the DateSpec array was bad.
INTL_ERR_BADITEM
locItem was not an existing locale item.
INTL_ERR_BADDATE
The date specified in the GregorianDate structure is not a valid date. For example, the gd_Month
is greater than 12.

Implementation
Folio call implemented in international folio V24.

Associated Files
intl.h

See Also
intlOpenLocale(), IntlFormatNumber()

file:///C|/%23%23DDOC/spr/06spr004.html (3 of 3) [4/16/2002 11:14:35 PM]

IntlFormatNumber

IntlFormatNumber
Format a number in a localized manner.

Synopsis
int32 intlFormatNumber(Item locItem,const NumericSpec *spec,uint32
whole, uint32 frac,bool negative, bool doFrac,unichar *result, uint32
resultSize);

Description
This function formats a number according to the rules contained in the NumericSpec structure. The
NumericSpec structure is normally taken from a Locale structure. The Locale structure contains three
initialized NumericSpec structures (loc_Numbers, loc_Currency, and loc_SmallCurrency) which let you
format numbers in an appropriate manner for the current system.
You can create your own NumericSpec structure which lets you use intlFormatNumber() to handle
custom formatting needs. The fields in the structure have the following meaning:
●

ns_PosGroups =A GroupingDesc value defining how digits are grouped to the left of the decimal
character. A GroupingDesc is simply a 32-bit bitfield. Every ON bit in the bitfield indicates that
the separator sequence should be inserted after the associated digit. So if the third bit (bit #2) is
ON, it means that the grouping separator should be inserted after the third digit of the formatted
number.

●

ns_PosGroupSep =A string used to separate groups of digits to the left of the decimal character.

●

ns_PosRadix =A string used as a decimal character.

●

●

●

ns_PosFractionalGroups A GroupingDesc value defining how digits are grouped to the right of
the decimal character.
ns_PosFractionalGroupSep = A string used to separate groups of digits to the right of the decimal
character.
ns_PosFormat =This field is used to do post-processing on a formatted number. This is typically
used to add currency notation around a numeric value. The string in this field is used as a format
string in a sprintf() function call, and the formatted numeric value is supplied as a parameter
to the same sprintf() call. For example, if the ns_PosFormat field is defined as "$%s", and
the formatted numeric value is "0.02", then the result of the post-processing will be "$0.02".

file:///C|/%23%23DDOC/spr/06spr005.html (1 of 3) [4/16/2002 11:14:36 PM]

IntlFormatNumber

When this field is NULL, no post-processing occurs.
●

●

●

●

●

ns_PosMinFractionalDigits =Specifies the minimum number of digits to display to the right of the
decimal character. If there are not enough digits, then the string will be padded on the right with
0s.
ns_PosMaxFractionalDigits= Specifies the maximum number of digits to display to the right of
the decimal character. Any excess digits are just removed.
ns_NegGroups, ns_NegGroupSep, ns_NegRadix, ns_NegFractionalGroups,
ns_NegFractionalGroupSep, ns_NegFormat, ns_NegMinFractionalDigits,
ns_NegMaxFractionalDigits = These fields have the same function as the eight fields described
above, except that they are used to process negative amounts, while the previous fields are used
for positive amounts.
ns_Zero =If the number being processed is 0, then this string pointer us used asis'andiscopieddirectlyintotheresultbuffer.'If this field is NULL, the number is formatted as if it
were a positive number.
ns_Flags =This is reserved for future use and must always be 0.

Arguments
locItem
A Locale Item, as obtained from intlOpenLocale().
spec
The formatting template describing the number layout. This structure is typically taken from a
Locale structure (loc_Numbers, loc_Currency, loc_SmallCurrency), but it can also be built up by
the title for custom formatting.
whole
The whole component of the number to format. (The part of the number to the left of the radix
character.)
frac
The decimal component of the number to format. (The part of the number to the right of the radix
character.). This is specified in number of billionth. For example, to represent .5, you would use
500000000. To represent .0004, you would use 400000.
negative

file:///C|/%23%23DDOC/spr/06spr005.html (2 of 3) [4/16/2002 11:14:36 PM]

IntlFormatNumber

TRUE if the number is negative, and FALSE
if the number is positive.
doFrac
TRUE if a complete number with a decimal mark and decimal digits is desired. FALSE if only the
whole part of the number should be output.
result
Where the result of the formatting is put.
resultSize
The number of bytes available in the result buffer. This limits the number of bytes which are put
into the buffer.

Return Value
If positive, then the number of characters in the result buffer. If negative, then an error code. The string
copied into the result buffer is guaranteed to be NULL-terminated.
greater than or equal to 0 Number of characters copied.
INTL_ERR_BADNUMERICSPEC - The pointer to the NumericSpec structure was bad.
INTL_ERR_NORESULTBUFFER- "result" was NULL.
INTL_ERR_BUFFERTOOSMALL - There was not enough room in the result buffer.
INTL_ERR_BADITEM loc- Item was not an existing Locale Item.

Implementation
Folio call implemented in international folio V24.

Associated Files
intl.h

See Also
intlOpenLocale(), intlFormatDate()
file:///C|/%23%23DDOC/spr/06spr005.html (3 of 3) [4/16/2002 11:14:36 PM]

intlGetCharAttrs

intlGetCharAttrs
Returns attributes describing a given character.

Synopsis
uint32 intlGetCharAttrs(Item locItem, unichar character);

Description
This function examines the provided UniCode character and returns general information about it.

Arguments
locItem
A locale item, as obtained from intlOpenLocale().
character
The character to get the attribute of.

Return Value
Returns a bit mask, with bit sets to indicate various characteristics as defined by the UniCode standard.
The possible bits are:
This character is uppercase.
INTL_ATTRF_LOWERCASE
This character is lowercase.
INTL_ATTRF_PUNCTUATION
This character is a punctuation mark.
INTL_ATTRF_DECIMAL_DIGIT
This character is a numeric digit.
INTL_ATTRF_NUMBER
This character represent a numerical value not representable as a single decimal digit. For
example, a character 0x00bc represents the constant 1/2.
file:///C|/%23%23DDOC/spr/06spr006.html (1 of 2) [4/16/2002 11:14:36 PM]

intlGetCharAttrs

INTL_ATTRF_NONSPACING
This character is a nonspacing mark.
INTL_ATTRF_SPACE
This character is a space character.
INTL_ATTRF_HALF_WIDTH
This character is HalfKana.
INTL_ATTRF_FULL_WIDTH
This character is FullKana.
INTL_ATTRF_KANA
This character is Kana (Katakana).
INTL_ATTRF_HIRAGANA
This character is Hiragana.
INTL_ATTRF_KANJI
This character is Kanji.

Implementation
Folio call implemented in international folio V24.

Associated Files
intl.h

Caveats
This function currently does not report any attributes for many upper UniCode characters. Only the
ECMA Latin-1 character page (0x0000 to 0x00ff) is handled correctly at this time. If the language bound
to the Locale structure is Japanese, then this function will also work correctly for Japanese characters.

See Also
intlOpenLocale(), intlConvertString()

file:///C|/%23%23DDOC/spr/06spr006.html (2 of 2) [4/16/2002 11:14:36 PM]

intlTransliterateString

intlTransliterateString
Converts a string between character sets.

Synopsis
int32 intlTransliterateString(const void *string,CharacterSets
stringSet,void *result,CharacterSets resultSet,uint32 resultSize,uint8
unknownFiller);

Description
Converts a string between two character sets. This is typically used to convert a string from or to
UniCode. The conversion is done as well as possible. If certain characters from the source string cannot
be represented in the destination character set, the unknownFiller byte will be inserted in the result buffer
in their place.

Arguments
string
The string to transliterate.
stringSet
The character set of the string to transliterate. This describes the interpretation of the bytes in the
source string.
result
A memory buffer where the result of the transliteration can be put.
resultSet
The character set to use for the resulting string.
resultSize
The number of bytes available in the result buffer. This limits the number of bytes that are put into
the buffer.
unknownFiller
If a character sequence cannot be adequately converted from the source character set, then this
byte will be put into the result buffer in place of the character sequence. When converting to a 16bit character set, then this byte will be extended to 16-bits and inserted.
file:///C|/%23%23DDOC/spr/06spr009.html (1 of 3) [4/16/2002 11:14:37 PM]

intlTransliterateString

Return Value
If positive, returns the number of characters in the result buffer. If negative, returns an error code.
>=0
Number of characters in the result buffer.
INTL_ERR_BADSOURCEBUFFER
The string pointer supplied was bad.
INTL_ERR_BADCHARACTER
SET
The "stringSet" or "resultSet" arguments did not specify valid character sets.
INTL_ERR_BADRESULTBUFFER
The result buffer pointer was NULL or wasn't invalid writable memory.
INTL_ERR_BUFFERTOOSMALL
There was not enough room in the result buffer.
INTL_ERR_BADITEM
locItem was not an existing locale item.

Implementation
Folio call implemented in international folio V24.

Caveats
This function is not as smart as it could be. When converting from UniCode to ASCII, characters not in
the first UniCode page (codes greater than 0x00ff) are never converted and always replaced with the
unknownFiller byte. The upper pages of the UniCode set contain many characters which could be
converted to equivalent ASCII characters, but these are not supported at this time.

Associated Files
file:///C|/%23%23DDOC/spr/06spr009.html (2 of 3) [4/16/2002 11:14:37 PM]

intlTransliterateString

intl.h

file:///C|/%23%23DDOC/spr/06spr009.html (3 of 3) [4/16/2002 11:14:37 PM]

What Is Internationalization?

What Is Internationalization?
Internationalization is the process by which software is developed and modified so it transparently
adapts to multiple cultural environments. Localization is the process of preparing specialized software, or
special versions of existing software, targeted to individual cultural environments.
Internationalization of software has the following advantages:
●

●

It lets you maintain a single set of source code for each title, instead of slightly different source
code for each target culture. A single set of source considerably reduces the testing burden and
increases confidence in code product reliability.
It potentially lets both you and The 3DO Company deal with fewer master CD-ROMs than would
otherwise be required. Instead of producing a different CD-ROM for each target culture, a single
CD-ROM can support all cultures.

The International folio provides a structure and calls that behave in an expected manner to create a title
for international environments. For example, using the 3DO International folio, your application can
determine the current language and country codes, display dates, currency, and numeric values that are
consistent with the current language and country codes of a target culture. The International folio also
works with a separate folio, JString, to convert character sets from one format to another.
The International folio uses UniCode as its base character set. The functions and structures within the
folio use the unichar data type, which is a 16-bit version of the standard char type.
UniCode is a standard defining a 16-bit character set, which is an international version of ASCII.
UniCode specifies enough glyphs to represent all languages currently spoken around the world.
Although UniCode is the standard character set the International folio uses, it must support other
character sets. For example, the Western computer world currently relies extensively on ASCII, and
Japan relies on JIS and shift JIS. The International folio provides tools to convert strings from one
character set to another, such as enabling applications to convert ASCII text into UniCode. The following
books provide additional information on the UniCode standard:
●

●

The UniCode Standard Worldwide Character Encoding Version 1.0, Volume 1 ISBN 0-20156788-1
The UniCode Standard Worldwide Character Encoding Version 1.0, Volume 2 ISBN 0-20160845-6

file:///C|/%23%23DDOC/spg/13spg001.html [4/16/2002 11:14:37 PM]

The Locale Data Structure

The Locale Data Structure
The Locale data structure is like a little data base the system provides. Once you get a pointer to the Locale
structure, it has, among other things, the current language being used, the country code, and the format of dates
for the user's cultural environment.
The system creates a Locale structure when an application calls intlOpenLocale(). intlOpenLocale()
returns an Item, which must be disposed of using the intlCloseLocale() macro.
To examine the contents of the Locale structure, an application calls intlLookupLocale(), which returns a
pointer to the Locale structure for the specified Item. The definition of the Locale structure is shown below.
typedef struct Locale
{
ItemNode
loc_Item;

/* system linkage */

/* prefered language to use */
LanguageCodes
loc_Language;
/* An array of dialects for the current language, listed in order
* of preference, and terminated with INTL_DIALECTS_ARRAY_END
*/
DialectCodes
*loc_Dialects;
/* ISO-3166 numeric-3 code for the user's country */
CountryCodes
loc_Country;
/* general description of the user's environment */
int32
loc_GMTOffset;
/* minutes from GMT */
MeasuringSystems loc_MeasuringSystem; /* measuring system to use */
CalendarTypes
loc_CalendarType;
/* calendar type to use */
DrivingTypes
loc_DrivingType;
/* side of the street */
/* number formatting */
NumericSpec
loc_Numbers;
NumericSpec
loc_Currency;
NumericSpec
loc_SmallCurrency;
/* date formatting */
DateSpec
loc_Date;
DateSpec
loc_ShortDate;
DateSpec
loc_Time;
DateSpec
loc_ShortTime;
} Locale;

file:///C|/%23%23DDOC/spg/13spg002.html (1 of 5) [4/16/2002 11:14:38 PM]

The Locale Data Structure

The fields in the Locale structure are as follows:
●

●

●

●

●

●

●

●

●

●

●

loc_Item provides system linkage for Locale structures which are allocated in system space so that they
can be shared among multiple applications.
loc_Language defines the language to use within an application. Each supported language has a code,
which is taken from the ISO 639 Standard.
loc_Dialects is a pointer to an array of dialects. Regional variations within a given language are
accommodated through dialect tables, which are an array of dialect codes, terminated by
INTL_DIALECT_ARRAY_END.
The dialects appear in the array in decreasing order of user preference. For example, if the language is
INTL_LANG_ENGLISH, then the dialect array could hold INTL_ED_AMERICAN,
INTL_ED_AUSTRALIAN, INTL_ED_BRITISH, and so on.
loc_Country contains the standard international country code for the current country. These codes are
taken from the ISO 3166 Standard.
loc_GMTOffset contains the offset in minutes of the current location relative to the standard GMT
reference point.
loc_MeasuringSystem indicates the measuring system to use. This can be INTL_MS_METRIC,
INTL_MS_AMERICAN, or INTL_MS_IMPERIAL.
loc_CalendarType indicates what type of calendar to use. This can be the traditional Gregorian
calendar, with either Monday or Sunday as the first day of the week, or it can be the Arabic, Jewish, or
Persian calendar.
loc_DrivingType indicates on which side of the street cars usually travel in the current country.
loc_Numbers, loc_Currency, loc_SmallCurrency specifies how to format numbers and
currency. The NumericSpec structure contains the necessary information to properly localize number
output and input. These three NumericSpec structures can be passed directly to the
intlFormatNumber() function to apply localized formatting.
loc_Date, loc_ShortDate, loc_Time, loc_ShortTime specifies how to format dates and time.
The DateSpec array contains the necessary information needed to properly localize date and time output
and input. These four DateSpec arrays can be passed directly to the intlFormatDate() function to
apply localized formatting.

NumericSpec Structure
Each culture has its own way of writing numbers and currency. The Locale structure contains three NumericSpec
file:///C|/%23%23DDOC/spg/13spg002.html (2 of 5) [4/16/2002 11:14:38 PM]

The Locale Data Structure

structures that contain number and currency formatting specifications and are used to produce correctly localized
output for the target cultures.
The NumericSpec structure defines how numbers should be formatted. It is sufficiently flexible to cover plain
numbers and currency values. The structure is shown below.
typedef struct NumericSpec
{
/* how to generate a positive number */
GroupingDesc ns_PosGroups; /* grouping description */
unichar
*ns_PosGroupSep; /* separates the groups */
unichar
*ns_PosRadix;
/* decimal mark
*/
GroupingDesc ns_PosFractionalGroups; /* grouping description */
unichar
*ns_PosFractionalGroupSep; /* separates the groups */
unichar
*ns_PosFormat;
/* for post-processing */
uint32
ns_PosMinFractionalDigits; /* min # of frac digits */
uint32
ns_PosMaxFractionalDigits; /* max # of frac digits */
/* how to generate a negative number */
GroupingDesc ns_NegGroups;
/* grouping description */
unichar
*ns_NegGroupSep; /* separates the groups */
unichar
*ns_NegRadix;
/* decimal mark
*/
GroupingDesc ns_NegFractionalGroups;
/* grouping description */
unichar
*ns_NegFractionalGroupSep; /* separates the groups */
unichar
*ns_NegFormat;
/* for post-processing */
uint32
ns_NegMinFractionalDigits; /* min # of frac digits */
uint32
ns_NegMaxFractionalDigits; /* max # of frac digits */
/* when the number is zero, this string is used 'as-is' */
unichar
*ns_Zero;
} NumericSpec;
Using the fields in the NumericSpec structure, the intlFormatNumber() function can correctly format
numbers and currency according to local rules and customs. The fields of the NumericSpec structure are as
follows:
●

ns_PosGroups defines how digits are grouped left of the decimal mark. An EgroupingDesc is a 32bit bitfield in which every ON bit in the bitfield indicates a separator sequence should be inserted after the
associated digit. If bit 0 is ON, the grouping separator is inserted after digit 0 of the formatted number.

●

ns_PosGroupSep is a string that separates groups of digits to the left of the decimal mark.

●

ns_PosRadix is a string used as a decimal character.

●

ns_PosFractionalGroups is a GroupingDesc array that defines how digits are grouped to the
right of the decimal character.

file:///C|/%23%23DDOC/spg/13spg002.html (3 of 5) [4/16/2002 11:14:38 PM]

The Locale Data Structure

●

●

ns_PosFractionalGroupSep is a string used to separate groups of digits to the right of the decimal
mark.
ns_PosFormat is used for post-processing on a formatted number. Typically it is used to add currency
notation around a numeric value. The string in this field is used as a format string in sprintf(), and the
formatted numeric value is also a parameter to sprintf().

For example, if ns_PosFormat is defined as $%s, and the formatted numeric value is 0.02. The result of the
post-processing will be $0.02. When this field is NULL, no post-processing occurs.
●

●

ns_PosMinFractionalDigits specifies the minimum number of characters to the right of the
decimal mark. If there are fewer characters than the minimum, the number is padded with 0s.
ns_PosMaxFractionalDigits specifies the maximum number of characters to the right of the
decimal mark. If there are more characters than the maximum, the string is truncated.

●

ns_NegGroups is similar to ns_PosGroups, except it specifies negative numbers.

●

ns_NegGroupSep is similar to ns_PosGroupSep but for negative numbers.

●

ns_NegRadix is similar to ns_PosRadix except it specifies negative
numbers.

●

ns_NegFractionalGroups is similar to ns_PosFractionalGroups, except it
specifies negative numbers.

●

●

●

●

●

ns_NegFractionalGroupSep is similar to ns_PosFractionalGroupSep,except it specifies
negative numbers.
ns_NegFormat similar to ns_PosFormat, except it specifies negative
numbers.
ns_NegMinFractionalDigits is similar to ns_PosMinFractionalDigits, except it
specifies negative numbers.
ns_NegMaxFractionalDigits is similar to ns_PosMaxFractionalDigits, except it
specifies negative numbers.
ns_Zer If the number being processed is 0, then this string pointer is used as is and is copied directly
into the resulting buffer. If this field is NULL, then the number is formatted as if it were a positive
number.

Typically, an application doesn't have to deal with the interpretation of a NumericSpec structure. The Locale
structure contains three NumericSpec structures initialized with the correct information for the target culture,
file:///C|/%23%23DDOC/spg/13spg002.html (4 of 5) [4/16/2002 11:14:38 PM]

The Locale Data Structure

which can be passed to intlFormatNumber() to convert numbers into string form.

DateSpec Arrays
Dates also vary in format across different cultures. The Locale structure contains four DateSpec arrays which
define the local formats for date and time representation.
The DateSpec arrays contain format commands similar to printf() format strings. The% commands are
inserted in the formatting string to produce custom date output. An application can provide the DateSpec
structure from the Locale structure to the intlFormatDate() function or it can create its own DateSpec
structures for custom formatting.

file:///C|/%23%23DDOC/spg/13spg002.html (5 of 5) [4/16/2002 11:14:38 PM]

Using the Locale Structure

Using the Locale Structure
The main use of the International folio is to obtain the target language and country codes. The folio also
provides tools to format dates, numbers, and currency for the target language and country. This section
describes how to use these tools.

Determining the Current Language and Country
The intlOpenLocale() call determines the current user settings for language or country:
Item intlOpenLocale(const TagArg *tags)
This call accepts one argument, tags, a pointer to a tag argument list. This pointer is currently unused
and should be set to NULL. intlOpenLocale() returns an Item.
The application should then use the following call to obtain the Locale structure for the Item:
Locale *intlLookupLocale(Item locItem)
This call accepts one argument, locItem, an Item as returned from intlOpenLocale(). The
language code in the Locale structure can then determine which set of messages and artwork to use.
For example, if the language code were "de," the application would use a directory containing the
German message text and artwork ("de" being the code for Deutsch). The application has a directory
containing message text and artwork for each language code it uses.
Note: An application must supply any text or artwork it displays. The application must supply text
strings or artwork for each language it supports.
When an application finishes using an Item, use the following call to terminate its use of it:
Err intlCloseLocale(Item locItem)
intlCloseLocale() l accepts one argument, locItem, the item to be closed. It returns zero if the
call was successful, otherwise, an error code is returned.

Working With International Character Strings
file:///C|/%23%23DDOC/spg/13spg003.html (1 of 4) [4/16/2002 11:14:39 PM]

Using the Locale Structure

Comparing Character Strings
Applications use the intlCompareStrings() function to compare strings and sort text to be
displayed. Each language sorts text in different ways. intlCompareStrings() adapts its behavior
to the current language. By using this function, your title sorts text in the appropriate manner for the
target culture:
int32 intlCompareStrings(Item locItem, const unichar *string1,
const char *string2)
This call accepts three arguments: locItem is a Locale Item obtained from intlOpenLocale(),
string1 is a pointer to the first string to compare, and string2 is a pointer to the second string to
compare.
The comparison is performed according to the collation rules of locItem.
intlCompareStrings() is similar to the standard C strcmp() function, except that it handles
sorting variations of different languages.
IntlCompareStrings() returns -1 if string1 is less than string2; 0 if string1 is equal to
string2; and 1 if string1 is greater than string2. INTL_ERR_BADITEM is returned if
locItem was not a valid Item.

Changing Letters In Character Strings
intlConvertString() strips diacritical marks and changes the letter case of words or characters.
This function handles the language differences in rules for case conversion. It is similar to the standard C
toupper() and tolower() functions.
int32 intlConvertString(Item locItem, const unichar *string,
unichar *result, uint32 resultSize, uint32 flags);
The call accepts five arguments: locItem is an Item returned from intlOpenLocale(), string
is the string to be changed, result is where the result of the conversion is placed, resultSize is the
number of bytes available in result, and flags indicates the conversion to be performed. The string
copied to result is guaranteed to be NULL-terminated.
If successful, intlConvertString() returns a positive number indicating the number of characters
in result. Otherwise, it returns an error code.

Changing Character Sets
file:///C|/%23%23DDOC/spg/13spg003.html (2 of 4) [4/16/2002 11:14:39 PM]

Using the Locale Structure

intlTransliterateString() converts a string from one character set to another character set.
The International folio always generates UniCode strings. For example, intlFormatNumber()
generates a UniCode string holding the formatted number. The 3DO Portfolio currently supplies simple
text output routines in Lib3DO which only accept ASCII text. To display the formatted number, an
application must convert the UniCode string generated by the International folio to ASCII and call the
text output routines.
intlTransliterateString() can be used to convert data files generated in ASCII to UniCode or
to convert the output of the International folio into ASCII for use by other tools.
intlTranliterateString() is called as follows:
int32 intlTransliterateString(const void *string, CharacterSets
stringSet, void *result, CharacterSets resultSet, uint32
resultSize, uint8 unknownFiller);
The call accepts six arguments: string is the string to convert, stringSet is the character set of the
string to convert, result is where to put the converted string, resultSet is the character set to use
for the resulting string, resultSize is the number of bytes available in result, and
unknownFiller is used as filler for characters that cannot be converted.
If successful, intlTransliterateString() returns a positive number indicating the number of
characters in result. Otherwise, it returns an error code.

Providing C Functionality
intlGetCharAttrs() provides functionality similar to the standard C functions isupper(),
islower(), etc. It is called as follows:
uint32 intlGetCharAttrs(Item locItem, unichar character);
The call accepts two arguments: locItem, an Item as returned by intlOpenLocale(); and
character, the character for which attributes should be returned.
If successful, intlGetCharAttrs() returns a bit mask which indicates the attributes of the
character. INTL_ERR_BADITEM is returned if locItem is not a valid Item.

Formatting Numbers or Currency
file:///C|/%23%23DDOC/spg/13spg003.html (3 of 4) [4/16/2002 11:14:39 PM]

Using the Locale Structure

Numbers are represented in different ways in different countries, so a title should use the following call
to format a number to be displayed in the correct manner:
int32 intlFormatNumber(Item locItem, const NumericSpec *spec,
uint32 whole, uint32 frac, bool negative, bool doFrac, unichar
*result, uint32 resultSize);
The call accepts seven arguments: locItem is an Item returned from intlOpenLocale(), spec is
the format specification for the number (usually taken from the Locale structure), whole is the whole
component of the number, frac is the decimal component of the number expressed in billionths (to the
right of the decimal mark), negative is a Boolean that indicates whether the number is negative,
doFrac is a flag indicating which portions of the number should be formatted (if TRUE, the entire
number with a decimal mark is output, if FALSE, only the whole part of the number is output), result
is where the formatted number is put, and resultSize is the number of bytes in result.
The number is formatted according to the rules specified in locItem and spec. The string copied to
result is guaranteed to be NULL-terminated.
If successful, intlFormatNumber() returns a positive number indicating the number of characters in
result. Otherwise, it returns an error code.

Formatting Dates
An application should use the following call to format a date to be displayed:
int32 intlFormatDate(Item locItem, DateSpec spec, const
GregorianDate *date, unichar *result, uint32 resultSize);
The call accepts five arguments: locItem is an Item as returned from intlOpenLocale(), spec is
the format specification for the date (usually taken from the Locale structure), date is the date to
format, result is where to put the formatted date, and resultSize is the number of bytes in
result. The date is formatted according to the rules of locItem and spec arguments. The string
copied into result is guaranteed to be NULL-terminated.
If successful, intlFormatDate() returns a positive number indicating the number of characters in
result. Otherwise, an error code is returned.

file:///C|/%23%23DDOC/spg/13spg003.html (4 of 4) [4/16/2002 11:14:39 PM]

Converting Character Sets With the JString Folio

Converting Character Sets With the
JString Folio
The International folio uses calls from the JString folio to convert character sets from one format to
another. The JString folio contains four calls:
●
●
●
●

ConvertASCII2ShiftJIS()converts a string from ASCII to Shift-JIS.
ConvertShiftJIS2ASCII()converts a string from Shift-JIS to ASCII.
ConvertShiftJIS2UniCode()converts a string from Shift-JIS to UniCode.
ConvertUniCode2ShiftJIS() converts a string from UniCode to Shift-JIS.

These calls are used to enter data or develop applications using the Shift-JIS character set and then
convert the date to ASCII or UniCode at runtime.
For example, the International folio generates dates and currency in UniCode. Because the current 3DO
text routines can only handle ASCII or Shift-JIS, you need to convert it to render the information on the
display. You can parse the UniCode and render it using your own font technology, or use the 3DO
JString calls to convert the text to Shift-JIS.
The International folio automatically loads the JString folio when you call
intlTransliterateString and requests Shift-JIS translation.

file:///C|/%23%23DDOC/spg/13spg004.html [4/16/2002 11:14:40 PM]

Function Calls and Macros

Function Calls and Macros
Obtaining a Locale Structure
The following International folio macros obtain a Locale structure:
●
●
●

intlCloseLocale() Terminates use of a Locale Item.
intlLookupLocale() Returns a pointer to the Locale structure for an Item.
intlOpenLocale() Gains access to a Locale Item.

Manipulating Characters and Dates
The following International folio calls manipulate characters, dates, and numbers:
●
●
●
●
●
●

intlCompareStrings() Compares two character strings.
intlConvertString() Changes attributes of a character string.
intlFormatDate() Formats a date according to a specified format.
IntlFormatNumber() Formats a number according to a specified format.
intlGetCharAttrs()Returns attributes of a specified character.
intlTransliterateString()Converts a character string from one character set to
another.

Converting Character Sets
The following JString folio calls are used to convert from one character set to another.
●
●
●
●

ConvertASCII2ShiftJIS()Converts a string from ASCII to Shift-JIS
ConvertShiftJIS2ASCII() Converts a string from Shift-JIS to ASCII.
ConvertShiftJIS2UniCode() Converts a string from Shift-JIS to UniCode.
ConvertUniCode2ShiftJIS() Converts a string from UniCode to Shift-JIS.

file:///C|/%23%23DDOC/spg/13spg005.html [4/16/2002 11:14:40 PM]

ConvertASCII2ShiftJIS

ConvertASCII2ShiftJIS
Converts an ASCII string to Shift-JIS.

Synopsis
int32 ConvertASCII2ShiftJIS(const char *string,char *result, uint32
resultSize,uint8 unknownFiller);

Description
Converts a string from ASCII to Shift-JIS. The conversion is done as well as possible. If certain
characters from the source string cannot be represented in ASCII, the unknownFiller byte will be inserted
in the result buffer in their place.

Arguments
string
The string to convert.
result
A memory buffer where the result of the conversion can be put.
resultSize
The number of bytes available in the result buffer. This limits the number of bytes that are put into
the buffer.
unknownFiller
If a character sequence cannot be adequately converted, then this byte will be put into the result
buffer in place of the character sequence.

Return Value
If positive, returns the number of characters in the result buffer. If negative, returns an error code.
>=0
Number of characters in the result buffer.
JSTR_ERR_BUFFERTOO
file:///C|/%23%23DDOC/spr/07spr001.html (1 of 2) [4/16/2002 11:14:40 PM]

ConvertASCII2ShiftJIS

SMALL
There was not enough room in the result buffer.

Implementation
Folio call implemented in jstring folio V24.

Associated Files
jstring.h

file:///C|/%23%23DDOC/spr/07spr001.html (2 of 2) [4/16/2002 11:14:40 PM]

ConvertShiftJIS2ASCII

ConvertShiftJIS2ASCII
Converts a Shift-JIS string to ASCII.

Synopsis
int32 ConvertShiftJIS2ASCII(const char *string,char *result, uint32
resultSize,uint8 unknownFiller);

Description
Converts a string from Shift-JIS to ASCII. The conversion is done as well as possible. If certain
characters from the source string cannot be represented in ASCII, the unknownFiller byte will be inserted
in the result buffer in their place.

Arguments
string
The string to convert.
result
A memory buffer where the result of the conversion can be put.
resultSize
The number of bytes available in the result buffer. This limits the number of bytes that are put into
the buffer.
unknownFiller
If a character sequence cannot be adequately converted, then this byte will be put into the result
buffer in place of the character sequence.

Return Value
If positive, then the number of characters in the result buffer. If negative, then an error code.
>=0
Number of characters in the result buffer.
JSTR_ERR_BUFFERTOO
file:///C|/%23%23DDOC/spr/07spr002.html (1 of 2) [4/16/2002 11:14:41 PM]

ConvertShiftJIS2ASCII

SMALL
There was not enough room in the result buffer.

Implementation
Folio call implemented in jstring folio V24.

Associated Files
jstring.h

file:///C|/%23%23DDOC/spr/07spr002.html (2 of 2) [4/16/2002 11:14:41 PM]

ConvertShiftJIS2UniCode

ConvertShiftJIS2UniCode
Converts a Shift-JIS string to UniCode.

Synopsis
int32 ConvertShiftJIS2UniCode(const char *string,unichar *result,
uint32 resultSize,uint8 unknownFiller);

Description
Converts a string from Shift-JIS to UniCode. The conversion is done as well as possible. If certain
characters from the source string cannot be represented in ASCII, the unknownFiller byte will be inserted
in the result buffer in their place.

Arguments
string
The string to convert.
result
A memory buffer where the result of the conversion can be put.
resultSize
The number of bytes available in the result buffer. This limits the number of bytes that are put into
the buffer.
unknownFiller
If a character sequence cannot be adequately converted, then this byte will be put into the result
buffer in place of the character sequence.

Return Value
If positive, then the number of characters in the result buffer. If negative, then an error code.
>=0
Number of characters in the result buffer.
JSTR_ERR_BUFFERTOO
file:///C|/%23%23DDOC/spr/07spr003.html (1 of 2) [4/16/2002 11:14:41 PM]

ConvertShiftJIS2UniCode

SMALL
There was not enough room in the result buffer.

Implementation
Folio call implemented in jstring folio V24.

Associated Files
jstring.h

file:///C|/%23%23DDOC/spr/07spr003.html (2 of 2) [4/16/2002 11:14:41 PM]

ConvertUniCode2ShiftJIS

ConvertUniCode2ShiftJIS
Converts a UniCode string to Shift-JIS.

Synopsis
int32 ConvertUniCode2ShiftJIS(const unichar *string,char *result,
uint32 resultSize,uint8 unknownFiller);

Description
Converts a string from UniCode to Shift-JIS. The conversion is done as well as possible. If certain
characters from the source string cannot be represented in ASCII, the unknownFiller byte will be inserted
in the result buffer in their place.

Arguments
string
The string to convert.
result
A memory buffer where the result of the conversion can be put.
resultSize
The number of bytes available in the result buffer. This limits the number of bytes that are put into
the buffer.
unknownFiller
If a character sequence cannot be adequately converted, then this byte will be put into the result
buffer in place of the character sequence.

Return Value
If positive, then the number of characters in the result buffer. If negative, then an error code.
>=0
Number of characters in the result buffer.
JSTR_ERR_BUFFERTOO
file:///C|/%23%23DDOC/spr/07spr004.html (1 of 2) [4/16/2002 11:14:41 PM]

ConvertUniCode2ShiftJIS

SMALL
There was not enough room in the result buffer.

Implementation
Folio call implemented in jstring folio V24.

Associated Files
jstring.h

file:///C|/%23%23DDOC/spr/07spr004.html (2 of 2) [4/16/2002 11:14:41 PM]

The Compression Folio

The Compression Folio
This chapter describes the Compression folio that provides general purpose compression and
decompression services. It contains the following topics:
●
●
●
●
●
●
●

Introduction
How the Compression Folio Works
The Callback Function
Controlling Memory Allocations
Convenience Calls
Example
Function Calls

file:///C|/%23%23DDOC/spg/14spg.html [4/16/2002 11:14:42 PM]

Introduction

Introduction
This section provides an overview of the Compression folio and describes how it works. See 3DO System
Programmer's Reference for complete descriptions of the calls mentioned in this section.
The compression folio provides services that compress and decompress data in a non-lossy manner. The
compression quality differs depending on the type of data. Compression ratios range typically from 50
percent up to 80 percent.
The intended use of the Compression folio is to compress data that is being written to NVRAM. It is
critical that data being written to NVRAM be as compact as possible because it is a limited resource. The
interface to the compression and decompression engine is totally generic, allowing the folio to be used
for any data that needs to be compressed.

file:///C|/%23%23DDOC/spg/14spg001.html [4/16/2002 11:14:42 PM]

3DO System Programmer's Reference

3DO System Programmer's
Reference
This book is a command reference. It contains examples of Portfolio procedure calls, syntax, and use. It
contains these chapters:
●
●
●
●
●
●
●
●
●

Kernel Folio Calls- Describes the kernel folio procedure calls.
File Folio Calls- Lists the file folio calls.
Math Folio Calls -Lists the math folio procedure calls.
Event Broker Calls- Lists event broker calls.
Timer Calls-Lists the Portfolio timer calls.
International Folio Calls-Lists the International folio calls.
JString Folio Calls-- Lists the JString folio calls.
Compression Folio Calls-Lists the Compression folio calls.
Portfolio Items-Lists the Portfolio items.

file:///C|/%23%23DDOC/spr/00spr1.html [4/16/2002 11:14:42 PM]

File Folio Calls

File Folio Calls
This chapter lists the file folio calls in alphabetical order. The list below is a quick summary of each,
followed by the page number where you'll find the procedure described.
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●

ChangeDirectory Changes the current directory.
CloseDirectory Closes a directory.
CloseDiskFile Closes a file.
CloseDiskStream Closes a disk stream.
CreateAlias Creates a file system alias.
CreateFile Creates a file.
DeleteFile Deletes a file.
ExecuteAsSubroutine Executes previously loaded code as a subroutine.
ExecuteAsThread Executes previously loaded code as a thread.
GetDirectory Gets the item number and pathname for the current directory.
LoadCode Loads a binary image into memory, and obtains a handle to it.
LoadProgram Loads a binary image and spawns it as a task.
LoadProgramPrio Loads a binary image and spawns it as a task, with priority.
OpenDirectoryItem Opens a directory specified by an item.
OpenDirectoryPath Opens a directory specified by a pathname.
OpenDiskFile Opens a disk file.
OpenDiskFileInDir Opens a disk file contained in a specific directory.
OpenDiskStream Opens a disk stream for stream-oriented I/O.
ReadDirectory Reads the next entry from a directory.
ReadDiskStream Reads from a disk stream.
SeekDiskStream Performs a seek operation on a disk stream.
UnloadCode Unloads a binary image previously loaded with LoadCode().

file:///C|/%23%23DDOC/spr/02spr.html [4/16/2002 11:14:43 PM]

Math Folio Calls

Math Folio Calls
This chapter lists the math folio procedure calls in alphabetical order. The list below is a quick summary
of each, followed by the page number where you'll find the procedure described.
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●

AbsVec3_F16 Computes the absolute value of a vector of 16.16 values.
AbsVec4_F16 Computes the absolute value of a vector of 16.16 values.
Add32 Adds two 32-bit integer quantities together.
Add64 Adds two 64-bit integers together.
AddF14 Adds two 2.14-format fixed-point fractions together.
AddF16 Adds two 16.16-format fixed-point fractions together.
AddF30 Adds two 2.30-format fixed-point fractions together.
AddF32 Adds two 32.32-format fixed-point fractions together.
AddF60 Adds two 32.32-format fixed-point fractions together.
Atan2F16 Adds two 4.60-format fixed-point fractions together.
CloseMathFolio Closes the math folio and resets the mathbase global variable to zero.
CompareS64 Compares two signed 64-bit integer quantities.
CompareSF32 Compares two signed 32.32-format fractions.
CompareSF60 Compares two signed 4.60-format fractions.
CompareU64 Compares two unsigned 64-bit integer quantities.
CompareUF32 Compares two unsigned 32.32-format fractions.
CompareUF60 Compares two unsigned 4.60-format fractions.
Convert32_F16 Converts a 32-bit integer to a 16.16 fraction.
Convert32_F32 Converts a 32-bit integer to a 32.32 fraction.
ConvertF14_F16 Converts a 2.14 fraction to a 16.16 fraction.
ConvertF16_32 Converts a 16.16 fraction to a 32-bit integer.
ConvertF16_F14 Converts a 16.16 fraction to a 2.14 fraction.
ConvertF16_F30 Converts a 16.16 fraction to a 2.30 fraction.
ConvertF30_F16 Converts a 2.30 fraction to a 16.16 fraction.
ConvertF32_F16 Converts a 32.32 fraction to a 16.16 fraction.
ConvertS32_64 Converts a 32-bit integer to a 64-bit integer.
ConvertSF16_F32 Converts a 16.16 fraction to a 32.32 fraction.
ConvertU32_64 Converts an unsigned 32-bit integer to an unsigned 64-bit integer.
ConvertUF16_F32 Converts an unsigned 16.16 fraction to an unsigned 32.32fraction.

file:///C|/%23%23DDOC/spr/03spr.html (1 of 4) [4/16/2002 11:14:44 PM]

Math Folio Calls
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●

●
●
●
●

●

●

●

●
●
●
●
●
●

CosF16 Computes the 16.16 operamath cosine of a 16.16 fraction angle.
CosF30 Computes the operamath 2.30 cosine of a 16.16 fraction.
CosF32 Computes the operamath 32.32 cosine of a 16.16 fraction.
Cross3_F16 Computes the cross-product of two vectors of 16.16 values.
DivRemS32 Computes the quotient and remainder of a 32-bit division.
DivRemSF16 Computes the quotient and remainder of a 16.16 division.
DivRemU32 Computes the quotient and remainder of a 32-bit division.
DivRemUF16 Computes the quotient and remainder of a 16.16 division.
DivS64 Computes the quotient and remainder of a 64-bit division.
DivSF16 Computes the quotient of a 16.16 division.
DivU64 Computes the quotient and remainder of a 64-bit division.
DivUF16 Computes the quotient of a 16.16 division.
Dot3_F16 Multiplies two vectors of 16.16 values.
Dot4_F16 Multiplies two vectors of 16.16 values.
Mul32 Multiplies two 32-bit integers.
Mul64 Multiplies two 64-bit integers.
MulF14 Multiplies two 2.14 fractions.
MulManyF16 Multiplies an array of 16.16 values by another array of 16.16 values.
MulManyVec3Mat33_F16 Multiplies one or more vectors by a 3x3 matrix of 16.16 values.
MulManyVec3Mat33DivZ_F16 Multiplies a 3x3 matrix of 16.16 values by 1 or more 3coordinate vectors of 16.16 values, then multiplies x and y elements of the result vector by ratio of
n/z.
MulManyVec4Mat44_F16 Multiplies one or more vectors by a 4x4 matrix of 16.16 values.
MulMat33Mat33_F16 Computes the product of two 3x3 matrices of 16.16values.
MulMat44Mat44_F16 Computes the product of two 4x4 matrices of 16.16 values.
MulObjectMat33_F16 Multiplies a matrix within an object structure by an external 3x3
matrix of 16.16 values.
MulObjectMat44_F16 Multiplies a matrix within an object structure by an external 4x4
matrix of 16.16 values.
MulObjectVec3Mat33_F16 Multiplies many vectors within an object structure by a 3x3
matrix of 16.16 values.
MulObjectVec4Mat44_F16 Multiplies many vectors within an object structure by a 4x4
matrix of 16.16 values.
MulS32_64 Multiplies two 32-bit integers and returns a 64-bit result.
MulScalarF16 Multiplies a 16.16 scalar by an array of 16.16 values.
MulSF16 Multiplies two signed 16.16 fractions.
MulSF16_F32 Multiplies two signed 16.16 numbers and returns a 32.32 result.
MulSF30 Multiplies two 2.30 fractions.
MulSF30_F60 Multiplies two signed 2.30 numbers and returns a 4.60 result.

file:///C|/%23%23DDOC/spr/03spr.html (2 of 4) [4/16/2002 11:14:44 PM]

Math Folio Calls
●
●
●
●
●
●

●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●

MulU32_64 Multiplies two unsigned 32-bit integers and returns a 64-bit result.
MulUF16 Multiplies two unsigned 16.16 fractions.
MulUF16_F32 Multiplies two unsigned 16.16 numbers and returns a 32.32 result.
MulUF30_F60 Multiplies two unsigned 2.30 numbers and returns a 4.60 result.
MulVec3Mat33_F16 Computes the product of a 3x3 matrix and a vector.
MulVec3Mat33DivZ_F16 Computes the product of a 3x3 matrix and a vector, then
multiplies the x, y elements of the result by the ratio n/z.
MulVec4Mat44_F16 Computes the product of a 4x4 matrix and a vector.
Neg32 Computes the two's complement of a 32-bit integer.
Neg64 Computes the two's complement of a 64-bit integer.
NegF14 Computes the two's complement of a 2.14 fraction.
NegF16 Computes the two's complement of a 16.16 fraction.
NegF30 Computes the two's complement of a 2.30 fraction.
NegF32 Computes the two's complement of a 32.32 fraction.
NegF60 Computes the two's complement of a 4.60 fraction.
Not32 Computes one's complement of a 32-bit integer.
Not64 Computes one's complement of a 64-bit integer.
NotF14 Computes one's complement of a 2.14 fraction.
NotF16 Computes one's complement of a 16.16 fraction.
NotF30 Computes one's complement of a 2.30 fraction.
NotF32 Computes one's complement of a 32.32 number.
NotF60 Computes one's complement of a 4.60 number.
OpenMathFolio Opens the math folio and sets _MathBase global variable.
RecipSF16 Computes the reciprocal of a signed 16.16 number.
RecipUF16 Computes the reciprocal of an unsigned 16.16 number.
SinF16 Computes the 16.16 sine of a 16.16 fraction angle.
SinF30 Computes the operamath 2.30 sine of a 16.16 fraction.
SinF32 Computes the operamath 32.32 sine of a 16.16 fraction.
Sqrt32 Computes square root of an unsigned 32-bit number.
Sqrt64_32 Computes the 32-bit square root of an unsigned 64-bit integer.
SqrtF16 Computes the square root of an unsigned 16.16 number.
SqrtF32_F16 Computes the square root of a 32.32 fraction.
SqrtF60_F30 Computes the square root of a 4.60 fraction as a 2.30 fraction.
Square64 Squares a 64-bit integer.
SquareSF16 Squares a signed 16.16 fraction.
SquareUF16 Squares an unsigned 16.16 fraction.
Sub32 Subtracts a 32-bit integer from another.
Sub64 Subtracts a 64-bit integer from another.
SubF14 Subtracts a 2.14 fraction from another.

file:///C|/%23%23DDOC/spr/03spr.html (3 of 4) [4/16/2002 11:14:44 PM]

Math Folio Calls
●
●
●
●
●
●

SubF16 Subtracts a 16.16 fraction from another.
SubF30 Subtracts a 2.30 fraction from another.
SubF32 Subtracts a 32.32 fraction from another.
SubF60 Subtracts a 4.60 fraction from another.
Transpose33_F16 Transposes a 3x3 matrix of 16.16 values.
Transpose44_F16 Transposes a 4x4 matrix of 16.16 values.

file:///C|/%23%23DDOC/spr/03spr.html (4 of 4) [4/16/2002 11:14:44 PM]

AbsVec3_F16

AbsVec3_F16
Computes the absolute value of a vector of 16.16 values.

Synopsis
frac16 AbsVec3_F16( vec3f16 vec )

Description
This function computes the absolute value of a vector of 16.16 values.

Arguments
vec
The vector whose absolute value to compute.

Return Value
The function returns the absolute value (a 16.16 fraction).

Implementation
SWI implemented in operamath V20.

Associated Files
operamath.h

Caveats
This function does not detect overflow conditions and will return unpredictable results in case of
overflow.

See Also
AbsVec4_F16()

file:///C|/%23%23DDOC/spr/03spr001.html [4/16/2002 11:14:44 PM]

AbsVec4_F16

AbsVec4_F16
Computes the absolute value of a vector of 16.16 values.

Synopsis
frac16 AbsVec4_F16( vec4f16 vec )

Description
This function computes the absolute value of a vector of 16.16 values.

Arguments
vec
The vector whose absolute value to compute.

Return Value
The function returns the absolute value (a 16.16 fraction).

Implementation
SWI implemented in operamath V20.

Associated Files
operamath.h

Caveats
This function does not detect overflow conditions and will return unpredictable results in case of
overflow.

See Also
AbsVec3_F16()

file:///C|/%23%23DDOC/spr/03spr002.html [4/16/2002 11:14:44 PM]

Add32

Add32
Adds two 32-bit integer quantities together.

Synopsis
int32 Add32( int32 x, int32 y )

Description
This macro adds two 32-bit numbers together and returns the result. The macro is included for
completeness.
The macro is actually defined as simple addition of its arguments, and does not check for or enforce any
typecast requirements.

Arguments
x, y 32-bit integers.

Return Value
The macro returns the sum of its arguments.

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
AddF16(), AddF14(), AddF30()

file:///C|/%23%23DDOC/spr/03spr003.html [4/16/2002 11:14:45 PM]

AddF16

AddF16
Adds two 16.16-format fixed-point fractions together.

Synopsis
frac16 AddF16( frac16 x, frac16 y )

Description
This macro adds two 16.16-format fixed-point fractions together and returns the result. The macro is
included for completeness.
The macro is actually defined as simple addition of its arguments, and does not check for or enforce any
typecast requirements.

Arguments
x, y 16.16-format fixed-point fractions.

Return Value
The function returns the sum of the arguments.

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
Add32(), AddF14(), AddF30()

file:///C|/%23%23DDOC/spr/03spr006.html [4/16/2002 11:14:45 PM]

AddF14

AddF14
Adds two 2.14-format fixed-point fractions together.

Synopsis
frac14 AddF14( frac14 x, frac14 y )

Description
This macro adds two 2.14-format fixed-point fractions together and returns the result. The macro is
included for completeness.
The macro is actually defined as simple addition of its arguments, and does not check for or enforce any
typecast requirements.

Arguments
x, y 2.14-format fixed-point fractions.

Return Value
The macro returns the sum of the arguments.

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
Add32(), AddF16(), AddF30()

file:///C|/%23%23DDOC/spr/03spr005.html [4/16/2002 11:14:45 PM]

AddF30

AddF30
Adds two 2.30-format fixed-point fractions together.

Synopsis
frac30 AddF30( frac30 x, frac30 y )

Description
This macro adds two 2.30 format fixed-point fractions together and returns the result. The macro is
included for completeness.
The macro is actually defined as the simple addition of its arguments. It does not check for or enforce
any typecast requirements.

Arguments
x, y 2.30-format fixed-point fractions.

Return Value
The macro returns the sum of its arguments.

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
Add32(), AddF16(), AddF14()

file:///C|/%23%23DDOC/spr/03spr007.html [4/16/2002 11:14:45 PM]

Add64

Add64
Adds two 64-bit integers together.

Synopsis
void Add64( int64 *r, int64 *a1, int64 *a2 )

Description
This function adds two 64-bit integers together and returns the result. The value deposited in r is the sum
of the arguments. This function is actually the same function as AddF32().

Arguments
r
A pointer to a 64-bit integer structure to store the result.
a1, a2
Pointers to 64-bit integer addends.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
AddF32(), AddF60()

file:///C|/%23%23DDOC/spr/03spr004.html [4/16/2002 11:14:46 PM]

AddF32

AddF32
Adds two 32.32-format fixed-point fractions together.

Synopsis
void AddF32( frac32 *r, frac32 *a1, frac32 *a2 )

Description
This function adds two 32.32- format fixed-point fractions together and deposits the result in the location
pointed to by the r argument. This function is actually the same function as Add64().

Arguments
r
A pointer to a 32.32-fraction structure to store the result.
a1, a2
Pointers to 32.32-format fixed-point fraction addends.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
Add64(), AddF60()

file:///C|/%23%23DDOC/spr/03spr008.html [4/16/2002 11:14:46 PM]

AddF60

AddF60
Adds two 4.60-format fixed-point fractions together.

Synopsis
void AddF60( frac60 *r, frac60 *a1, frac60 *a2 )

Description
This function adds two 4.60-format fixed-point fractions together and deposits the result in the location
pointed to by the r argument.

Arguments
r
A pointer to a 4.60-fraction structure to store the result.
a1, a2
Pointers to 4.60-format fixed-point fraction addends.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
Add64(), AddF32()

file:///C|/%23%23DDOC/spr/03spr009.html [4/16/2002 11:14:46 PM]

Atan2F16

Atan2F16
Computes the arctangent of a ratio.

Synopsis
frac16 Atan2F16( frac16 x, frac16 y )

Description
This function computes the arctangent of the ratio y/x.
The result assumes 256.0 units in the circle (or 16,777,216 units if used as an integer). A correct 16.16
result is returned if the arguments are int32, frac30 or frac14, as long as both arguments are the same
type.

Arguments
x, y 16.16-format fractions.

Return Value
The function returns the arctangent of the ratio of the arguments.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

file:///C|/%23%23DDOC/spr/03spr010.html [4/16/2002 11:14:47 PM]

CloseMathFolio

CloseMathFolio
Closes the math folio and resets the mathbase global variable to zero.

Synopsis
Err CloseMathFolio(void)

Description
CloseMathFolio attempts to close the math folio structure. If successful, it also sets _Mathfolio to zero
and returns zero. On failure a negative error is returned.

Implementation
Convenience call implemented in operamath.lib V22.

See Also
OpenMathFolio()

file:///C|/%23%23DDOC/spr/03spr011.html [4/16/2002 11:14:47 PM]

OpenMathFolio

OpenMathFolio
Opens the math folio and sets _MathBase global variable.

Synopsis
int32 OpenMathFolio( void )

Description
This function attempts to open the math folio structure. If it successfully locates the math folio, it sets the
global variable _MathBase to point to the math folio structure. If it fails to open the folio, it returns a
negative number that can be printed with the PrintfSysError function.
Programs must call OpenMathFolio before attempting to use any of the math folio functions.

Return Value
If successful, the function sets the global variable _MathBase to point to the math folio structure. If
unsuccessful, it returns a negative number.

Implementation
Convenience call implemented in operamath.lib V20.

Associated Files
operamath.h, operamath.lib

file:///C|/%23%23DDOC/spr/03spr084.html [4/16/2002 11:14:47 PM]

CompareS64

CompareS64
Compares two signed 64-bit integer quantities.

Synopsis
int32 CompareS64( int64 *s1, int64 *s2 )

Description
This function compares two signed 64-bit integers. This function is actually the same function as
CompareSF32() and CompareSF60().

Arguments
s1, s2 Pointers to signed 64-bit integers.

Return Value
s1 == s2

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
CompareSF32(), CompareU64(), CompareUF32(), CompareUF60(),
CompareSF60()

file:///C|/%23%23DDOC/spr/03spr012.html [4/16/2002 11:14:47 PM]

CompareSF32

CompareSF32
Compares two signed 32.32-format fractions.

Synopsis
int32 CompareSF32( frac32 *s1, frac32 *s2 )

Description
This function compares two signed 32.32-format fractions. This function is actually the same function as
CompareS64() and CompareSF60().

Arguments
s1, s2 Pointers to signed 32.32 fractions.

Return Value
s1 == s2

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
CompareS64(), CompareU64(), CompareUF32(), CompareUF60(),
CompareSF60()

file:///C|/%23%23DDOC/spr/03spr013.html [4/16/2002 11:14:48 PM]

CompareU64

CompareU64
Compares two unsigned 64-bit integer quantities.

Synopsis
int32 CompareU64( uint64 *s1, uint64 *s2 )

Description
This function compares two unsigned 64-bit integers. This function is actually the same function as
CompareUF32() and CompareUF60().

Arguments
s1, s2 Pointers to unsigned 64-bit integers.

Return Value
The function returns 1 if s1 > s2, zero if s1 == s2, or -1 if s1 < s2.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
CompareSF32(), CompareS64(), CompareUF32(), CompareSF60(),
CompareUF60()

file:///C|/%23%23DDOC/spr/03spr015.html [4/16/2002 11:14:48 PM]

CompareUF32

CompareUF32
Compares two unsigned 32.32-format fractions.

Synopsis
int32 CompareUF32( ufrac32 *s1, ufrac32 *s2 )

Description
This function compares two unsigned 32.32-format fractions. This function is actually the same function
as CompareU64() and CompareUF60().

Arguments
s1, s2 Pointers to unsigned 32.32 fractions.

Return Value
The function returns 1 if s1 > s2, zero if s1 == s2, or -1 if s1 < s2.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
CompareS64(), CompareSF32(), CompareU64(), CompareUF60(),
CompareSF60()

file:///C|/%23%23DDOC/spr/03spr016.html [4/16/2002 11:14:48 PM]

CompareUF60

CompareUF60
Compares two unsigned 4.60-format fractions.

Synopsis
int32 CompareUF60( ufrac60 *s1, ufrac60 *s2 )

Description
This function compares two unsigned 4.60-format fractions. This function is actually the same function
as CompareU64() and CompareUF32().

Arguments
s1, s2 Pointers to unsigned 4.60 fractions.

Return Value
The function returns 1 if s1 > s2, zero if s1 == s2, or -1 if s1 < s2.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
CompareS64(), CompareSF32(), CompareU64(), CompareUF32(),
CompareSF60()

file:///C|/%23%23DDOC/spr/03spr017.html [4/16/2002 11:14:48 PM]

CompareSF60

CompareSF60
Compares two signed 4.60-format fractions.

Synopsis
int32 CompareSF60( frac60 *s1, frac60 *s2 )

Description
This function compares two signed 4.60-format fractions. This function is actually the same function as
CompareS64() and CompareSF32().

Arguments
s1, s2 Pointers to signed 4.60 fractions.

Return Value
The function returns 1 if s1 > s2, zero if s1 == s2, or -1 if s1 < s2.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
CompareS64(), CompareU64(), CompareUF32(), CompareUF60(),
CompareSF32()

file:///C|/%23%23DDOC/spr/03spr014.html [4/16/2002 11:14:49 PM]

Convert32_F16

Convert32_F16
Converts a 32-bit integer to a 16.16 fraction.

Synopsis
frac16 Convert32_F16( int32 x )

Description
This macro converts a 32-bit integer into a 16.16 fraction.

Arguments
x
The 32-bit integer to be converted.

Return Value
The function returns the 16.16 result of the conversion. The fractional 1- bits of the result are zero, and
the upper 16-bits of the argument are lost.

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
ConvertF14_F16(), ConvertF16_F14(), ConvertF16_F30(),
ConvertF30_F16(), Convert32_F32(), ConvertF16_32(), ConvertF32_F16(),
ConvertS32_64(), ConvertSF16_F32(), ConvertU32_64(), ConvertUF16_F32()

file:///C|/%23%23DDOC/spr/03spr018.html [4/16/2002 11:14:49 PM]

ConvertF14_F16

ConvertF14_F16
Converts a 2.14 fraction to a 16.16 fraction.

Synopsis
frac16 ConvertF14_F16( frac14 x )

Description
This macro converts a 2.14 fraction to a 16.16 fraction.

Arguments
x
The 2.14 fraction to be converted.

Return Value
The function returns the 16.16 fraction result of the conversion.

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
ConvertF16_F14(), ConvertF16_F30(), ConvertF16_32(), ConvertF30_F16(),
ConvertF32_F16(), Convert32_F32(), Convert32_F16(), ConvertS32_64(),
ConvertSF16_F32(), ConvertU32_64(), ConvertUF16_F32()

file:///C|/%23%23DDOC/spr/03spr020.html [4/16/2002 11:14:49 PM]

ConvertF16_F14

ConvertF16_F14
Converts a 16.16 fraction to a 2.14 fraction.

Synopsis
frac14 ConvertF16_F14( frac16 x )

Description
This macro converts a 16.16 fraction to a 2.14 fraction, using the upper 16-bits of a 32-bit quantity.

Arguments
x
The 16.16 fraction to be converted.

Return Value
The function returns the 2.14 fraction result of the conversion.

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
ConvertF14_F16(), ConvertF16_F30(), ConvertF16_32(), ConvertF30_F16(),
ConvertF32_F16(), Convert32_F32(), Convert32_F16(), ConvertS32_64(),
ConvertSF16_F32(), ConvertU32_64(), ConvertUF16_F32()

file:///C|/%23%23DDOC/spr/03spr022.html [4/16/2002 11:14:50 PM]

ConvertF16_F30

ConvertF16_F30
Converts a 16.16 fraction to a 2.30 fraction.

Synopsis
frac30 ConvertF16_F30( frac16 x )

Description
This macro converts a 16.16 fraction to a 2.30 fraction.

Arguments
x
The 16.16 fraction to be converted.

Return Value
The function returns the 2.30 fraction result of the conversion.

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
ConvertF14_F16(), ConvertF16_F14(), ConvertF16_32(), ConvertF30_F16(),
ConvertF32_F16(), Convert32_F32(), Convert32_F16(), ConvertS32_64(),
ConvertSF16_F32(), ConvertU32_64(), ConvertUF16_F32()

file:///C|/%23%23DDOC/spr/03spr023.html [4/16/2002 11:14:50 PM]

ConvertF16_32

ConvertF16_32
Converts a 16.16 fraction to a 32-bit integer.

Synopsis
int32 ConvertF16_32( frac16 x )

Description
This macro converts a 16.16 fraction to a 32-bit integer. The upper 16-bits are zero or are filled with the
sign bit of the argument. The fraction bits of the argument are lost.

Arguments
x
The 16.16 fraction to be converted.

Return Value
The function returns the 32-bit integer result of the conversion.

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
ConvertF14_F16(), ConvertF16_F14(), ConvertF16_F30(),
ConvertF30_F16(), ConvertF32_F16(), Convert32_F32(), Convert32_F16(),
ConvertS32_64(), ConvertSF16_F32(), ConvertU32_64(), ConvertUF16_F32()

file:///C|/%23%23DDOC/spr/03spr021.html [4/16/2002 11:14:50 PM]

ConvertF30_F16

ConvertF30_F16
Converts a 2.30 fraction to a 16.16 fraction.

Synopsis
frac16 ConvertF30_F16( frac30 x )

Description
This macro converts a 2.30 fraction to a 16.16 fraction. The upper 14-bits will be filled with the sign bit
of the argument.

Arguments
x
A 2.30 fraction to be converted.

Return Value
The function returns the 16.16 fraction result of the conversion.

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
ConvertF14_F16(), ConvertF16_F14(), ConvertF16_F30(), ConvertF16_32,
ConvertF32_F16(), Convert32_F32(), Convert32_F16(), ConvertS32_64(),
ConvertSF16_F32(), ConvertU32_64(), ConvertUF16_F32()

file:///C|/%23%23DDOC/spr/03spr024.html [4/16/2002 11:14:50 PM]

ConvertF32_F16

ConvertF32_F16
Converts a 32.32 fraction to a 16.16 fraction.

Synopsis
frac16 ConvertF32_F16( frac32 *x )

Description
This macro converts a 32.32 fraction to a 16.16 fraction. The result will be correct only if the integer part
of the argument can be expressed in 16-bits. Only the most-significant 16-bits of the fractional part of the
argument are preserved.

Arguments
x
A pointer to a 32.32 fraction to be converted.

Return Value
The function returns the 16.16 fraction result of the conversion.

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
ConvertF14_F16(), ConvertF16_F14(), ConvertF16_F30(),
ConvertF30_F16(), ConvertF16_32(), Convert32_F32(), Convert32_F16(),
ConvertS32_64(), ConvertSF16_F32(), ConvertU32_64(), ConvertUF16_F32()

file:///C|/%23%23DDOC/spr/03spr025.html [4/16/2002 11:14:51 PM]

Convert32_F32

Convert32_F32
Converts a 32-bit integer to a 32.32 fraction.

Synopsis
void Convert32_F32( frac32 *d, int32 x )

Description
This macro converts a 32-bit integer to a 32.32 fraction. The fractional portion of the result is zero. The
32.32 result of the conversion is deposited in the location pointed to by the dest argument.

Arguments
d
A pointer to a 32.32 structure to store the result.
x
A 32-bit integer to be converted.

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
ConvertF14_F16(), ConvertF16_F14(), ConvertF16_F30(),
ConvertF30_F16(), ConvertF32_F16(), ConvertF16_32(), ConvertF32_F16(),
ConvertS32_64(), ConvertSF16_F32(), ConvertU32_64(), ConvertUF16_F32()

file:///C|/%23%23DDOC/spr/03spr019.html [4/16/2002 11:14:51 PM]

ConvertS32_64

ConvertS32_64
Converts a 32-bit integer to a 64-bit integer.

Synopsis
void ConvertS32_64( int64 *d, int32 x )

Description
This macro converts a 32-bit integer to a 64-bit integer. The upper 32-bits of the result are the sign bit of
the argument. The 64-bit integer result is deposited in the location pointed to by the d argument.

Arguments
d
A pointer to a 64-bit integer structure to store the result.
x
A 32-bit integer to be converted.

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
ConvertF14_F16(), ConvertF16_F14(), ConvertF16_F30(),
ConvertF30_F16(), ConvertF16_32(), Convert32_F32(), ConvertF32_F16(),
Convert32_F16(), ConvertSF16_F32(), ConvertU32_64(), ConvertUF16_F32()

file:///C|/%23%23DDOC/spr/03spr026.html [4/16/2002 11:14:51 PM]

ConvertSF16_F32

ConvertSF16_F32
Converts a 16.16 fraction to a 32.32 fraction.

Synopsis
void ConvertSF16_F32( frac32 *d, frac16 x )

Description
This macro converts a 16.16 fraction to a 32.32 fraction. The upper 16-bits of the result are the sign bit of
the argument, the least 16-bits of the result are zero. The 32.32 fraction result is deposited in the location
pointed to by the d argument.

Arguments
d
A pointer to a 32.32 fraction structure to store the result.
x
A 16.16 fraction to be converted.

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
ConvertF14_F16(), ConvertF16_F14(), ConvertF16_F30(),
ConvertF30_F16(), ConvertF16_32(), Convert32_F32(), ConvertF32_F16(),
ConvertS32_64(), Convert32_F16(), ConvertU32_64(), ConvertUF16_F32()

file:///C|/%23%23DDOC/spr/03spr027.html [4/16/2002 11:14:52 PM]

ConvertU32_64

ConvertU32_64
Converts an unsigned 32-bit integer to an unsigned 64-bit integer.

Synopsis
void ConvertU32_64( uint64 *d, uint32 x )

Description
This macro converts an unsigned 32-bit integer to an unsigned 64-bit integer. The upper 32-bits of the
result are zero. The 64-bit unsigned integer result is deposited in the location pointed to by the d
argument.

Arguments
d
A pointer to a unsigned 64-bit integer structure to store the result.
x
The unsigned 32-bit integer to be converted.

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
ConvertF14_F16(), ConvertF16_F14(), ConvertF16_F30(),
ConvertF30_F16(), ConvertF16_32(), Convert32_F32(), ConvertF32_F16(),
Convert32_F16(), ConvertSF16_F32(), ConvertUF16_F32()

file:///C|/%23%23DDOC/spr/03spr028.html [4/16/2002 11:14:52 PM]

ConvertUF16_F32

ConvertUF16_F32
Converts an unsigned 16.16 fraction to an unsigned 32.32fraction.

Synopsis
void ConvertUF16_F32( frac32 *d, ufrac16 x )

Description
This macro converts an unsigned 16.16 fraction to a 32.32 fraction. The upper 16-bits of the result and
the least 16-bits of the result are zero. The 32.32 fraction result is deposited in the location pointed to by
the d argument.

Arguments
d
A pointer to a 32.32 fraction to store the result.
x
An unsigned 16.16 fraction to be converted.

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
ConvertF14_F16(), ConvertF16_F14(), ConvertF16_F30(),
ConvertF30_F16(), ConvertF16_32(), Convert32_F32(), ConvertF32_F16(),
ConvertS32_64(), Convert32_F16(), ConvertU32_64()

file:///C|/%23%23DDOC/spr/03spr029.html [4/16/2002 11:14:52 PM]

CosF16

CosF16
Computes the 16.16 operamath cosine of a 16.16 fraction angle.

Synopsis
frac16 CosF16( frac16 x )

Description
This function returns the 16.16 operamath cosine of a 16.16 fraction angle. In operamath coordinates,
there are 256.0 units in a circle.

Arguments
x
A 16.16 fraction describing the angle of the circle.

Return Value
The value returned is the cosine of the input angle.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
SinF16(), CosF32(), SinF32(), CosF30(), SinF30()

file:///C|/%23%23DDOC/spr/03spr030.html [4/16/2002 11:14:53 PM]

SinF16

SinF16
Computes the 16.16 sine of a 16.16 fraction angle.

Synopsis
frac16 SinF16( frac16 x )

Description
This function returns the 16.16 sine of a 16.16 fraction angle. In operamath coordinates, there are 256.0
units in a circle.

Arguments
x
A 16.16 fraction describing the angle of the circle.

Return Value
The value returned is the sine of the input angle.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
CosF16(), CosF32(), SinF32(), CosF30(), SinF30()

file:///C|/%23%23DDOC/spr/03spr087.html [4/16/2002 11:14:54 PM]

CosF32

CosF32
Computes the operamath 32.32 cosine of a 16.16 fraction.

Synopsis
frac32 CosF32( frac32 *c, frac16 x )

Description
This macro returns the operamath 32.32 cosine of a 16.16 fraction. In operamath coordinates, there are
256.0 units in a circle.
The macro actually calls the SinF32() function with one quarter circle added to the input value.

Arguments
c
A pointer to a 32.32 fraction containing the result.
x
A 16.16 fraction describing the angle of the circle.

Return Value
The macro returns the cosine of the input angle.

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
SinF16(), CosF16(), SinF32(), CosF30(), SinF30()
file:///C|/%23%23DDOC/spr/03spr032.html (1 of 2) [4/16/2002 11:14:54 PM]

CosF32

file:///C|/%23%23DDOC/spr/03spr032.html (2 of 2) [4/16/2002 11:14:54 PM]

SinF32

SinF32
Computes the operamath 32.32 sine of a 16.16 fraction.

Synopsis
void SinF32( frac32 *dest, frac16 x )

Description
This function returns the operamath 32.32 sine of a 16.16 fraction. In operamath coordinates, there are
256.0 units in a circle.

Arguments
dest
A pointer to a 32.32 fraction containing the result.
x
A 16.16 fraction describing the angle of the circle.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
SinF16(), CosF16(), CosF32(), CosF30(), SinF30()

file:///C|/%23%23DDOC/spr/03spr089.html [4/16/2002 11:14:54 PM]

CosF30

CosF30
Computes the operamath 2.30 cosine of a 16.16 fraction.

Synopsis
frac30 CosF30( frac16 x )

Description
This function returns the operamath 2.30 cosine of a 16.16 fraction. In operamath coordinates, there are
256.0 units in a circle.

Arguments
x
A 16.16 fraction describing the angle of the circle.

Return Value
The function returns the 2.30 cosine of the input angle.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
SinF16(), CosF16(), SinF32(), CosF32(), SinF30()

file:///C|/%23%23DDOC/spr/03spr031.html [4/16/2002 11:14:54 PM]

SinF30

SinF30
Computes the operamath 2.30 sine of a 16.16 fraction.

Synopsis
frac30 SinF30( frac16 x )

Description
This function returns the operamath 2.30 sine of a 16.16 fraction. In operamath coordinates, there are
256.0 units in a circle.

Arguments
x
A 16.16 fraction describing the angle of the circle.

Return Value
The function returns the 2.30 sine of the input angle.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
SinF16(), CosF16(), SinF32(), CosF32(), CosF30()

file:///C|/%23%23DDOC/spr/03spr088.html [4/16/2002 11:14:55 PM]

Cross3_F16

Cross3_F16
Computes the cross-product of two vectors of 16.16 values.

Synopsis
void Cross3_F16( vec3f16 *dest, vec3f16 v1, vec3f16 v2 )

Description
This function multiplies two 3-coordinate vectors of 16.16 values together and deposits the cross-product
in the location pointed to by dest.

Arguments
dest
A pointer to a destination vector to store the resulting cross product.
v1, v2
3-coordinate vector multiplicands.

Implementation
SWI implemented in operamath V20.

Associated Files
operamath.h

file:///C|/%23%23DDOC/spr/03spr033.html [4/16/2002 11:14:55 PM]

DivRemS32

DivRemS32
Computes the quotient and remainder of a 32-bit division.

Synopsis
int32 DivRemS32( int32 *rem, int32 d1, int32 d2 )

Description
This function divides one 32-bit integer by another and returns the quotient and remainder.
This function calls the standard C function for division. If you need only the quotient or only the
remainder, use the standard C notation for division instead.

Arguments
rem
A pointer to a 32-bit integer to store the remainder.
d1
The dividend.
d2
The divisor.

Return Value
The function returns the quotient of the division. The remainder is deposited in the location pointed to by
the rem argument.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib
file:///C|/%23%23DDOC/spr/03spr034.html (1 of 2) [4/16/2002 11:14:55 PM]

DivRemS32

Caveats
The function does not detect overflows.

See Also
DivRemU32(), DivS64(), DivU64(), DivSF16(), DivUF16(), DivRemUF16(),
DivRemSF16()

file:///C|/%23%23DDOC/spr/03spr034.html (2 of 2) [4/16/2002 11:14:55 PM]

DivRemU32

DivRemU32
Computes the quotient and remainder of a 32-bit division.

Synopsis
uint32 DivRemU32( uint32 *rem, uint32 d1, uint32 d2 )

Description
This function divides one unsigned 32-bit integer by another and returns the quotient and remainder.
This function calls the standard C function for division. If only the quotient or only the remainder is
desired, the standard C notation for divide should be used.

Arguments
rem
A pointer to a unsigned 32-bit integer to store the remainder.
d1
The dividend.
d2
The divisor.

Return Value
The function returns the quotient of the division. The remainder is deposited in the location pointed to by
the rem argument.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib
file:///C|/%23%23DDOC/spr/03spr036.html (1 of 2) [4/16/2002 11:14:56 PM]

DivRemU32

Caveats
The function does not detect overflows.

See Also
DivRemSF16(), DivRemS32(), DivU64(), DivSF16(), DivUF16(),
DivRemUF16(), DivS64()

file:///C|/%23%23DDOC/spr/03spr036.html (2 of 2) [4/16/2002 11:14:56 PM]

DivRemSF16

DivRemSF16
Computes the quotient and remainder of a 16.16 division.

Synopsis
frac16 DivRemSF16( frac16 *rem, frac16 d1, frac16 d2 )

Description
This function divides one signed 16.16 fraction by another and returns the quotient and remainder. This
function returns a correct result if the arguments are int32 or frac30, as long as both d1 and d2 are the
same type.
The remainder is not a 16.16 fraction; instead, it is a signed fraction in 0.32 format. The most-significant
bit of the remainder is a sign bit, and this must be extended if the remainder is to be used in subsequent
calculations. An overflow value is denoted by maximum positive return in both values.

Arguments
rem
A pointer to the remainder of the division, a signed fraction in 0.32 format.
d1
The dividend.
d2
The divisor.

Return Value
The function returns the quotient of the division. The remainder is deposited in the location pointed to by
the rem argument.

Implementation
Folio call implemented in operamath V20.

file:///C|/%23%23DDOC/spr/03spr035.html (1 of 2) [4/16/2002 11:14:56 PM]

DivRemSF16

Associated Files
operamath.h, operamath.lib

See Also
DivRemU32(), DivRemS32(), DivU64(), DivUF16(), DivSF16(),
DivRemUF16(), DivS64()

file:///C|/%23%23DDOC/spr/03spr035.html (2 of 2) [4/16/2002 11:14:56 PM]

DivS64

DivS64
Computes the quotient and remainder of a 64-bit division.

Synopsis
int64 *DivS64( int64 *q, int64 *r, int64 *d1, int64 *d2 )

Description
This function divides one 64-bit integer by another and returns the quotient and remainder.

Arguments
q
A pointer to a 64-bit integer to store the quotient.
r
A pointer to a 64-bit integer to store the remainder.
d1
A pointer to a dividend.
d2
A pointer to a divisor.

Return Value
The function returns a pointer to q.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

file:///C|/%23%23DDOC/spr/03spr038.html (1 of 2) [4/16/2002 11:14:56 PM]

DivS64

Caveats
The function does not detect overflows.

See Also
DivRemU32(), DivRemS32(), DivU64(), DivSF16(), DivUF16(),
DivRemUF16(), DivRemSF16()

file:///C|/%23%23DDOC/spr/03spr038.html (2 of 2) [4/16/2002 11:14:56 PM]

DivU64

DivU64
Computes the quotient and remainder of a 64-bit division.

Synopsis
int64 *DivU64( uint64 *q, uint64 *r, uint64 *d1, uint64 *d2 )

Description
This function divides one unsigned 64-bit integer by another and returns the quotient and remainder.

Arguments
q
A pointer to a 64-bit integer to store the quotient.
r
A pointer to a 64-bit integer to store the remainder.
d1
A pointer to the dividend.
d2
A pointer to the divisor.

Return Value
The function returns a pointer to q. The quotient is deposited in the location pointed to by q. The
remainder is deposited in the location pointed to by r.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib
file:///C|/%23%23DDOC/spr/03spr040.html (1 of 2) [4/16/2002 11:14:57 PM]

DivU64

Caveats
The function does not detect overflows.

See Also
DivRemSF16(), DivRemS32(), DivRemU32(), DivSF16(), DivUF16(),
DivRemUF16(), DivS64()

file:///C|/%23%23DDOC/spr/03spr040.html (2 of 2) [4/16/2002 11:14:57 PM]

DivSF16

DivSF16
Computes the quotient of a 16.16 division.

Synopsis
frac16 DivSF16( frac16 d1, frac16 d2 )

Description
This function divides one 16.16 fraction by another and returns the quotient.
This function also returns a correct result if the arguments are int32 or frac30, as long as both d1 and d2
are the same type.

Arguments
d1
The dividend.
d2
The divisor.

Return Value
The function returns the quotient of the division.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

Caveats
The function does not detect overflows.
file:///C|/%23%23DDOC/spr/03spr039.html (1 of 2) [4/16/2002 11:14:57 PM]

DivSF16

See Also
DivRemU32(), DivRemS32(), DivU64(), DivRemSF16(), DivUF16(),
DivRemUF16(), DivS64()

file:///C|/%23%23DDOC/spr/03spr039.html (2 of 2) [4/16/2002 11:14:57 PM]

DivUF16

DivUF16
Computes the quotient of a 16.16 division.

Synopsis
ufrac16 DivUF16( ufrac16 d1, ufrac16 d2 )

Description
This function divides one unsigned 16.16 fraction by another and returns the quotient. This function
returns a correct 16.16 result if the arguments are uint32 or ufrac30, as long as both arguments, d1 and
d2, are the same type.

Arguments
d1
The dividend.
d2
The divisor.

Return Value
The function returns the quotient of the division.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

Caveats
The function does not detect overflows.

file:///C|/%23%23DDOC/spr/03spr041.html (1 of 2) [4/16/2002 11:14:57 PM]

DivUF16

See Also
DivRemSF16(), DivRemS32(), DivRemU32(), DivSF16(), DivRemUF16(),
DivU64(), DivS64()

file:///C|/%23%23DDOC/spr/03spr041.html (2 of 2) [4/16/2002 11:14:57 PM]

DivRemUF16

DivRemUF16
Computes the quotient and remainder of a 16.16 division.

Synopsis
ufrac16 DivRemUF16( ufrac16 *rem, ufrac16 d1, ufrac16 d2 )

Description
This function divides one unsigned 16.16 fraction by another and returns the quotient and remainder.
This function returns a correct 16.16 result if the arguments are uint32 or ufrac30, as long as both
arguments, d1 and d2, are the same type.
The remainder is not a 16.16 fraction; instead, it is an unsigned fraction in 0.32 format. An overflow
condition is signaled by maximum return in both values.

Arguments
rem
A pointer to a unsigned fraction in 0.32 format to store the remainder.
d1
The dividend.
d2
The divisor.

Return Value
The function returns the quotient of the division. The remainder is deposited in the location pointed to by
the rem argument.

Implementation
Folio call implemented in operamath V20.

Associated Files
file:///C|/%23%23DDOC/spr/03spr037.html (1 of 2) [4/16/2002 11:14:58 PM]

DivRemUF16

operamath.h, operamath.lib

Caveats
The function does not detect overflows.

See Also
DivRemSF16(), DivRemS32(), DivRemU32(), DivSF16(), DivUF16(),
DivU64(), DivS64()

file:///C|/%23%23DDOC/spr/03spr037.html (2 of 2) [4/16/2002 11:14:58 PM]

Dot3_F16

Dot3_F16
Multiplies two vectors of 16.16 values.

Synopsis
frac16 Dot3_F16( vec3f16 v1, vec3f16 v2 )

Description
This function multiplies two 3-coordinate vectors of 16.16 values together and returns the dot product.

Arguments
v1, v2
3-coordinate vector multiplicands.

Return Value
The function returns the dot product of the two vectors.

Implementation
SWI implemented in operamath V20.

Associated Files
operamath.h

See Also
Dot4_F16()

file:///C|/%23%23DDOC/spr/03spr042.html [4/16/2002 11:14:58 PM]

Dot4_F16

Dot4_F16
Multiplies two vectors of 16.16 values.

Synopsis
frac16 Dot4_F16( vec4f16 v1, vec4f16 v2 )

Description
This function multiplies two 4-coordinate vectors of 16.16 values together and returns the dot product.

Arguments
v1, v2 4-coordinate vector multiplicands.

Return Value
The function returns the dot product of the two vectors.

Implementation
SWI implemented in operamath V20.

Associated Files
operamath.h

See Also
Dot3_F16()

file:///C|/%23%23DDOC/spr/03spr043.html [4/16/2002 11:14:58 PM]

Mul32

Mul32
Multiplies two 32-bit integers.

Synopsis
int32 Mul32( int32 x, int32 y )

Description
This macro multiplies two 32-bit integers together and returns the product. The macro is only included
for completeness.

Arguments
x, y The multiplicands.

Return Value
The function returns the product of the two arguments.

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
Mul64(), MulS32_64(), MulU32_64(), MulF14(), MulSF16(), MulSF30(),
MulUF16(), MulSF16_F32(), MulUF16_F32(), MulSF30_F60(), MulUF30_F60()

file:///C|/%23%23DDOC/spr/03spr044.html [4/16/2002 11:14:59 PM]

Mul64

Mul64
Multiplies two 64-bit integers.

Synopsis
void Mul64( int64 *p, int64 *m1, int64 *m2 )

Description
This function multiplies two 64-bit integers together and returns the product. An overflow condition is
not detected. The 64-bit integer result is deposited in the location pointed to by the p argument.

Arguments
p
A pointer to a the location to store the 64-bit integer result.
m1, m2
Pointers to the locations of the two 64-bit integer multiplicands.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

Caveats
The function does not detect overflows.

See Also
Mul32(), MulS32_64(), MulU32_64(), MulF14(), MulSF16(), MulSF30(),
MulUF16(), MulSF16_F32(), MulUF16_F32(), MulSF30_F60(), MulUF30_F60()

file:///C|/%23%23DDOC/spr/03spr045.html [4/16/2002 11:14:59 PM]

MulS32_64

MulS32_64
Multiplies two 32-bit integers and returns a 64-bit result.

Synopsis
void MulS32_64( int64 *prod, int32 m1, int32 m2 )

Description
This function multiplies two signed 32-bit integers together and deposits the 64-bit product in the
location pointed to by the prod argument.

Arguments
prod
A pointer to the location to store the 64-bit result.
m1, m2
Two 32-bit multiplicands.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
Mul32(), Mul64(), MulSF16(), MulU32_64(), MulF14(), MulSF30(),
MulUF16(), MulSF16_F32(), MulUF16_F32(), MulSF30_F60(), MulUF30_F60()

file:///C|/%23%23DDOC/spr/03spr057.html [4/16/2002 11:14:59 PM]

MulSF16

MulSF16
Multiplies two signed 16.16 fractions.

Synopsis
frac16 MulSF16( frac16 m1, frac16 m2 )

Description
This function multiplies two signed 16.16 fractions together and returns the 16.16 resulting product. The
lower bits of the result are truncated.

Arguments
m1, m2 The multiplicands.

Return Value
The function returns the product of the two arguments.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

Caveats
The function does not detect overflows.

See Also
Mul32(), Mul64(), MulS32_64(), MulU32_64(), MulF14(), MulSF30(),
MulUF16(), MulSF16_F32(), MulUF16_F32(), MulSF30_F60(), MulUF30_F60()

file:///C|/%23%23DDOC/spr/03spr059.html [4/16/2002 11:15:00 PM]

MulU32_64

MulU32_64
Multiplies two unsigned 32-bit integers and returns a 64-bit result.

Synopsis
void MulU32_64( uint64 *prod, uint32 m1, uint32 m2 )

Description
This function multiplies two unsigned 32-bit integers together and deposits the unsigned 64-bit result in
the location pointed to by the prod argument.

Arguments
prod
A pointer to the location to store the 64-bit result.
m1, m2
Two unsigned 32-bit multiplicands.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
Mul32(), Mul64(), MulSF16(), MulS32_64(), MulF14(), MulSF30(),
MulUF16(), MulSF16_F32(), MulUF16_F32(), MulSF30_F60(), MulUF30_F60()

file:///C|/%23%23DDOC/spr/03spr063.html [4/16/2002 11:15:00 PM]

MulF14

MulF14
Multiplies two 2.14 fractions.

Synopsis
frac14 MulF14( frac14 x, frac14 y )

Description
This macro multiplies two 2.14 fractions together and returns the product.

Arguments
x, y The multiplicands.

Return Value
The function returns the product of the two arguments.

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

Caveats
The function does not detect overflows.

See Also
Mul32(), Mul64(), MulS32_64(), MulU32_64(), MulSF16(), MulUF16(),
MulSF30(), MulSF16_F32(), MulUF16_F32(), MulSF30_F60(), MulUF30_F60()

file:///C|/%23%23DDOC/spr/03spr046.html [4/16/2002 11:15:00 PM]

MulUF16

MulUF16
Multiplies two unsigned 16.16 fractions.

Synopsis
ufrac16 MulUF16( ufrac16 m1, ufrac16 m2 )

Description
This function multiplies two unsigned 16.16 fractions together and returns the 16.16 resulting product.
The lower bits of the result are truncated.

Arguments
m1, m2 The multiplicands.

Return Value
The function returns the product of the two arguments.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

Caveats
The function does not detect overflows.

See Also
Mul32(), Mul64(), MulS32_64(), MulU32_64(), MulF14(), MulSF30(),
MulSF16(), MulSF16_F32(), MulUF16_F32(), MulSF30_F60(), MulUF30_F60()

file:///C|/%23%23DDOC/spr/03spr064.html [4/16/2002 11:15:01 PM]

MulSF30

MulSF30
Multiplies two 2.30 fractions.

Synopsis
frac30 MulSF30( frac30 m1, frac30 m2 )

Description
This function multiplies two 2.30 fractions together and returns the 2.30 resulting product. The lower bits
of the result are truncated.

Arguments
m1, m2 The multiplicands.

Return Value
The function returns the product of the two arguments.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

Caveats
The function does not detect overflows.

See Also
Mul32(), Mul64(), MulS32_64(), MulU32_64(), MulF14(), MulSF16(),
MulUF16(), MulSF16_F32(), MulUF16_F32(), MulSF30_F60(), MulUF30_F60()

file:///C|/%23%23DDOC/spr/03spr061.html [4/16/2002 11:15:01 PM]

MulSF16_F32

MulSF16_F32
Multiplies two signed 16.16 numbers and returns a 32.32 result.

Synopsis
void MulSF16_F32( frac32 *prod, frac16 m1, frac16 m2 )

Description
This function multiplies two signed 16.16 numbers together and deposits the 32.32 result in the location
pointed to by the prod argument.

Arguments
prod
A pointer to the location to store the 32-bit result.
m1, m2
Two 16.16 multiplicands.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
Mul32(), Mul64(), MulSF16(), MulU32_64(), MulF14(), MulSF30(),
MulUF16(), MulS32_64(), MulUF16_F32(), MulSF30_F60(), MulUF30_F60()

file:///C|/%23%23DDOC/spr/03spr060.html [4/16/2002 11:15:01 PM]

MulUF16_F32

MulUF16_F32
Multiplies two unsigned 16.16 numbers and returns a 32.32 result.

Synopsis
void MulUF16_F32( ufrac32 *prod, ufrac16 m1, ufrac16 m2 )

Description
This function multiplies two unsigned 16.16 numbers together and deposits the unsigned 32.32 result in
the location pointed to by the prod argument.

Arguments
prod
A pointer to the location to store the result.
m1, m2
Two unsigned 16.16 multiplicands.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
Mul32(), Mul64(), MulSF16(), MulU32_64(), MulF14(), MulSF30(),
MulUF16(), MulS32_64(), MulSF16_F32(), MulSF30_F60(), MulUF30_F60()

file:///C|/%23%23DDOC/spr/03spr065.html [4/16/2002 11:15:02 PM]

MulSF30_F60

MulSF30_F60
Multiplies two signed 2.30 numbers and returns a 4.60 result.

Synopsis
void MulSF30_F60( frac60 *prod, frac30 m1, frac30 m2 )

Description
This function multiplies two signed 2.30 numbers together and deposits the 4.60 result in the location
pointed to by the prod argument.

Arguments
prod
A pointer to the location to store the 4.60
result.
m1, m2
Two 2.30 multiplicands.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
Mul32(), Mul64(), MulSF16(), MulU32_64(), MulF14(), MulSF30(),
MulUF16(), MulS32_64(), MulUF16_F32(), MulSF16_F32(), MulUF30_F60()

file:///C|/%23%23DDOC/spr/03spr062.html [4/16/2002 11:15:02 PM]

MulUF30_F60

MulUF30_F60
Multiplies two unsigned 2.30 numbers and returns a 4.60 result.

Synopsis
void MulUF30_F60( ufrac60 *prod, ufrac30 m1, ufrac30 m2 )

Description
This function multiplies two unsigned 2.30 numbers together and deposits the unsigned 4.60 result in the
location pointed to by the prod argument.

Arguments
prod
A pointer to the location to store the unsigned 4.60 result.
m1, m2
Two unsigned 2.30 multiplicands.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
Mul32(), Mul64(), MulSF16(), MulU32_64(), MulF14(), MulSF30(),
MulUF16(), MulS32_64(), MulUF16_F32(), MulSF16_F32(), MulSF30_F60()

file:///C|/%23%23DDOC/spr/03spr066.html [4/16/2002 11:15:02 PM]

MulManyF16

MulManyF16
Multiplies an array of 16.16 values by another array of 16.16 values.

Synopsis
void MulManyF16( frac16 *dest, frac16 *src1, frac16 *src2,int32 count
)

Description
This function multiplies an array of 16.16 fractions by another array of 16.16 fractions. Every element of
the first array is multiplied by the corresponding element in the other array, and the results are deposited
in the destination array.

Arguments
dest
A pointer to the destination array to store the results.
src1
Pointer to source array of 16.16 fractions to be multiplied.
src2
Pointer to source array of 16.16 fractions to be multiplied.
count
Number of vectors for the multiplication.

Implementation
SWI implemented in operamath V20.

Associated Files
operamath.h

See Also
file:///C|/%23%23DDOC/spr/03spr047.html (1 of 2) [4/16/2002 11:15:03 PM]

MulManyF16

MulScalarF16()

file:///C|/%23%23DDOC/spr/03spr047.html (2 of 2) [4/16/2002 11:15:03 PM]

file:///C|/%23%23DDOC/spr/03spr058.html

MulScalarF16
Multiplies a 16.16 scalar by an array of 16.16 values.

Synopsis
void MulScalarF16( frac16 *dest, frac16 *src, frac16 scalar,int32
count )

Description
This function multiplies a 16.16 scalar by an array of 16.16 fractions. Every element of the array of
frac16 values is multiplied by the same value, and the results are deposited in the destination array.

Arguments
dest
A pointer to the destination array to store the results.
src
A pointer to the source array of 16.16 fractions to be multiplied.
scalar
A 16.16 scalar.
count
The number of elements in the vector.

Implementation
SWI implemented in operamath V20.

Associated Files
operamath.h

See Also

file:///C|/%23%23DDOC/spr/03spr058.html (1 of 2) [4/16/2002 11:15:03 PM]

file:///C|/%23%23DDOC/spr/03spr058.html

MulManyF16()

file:///C|/%23%23DDOC/spr/03spr058.html (2 of 2) [4/16/2002 11:15:03 PM]

MulManyVecMat33_F16

MulManyVec3Mat33_F16
Multiplies one or more vectors by a 3x3 matrix of 16.16 values.

Synopsis
void MulManyVec3Mat33_F16( vec3f16 *dest, vec3f16 *src,mat33f16 mat,
int32 count )

Description
This function multiplies an array of one or more vectors by a 3x3 matrix of 16.16 fractions. The results
of the products are deposited in the array of vectors pointed to by the dest argument.

Arguments
dest
A pointer to the array of destination vectors to store the results.
src
A pointer to the array of source vectors to be multiplied with the matrix.
mat
A 3x3 matrix of 16.16 fractions.
count
The number of vectors for the multiplication.

Implementation
SWI implemented in operamath V20.

Associated Files
operamath.h

See Also

file:///C|/%23%23DDOC/spr/03spr048.html (1 of 2) [4/16/2002 11:15:04 PM]

MulManyVecMat33_F16

MulManyVec4Mat44_F16()

file:///C|/%23%23DDOC/spr/03spr048.html (2 of 2) [4/16/2002 11:15:04 PM]

MulManyVec4Mat44_F16

MulManyVec4Mat44_F16
Multiplies one or more vectors by a 4x4 matrix of 16.16 values.

Synopsis
void MulManyVec4Mat44_F16( vec4f16 *dest, vec4f16 *src,mat44f16 mat,
int32 count )

Description
This function multiplies an array of one or more vectors by a 3x3 matrix of 16.16 fractions. The results
of the products are deposited in the array of vectors pointed to by the dest argument.

Arguments
dest
A pointer to the array of destination vectors to store the results.
src
A pointer to the array of source vectors to be multiplied with the matrix.
mat
A 4x4 matrix of 16.16 fractions.
count
The number of vectors for the multiplication.

Implementation
SWI implemented in operamath V20.

Associated Files
operamath.h

See Also

file:///C|/%23%23DDOC/spr/03spr050.html (1 of 2) [4/16/2002 11:15:04 PM]

MulManyVec4Mat44_F16

MulManyVec3Mat33_F16()

file:///C|/%23%23DDOC/spr/03spr050.html (2 of 2) [4/16/2002 11:15:04 PM]

MulManyVec3Mat33DivZ_F16

MulManyVec3Mat33DivZ_F16
Multiplies a 3x3 matrix of 16.16 values by 1 or more 3-coordinate vectors of 16.16 values, then
multiplies x and y elements of the result vector by ratio of n/z.

Synopsis
void MulManyVec3Mat33DivZ_F16( mmv3m33d *s )

Description
This function multiplies a 3x3 matrix of 16.16 fractions by one or more 3-coordinate vectors of 16.16
values. It then multiplies the x and y elements of the result vector {x, y, z} by the ratio of n/z, and
deposits the result vector {x*n/z, y*n/z, z} in the product vector dest. This function can be used to
perform the final projection transformation on points just before rendering.
This function uses the structure mmv3m33d. Here is its definition:
// structure to pass arguments to MulManyVec3Mat33DivZ_F16 function typedef struct
mmv3m3dd{vec3f16*dest; vec3f16*src;mat33f16*mat; frac16n; uint32count;} mmv3m33d;

Arguments
s->dest
A pointer to the destination vector to store
results.
s->vec
A pointer to the vector to multiply.
s->mat
A pointer to the 3 X 3 matrix of 16.16
fractions to multiply.
s->n
Scale factor to be multiplied by x and y
projected results.
s->count

file:///C|/%23%23DDOC/spr/03spr049.html (1 of 2) [4/16/2002 11:15:04 PM]

MulManyVec3Mat33DivZ_F16

Number of vectors for the multiplication.

Implementation
SWI implemented in operamath V20.

Associated Files
operamath.h

See Also
MulManyVec3Mat33_F16()

file:///C|/%23%23DDOC/spr/03spr049.html (2 of 2) [4/16/2002 11:15:04 PM]

MulMat33Mat33_F16

MulMat33Mat33_F16
Computes the product of two 3x3 matrices of 16.16values.

Synopsis
void MulMat33Mat33_F16( mat33f16 dest, mat33f16 src1,mat33f16 src2 )

Description
This function multiplies two 3x3 matrices of 16.16 fractions together. The results of the product are
deposited in the location for the matrix dest. Note that incorrect results may occur if the destination
matrix is the same matrix as one of the source matrices.

Arguments
dest
A pointer to the destination matrix to store the results.
src1, src2
The source matrices to be multiplied.

Implementation
SWI implemented in operamath V20.

Associated Files
operamath.h

See Also
MulVec3Mat33_F16(), MulVec4Mat44_F16(), MulMat44Mat44_F16()

file:///C|/%23%23DDOC/spr/03spr051.html [4/16/2002 11:15:05 PM]

MulVec3Mat33_F16

MulVec3Mat33_F16
Computes the product of a 3x3 matrix and a vector.

Synopsis
void MulVec3Mat33_F16( vec3f16 dest, vec3f16 vec, mat33f16mat )

Description
This function multiplies a 3x3 matrix of 16.16 fractions by a 3-coordinate vector of 16.16 values and
deposits the results of the product in the vector dest.

Arguments
dest
The destination vector to store the results.
vec
The vector to multiply.
mat
The matrix to multiply.

Implementation
SWI implemented in operamath V20.

Associated Files
operamath.h

See Also
MulVec4Mat44_F16(), MulMat33Mat33_F16(), MulMat44Mat44_F16()

file:///C|/%23%23DDOC/spr/03spr067.html [4/16/2002 11:15:05 PM]

MulVec4Mat44_F16

MulVec4Mat44_F16
Computes the product of a 4x4 matrix and a vector.

Synopsis
void MulVec4Mat44_F16( vec4f16 dest, vec4f16 vec, mat44f16mat )

Description
This function multiplies a 4x4 matrix of 16.16 fractions by a 4-coordinate vector of 16.16 values and
deposits the results of the product in the vector dest.

Arguments
dest
The destination vector to store the results.
vec
The vector to multiply.
mat
The matrix to multiply.

Implementation
SWI implemented in operamath V20.

Associated Files
operamath.h

See Also
MulVec3Mat33_F16(), MulMat33Mat33_F16(), MulMat44Mat44_F16()

file:///C|/%23%23DDOC/spr/03spr069.html [4/16/2002 11:15:05 PM]

MulMat44Mat44_F16

MulMat44Mat44_F16
Computes the product of two 4x4 matrices of 16.16 values.

Synopsis
void MulMat44Mat44_F16( mat44f16 dest, mat44f16 src1,mat44f16 src2 )

Description
This function multiplies two 4x4 matrices of 16.16 fractions together. The results of the product are
deposited in the matrix dest. Note that incorrect results may occur if the destination matrix is the same
matrix as one of the source matrices.

Arguments
dest
The destination matrix to store the results.
src1, src2
The source matrices to be multiplied together.

Implementation
SWI implemented in operamath V20.

Associated Files
operamath.h

See Also
MulVec3Mat33_F16(), MulVec4Mat44_F16(), MulMat33Mat33_F16()

file:///C|/%23%23DDOC/spr/03spr052.html [4/16/2002 11:15:06 PM]

MulObjectMat33_F16

MulObjectMat33_F16
Multiplies a matrix within an object structure by an external 3x3 matrix of 16.16 values.

Synopsis
void MulObjectMat33_F16( void *objectlist[],ObjOffset2 *offsetstruct,
mat33f16 mat, int32 count )

Description
This function multiplies a matrix within object structures by an external 3x3 matrix of 16.16 fractions,
and repeats over a number of objects. The results of the product are deposited in the destination matrix in
each object structure pointed to by the objectlist array.
The object structure argument defines offsets within objects to the elements to be manipulated. The
definition for ObjOffset2 is as follows:
typedef struct ObjOffset2 {int32 oo2_DestMatOffset; int32 oo2_SrcMatOffset;} ObjOffset2;
●

●

oo2_DestMatOffset is the offset (in bytes) from the beginning of an object structure to where to
write the result of the matrix to multiply.
oo2_SrcMatOffset is the offset (in bytes) from the beginning of an object structure to the location
of the matrix to be multiplied.

Arguments
objectlist
An array of pointers to object structures to modify.
offsetstruct
A pointer to the source object structure that defines offsets within object's to the elements to be
multiplied.
mat
A 3x3 matrix of 16.16 fractions to be multiplied.
count
The number of vectors for the multiplication.

file:///C|/%23%23DDOC/spr/03spr053.html (1 of 2) [4/16/2002 11:15:06 PM]

MulObjectMat33_F16

Implementation
SWI implemented in operamath V20.

Associated Files
operamath.h

See Also
MulObjectMat44_F16()

file:///C|/%23%23DDOC/spr/03spr053.html (2 of 2) [4/16/2002 11:15:06 PM]

MulObjectMat44_F16

MulObjectMat44_F16
Multiplies a matrix within an object structure by an external 4x4 matrix of 16.16 values.

Synopsis
void MulObjectMat44_F16( void *objectlist[],ObjOffset2 *offsetstruct,
mat44f16 mat, int32 count )

Description
This function multiplies a matrix within object structures by an external 4x4 matrix of 16.16 fractions,
and repeats over a number of objects. The results of the product are deposited in the destination matrix in
each object structure pointed to by the objectlist array.
The object structure argument defines offsets within objects to the elements to be manipulated. The
definition for ObjOffset2 is as follows:
typedef struct ObjOffset2 {int32 oo2_DestMatOffset; int32
oo2_SrcMatOffset;} ObjOffset2;
●

●

oo2_DestMatOffset is the offset (in bytes) from the beginning of an object structure to where to
write the result of the matrix multiply.
oo2_SrcMatOffset is the offset (in bytes) from the beginning of an object structure to the location
of the matrix to be multiplied.

Arguments
objectlist
An array of pointers to object structures to modify.
offsetstruct
A pointer to the source object structure that defines offsets within object's to the elements to be
multiplied.
mat
A 4x4 matrix of 16.16 fractions to be multiplied.
count

file:///C|/%23%23DDOC/spr/03spr054.html (1 of 2) [4/16/2002 11:15:06 PM]

MulObjectMat44_F16

The number of vectors for the multiplication.

Implementation
SWI implemented in operamath V20.

Associated Files
operamath.h

See Also
MulObjectMat33_F16()

file:///C|/%23%23DDOC/spr/03spr054.html (2 of 2) [4/16/2002 11:15:06 PM]

MulObjectVec3Mat33_F16

MulObjectVec3Mat33_F16
Multiplies many vectors within an object structure by a 3x3 matrix of 16.16 values.

Synopsis
void MulObjectVec3Mat33_F16( void *objectlist[],ObjOffset1
*offsetstruct, int32 count )

Description
This function multiplies one or more vectors within object structures by a 3x3 matrix of 16.16 fractions
also within that structure, and repeats over a number of objects. The results of the product are deposited
in the destination arrays pointed to by object structures pointed to by the objectlist array.
The object structure argument defines offsets within objects to the elements to be manipulated. The
object structure has a pointer to an array of points associated with the object, a pointer to an array of
transformed points, a count of the number of points, and an orientation matrix. The definition for
ObjOffset1 is as follows:
typedef struct ObjOffset1 {int32 oo1_DestArrayPtrOffset; int32 oo1_SrcArrayPtrOffset; int32
oo1_MatOffset; int32 oo1_CountOffset;} ObjOffset1;
●

●

●

●

oo1_DestArrayPtrOffset is the offset (in bytes) from the beginning of an object structure to the
location of the pointer to an array of vectors to fill with the results of the multiplies.
oo1_SrcArrayPtrOffset is the offset (in bytes) from the beginning of an object structure to the
location of the pointer to an array of vectors to be multiplied.
oo1_MatOffset is the offset (in bytes) from the beginning of an object structure to the location of
the matrix to be multiplied.
oo1_CountOffset is the offset (in bytes) from the beginning of an object structure to the location
of the count of the number of vectors to be multiplied.

Arguments
objectlist
An array of pointers to object structures to modify.
offsetstruct
A pointer to the source object structure that defines offsets within object's to the elements to be
multiplied.
file:///C|/%23%23DDOC/spr/03spr055.html (1 of 2) [4/16/2002 11:15:07 PM]

MulObjectVec3Mat33_F16

count
The number of vectors for the multiplication.

Implementation
SWI implemented in operamath V20.

Associated Files
operamath.h

See Also
MulObjectVec4Mat44_F16()

file:///C|/%23%23DDOC/spr/03spr055.html (2 of 2) [4/16/2002 11:15:07 PM]

MulObjectVec4Mat44_F16

MulObjectVec4Mat44_F16
Multiplies many vectors within an object structure by a 4x4 matrix of 16.16 values.

Synopsis
void MulObjectVec4Mat44_F16( void *objectlist[],ObjOffset1
*offsetstruct, int32 count )

Description
This function multiplies one or more vectors within object structures by a 3x3 matrix of 16.16 fractions
also within that structure, and repeats over a number of objects. The results of the product are deposited
in the destination arrays pointed to by object structures pointed to by the objectlist array.
The object structure argument defines offsets within objects to the elements to be manipulated. The
object structure has a pointer to an array of points associated with the object, a pointer to an array of
transformed points, a count of the number of points, and an orientation matrix. The definition for
ObjOffset1 is as follows:
typedef struct ObjOffset1 {int32 oo1_DestArrayPtrOffset; int32
oo1_SrcArrayPtrOffset; int32 oo1_MatOffset; int32 oo1_CountOffset;}
ObjOffset1;
●

●

●

●

oo1_DestArrayPtrOffset is the offset (in bytes) from the beginning of an object structure to the
location of the pointer to an array of vectors to fill with the results of the multiplies.
oo1_SrcArrayPtrOffset is the offset (in bytes) from the beginning of an object structure to the
location of the pointer to an array of vectors to be multiplied.
oo1_MatOffset is the offset (in bytes) from the beginning of an object structure to the location of
the matrix to be multiplied.
oo1_CountOffset is the offset (in bytes) from the beginning of an object structure to the location
of the count of the number of vectors to be multiplied.

Arguments
objectlist
An array of pointers to object structures to modify.
offsetstruct
A pointer to the source object structure that defines offsets within object's to the elements to be
file:///C|/%23%23DDOC/spr/03spr056.html (1 of 2) [4/16/2002 11:15:07 PM]

MulObjectVec4Mat44_F16

multiplied.
count
The number of vectors for the multiplication.

Implementation
SWI implemented in operamath V20.

Associated Files
operamath.h

See Also
MulObjectVec3Mat33_F16()

file:///C|/%23%23DDOC/spr/03spr056.html (2 of 2) [4/16/2002 11:15:07 PM]

MulVec3Mat33DivZ_F16

MulVec3Mat33DivZ_F16
Computes the product of a 3x3 matrix and a vector, then multiplies the x, y elements of the result by the
ratio n/z.

Synopsis
void MulVec3Mat33DivZ_F16( vec3f16 dest, vec3f16 vec,mat33f16 mat,
frac16 n )

Description
This function multiplies a 3x3 matrix of 16.16 fractions by a 3-coordinate vector of 16.16 values, then
multiplies the x and y elements of the result vector {x, y, z} by the ratio n/z, and deposits the result
vector {x*n/z, y*n/z, z} in the product vector dest. This function can be used to perform the final
projection transformation on points just before rendering.

Arguments
dest
The destination vector to store the results.
vec
The vector to multiply.
mat
The matrix to multiply.
n
The scale factor to be multiplied by x and y projected results.

Implementation
SWI implemented in operamath V20.

Associated Files
operamath.h

file:///C|/%23%23DDOC/spr/03spr068.html (1 of 2) [4/16/2002 11:15:07 PM]

MulVec3Mat33DivZ_F16

See Also
MulVec3Mat33_F16(), MulManyVec3Mat33DivZ_F16()

file:///C|/%23%23DDOC/spr/03spr068.html (2 of 2) [4/16/2002 11:15:07 PM]

Neg32

Neg32
Computes the two's complement of a 32-bit integer.

Synopsis
int32 Neg32( int32 x )

Description
This macro returns the two's complement of a 32-bit integer.

Arguments
x
A 32-bit integer for which to get the two's complement.

Return Value
The function returns the two's complement of x.

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
NegF16(), NegF30(), NegF14(), Neg64(), NegF32()

file:///C|/%23%23DDOC/spr/03spr070.html [4/16/2002 11:15:08 PM]

NegF16

NegF16
Computes the two's complement of a 16.16 fraction.

Synopsis
frac16 NegF16( frac16 x )

Description
This macro returns the two's complement of a 16.16 fraction.

Arguments
x
A 16.16 fraction for which the two's complement is desired.

Return Value
The function returns the two's complement of x.

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
NegF14(), NegF30(), Neg32(), Neg64(), NegF32()

file:///C|/%23%23DDOC/spr/03spr073.html [4/16/2002 11:15:08 PM]

NegF14

NegF14
Computes the two's complement of a 2.14 fraction.

Synopsis
frac14 NegF14( frac14 x )

Description
This macro returns the two's complement of a 2.14 fraction.

Arguments
x
A 2.14 fraction for which the two's complement is desired.

Return Value
The function returns the two's complement of x.

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
NegF16(), NegF30(), Neg32(), Neg64(), NegF32()

file:///C|/%23%23DDOC/spr/03spr072.html [4/16/2002 11:15:08 PM]

NegF30

NegF30
Computes the two's complement of a 2.30 fraction.

Synopsis
frac30 NegF30( frac30 x )

Description
This function returns the two's complement of a 2.30 fraction.

Arguments
x
A 2.30 fraction for which the two's complement is desired.

Return Value
The function returns the two's complement of x.

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h, operamath.lib

See Also
NegF16(), NegF14(), Neg32(), Neg64(), NegF32()

file:///C|/%23%23DDOC/spr/03spr074.html [4/16/2002 11:15:08 PM]

Neg64

Neg64
Computes the two's complement of a 64-bit integer.

Synopsis
void Neg64( int64 *dest, int64 *src )

Description
This function computes the two's complement of a 64-bit integer. The two's complement of the location
pointed to by src is deposited in the location pointed to by dest.

Arguments
dest
A pointer to the location to store the 64-bit integer result.
src
A pointer to the location of the 64-bit integer to be acted upon.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
NegF16(), NegF14(), Neg32(), NegF30(), NegF32()

file:///C|/%23%23DDOC/spr/03spr071.html [4/16/2002 11:15:09 PM]

NegF32

NegF32
Computes the two's complement of a 32.32 fraction.

Synopsis
void NegF32( frac32 *dest, frac32 *src )

Description
This function returns the two's complement of a 32.32 fraction.

Arguments
dest
A pointer to the location to store the frac32 result.
src
A pointer to the location of the 32.32 fraction to be acted upon.

Return Value
The function returns the two's complement of x.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
NegF16(), NegF14(), Neg32(), Neg64(), NegF30()

file:///C|/%23%23DDOC/spr/03spr075.html [4/16/2002 11:15:09 PM]

NegF60

NegF60
Computes the two's complement of a 4.60 fraction.

Synopsis
void NegF60( frac60 *dest, frac60 *src )

Description
This function returns the two's complement of a 4.60 fraction.

Arguments
dest
A pointer to the location to store the 4.60 fraction result.
src
A pointer to the location of the 4.60 fraction to be acted upon.

Return Value
The function returns the two's complement of x.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
NegF16(), NegF14(), Neg32(), Neg64(), NegF30(), NegF32()

file:///C|/%23%23DDOC/spr/03spr076.html [4/16/2002 11:15:09 PM]

Not32

Not32
Computes one's complement of a 32-bit integer.

Synopsis
int32 Not32( int32 x )

Description
This macro returns the one's complement of a 32-bit integer.

Arguments
x
A 32-bit integer for which the one's complement is desired.

Return Value
The function returns the one's complement of x.

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
NotF16(), NotF30(), NotF14(), Not64(), NotF32()

file:///C|/%23%23DDOC/spr/03spr077.html [4/16/2002 11:15:10 PM]

NotF16

NotF16
Computes one's complement of a 16.16 fraction.

Synopsis
frac16 NotF16( frac16 x )

Description
This macro returns the one's complement of a 16.16 fraction.

Arguments
x
A 16.16 fraction for which the one's complement is desired.

Return Value
The function returns the one's complement of x.

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
NotF14(), NotF30(), Not32(), Not64(), NotF32()

file:///C|/%23%23DDOC/spr/03spr080.html [4/16/2002 11:15:10 PM]

NotF14

NotF14
Computes one's complement of a 2.14 fraction.

Synopsis
frac14 NotF14( frac14 x )

Description
This macro returns the one's complement of a 2.14 fraction.

Arguments
x
A 2.14 fraction for which the one's complement is desired.

Return Value
The function returns the one's complement of x.

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
NotF16(), NotF30(), Not32(), Not64(), NotF32()

file:///C|/%23%23DDOC/spr/03spr079.html [4/16/2002 11:15:10 PM]

NotF30

NotF30
Computes one's complement of a 2.30 fraction.

Synopsis
frac30 NotF30( frac30 x )

Description
This macro returns the one's complement of a 2.30 fraction.

Arguments
x
A 2.30 fraction for which the one's complement is desired.

Return Value
The function returns the one's complement of x.

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
NotF16(), NotF14(), Not32(), Not64(), NotF32()

file:///C|/%23%23DDOC/spr/03spr081.html [4/16/2002 11:15:11 PM]

Not64

Not64
Computes one's complement of a 64-bit integer.

Synopsis
void Not64( int64 *dest, int64 *src )

Description
This function computes the one's complement of a 64-bit integer in the location pointed to by src. The
result is deposited in the location pointed to by dest.

Arguments
dest
A pointer to the location to store the 64-bit integer result.
src
A pointer to the location of the 64-bit integer to be acted upon.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
NotF16(), NotF14(), Not32(), NotF30(), NotF32()

file:///C|/%23%23DDOC/spr/03spr078.html [4/16/2002 11:15:11 PM]

NotF32

NotF32
Computes one's complement of a 32.32 number.

Synopsis
void NotF32( frac32 *dest, frac32 *src )

Description
This function computes the one's complement of a 32.32 number in the location pointed to by src. The
result is deposited in the location pointed to by dest.

Arguments
dest
A pointer to the location to store the 32.32 number result.
src
A pointer to the location of the 32.32 number to be acted upon.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
NotF16(), NotF14(), Not32(), NotF30(), NotF60(), Not64()

file:///C|/%23%23DDOC/spr/03spr082.html [4/16/2002 11:15:11 PM]

NotF60

NotF60
Computes one's complement of a 4.60 number.

Synopsis
void NotF60( frac60 *dest, frac60 *src )

Description
This function computes the one's complement of a 4.60 number in the location pointed to by src. The
result is deposited in the location pointed to by dest.

Arguments
dest
A pointer to the location to store the 4.60 number result.
src
A pointer to the location of the 4.60 number to be acted upon.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
NotF16(), NotF14(), Not32(), NotF30(), Not64(), NotF32()

file:///C|/%23%23DDOC/spr/03spr083.html [4/16/2002 11:15:11 PM]

RecipSF16

RecipSF16
Computes the reciprocal of a signed 16.16 number.

Synopsis
frac16 RecipSF16( frac16 d )

Description
This function computes the reciprocal of a signed 16.16 number and returns the 16.16 result. An
overflow is signaled by all bits set in the return value.

Arguments
d
16.16 format fractions.

Return Value
The function returns the reciprocal number.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
RecipUF16()

file:///C|/%23%23DDOC/spr/03spr085.html [4/16/2002 11:15:12 PM]

RecipUF16

RecipUF16
Computes the reciprocal of an unsigned 16.16 number.

Synopsis
ufrac16 RecipUF16( ufrac16 d )

Description
This function computes the reciprocal of an unsigned 16.16 number and returns the 16.16 result. An
overflow is signaled by all bits set in the return value.

Arguments
d
16.16 format fractions.

Return Value
The function returns the reciprocal number.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
RecipSF16()

file:///C|/%23%23DDOC/spr/03spr086.html [4/16/2002 11:15:12 PM]

Sqrt32

Sqrt32
Computes square root of an unsigned 32-bit number.

Synopsis
uint32 Sqrt32( uint32 x )

Description
This function computes the positive square root of an unsigned 32-bit number.

Arguments
x
The number for which the square root is desired.

Return Value
The function returns the square root of x.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
SqrtF16(), Sqrt64_32(), SqrtF32_F16()

file:///C|/%23%23DDOC/spr/03spr090.html [4/16/2002 11:15:12 PM]

SqrtF16

SqrtF16
Computes the square root of an unsigned 16.16 number.

Synopsis
ufrac16 SqrtF16( ufrac16 x )

Description
This function computes the positive square root of an unsigned 16.16 number.

Arguments
x
The number for which the square root is desired.

Return Value
The function returns the square root of x.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
Sqrt32(), Sqrt64_32(), SqrtF32_F16()

file:///C|/%23%23DDOC/spr/03spr092.html [4/16/2002 11:15:13 PM]

Sqrt64_32

Sqrt64_32
Computes the 32-bit square root of an unsigned 64-bit integer.

Synopsis
uint32 Sqrt64_32( uint64 *x )

Description
This function computes the 32-bit square root of an unsigned 64-bit integer.

Arguments
x
A pointer to the 64-bit number for which the square root is desired.

Return Value
The function returns the 32-bit square root of x.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
Sqrt32(), SqrtF32_F16(), SqrtF60_F30()

file:///C|/%23%23DDOC/spr/03spr091.html [4/16/2002 11:15:13 PM]

SqrtF32_F16

SqrtF32_F16
Computes the square root of a 32.32 fraction.

Synopsis
ufrac16 SqrtF32_F16( ufrac32 *x )

Description
This function computes the 16.16 fraction square root of a 32.32 fraction.

Arguments
x
A pointer to the 32.32 fraction for which the square root is desired.

Return Value
The function returns the 16.16 fraction square root of x.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
Sqrt32(), Sqrt64_32(), SqrtF60_F30()

file:///C|/%23%23DDOC/spr/03spr093.html [4/16/2002 11:15:13 PM]

SqrtF60_F30

SqrtF60_F30
Computes the square root of a 4.60 fraction as a 2.30 fraction.

Synopsis
frac30 SqrtF60_F30( frac60 *x )

Description
This function computes the 2.30 fraction square root of a 4.60 fraction.

Arguments
x
A pointer to the 4.60 fraction for which the square root is desired.

Return Value
The function returns the 2.30 fraction square root of x.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
Sqrt32(), Sqrt64_32(), SqrtF32_F16()

file:///C|/%23%23DDOC/spr/03spr094.html [4/16/2002 11:15:13 PM]

Square64

Square64
Squares a 64-bit integer.

Synopsis
void Square64( uint64 *p, int64 *m )

Description
This function computes the square of a 64-bit integer in the location pointed to by m. The result is
deposited in the location pointed to by p.

Arguments
p
A pointer to the result of the square operation.
m
A pointer to the location of the 64-bit integer to be squared.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

Caveats
The function does not detect overflows.

See Also
SquareSF16(), SquareUF16()

file:///C|/%23%23DDOC/spr/03spr095.html [4/16/2002 11:15:14 PM]

SquareSF16

SquareSF16
Squares a signed 16.16 fraction.

Synopsis
ufrac16 SquareSF16( frac16 m )

Description
This function computes the square of a 16.16 number. The lower bits of the result are truncated.

Arguments
m
The number to be squared.

Return Value
The function returns the square of m.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

Caveats
The function does not detect overflows.

See Also
SquareUF16(), Square64()

file:///C|/%23%23DDOC/spr/03spr096.html [4/16/2002 11:15:14 PM]

SquareUF16

SquareUF16
Squares an unsigned 16.16 fraction.

Synopsis
ufrac16 SquareUF16( ufrac16 m )

Description
This function computes the square of an unsigned 16.16 number. The lower bits of the result are
truncated.

Arguments
m
The number to be squared.

Return Value
The function returns the square of m.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

Caveats
The function does not detect overflows.

See Also
SquareSF16(), Square64()

file:///C|/%23%23DDOC/spr/03spr097.html [4/16/2002 11:15:14 PM]

Sub32

Sub32
Subtracts a 32-bit integer from another.

Synopsis
int32 Sub32( int32 x, int32 y )

Description
This macro returns the difference between two 32-bit integers.

Arguments
x, y Two 32-bit integers for the subtraction. y is subtracted from x.

Return Value
The macro returns the value (x - y).

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
SubF32(), SubF60(), SubF16(), SubF30(), SubF14(), Sub64()

file:///C|/%23%23DDOC/spr/03spr098.html [4/16/2002 11:15:14 PM]

SubF32

SubF32
Subtracts a 32.32 fraction from another.

Synopsis
void SubF32( frac32 *r, frac32 *s1, frac32 *s2 )

Description
This function subtracts two 32.32 fractions and deposits the result in the location pointed to by r.

Arguments
r
A pointer to the 32.32 fraction result of the subtraction.
s1, s2
Pointers to the two 32.32 fractions for the subtraction. s2 is subtracted from s1.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
Sub64(), SubF60(), SubF16(), SubF30(), SubF14(), Sub32()

file:///C|/%23%23DDOC/spr/03spr103.html [4/16/2002 11:15:15 PM]

Sub64

Sub64
Subtracts a 64-bit integer from another.

Synopsis
void Sub64( int64 *r, int64 *s1, int64 *s2 )

Description
This function subtracts one 64-bit integer from another and deposits the 64-bit result in the location
pointed to by r.

Arguments
r
A pointer to the 64-bit result of the subtraction.
s1, s2
Pointers to the two 64-bit numbers for the subtraction. s2 is subtracted from s1.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
SubF32(), SubF60(), SubF16(), SubF30(), SubF14(), Sub32()

file:///C|/%23%23DDOC/spr/03spr099.html [4/16/2002 11:15:15 PM]

SubF60

SubF60
Subtracts a 4.60 fraction from another.

Synopsis
void SubF60( frac60 *r, frac60 *s1, frac60 *s2 )

Description
This function subtracts two 4.60 fractions and deposits the result in the location pointed to by r.

Arguments
r
A pointer to the 4.60 fraction result of the subtraction.
s1, s2
Pointers to the two 4.60 fractions for the subtraction. s2 is subtracted from s1.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
Sub64(), SubF32(), SubF16(), SubF30(), SubF14(), Sub32()

file:///C|/%23%23DDOC/spr/03spr104.html [4/16/2002 11:15:15 PM]

SubF16

SubF16
Subtracts a 16.16 fraction from another.

Synopsis
frac16 SubF16( frac16 x, frac16 y )

Description
This macro returns the difference between two 16.16 fractions.

Arguments
x, y
Two 16.16 fractions for the subtraction. y is subtracted from x.

Return Value
The macro returns the value (x - y).

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
SubF32(), SubF60(), Sub32(), SubF30(), SubF14(), Sub64()

file:///C|/%23%23DDOC/spr/03spr101.html [4/16/2002 11:15:15 PM]

SubF30

SubF30
Subtracts a 2.30 fraction from another.

Synopsis
frac30 SubF30( frac30 x, frac30 y )

Description
This macro returns the difference between two 2.30 fractions.

Arguments
x, y
Two 2.30 fractions for the subtraction. y is subtracted from x.

Return Value
The macro returns the value (x - y).

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
SubF32(), SubF60(), Sub32(), SubF16(), SubF14(), Sub64()

file:///C|/%23%23DDOC/spr/03spr102.html [4/16/2002 11:15:16 PM]

SubF14

SubF14
Subtracts a 2.14 fraction from another.

Synopsis
frac14 SubF14( frac14 x, frac14 y )

Description
This macro returns the difference between two 2.14 fractions.

Arguments
x, y
Two 2.14 fractions for the subtraction. y is subtracted from x.

Return Value
The macro returns the value (x - y).

Implementation
Macro implemented in operamath.h V20.

Associated Files
operamath.h

See Also
SubF32(), SubF60(), Sub32(), SubF30(), SubF16(), Sub64()

file:///C|/%23%23DDOC/spr/03spr100.html [4/16/2002 11:15:16 PM]

Transpose33_F16

Transpose33_F16
Transposes a 3x3 matrix of 16.16 values.

Synopsis
void Transpose33_F16( mat33f16 dest, mat33f16 src )

Description
This function transposes a 3-by-3 matrix of 16.16 values and deposits the result in the matrix dest.

Arguments
dest
Pointer to destination matrix to store the result.
src
The matrix to transpose.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
Transpose44_F16()

file:///C|/%23%23DDOC/spr/03spr105.html [4/16/2002 11:15:16 PM]

file:///C|/%23%23DDOC/spr/03spr106.html

Transpose44_F16
Transposes a 4x4 matrix of 16.16 values.

Synopsis
void Transpose44_F16( mat44f16 dest, mat44f16 src )

Description
This function transposes a 4 x 4 matrix of 16.16 values and deposits the result in the matrix dest.

Arguments
dest
Pointer to destination matrix to store the result.
src
The matrix to transpose.

Implementation
Folio call implemented in operamath V20.

Associated Files
operamath.h, operamath.lib

See Also
Transpose33_F16()

file:///C|/%23%23DDOC/spr/03spr106.html [4/16/2002 11:15:17 PM]

Event Broker Calls

Event Broker Calls
This chapter lists event broker calls in alphabetical order. The list below is a quick summary of each,
followed by the page number where you'll find the procedure described.
●
●
●
●

GetControlPad Gets control pad events.
GetMouse Gets mouse events.
InitEventUtility Connects task to the event broker.
KillEventUtility Disconnects a task from the event broker.

file:///C|/%23%23DDOC/spr/04spr.html [4/16/2002 11:15:17 PM]

Timer Calls

Timer Calls
This chapter lists timer calls in alphabetical order. The list below is a quick summary of each, followed
by the page number where you'll find the procedure described.
●
●
●
●
●
●
●

●
●

AddTimes Adds two time values together.
CompareTimes Compares two time values.
CreateTimerIOReq Creates a timer device I/O request.
DeleteTimerIOReq Delete a timer device I/O request.
SubTimes Subtracts one time value from another.
TimeLaterThan Returns whether a time value comes before another.
TimeLaterThanOrEqual Returns whether a time value comes before or at the same time as
another.
WaitTime Waits for a given amount of time to pass.
WaitUntil Waits for a given amount of time to pass.

file:///C|/%23%23DDOC/spr/05spr.html [4/16/2002 11:15:17 PM]

AddTimes

AddTimes
Adds two time values together.

Synopsis
void AddTimes(const TimeVal *tv1, const TimeVal *tv2,TimeVal *result);

Description
Adds two time values together, yielding the total time for both.

Arguments
tv1
The first time value to add.
tv2
The second time value to add.
result
A pointer to the location where the resulting time value will be stored. This pointer can match
either tv1 or tv2.

Implementation
Convenience call implemented in clib.lib V24.

Associated Files
time.h, clib.lib

See Also
SubTimes(), CompareTimes()

file:///C|/%23%23DDOC/spr/05spr001.html [4/16/2002 11:15:17 PM]

SubTimes

SubTimes
Subtracts one time value from another.

Synopsis
void SubTimes(const TimeVal *tv1, const TimeVal *tv2,TimeVal *result);

Description
Subtracts two time values, yielding the difference in time between the two.

Arguments
tv1
The first time value.
tv2
The second time value.
result
A pointer to the location where the resulting time value will be stored. This pointer can match
either of tv1 or tv2. The value stored corresponds to (tv2 - tv1).

Implementation
Convenience call implemented in clib.lib V24.

Associated Files
time.h, clib.lib

See Also
AddTimes(), CompareTimes()

file:///C|/%23%23DDOC/spr/05spr005.html [4/16/2002 11:15:18 PM]

CompareTimes

CompareTimes
Compares two time values.

Synopsis
int32 CompareTimes(const TimeVal *tv1,const TimeVal *tv2);

Description
Compares two time values to determine which came first.

Arguments
tv1
The first time value.
tv2
The second time value.

Return Value
< 0 if (tv1 < tv2)
== 0 if (tv1 == tv2)
> 0 if (tv1 > tv2)

Implementation
Convenience call implemented in clib.lib V24.

Associated Files
time.h, clib.lib

See Also
file:///C|/%23%23DDOC/spr/05spr002.html (1 of 2) [4/16/2002 11:15:18 PM]

CompareTimes

AddTimes(), SubTimes(), TimeLaterThan(), TimeLaterThanOrEqual()

file:///C|/%23%23DDOC/spr/05spr002.html (2 of 2) [4/16/2002 11:15:18 PM]

TimeLaterThan

TimeLaterThan
Returns whether a time value comes before another.

Synopsis
bool TimeLaterThan(const TimeVal *tv1,const TimeVal *tv2);

Description
Returns whether tv1 comes chronologically after tv2.

Arguments
tv1
The first time value.
tv2
The second time value.

Return Value
TRUE
if tv1 comes after tv2
FALSE
if tv1 comes before or is the same as tv2

Implementation
Macro implemented in time.h V24.

Associated Files
time.h

See Also

file:///C|/%23%23DDOC/spr/05spr006.html (1 of 2) [4/16/2002 11:15:18 PM]

TimeLaterThan

CompareTimes(), TimeLaterThanOrEqual()

file:///C|/%23%23DDOC/spr/05spr006.html (2 of 2) [4/16/2002 11:15:18 PM]

TimeLaterThanOrEqual

TimeLaterThanOrEqual
Returns whether a time value comes before or at the same time as another.

Synopsis
bool TimeLaterThanOrEqual(const TimeVal *tv1,const TimeVal *tv2);

Description
Returns whether tv1 comes chronologically after tv2, or is the same as tv2.

Arguments
tv1
The first time value.
tv2
The second time value.

Return Value
TRUE
if tv1 comes after tv2 or is the same as tv2
FALSE
if tv1 comes before tv2

Implementation
Macro implemented in time.h V24.

Associated Files
time.h

See Also

file:///C|/%23%23DDOC/spr/05spr007.html (1 of 2) [4/16/2002 11:15:18 PM]

TimeLaterThanOrEqual

CompareTimes(), TimeLaterThan()

file:///C|/%23%23DDOC/spr/05spr007.html (2 of 2) [4/16/2002 11:15:18 PM]

CreateTimerIOReq

CreateTimerIOReq
Creates a timer device I/O request.

Synopsis
Item CreateTimerIOReq(void);

Description
Creates an I/O request for communication with the timer device.

Return Value
Returns a timer I/O request item, or a negative error code for failure.

Implementation
Convenience call implemented in clib.lib V24.

Associated Files
time.h, clib.lib

See Also
DeleteTimerIOReq(), WaitTime(), WaitUntil()

file:///C|/%23%23DDOC/spr/05spr003.html [4/16/2002 11:15:19 PM]

DeleteTimerIOReq

DeleteTimerIOReq
Delete a timer device I/O request.

Synopsis
Err DeleteTimerIOReq(Item ioreq);

Description
Frees any resources used by a previous call to CreateTimerIOReq().

Arguments
ioreq
The I/O request item, as returned by a previous call to CreateTimerIOReq().

Return Value
Return >=0 if successful, or a negative error code for failure.

Implementation
Convenience call implemented in clib.lib V24.

Associated Files
time.h, clib.lib

See Also
CreateTimerIOReq(), WaitTime(), WaitUntil()

file:///C|/%23%23DDOC/spr/05spr004.html [4/16/2002 11:15:21 PM]

WaitTime

WaitTime
Waits for a given amount of time to pass.

Synopsis
Err WaitTime(Item ioreq, uint32 seconds, uint32 micros);

Description
Puts the current context to sleep for a specific amount of time.

Arguments
ioreq
An active timer device I/O request, as obtained from CreateTimerIOReq().
seconds
The number of seconds to wait for.
micros
The number of microseconds to wait for.

Return Value
Returns >=0 if successful, or a negative error code if it fails.

Implementation
Convenience call implemented in clib.lib V24.

Associated Files
time.h, clib.lib

See Also
CreateTimerIOReq(), DeleteTimerIOReq(), WaitUntil()
file:///C|/%23%23DDOC/spr/05spr008.html (1 of 2) [4/16/2002 11:15:21 PM]

WaitTime

file:///C|/%23%23DDOC/spr/05spr008.html (2 of 2) [4/16/2002 11:15:21 PM]

WaitUntil

WaitUntil
Waits for a given amount of time to pass.

Synopsis
Err WaitTime(Item ioreq, uint32 seconds, uint32 micros);

Description
Puts the current context to sleep until the system clock reaches a given time.

Arguments
ioreq
An active timer device I/O request, as obtained from CreateTimerIOReq().
seconds
The seconds value that the timer must reach.
micros
The microseconds value that the timer must reach.

Return Value
Returns >= 0 for success, or a negative error code for failure.

Implementation
Convenience call implemented in clib.lib V24.

Associated Files
time.h, clib.lib

See Also
CreateTimerIOReq(), DeleteTimerIOReq(), WaitTime()
file:///C|/%23%23DDOC/spr/05spr009.html (1 of 2) [4/16/2002 11:15:21 PM]

WaitUntil

file:///C|/%23%23DDOC/spr/05spr009.html (2 of 2) [4/16/2002 11:15:21 PM]

JString Folio Calls

JString Folio Calls
This chapter describes the international folio procedure calls. The following list provides a brief
description of each call.
●
●
●
●

ConvertASCII2ShiftJIS Converts an ASCII string to Shift-JIS.
ConvertShiftJIS2ASCII Converts a Shift-JIS string to ASCII.
ConvertShiftJIS2UniCode Converts a Shift-JIS string to UniCode.
ConvertUniCode2ShiftJIS Converts a UniCode string to Shift-JIS.

file:///C|/%23%23DDOC/spr/07spr.html [4/16/2002 11:15:22 PM]

Compression Folio Calls

Compression Folio Calls
This chapter describes the compression folio procedure calls. The following list provides a brief
description of each call.
●
●
●
●
●
●
●

●

●
●

CreateCompressor Creates a compression engine.
CreateDecompressor Creates a decompression engine.
DeleteCompressor Deletes a compression engine.
DeleteDecompressor Deletes a decompression engine.
FeedCompressor Gives data to a compression engine.
FeedDecompressor Gives data to the decompression engine.
GetCompressorWorkBufferSize Gets the size of the work buffer needed by a
compression engine.
GetDecompressorWorkBufferSize Gets the size of the work buffer needed by a
decompression engine.
SimpleCompress Compresses some data in memory.
SimpleDecompress Decompresses some data in memory.

file:///C|/%23%23DDOC/spr/08spr.html [4/16/2002 11:15:22 PM]

CreateCompressor

CreateCompressor
Creates a compression engine.

Synopsis
Err CreateCompressor(Compressor **comp, CompFunc cf,const TagArg
*tags);
Err CreateCompressorVA(Compressor **comp, CompFunc cf,uint32 tags,
...);

Description
Creates a compression engine. Once the engine is created, you can call FeedCompressor() to have
the engine compress the data you supply.

Arguments
comp
A pointer to a compressor variable, where a handle to the compression engine can be put.
cf
A data output function. Every word of compressed data is sent to this function. This function is
called with two parameters: one is a user-data value as supplied with the
COMP_TAG_USERDATA tag. The other is the word of compressed data being output by the
compressor.
tags
A pointer to an array of tag arguments containing extra data for this function. See below for a
description of the tags supported.

Tag Arguments
The following tag arguments may be supplied in array form to this function. The array must be
terminated with TAG_END.
COMP_TAG_WORKBUFFER(void *)
A pointer to a work buffer. This buffer is used by the compressor to store state information. If this
tag is not supplied, the buffer is allocated and freed by the folio automatically. To obtain the
file:///C|/%23%23DDOC/spr/08spr002.html (1 of 2) [4/16/2002 11:15:22 PM]

CreateCompressor

required size for the buffer, call the GetCompressorWorkBufferSize() function. The buffer you
supply must be aligned on a 4-byte boundary, and must remain valid until DeleteCompressor() is
called. When you supply a work buffer, this routine allocates no memory of its own.
COMP_TAG_USERDATA(void *)
A value that the compressor will pass to cf when it is called. This value can be anything you want.
For example, it can be a pointer to a private data structure containing some context such as a file
handle. If this tag is not supplied, then NULL is passed to cf when it is called.

Return Value
Returns >= 0 for success, or a negative error code if the compression engine could not be created.
Possible error codes include:
COMP_ERR_BADPTR
An invalid output function pointer or work buffer was supplied.
COMP_ERR_BADTAG
An unknown tag was supplied.
COMP_ERR_NOMEM
There was not enough memory to initialize the compressor.

Implementation
Folio call implemented in compression folio V24.

Associated Files
compression.h

See Also
FeedCompressor(), DeleteCompressor(), GetCompressorWorkBufferSize(),
CreateDecompressor()

file:///C|/%23%23DDOC/spr/08spr002.html (2 of 2) [4/16/2002 11:15:22 PM]

FeedCompressor

FeedCompressor
Gives data to a compression engine.

Synopsis
Err FeedCompressor(Compressor *comp, void *data,uint32 numDataWords);

Description
Gives data to a compressor engine for compression. As data is compressed, the call back function
supplied when the compressor was created is called for every word of compressed data generated.

Arguments
comp
An active compression handle, as obtained from CreateCompressor().
data
A pointer to the data to compress.
numDataWords
The number of words of data being given to the compressor.

Return Value
Returns >= 0 for success, or a negative error code if it fails. Possible error codes include:
COMP_ERR_BADPTR
An invalid compression handle was supplied.

Implementation
Folio call implemented in compression folio V24.

Associated Files
compression.h
file:///C|/%23%23DDOC/spr/08spr007.html (1 of 2) [4/16/2002 11:15:23 PM]

FeedCompressor

See Also
CreateCompressor(), DeleteCompressor()

file:///C|/%23%23DDOC/spr/08spr007.html (2 of 2) [4/16/2002 11:15:23 PM]

DeleteCompressor

DeleteCompressor
Deletes a compression engine.

Synopsis
Err DeleteCompressor(Compressor *comp);

Description
Deletes a compression engine previously created by CreateCompressor(). This flushes any data
left to be output by the compressor and generally cleans things up.

Arguments
comp
An active compression handle, as obtained from CreateCompressor(). Once this call is made, the
compression handle becomes invalid and can no longer be used.

Return Value
Returns > = 0 if successful, or a negative error code if it fails. Possible error codes include:
COMP_ERR_BADPTR
An invalid compression handle was supplied.

Implementation
Folio call implemented in compression folio V24.

Associated Files
compression.h

See Also
CreateCompressor()

file:///C|/%23%23DDOC/spr/08spr005.html [4/16/2002 11:15:23 PM]

GetCompressorWorkBufferSize

GetCompressorWorkBufferSize
Gets the size of the work buffer needed by a compression engine.

Synopsis
int32 GetCompressorWorkBufferSize(const TagArg *tags);
int32 GetCompressorWorkBufferSizeVA(uint32 tags, ...);

Description
Returns the size of the work buffer needed by a compression engine. You can then allocate a buffer of
that size and supply the pointer with the COMP_TAG_WORKBUFFER tag when creating a
compression engine. If the COMP_TAG_WORKBUFFER tag is not supplied when creating a
compressor, the folio automatically allocates the memory needed for the compression engine.

Arguments
tags
A pointer to an array of tag arguments containing extra data for this function. This must currently
always be NULL.

Return Value
A positive value indicates the size of the work buffer needed in bytes, while a negative value indicates an
error. Possible error codes currently include:
COMP_ERR_BADTAG
An unknown tag was supplied.

Implementation
Folio call implemented in compression folio V24.

Associated Files
compression.h

file:///C|/%23%23DDOC/spr/08spr009.html (1 of 2) [4/16/2002 11:15:23 PM]

GetCompressorWorkBufferSize

See Also
CreateCompressor(), DeleteCompressor()

file:///C|/%23%23DDOC/spr/08spr009.html (2 of 2) [4/16/2002 11:15:23 PM]

CreateDecompressor

CreateDecompressor
Creates a decompression engine.

Synopsis
Err CreateDecompressor(Decompressor **comp, CompFunc cf,const TagArg
*tags);
Err CreateDecompressorVA(Decompressor **comp, CompFunc cf,uint32 tags,
...);

Description
Creates a decompression engine. Once the engine is created, you can call FeedDecompressor() to
have the engine decompress the data you supply.

Arguments
decomp
A pointer to a decompressor variable, where a handle to the decompression engine can be put.
cf
A data output function. Every word of decompressed data is sent to this function. This function is
called with two parameters: one is a user-data value as supplied with the
COMP_TAG_USERDATA tag. The other is the word of decompressed data being output by the
decompressor.
tags
A pointer to an array of tag arguments containing extra data for this function. See below for a
description of the tags supported.

Tag Arguments
The following tag arguments may be supplied in array form to this function. The array must be
terminated with TAG_END.
COMP_TAG_WORKBUFFER(void *)
A pointer to a work buffer. This buffer is used by the decompressor to store state information. If
this tag is not supplied, the buffer is allocated and freed by the folio automatically. To obtain the
file:///C|/%23%23DDOC/spr/08spr003.html (1 of 2) [4/16/2002 11:15:24 PM]

CreateDecompressor

required size for the buffer, call the GetDecompressorWorkBufferSize() function. The buffer you
supply must be aligned on a 4-byte boundary, and must remain valid until DeleteDecompressor()
is called. When you supply a work buffer, this routine allocates no memory of its own.
COMP_TAG_USERDATA(void *)
A value that the decompressor will pass to cf when it is called. This value can be anything you
want. For example, it can be a pointer to a private data structure containing some context such as
a file handle. If this tag is not supplied, then NULL is passed to cf when it is called.

Return Value
Returns >= 0 for success, or a negative error code if the decompression engine could not be created.
Possible error codes include:
COMP_ERR_BADPTR
An invalid output function pointer or work buffer was supplied.
COMP_ERR_BADTAG
An unknown tag was supplied.
COMP_ERR_NOMEM
There was not enough memory to initialize the compressor.

Implementation
Folio call implemented in compression folio V24.

Associated Files
compression.h

See Also
FeedDecompressor(), DeleteDecompressor(),
GetDecompressorWorkBufferSize(), CreateCompressor()

file:///C|/%23%23DDOC/spr/08spr003.html (2 of 2) [4/16/2002 11:15:24 PM]

FeedDecompressor

FeedDecompressor
Gives data to the decompression engine.

Synopsis
Err FeedDecompressor(Decompressor *decomp, void *data,uint32
numDataWords);

Description
Gives data to the decompressor engine for decompression. As data is decompressed, the call back
function supplied when the decompressor was created is called for every word of decompressed data
generated.

Arguments
decomp
An active decompression handle, as obtained from CreateDecompressor().
data
A pointer to the data to decompress.
numDataWords
The number of words of compressed data being given to the decompressor.

Return Value
Returns >= 0 for success, or a negative error code if it fail. Possible error codes include:
COMP_ERR_BADPTR
An invalid decompression handle was supplied.

Implementation
Folio call implemented in compression folio V24.

Associated Files
file:///C|/%23%23DDOC/spr/08spr008.html (1 of 2) [4/16/2002 11:15:24 PM]

FeedDecompressor

compression.h

See Also
CreateDecompressor(), DeleteDecompressor()

file:///C|/%23%23DDOC/spr/08spr008.html (2 of 2) [4/16/2002 11:15:24 PM]

DeleteDecompressor

DeleteDecompressor
Deletes a decompression engine.

Synopsis
Err DeleteDecompressor(Decompressor *decomp);

Description
Deletes a decompression engine previously created by CreateDecompressor(). This flushes any
data left to be output by the decompressor and generally cleans things up.

Arguments
decomp
An active decompression handle, as obtained from CreateDecompressor(). Once this call is made,
the decompression handle becomes invalid and can no longer be used.

Return Value
Returns >= 0 for success, or a negative error code if it fails. Possible error codes include:
COMP_ERR_BADPTR
An invalid decompression handle was supplied.
COMP_ERR_DATAREMAINS
The decompressor thinks it is finished, but there remains extra data in its buffers. This happens
when the compressed data is somehow corrupt.
COMP_ERR_DATAMISSING
The decompressor thinks that not all of the compressed data was given to be decompressed. This
happens when the compressed data is somehow corrupt.

Implementation
Folio call implemented in compression folio V24.

file:///C|/%23%23DDOC/spr/08spr006.html (1 of 2) [4/16/2002 11:15:24 PM]

DeleteDecompressor

Associated Files
compression.h

See Also
CreateCompressor()

file:///C|/%23%23DDOC/spr/08spr006.html (2 of 2) [4/16/2002 11:15:24 PM]

GetDecompressorWorkBufferSize

GetDecompressorWorkBufferSize
Gets the size of the work buffer needed by a decompression engine.

Synopsis
int32 GetDecompressorWorkBufferSize(const TagArg *tags);
int32 GetDecompressorWorkBufferSizeVA(uint32 tags, ...);

Description
Returns the size of the work buffer needed by a decompression engine. You can then allocate a buffer of
that size and supply the pointer with the COMP_TAG_WORKBUFFER tag when creating a
decompression engine. If the COMP_TAG_WORKBUFFER tag is not supplied when creating a
decompressor, the folio automatically allocates the memory needed for the decompression engine.

Arguments
tags
A pointer to an array of tag arguments containing extra data for this function. This must currently
always be NULL.

Return Value
A positive value indicates the size of the work buffer needed in bytes, while a negative value indicates an
error. Possible error codes currently include:
COMP_ERR_BADTAG
An unknown tag was supplied.

Implementation
Folio call implemented in compression folio V24.

Associated Files
compression.h

file:///C|/%23%23DDOC/spr/08spr010.html (1 of 2) [4/16/2002 11:15:25 PM]

GetDecompressorWorkBufferSize

See Also
CreateDecompressor(), DeleteDecompressor()

file:///C|/%23%23DDOC/spr/08spr010.html (2 of 2) [4/16/2002 11:15:25 PM]

SimpleCompress

SimpleCompress
Compresses some data in memory.

Synopsis
Err SimpleCompress(void *source, uint32 sourceWords,void *result,
uint32 resultWords);

Description
Compresses a chunk of memory to a different chunk of memory.

Arguments
source
A pointer to memory containing the data to be compressed. This pointer must be on a 4-byte
boundary.
sourceWords
The number of words of data to compress.
result
A pointer to where the compressed data is to be deposited.
resultWords
The number of words available in the result buffer. If the compressed data is larger than this size,
an overflow will be reported.

Return Value
If the return value is positive, it indicates the number of words copied to the result buffer. If the return
value is negative, it indicates an error code. Possible error codes include:
COMP_ERR_NOMEM
There was not enough memory to initialize the compressor.
COMP_ERR_OVERFLOW
There was not enough room in the result buffer to hold all of the compressed data.
file:///C|/%23%23DDOC/spr/08spr001.html (1 of 2) [4/16/2002 11:15:25 PM]

SimpleCompress

Implementation
Convenience call implemented in compression.lib V24.

Associated Files
compression.h

See Also
SimpleDecompress()

file:///C|/%23%23DDOC/spr/08spr001.html (2 of 2) [4/16/2002 11:15:25 PM]

SimpleDecompress

SimpleDecompress
Decompresses some data in memory.

Synopsis
Err SimpleDecompress(void *source, uint32 sourceWords,void *result,
uint32 resultWords);

Description
Decompresses a chunk of memory to a different chunk of memory.

Arguments
source
A pointer to memory containing the data to be decompressed. This pointer must be on a 4-byte
boundary.
sourceWords
The number of words of data to decompress.
result
A pointer to where the decompressed data is to be deposited.
resultWords
The number of words available in the result buffer. If the decompressed data is larger than this
size, an overflow will be reported.

Return Value
If positive, returns the number of words copied to the result buffer. If negative, returns an error code.
Possible error codes include:
COMP_ERR_NOMEM
There was not enough memory to initialize the decompressor.
COMP_ERR_OVERFLOW
There was not enough room in the result buffer to hold all of the decompressed data.
file:///C|/%23%23DDOC/spr/08spr004.html (1 of 2) [4/16/2002 11:15:25 PM]

SimpleDecompress

Implementation
Convenience call implemented in compression.lib V24.

Associated Files
compression.h

See Also
SimpleCompress()

file:///C|/%23%23DDOC/spr/08spr004.html (2 of 2) [4/16/2002 11:15:25 PM]

How the Compression Folio Works

How the Compression Folio Works
The sections below describe how to compress and decompress data.

Compressing Data
To compress data, you must create a compression engine by calling CreateCompressor().
You must also allocate a buffer of the correct size and supply a pointer to it with the
COMP_TAG_WORKBUFFER tag and pass in a pointer to your output function.
Once you create the engine, call FeedCompressor() to have the engine compress the data you
supply. FeedCompressor() then gives data to the compression engine, which in turn sends it to your
output function, one word at a time. When the compression engine is finished compressing the data, call
DeleteCompressor() to delete the engine and clean up.

Decompressing Data
Decompression works almost the same as compressing data. First, you create a decompression engine
with CreateDecompressor(). Then, allocate a buffer of the correct size and supply a pointer to it
with the COMP_TAG_WORKBUFFER tag and provide a pointer to your output function.
Feed compressed data to the decompression engine with the FeedDecompressorEngine() call,
which in turn sends it to the output call. Again when you are finished decompressing data, call
DeleteDecompressor() to delete the engine and clean up.

file:///C|/%23%23DDOC/spg/14spg002.html [4/16/2002 11:15:26 PM]

The Callback Function

The Callback Function
When you create a compression or decompression engine, you must supply a function pointer. This
function is called whenever either engine has data to output. The function then takes the data and do
whatever the application wants with the data. For example, the callback function can deposit the data in a
buffer, and once the engine is deleted, the buffer can be written out to a file.
The callback function has two parameters passed to it, and is defined as:
typedef void (* CompFunc)(void *userData, uint32 word);
The userData field is normally NULL, unless you supply the COMP_TAG_USERDATA tag when
creating the engine. Whatever value is associated with the tag gets passed directly to the callback
function. The purpose of the userData field is to pass things like a file pointer to the callback function.
You would pass the file pointer as the data value associated with the COMP_TAG_USERDATA tag. The
engines then pass the value to the callback function whenever it is called.
The word parameter to the callback is the word of data being generated by the engine. You must do
something useful with this word. For example, you could copy it into a memory buffer, or write it to a
file.

file:///C|/%23%23DDOC/spg/14spg003.html [4/16/2002 11:15:26 PM]

Controlling Memory Allocations

Controlling Memory Allocations
When you create a compression or decompression engine, the CreateCompressor() and
CreateDecompressor() functions normally allocate some memory to hold the state of the engines.
The compression engine needs around 50 KB of storage, while the decompressor needs around 5 KB.
If your title has sophisticated memory management needs, you can supply a memory buffer yourself to
avoid having the folio allocate any memory. To do this, call the
GetCompressorWorkBufferSize() routine to obtain the size of the buffer needed for the
compression engine, or you can call GetDecompressorWorkBufferSize() to get the size of the
buffer needed for the decompression engine. Once you have determined the size, then you can allocate a
memory buffer, and pass a pointer to the buffer using the COMP_TAG_WORKBUFFER tag when you
create the compressor or decompressor.
When you supply the work buffer, the Compression folio allocates no, or almost no, resources when a
compression or decompression engine is created. This allows your title to control where memory
resources come from.

file:///C|/%23%23DDOC/spg/14spg004.html [4/16/2002 11:15:26 PM]

Convenience Calls

Convenience Calls
There are two function calls supplied in compression.lib that provide a simple interface to the lower-level
functions of the Compression folio. The two functions implement the most common uses for the folio
functions.
The Compress() function compresses data from one memory buffer into another memory buffer. You
give it a source buffer pointer, the size of the source buffer, a destination buffer pointer, and the size of
the destination buffer. Compress() then compresses the data and deposits the compressed result in the
destination buffer. This function returns the number of words of data copied into the destination buffer,
or a negative error if something went wrong, such as a lack of memory or a lack of space in the
destination buffer.
The Decompress() function decompresses in much the same way as the Compress() function
compresses data. This time, the source buffer contains the compressed data, and the destination buffer
gets filled with decompressed data. This function returns the number of words of decompressed data that
were put in the destination buffer, or a negative error code if something went wrong.

file:///C|/%23%23DDOC/spg/14spg005.html [4/16/2002 11:15:27 PM]

Example

Example
Example 1 contains the sample program compressexample.c (located in the Examples folder), which shows how to use
the Compression folio. This program loads itself into a memory buffer, compresses the data, decompresses it, and finally
compares the original data with the decompressed data to make sure the compression process was successful.
Example 1: Example of compressing and decompressing data (compressexample.c).
#include
#include
#include
#include
#include
#include

"types.h"
"filestream.h"
"filestreamfunctions.h"
"stdio.h"
"mem.h"
"compression.h"

/*****************************************************************************/
int main(int argc, char **argv)
{
Stream
*stream;
Err
err;
bool
same;
uint32
i;
int32
fileSize;
uint32
*originalData;
uint32
*compressedData;
uint32
*finalData;
int32
numFinalWords;
int32
numCompWords;
err = OpenCompressionFolio();
if (err >= 0)
{
stream = OpenDiskStream(argv[0],0);
if (stream)
{
fileSize
= stream->st_FileLength & 0xfffffffc;
originalData
= (uint32 *)malloc(fileSize);
compressedData = (uint32 *)malloc(fileSize);
finalData
= (uint32 *)malloc(fileSize);
if (originalData && compressedData && finalData)
{
if (ReadDiskStream(stream,(char *)originalData,fileSize) ==
fileSize)
{
err = Compress(originalData, fileSize / sizeof(uint32),
file:///C|/%23%23DDOC/spg/14spg006.html (1 of 3) [4/16/2002 11:15:27 PM]

Example

compressedData, fileSize / sizeof(uint32));
if (err >= 0)
{
numCompWords = err;
err = Decompress(compressedData, numCompWords,
finalData, fileSize / sizeof(uint32));
if (err >= 0)
{
numFinalWords = err;
printf("Original data size
: %d\n",fileSize /
sizeof(uint32));
printf("Compressed data size : %d\n",numCompWords);
printf("Uncompressed data size: %d\n",numFinalWords);
same = TRUE;
for (i = 0; i < fileSize / sizeof(uint32); i++)
{
if (originalData[i] != finalData[i])
{
same = FALSE;
break;
}
}
if (same)
{
printf("Uncompressed data matched original\n");
}
else
{
printf("Uncompressed data differed with
original!\n");
for (i = 0; i < 10; i++)
{
printf("orig $%08x, final $%08x, comp
$%08x\n",
originalData[i],
finalData[i],
compressedData[i]);
}
}
}
else
{
PrintError(NULL,"decompress data",NULL,err);
}
}

file:///C|/%23%23DDOC/spg/14spg006.html (2 of 3) [4/16/2002 11:15:27 PM]

Example

else
{
PrintError(NULL,"compress data",NULL,err);
}
}
else
{
printf("Could not read whole file\n");
}
}
else
{
printf("Could not allocate memory buffers\n");
}
free(originalData);
free(compressedData);
free(finalData);
CloseDiskStream(stream);
}
else
{
printf("Could not open '%s' as an input file\n",argv[0]);
}
CloseCompressionFolio();
}
else
{
PrintError(NULL,"open the compression folio",NULL,err);
}
return (0);
}

file:///C|/%23%23DDOC/spg/14spg006.html (3 of 3) [4/16/2002 11:15:27 PM]

Function Calls

Function Calls
The Compression folio currently includes the following calls, which are listed here by the type of
function they perform.

Convenience calls
●
●

Compress() Compresses a chunk of memory to a different chunk of memory.
Decompress() Decompresses a chunk of memory to a different chunk of memory

The following calls are convenience calls:

Compression Calls
●
●

●

CreateCompressor() Creates a compression engine.
FeedCompressor() Gives data to a compressor engine to compress and pass to the output
function.
DeleteCompressor() Deletes the compressor engine.

The following calls compress data:

Decompression Calls
The following calls compress data:
●
●

●

CreateDecompressor() Creates a decompression engine.
FeedDecompressor() Gives data to a decompressor engine to have it decompressed and
pass it to the output function.
DeleteDecompressor() Deletes the decompressor engine.

Buffer Calls
The following calls get the size of working buffers:
●

GetCompressorWorkBufferSize() Gets the size of the work buffer needed by a

file:///C|/%23%23DDOC/spg/14spg007.html (1 of 2) [4/16/2002 11:15:28 PM]

Function Calls

●

compression engine.
GetDecompressorWorkBufferSize() Gets the size of the work buffer needed by a
decompression engine.

file:///C|/%23%23DDOC/spg/14spg007.html (2 of 2) [4/16/2002 11:15:28 PM]

The Math Folio

The Math Folio
The Math folio offers a large number of functions that perform many common mathematical operations.
Many of these functions use the special math hardware built into the 3DO architecture to give better
performance.
This chapter organizes the many Math folio calls in logical groupings so you can find the appropriate call
for the math operation you want to perform. Most of these calls are very straightforward. For detailed
information on the operation of each call, see the 3DO System Programmer's Reference.
Like all other folios, each task or thread that uses calls from the Math folio must open the folio explicitly
using OpenMathFolio().
This chapter contains the following topics:
●
●

Dealing With Overflow
List of Math Calls

file:///C|/%23%23DDOC/spg/15spg.html [4/16/2002 11:15:28 PM]

Dealing With Overflow

Dealing With Overflow
Most Math folio function calls do not detect overflow. When overflow occurs, the result is most often a
garbage value. The exceptions to this rule are many division calls. If overflow occurs when using an
unsigned division call, the call normally returns a value with all bits set (the maximum possible value).
When overflow occurs using a signed division call, the call returns either a value with all bits set (the
smallest possible negative value), or all bits clear except the least-significant bit (the smallest positive
value).

file:///C|/%23%23DDOC/spg/15spg001.html [4/16/2002 11:15:29 PM]

List of Math Calls

List of Math Calls
Addition Calls
These calls add two values of the same data type together and return the result in the same data type.

Integers
●
●

Add32() Adds 32-bit integers.
Add64() Adds 64-bit integers.

Fractions
●
●
●
●
●

AddF14()
AddF16()
AddF30()
AddF32()
AddF60()

Adds 2.14 format fixed-point fractions.
Adds 16.16 format fixed-point fractions.
Adds 2.30 format fixed-point fractions.
Adds 32.32 format fixed-point fractions.
Adds 4.60 format fixed-point fractions.

Subtraction Calls
These calls subtract one value from another and return the result. Both the values and the result are the
same data type.

Integers
●
●

Sub32() Subtracts two 32-bit integers.
Sub64() Subtracts two 64-bit integers.

Fractions
●

SubF14() Subtracts two 2.14 fractions.

file:///C|/%23%23DDOC/spg/15spg002.html (1 of 8) [4/16/2002 11:15:30 PM]

List of Math Calls
●
●
●
●

SubF16()
SubF30()
SubF32()
SubF60()

Subtracts two 16.16 fractions.
Subtracts two 2.30 fractions.
Subtracts two 32.32 fractions.
Subtracts two 4.60 fractions.

Division Calls
These calls take two values of the same data type and divide the first by the second to return a quotient
and/or a remainder of the same data type.

Integers
●
●
●
●

DivRemS32() 32-bit quotient, remainder of a 32-bit division.
DivS64() 64-bit quotient, remainder of a 64-bit division.
DivRemU32() 32-bit quotient, remainder of a 32-bit division.
DivU64() 64-bit quotient, remainder of a 64-bit division.

Fractions
●
●
●
●

DivSF16() 16.16 quotient of a 16.16 division.
DivRemSF16() 16.16 quotient, remainder of a 16.16 division.
DivUF16() 16.16 quotient of a 16.16 division.
DivRemUF16() 16.16 quotient, remainder of a 16.16 division.

Same-Product Multiplication Calls
These calls multiply two values that can be numbers, vectors, or matrices. They return products of the
same type as the multipliers.

Cross-Product Multiplication
●

Cross3_F16() 16.16 cross-product of 2 vectors of 16.16 values.

Integer Multiplication
file:///C|/%23%23DDOC/spg/15spg002.html (2 of 8) [4/16/2002 11:15:30 PM]

List of Math Calls
●
●

Mul32() Multiplies two 32-bit integers; 32-bit integer result.
Mul64() Multiplies two 64-bit integers; 64-bit integer result.

Fraction Multiplication
●
●
●

MulF14() Multiplies two 2.14 fractions; 2.14 fraction result.
MulSF16() Multiplies two signed 16.16 fractions; 16.16 result.
MulUF16() Multiplies two unsigned 16.16 fractions; 16.16 result.

Scalar Multiplication
●

MulScalarF16() Multiplies 16.16 scalar by an array of 16.16 values; 16.16 array result.

Vector by Vector Multiplication
●

MulManyF16() Multiplies an array of 16.16 values by another array of 16.16 values.

Matrix by Matrix Multiplication
These calls multiply a matrix within an object structure by an external matrix.
●
●
●

●

MulMat33Mat33_F16() Multiplies two 3x3 matrices of 16.16 values.
MulMat44Mat44_F16()Multiplies two 4x4 matrices of 16.16 values.
MulObjectMat33_F16()Multiplies matrix within an object structure by an external 3x3
matrix of 16.16 values.
MulObjectMat44_F16()Multiplies matrix within an object structure by an external 4x4
matrix of 16.16 values.

Vector by Matrix Multiplication
These calls multiply many vectors within an object structure by an external matrix.
●
●
●
●

MulManyVec3Mat33_F16() Multiplies 16.16 vector(s) by a 3x3 matrix of 16.16 values.
MulManyVec4Mat44_F16() Multiplies 16.16 vector(s) by a 4x4 matrix of 16.16 values.
MulVec3Mat33_F16() Multiplies a 16.16 vector and a 3x3 matrix.
MulVec4Mat44_F16() Multiplies a 16.16 vector and a 4x4 matrix.

file:///C|/%23%23DDOC/spg/15spg002.html (3 of 8) [4/16/2002 11:15:30 PM]

List of Math Calls
●

●

●

●

MulObjectVec3Mat33_F16() Multiplies many 16.16 vectors within an object structure by
a 3x3 matrix of 16.16 values.
MulObjectVec4Mat44_F16() Multiplies many 16.16 vectors within an object structure by
a 4x4 matrix of 16.16 values.
MulVec3Mat33DivZ_F16() Multiplies a 3x3 matrix of 16.16 fractions by a 3-coordinate
vector of 16.16 values, then multiply the x and y elements of the results vector by the ratio n/z.
MulManyVec3Mat33DivZ_F16() Multiplies a 3x3 matrix of 16.16 fractions by one or more
3-coordinate vectors of 16.16 values, then multiply the x and y elements of the result vector by the
ration n/z.

Different-Product Multiplication Calls
These calls multiply two values and return a product of a different type than the arguments.

Standard Multiplication
●
●
●
●
●
●

MulS32_64() Multiplies two 32-bit integers; 64-bit result.
MulSF16_F32() Multiplies two signed 16.16 numbers; 32.32 result.
MulSF30_F60() Multiplies two signed 2.30 numbers; a 4.60 result.
MulU32_64() Multiplies two unsigned 32-bit integers; 64-bit result.
MulUF16_F32() Multiplies two unsigned 16.16 numbers; 32.32 result.
MulUF30_F60() Multiplies two unsigned 2.30 numbers; 4.60 result.

Dot Product Multiplication
●
●

Dot3_F16() Dot product of 2 three-coordinate vectors of 16.16 values.
Dot4_F16() Dot product of 2 four-coordinate vectors of 16.16 values.

Matrix Transposition Calls
These calls transpose matrices.
●
●

Transpose33_F16() Transposes a 3x3 matrix of 16.16 values.
Transpose44_F16() Transposes a 4x4 matrix of 16.16 values.

file:///C|/%23%23DDOC/spg/15spg002.html (4 of 8) [4/16/2002 11:15:30 PM]

List of Math Calls

Geometry Calls
These calls compute geometric functions: sines, cosines, and so on.

Arctangent
●

Atan2F16() Arctangent of a ratio.

Cosines
●
●
●

CosF16() 16.16 cosine of a 16.16 fraction angle.
CosF30() 2.30 cosine of a 16.16 fraction.
CosF32() 32.32 cosine of a 16.16 fraction.

Sines
●
●
●

SinF16() 16.16 sine of a 16.16 fraction angle.
SinF30() 2.30 sine of a 16.16 fraction.
SinF32() 32.32 sine of a 16.16 fraction.

Conversion Calls
These calls convert a value in one data type to the corresponding value in another data type.

Integers to Fractions
●
●

Convert32_F16() Converts 32-bit integer to 16.16 fraction.
Convert32_F32() Converts 32-bit integer to 32.32 fraction.

Integers to Integers
●
●

ConvertS32_64() Converts 32-bit integer to 64-bit integer.
ConvertU32_64() Converts unsigned 32-bit integer to unsigned 64-bit integer.

file:///C|/%23%23DDOC/spg/15spg002.html (5 of 8) [4/16/2002 11:15:30 PM]

List of Math Calls

Fractions to Fractions
●
●
●
●
●
●
●

ConvertF14_F16() Converts 2.14 fraction to 16.16 fraction.
ConvertF16_F14() Converts 16.16 fraction to 2.14 fraction.
ConvertF16_F30() Converts 16.16 fraction to 2.30 fraction.
ConvertF30_F16() Converts 2.30 fraction to 16.16 fraction.
ConvertF32_F16() Converts 32.32 fraction to 16.16 fraction.
ConvertSF16_F32() Converts 16.16 fraction to 32.32 fraction.
ConvertUF16_F32() Converts unsigned 16.16 fraction to unsigned 32.32 fraction.

Fraction to Integers
●

ConvertF16_32() Converts 16.16 fraction to 32-bit integer.

Comparative Calls
These calls compare two values of the same data type and return a result that is a positive value if the
first value is greater than the second, a 0 if the two values are equal, and a negative number if the second
value is greater than the first.

Integers
●
●

CompareS64() Compares signed 64-bit integers.
CompareU64() Compares unsigned 64-bit integers.

Fractions
●
●
●
●

CompareSF32()
CompareSF60()
CompareUF32()
CompareUF60()

Compares signed 32.32 format fractions.
Compares signed 4.60 format fractions.
Compares unsigned 32.32 format fractions.
Compares unsigned 4.60 format fractions.

One's and Two's Complement Calls
These calls return one's and two's complements of a value.

file:///C|/%23%23DDOC/spg/15spg002.html (6 of 8) [4/16/2002 11:15:30 PM]

List of Math Calls

Two's Complements
●
●
●
●
●
●

Neg32() Two's complement of a 32-bit integer.
NegF14() Two's complement of a 2.14 fraction.
NegF16() Two's complement of a 16.16 fraction.
NegF30() Two's complement of a 2.30 fraction.
Neg64() Two's complement of a 64-bit integer.
NegF32() Two's complement of a 32.32 number.

One's Complements
●
●
●
●
●
●

Not32() One's complement of a 32-bit integer.
NotF14() One's complement of a 2.14 fraction.
NotF16() One's complement of a 16.16 fraction.
NotF30() One's complement of a 2.30 fraction.
Not64() One's complement of a 64-bit integer.
NotF32() One's complement of a 32.32 number.

Reciprocal Calls
These calls return the reciprocal of a number.
●
●

RecipSF16() Reciprocal of a signed 16.16 number.
RecipUF16() Reciprocal of an unsigned 16.16 number.

Squaring and Square Root Calls
These calls return the square or the square root of a number.

Squares
●
●
●

Square64() Square a 64-bit integer.
SquareSF16() Square a signed 16.16 fraction.
SquareUF16() Square an unsigned 16.16 fraction.

file:///C|/%23%23DDOC/spg/15spg002.html (7 of 8) [4/16/2002 11:15:30 PM]

List of Math Calls

Square Roots
●
●
●
●

Sqrt32() Unsigned 32-bit square root of an unsigned 32-bit number.
SqrtF16() 16.16 fraction square root of an unsigned 16.16 number.
Sqrt64_32() 32-bit square root of an unsigned 64-bit integer.
SqrtF32_F16() 16.16 square root of a32.32 fraction.

Absolue Value
The following calls compute the absolute value of a vector call.
●
●

AbsVec3_F16 Computes the absolute value of a vector of 16.16 values.
AbsVec4_F16 Computes the absolute value of a vector of 16.16 values.

file:///C|/%23%23DDOC/spg/15spg002.html (8 of 8) [4/16/2002 11:15:30 PM]

</pre><hr>Source Exif Data: <br /><pre>File Type                       : PDF
File Type Extension             : pdf
MIME Type                       : application/pdf
PDF Version                     : 1.4
Linearized                      : Yes
Modify Date                     : 2002:04:16 23:16:13+02:00
Create Date                     : 2002:04:16 23:12:19Z
Page Count                      : 855
Mod Date                        : 2002:04:16 23:16:13+02:00
Creation Date                   : 2002:04:16 23:12:19Z
Producer                        : Acrobat Web Capture 5.0
Metadata Date                   : 2002:04:16 23:16:13+02:00
Title                           : 3DO System Programmer's Guide
Page Mode                       : UseOutlines
</pre>
<small>EXIF Metadata provided by <a href="https://exif.tools/">EXIF.tools</a></small>

<div id="ezoic-pub-ad-placeholder-110">
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- usermanual link ad -->
<ins class="adsbygoogle"
     style="display:block"
     data-ad-client="ca-pub-0545639743190253"
     data-ad-slot="6172135303"
     data-ad-format="link"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
</div>
</div>
				<div id="catlinks" class="catlinks catlinks-allhidden" data-mw="interface"></div>				<div class="visualClear"></div>
							</div>
		</div>
		<div id="mw-navigation">
			<h2>Navigation menu</h2>

			<div id="mw-head">
									<div id="p-personal" role="navigation" class="" aria-labelledby="p-personal-label">
                                                 <!--                              <div id="p-search" role="search">

                                                <form action="https://usermanual.wiki/search.php" id="searchform">
                                                        <div id="simpleSearch">
                                                        <input type="search" name="search" placeholder="Search UserManual.wiki" title="Search UserManual.wiki [ctrl-option-f]" accesskey="f" id="searchInput" tabindex="1" autocomplete="off"><input type="hidden" value="Special:Search" name="title"><input type="submit" name="go" value="Go" title="Find a User Manual" id="searchButton" class="searchButton">                                                 </div>
                                                </form>
                                        </div>-->
                                                <ul>
<li id="pt-mycontris"><a href="https://usermanual.wiki/upload" title="Upload User Manual" accesskey="y">Upload a User Manual</a></li>
</ul>
					</div>
									<div id="left-navigation">
										<div id="p-namespaces" role="navigation" class="vectorTabs" aria-labelledby="p-namespaces-label">
						<h3 id="p-namespaces-label">Versions of this User Manual:</h3>
						<ul>
 <li id="ca-nstab-main"><span><a href="https://usermanual.wiki/Document/3DO20System20Programmers20Guide.659590738" title="User Manual Wiki" accesskey="c">Wiki Guide</a></span></li> <li id="ca-nstab-main"><span><a href="https://usermanual.wiki/Document/3DO20System20Programmers20Guide.659590738/html" title="HTML" accesskey="c">HTML</a></span></li> <li id="ca-nstab-main"><span><a href="https://usermanual.wiki/Document/3DO20System20Programmers20Guide.659590738/amp" title="Mobile AMP" accesskey="c">Mobile</a></span></li> <li id="ca-nstab-main" class="selected" ><span><a href="https://usermanual.wiki/Document/3DO20System20Programmers20Guide.659590738/help" title="Discussion / FAQ / Help" accesskey="c">Download & Help</a></span></li>
													</ul>
					</div>
									</div>
				<div id="right-navigation">
										<div id="p-views" role="navigation" class="vectorTabs" aria-labelledby="p-views-label">
						<h3 id="p-views-label">Views</h3>
						<ul>
													
		<li id="ca-view"><span><a href="#">User Manual</a></span></li>

                                                                                                                        <li  class="selected"  id="ca-edit"><span><a href="https://usermanual.wiki/Document/3DO20System20Programmers20Guide.659590738/help" title="Ask a question" accesskey="e">Discussion / Help</a></span></li>

													</ul>
					</div>
									</div>
			</div>
			<div id="mw-panel">
				<div id="p-logo" role="banner"><a class="mw-wiki-logo" href="https://usermanual.wiki/Main_Page" title="Visit the main page"></a></div>
						<div class="portal" role="navigation" id="p-navigation" aria-labelledby="p-navigation-label">
			<h3 id="p-navigation-label">Navigation</h3>

		</div>
			<div class="portal" role="navigation" id="p-tb" aria-labelledby="p-tb-label">


		</div>
				</div>
		</div>
		<div id="footer" role="contentinfo">
							<ul id="footer-info">
											<li id="footer-info-lastmod">© 2024 UserManual.wiki</li>
									</ul>
							<ul id="footer-places">
											<li id="footer-places-privacy"><a href="https://usermanual.wiki/ContactUs" title="UserManual.wiki:Contact Us">Contact Us</a></li>
											<li id="footer-places-about"><a href="https://usermanual.wiki/DMCA" title="UserManual.wiki:DMCA">DMCA</a></li>
									</ul>
										<ul id="footer-icons" class="noprint">
											<li id="footer-poweredbyico">

</li>
									</ul>

		</div>

</div></body></html>
<script src="/cdn-cgi/scripts/7d0fa10a/cloudflare-static/rocket-loader.min.js" data-cf-settings="a48170f9aef4e189de1c5906-|49" defer></script>