ProDOS 8
Comman
GS/OS and ProDOS 8 both have a low-level command interpreter that serves as an
application's gateway to the operating system's commands. (The ProDOS 8 command
interpreter is called the machine language interface or MLI.) Applications call the
interpreter to perform various file-related operations, such as creating, deleting, open-
ing, closing, reading, and writing files.
The command interpreter for GS/OS supports 47 commands, and the one for
ProDOS 8 supports 26. (These totals will undoubtedly increase as Apple releases new
versions of the operating systems.) You invoke these commands from an assembly-
language program in the same general way, using standard calling protocols defined
by Apple. The protocols for GS/OS and ProDOS 8 are structurally similar but not
identical.
In this chapter, we take a close look at the GS/OS and ProDOS 8 MLI commands
and see how to use them in assembly-language programs. In particular, we see how to
z Call specific commands
z Set up command parameter tables
z Identify error conditions
z Interpret error codes
Along the way we look at several brief programming examples which should clarify
how to use operating system commands in your own programs.
71
USING PRODOS 8 MLI COMMANDS
It is very easy to execute a ProDOS 8 MLI command. A typical calling sequence looks
something like this:
[place values in the parameter table
before calling the MLI]
JSR $BF00
DFB CMDNUM
DA PARMTBL
BCS ERROR
[continue your
program here]
RTS
ERROR
[put an error
handler here]
RTS
PARMTBL DFB NPARMS
;$BF00 is the ProDOS 8 MLI entry point
The MLI command number
Address of command parameter table
Carry is set if error occurred
;NPARMS = of parameters in table
[place the rest of the parameters
here in the order the MLI command
expects]
The key instruction here is JSR ~BF00. $BF00 is the address of the entry point to the
ProDOS 8 MLI interpreter in main memory. This interpreter determines what MLI
command the application is requesting and passes control to the appropriate ProDOS
8 subroutine to handle the request.
The flowchart in Figure 4-1 shows what happens when an application executes a
JSR $BF00 instruction. As soon as the MLI takes control, it modifies four important
variables in the ProDOS 8 global page area: MLIACTY' ($BF9B), CMDADR ($BF9C/
$BF9D), SAVEX ($BF9E), and SAVEY ($BF9F). First, it changes bit 7 of MLIAC'IF'
from 0 to 1 so that an interrupt-handling subroutine can determine if the interrupt
condition occurred in the middle of an MLI operation. (We see why it's important to
know this information in Chapter 6.) Next, it saves the current values in the X and Y
registers in SAVEX and SAVEY. Finally, it stores the address of the instruction
immediately following the three data bytes after the JSR $BF00 instruction at CMDADR.
72 GS/OS and ProDOS 8 Commands
Figure 4-1 Flowchart of ProDOS 8 MLI operations
JSR $BF00 Set bit 7 of
Y in SAVEY MLIACTV = $BF9B
CMDADR = $BF9c/$BF9D
Store return SAVEX = $BF 9E
address + 4 SAVEY = $BF9F
in CMDADR
Using ProDOS 8 MLI Commands 73
Control passes to this address after ProDOS 8 executes the MlLI command. (The MLI
modifies the return address that the JSR places on the stack to ensure that control passes
to this address rather than to the address following the JSR $BF00 instruction.)
The MLI determines which command the application is requesting by examining
the value stored in the byte immediately following the JSR $BF00 instruction. This
byte contains the unique identifier code (or command number) associated with the
MLI command. If the MLI encounters an unknown command number, a system error
occurs. (We see how to identify and handle such errors later in this chapter.) Table 4-1
lists all 26 ProDOS 8 commands and command numbers.
The 2 bytes following the command number contain the address (low-order byte
first) of a parameter table the MLI command uses. This table begins with a byte
holding the number of parameters in the table; the rest of the table holds data that the
MLI command requires to process your request. After the MLI executes the com-
mand, the table also holds any results that are returned. We describe the contents of
the parameter table for each MLI command later in this chapter.
The parameters an application passes to a ProDOS 8 MLI subroutine are of two
types: pointers and values. A pointer is a 2-byte quantity that holds the address
(low-order byte first) of a data structure it is said to be pointing to. (Typical data
structures are an I/O buffer or an ASCII pathname preceded by a length byte.) A
value is a 1-, 2-, or 3-byte quantity that holds a binary number. Multibyte values are
always stored with the low-order bytes first.
The parameters returned by an MLI subroutine are called results. A result is
usually a 1-, 2-, or 3-byte numeric quantity (with the low-order bytes first), but it can
also be a 2-byte pointer, depending on the command involved.
If the number at the start of the parameter table does not correspond to the
parameter count expected by the command, a system error occurs. Otherwise, the
MLI proceeds to execute the command.
While a command is being executed, a critical error condition may occur. Critical
errors are very rare and occur only if ProDOS 8 data areas have been overwritten by
a runaway program or if an interrupt occurs and no interrupt handler is available to
deal with it. You cannot recover from such errors without rebooting the system. When
a critical error occurs, the MLI executes a JSR $BF0C instruction. The subroutine at
$BF0C (SYSDEATH) causes the following message to appear:
INSERT SYSTEM DISK AND RESTART -ERR xx
where xx is a two-digit hexadecimal error code. Four error conditions are possible:
01 unclaimed interrupt error
0A volume control block damaged
08 file control block damaged
DC allocation block damaged
74 GS/OS and ProDOS 8 Commands
Table 4-1 The ProDOS 8 MLI commands (in numerical order)
Command Name (number)
ALLOC INTERRUPT ($40)
DEALLOC INTERRUPT ($41)
QUIT ($65)
READ BLOCK ($80)
WRITE BLOCK ($81)
GETTIME ($82)
CREATE ($C0)
DESTROY ($C1)
RENAME ($C2)
SET~FILEINFO ($C3)
GET~FILEINFO ($C4)
ON-LINE ($C5)
SET PREFIX ($C6)
GET PREFIX ($C7)
OPEN ($C8)
NEWLINE ($C9)
READ ($CA)
WRITE ($CB)
CLOSE ($CC)
FLUSH ($CD)
SETH MARK ($CE)
GET MARK ($CF)
Function
Installs an interrupt-handling subroutine
Removes an interrupt-handling subroutine
Transfers control to another system program,
usually through a dispatcher program
Reads a data block from disk
Writes a data block to disk
Reads the current date and time
Creates a directory entry for a new file
Removes the directory entry for an existing file
or subdirectory and frees up the space it uses
on disk
Renames a file
Changes the attributes for a file
Returns the attributes for a file
Determines the name of the volume directory
for a disk
Sets the default pathname prefix
Returns the default pathname prefix
Opens a file for I/O operations
Sets the character that terminates a file read
operation
Reads data from a file
Writes data to a file
Closes a file
Flushes a file buffer
Sets the value of the Mark (position-in-file) pointer
Returns the value of the Mark (position-in-file)
pointer
Using ProDOS 8 MLI Commands 75
Table 4-1 Continued
Command Name (number)
SETEOF ($D0)
GETEOF ($D1)
SETBUF ($D2)
GETBUF ($D3)
Function
Sets the value of the EOF (end-of-file) pointer
Returns the value of the EOF (end-of-file)
pointer
Changes the position of a file buffer
Returns the position of a file buffer
The volume control, file control, and allocation blocks are internal data structures
ProDOS 8 uses to handle disk volumes and to open files.
Normally, the MLI command starts finishing up by restoring the values of the X
and Y registers (from SAVEX and SAVEY) and then, if a system error has occurred
(see the next section), by executing a JSR $BF09 instruction. The subroutine at $BF09
(SYSERR) stores an error code in SERR ($BF0F).
Since the MLI preserves the contents of the X and Y registers, there is no need for
the application to do so.
Finally, control passes to the instruction immediately following the pointer to the
parameter table (BCS ERROR in the above example). Recall that the MLI interpreter
stored this address at CMDADR ($BF9C/$BF9D) when it first took over.
USING GS/OS COMMANDS
The general procedure for calling a GS/OS command is similar to the one for calling a
ProDOS 8 MLI command. It goes something like this:
JSL $E100A8 ;Call GS/OS entry point
DC I2'CommandNum' ;GS/OS command number
DC I4'ParmTable' ;Address of parameter table
BCS Error (Control resumes here after call)
$E100A8 is the address of the GS/OS command interpreter entry point. You can call this
entry point while the IIgs's 65816 microprocessor is in either native or emulation mode.
Immediately following the JSL $E100A8 instruction is a word containing the
identification number of the GS/OS command you wish to use. Table 4-2 lists all the
GS/OS commands and command numbers.
Following the command number is the long address (4 bytes, low-order bytes first) of a
parameter table containing parameters required by the command and spaces for results
returned by the command. The parameters can be one- or two-word numeric values (a
word is 2 bytes) or long pointers (4 bytes) and are stored with the low-order bytes first.
76 GS/OS and ProDOS 8 Commands
Table 4-2 The GS/OS commands (in numerical order)
Command Name (number) Function
Create ($2001)
Destroy ($2002)
OSShutdown ($2003)
ChangePath ($2004)
SetFileInfo ($2005)
GetFileInfo ($2006)
Volume ($2008)
SetPrefix ($2009)
GetPrefix ($200A)
ClearBackup ($200B)
SetSysPrefs ($200C)
Null ($200D)
ExpandPath ($200E)
GetSysPrefs ($200F)
Open ($2010)
Newline ($2011)
Read ($2012)
Write ($2013)
Close ($2014)
Flush ($2015)
SetMark ($2016)
GetMark ($2017)
Creates a directory entry for a new file
Removes the directory entry for an existing file or
subdirectory and frees up the space it uses on disk
Shuts down GS/OS in preparation for a cold reboot or a
power down
Renames a file or moves a file's directory entry to
another subdirectory
Changes the attributes for a file
Returns the attributes for a file
Returns the volume name, total number of blocks on the
volume, number of free blocks on the volume, and the file
system identification number for a given disk device
Sets the pathname prefix for any of the standard GS/OS
prefixes (except */)
Returns the pathname prefix for any of the standard
GS/OS prefixes (except */)
Clears the backup bit in the file's access code byte
Sets system preferences
Executes all queued signals
Creates a full pathname string
Returns system preferences
Opens a file for I/O operations
Sets the character that terminates a file read operation
Reads data from a file
Writes data to a file
Closes a file
Flushes a file buffer
Sets the value of the Mark (position-in-file) pointer
Returns the value of the Mark (position-in-file) pointer
Using GS/OS Commands 77
Table 4-2 Continued
Command Name (number) Function
SetEOF ($2018)
GetEOF ($2019)
SetLevel ($201A)
GetLevel ($201B)
GetDirEntry ($201C)
BeginSession ($201D)
EndSession ($201E)
SessionStatus ($201F)
GetDevNumber ($2020)
Format ($2024)
EraseDisk ($2025)
ResetCache ($2026)
GetName ($2027)
GetBootVol ($2028)
Quit ($2029)
GetVersion ($202A)
GetFSTInfo ($202B)
DInfo ($202C)
DStatus ($202D)
DControl ($202E)
DRead ($202F)
DWrite ($2030)
Sets the value of the EOF (end-of-file) pointer
Returns the value of the EOF (end-of-file) pointer
Sets the value of the system file level
Returns the current value of the system file level
Returns information about the file entries in a directory
Begins a write-deferral session
Ends a write-deferral session
Returns write-deferral session status
Returns the device number for a given device name
Formats a disk and writes out the boot blocks, volume
bit map, and an empty root directory
Writes out the boot blocks, volume bit map, and an
empty root directory to a disk
Resizes the disk cache to the size stored in Battery RAM
Returns the name of the application that is currently
running
Returns the name of the disk GS/OS was booted from;
(this is the name assigned to the boot prefix, */)
Transfers control to another system program, usually
through a dispatcher program
Returns the GS/OS version number
Returns information about a file system translator
Returns the device name corresponding to a given device
number
Returns the status of a device
Sends control commands to a device
Reads data from a device
Writes data to a device
78 GS/OS and ProDOS 8 Commands
Table 4-2 Continued
Command Name (number) Function
BindInt ($2031)
UnbindInt ($2032)
FSTSpecific ($2033)
Installs an interrupt-handling subroutine
Removes an interrupt-handling subroutine
Sends FST-specific commands to a file system
translator
The exact structure of the parameter table varies from command to command, but it
always begins with a parameter count word called pcount. Generally, each GS/OS com-
mand allows a range of values for pcount, giving the application the choice of just how
much information it wants to provide to the command and just how much it wants
returned. The minimum and maximum pcount values for each GS/OS command are in
the descriptions of the command table parameters, which we present later in this chapter.
When a command finishes, GS/OS adds 6 to the return address pushed on the stack
by the JSL instruction and then ends with an RTL instruction. This causes control to
pass to the code beginning just after the pointer to the parameter table. On return, all
registers remain unchanged except the accumulator (which contains an error code),
the program counter (of course), and the status register. (The m, x, D, I, and e flags are
unchanged; N and V are undefined; the carry flag and zero flag reflect the error status.)
At this stage, you can check the state of the carry flag to determine whether an error
occurred: If the carry flag is clear, there was no error; if it is not clear, an error did occur.
Alternatively, you can check the zero flag; if an error occurred, it will be clear.
An error code indicating the nature of the error comes back in the accumulator; the
accumulator will contain 0 if no error occurred. We describe GS/OS and ProDOS 8
error codes in detail in the next section.
The Apple Programmer's Workshop (APW) comes with a set of macros you can use
to make it easier to call GS/OS commands. The macros are stored in a file called
M16.GSOS on the APW disk. To use a GS/OS command with a macro, use an
instruction of the form:
_CmdName ParmTbl
where CmdName represents the name of the command and ParmTbl represents the
address of the parameter table associated with the command. At assembly time, this
macro expands into the standard GS/OS calling sequence.
Note: All the macros for GS/OS commands in the M16.GSOS file have names that
include a GS suffix. The macro for the Open command, for example, is called
OpenGS. The reason for using the suffix is to ensure that the GS/OS macro names
Using GS/OS Commands 79
are different from their ProDOS 16 counterparts, making it possible to develop
programs that use both GS/OS and ProDOS 16 commands. Since it's unlikely
you'd ever want to mix commands, consider editing the M16.GSOS file to remove
the suffixes. That way you won't have to worry about forgetting to include the
suffix. The GS/OS command names used in this book do not include the GS suffix.
The main advantage of using the macros is you do not have to memorize command
numbers, only command names. It also makes assembly-language programs that use
GS/OS much easier to read.
Stack-Based Calling Method
You can also call a GS/OS command using a stack-based command interpreter entry
point at $E 100B0. Here is what such a call looks like:
PushPtr ParmTbl
PushWord #CommandNum
JSL $E100B0
;Push addr of parameter table
Push GS/OS command number
Call stack-based entry point
To use this method, first push the 4-byte address of the command's parameter table
and a 2-byte command number, and then perform a JSL $E100B0 instruction. PushPtr
and PushWord are standard APW macros for doing this.
GS/OS AND PRODOS 8 ERROR HANDLING
Any error that is not a critical error is called a system error. These errors can result for
many reasons: specifying an illegal pathname, writing to a write-protected disk,
opening a nonexistent file, and so on.
If no system error occurred during execution of a command, the accumulator is 0,
the carry flag is clear (0), and the zero flag is set (1).
If an error did occur, the accumulator holds the error code number, the carry flag is
set (1), and the zero flag is clear (0). This means you can use a BCS or a BNE
instruction to branch to the error-handling portion of your code.
You should always check for error conditions when a ProDOS 8 or GS/OS com-
mand ends. If you don't, you will undoubtedly have a program that won't always work
properly. (For example, think of the consequences of writing to a file that could not be
opened because it did not exist.)
For debugging, it is often handy to have a special subroutine available that the
application can call to print out helpful status information when an error occurs. Table
4-3 shows such a subroutine for ProDOS 8. When an application calls it, the message
MLI ERROR $xx OCCURRED AT LOCATION $yyyy
80 GS/OS and ProDOS 8 Commands