Difference between revisions of "P8 Tech Ref"
(New page: {{P8_Tech_Ref_Chapter_1}} {{P8_Tech_Ref_Chapter_2}} {{P8_Tech_Ref_Chapter_3}} {{P8_Tech_Ref_Chapter_4}} {{P8_Tech_Ref_Chapter_5}} {{P8_Tech_Ref_Chapter_6}} {{P8_Tech_Ref_Appendix_A}} {{P8_...) |
|||
| Line 1: | Line 1: | ||
| − | {{P8_Tech_Ref_Chapter_1}} | + | {{:P8_Tech_Ref_Chapter_1}} |
| − | {{P8_Tech_Ref_Chapter_2}} | + | {{:P8_Tech_Ref_Chapter_2}} |
| − | {{P8_Tech_Ref_Chapter_3}} | + | {{:P8_Tech_Ref_Chapter_3}} |
| − | {{P8_Tech_Ref_Chapter_4}} | + | {{:P8_Tech_Ref_Chapter_4}} |
| − | {{P8_Tech_Ref_Chapter_5}} | + | {{:P8_Tech_Ref_Chapter_5}} |
| − | {{P8_Tech_Ref_Chapter_6}} | + | {{:P8_Tech_Ref_Chapter_6}} |
| − | {{P8_Tech_Ref_Appendix_A}} | + | {{:P8_Tech_Ref_Appendix_A}} |
| − | {{P8_Tech_Ref_Appendix_B}} | + | {{:P8_Tech_Ref_Appendix_B}} |
| − | {{P8_Tech_Ref_Appendix_C}} | + | {{:P8_Tech_Ref_Appendix_C}} |
| − | {{P8_Tech_Ref_Appendix_D}} | + | {{:P8_Tech_Ref_Appendix_D}} |
| − | {{P8_Tech_Ref_Index}} | + | {{:P8_Tech_Ref_Index}} |
Revision as of 18:52, 27 September 2007
The ProDOS 8 Technical Reference Manual is identical in content to the previously published ProDOS Technical Reference Manual.
Information in this manual covers ProDOS 8 through 1.1.1. For details on changes to more recent versions, see ProDOS Technical Note #23.
About this Presentation
This document consists of 5 chapters and is presented here in wiki format, due to the technical design of MediaWiki, this document is broken down into it's originally divided chapters. The numbering system on the Wiki will reflect each chapter/section starting with '1.' as no method to specify starting numbers exists in WikiMarkup, only html list items afford this ability at this time. With that, only when viewed using the inline/cascaded Wiki page, will this document flow from Chapter 1-5. The Appendices, however, will be numbered even though all internal references refer to them by letter. This should explain the contradicting chapter/section numbers.
Lastly, you will find references to "Page xx" within this document, this is so that the index may be used and are left in place as a search to position anchor. IE, if you wish to find information on seedling files, you would see in the index, "seedling file ... 19, 156, 160, 161", you would then search for "Page 19", 156, etc. Tip: Search for one page preceding, so you don't have to scroll up.
Preface
The ProDOS Technical Reference Manual is the last of three manuals that describe ProDOS(TM), the most powerful disk operating system available for the Apple II.
The ProDOS User's Manual tells how to copy, rename, and remove ProDOS files using the ProDOS Filer program, and how to move files from DOS disks to ProDOS disks using the DOS-ProDOS Conversion program.
BASIC Programming With ProDOS describes ProDOS to a user of the BASIC system program. It explains how to store information on ProDOS disks and to retrieve information from ProDOS disks using Applesoft BASIC.
This manual, the ProDOS Technical Reference Manual, explains how to use the machine-language routines upon which the Filer program, the DOS-ProDOS Conversion program, and the BASIC system program are based. Appendix A reveals a more technical side of the BASIC system program.
About ProDOS
The set of machine-language routines described in this manual provides a consistent and interruptible interface to any of the disk devices manufactured by Apple Computer, Inc. for the Apple II. They are designed to be used in programs written in the 6502 machine language.
This manual
- describes the files that these routines create and access
- tells how each of the routines is used
- explains how to combine the routines into an application program
- tells how to write and install routines to be used when an interrupt is detected
- tells how to write a routine that automatically reads the date from a clock/calendar card when a file is created or modified
- explains how to attach other devices to ProDOS.
Some advantages of programs written using these ProDOS machine-language routines are:
- They store information on disks using a hierarchical directory structure.
- They are able to access all disk devices manufactured by Apple Computer, Inc. for the Apple II.
- They can read data from a Disk II drive at a rate of approximately eight kilobytes per second (compared to one kilobyte per second for DOS).
- They are interruptible.
- They have the same disk and directory format as Apple III SOS disks.
- Calls to ProDOS are very similar to calls to SOS; programs can be readily developed for both the Apple II and the Apple III. Appendix C explains the similarities and differences between ProDOS and SOS.
About This Manual
Apple II
In this manual the name Apple II implies the Apple II Plus, the Apple IIe, and the Apple IIc, as well as the Apple II, unless it specifically states otherwise.
This manual is written to serve as a learning tool and a reference tool. It assumes that you have had some experience with the 6502 assembly language, and that you are familiar with the Apple II's internal structure.
If you have read BASIC Programming With ProDOS and you want to find out more about how the BASIC system program works, refer first to Appendix A. If you still want more details, Chapters 1 through 3 tell what ProDOS is and how it works. If you plan to write machine-language programs that use ProDOS, you will also need to read Chapters 4 and 5. Chapter 6 shows techniques for adding various devices to the ProDOS system.
This manual does not explain 6502 assembly language. If you plan to read beyond Chapter 3, you should be familiar with the 6502 assembly language and with the ProDOS Editor/Assembler.
What These Mean
By the Way: Text set off in this manner presents sidelights or interesting points of information.
Important!
Text set off in this manner -- and with a tag in the margin -- presents important information.
Warning
Warnings like this indicate potential problems or disasters.
About the Apple IIc Although the Apple IIc has no slots for peripheral cards, it is configured as if it were an Apple IIe with
- 128 Kbytes of RAM
- serial I/O cards in slots 1 and 2
- an 80-column text card in slot 3
- a mouse (or joystick) card in slot 4
- a disk controller (for two disk drives) in slot 6.
Chapter 1 - Introduction
This chapter contains an overview of ProDOS and of the material explained in the rest of this manual. It presents a conceptual picture of the organization and capabilities of ProDOS. It also tells you where in the manual each aspect of ProDOS is explained.
What Is ProDOS?
ProDOS is an operating system that allows you to manage many of the resources available to an Apple II. It functions primarily as a disk operating system, but it also handles interrupts and provides a simple means for memory management. ProDOS marks files with the current date and time, taken from a clock/calendar card if you have one. All ProDOS startup disks have two files in common: PRODOS and XXX.SYSTEM (Chapter 2 explains the possible values for XXX). The file PRODOS contains the ProDOS operating system; it performs most of the communication between a system program and the computer's hardware. The file XXX.SYSTEM contains a system program, the program that usually communicates between the user and the operating system. Figure 1-1 shows a simplified block diagram of the ProDOS system.
------
( User )
------
^
|
v
+------------------+ From File
| System Program | xxx.SYSTEM
+------------------+
^
|
v
+------------------+ From File
| Operating System | PRODOS
+------------------+
^
|
v
+------------------+ Disk Drives,
| Hardware | Memory,
+------------------+ and Slots
A ProDOS system program -- such as the BASIC system program (file BASIC.SYSTEM on the ProDOS BASIC Programming Examples disk), the ProDOS Filer (file FILER on the ProDOS User's Disk), or the DOS-ProDOS Conversion program (file CONVERT on the ProDOS User's Disk) -- is an assembly-language program that accepts commands from a user, makes sure they are valid, and then takes the appropriate action. One course of action is to make a call to the Machine Language Interface (MLI), the portion of the operating system that receives, validates, and issues operating system commands.
Calls to the MLI give you control over various aspects of the hardware. MLI calls can be divided into housekeeping calls, filing calls, memory calls, and interrupt handling calls. The way that the MLI communicates with disk drives, memory, and interrupt driven devices is described in the following sections. Calls to the MLI: see Chapter 4.
About System Programs: If you have dealt with system programs before, you may be a bit confused about the term as used in this manual. True system programs are neither application programs (such as a word processor) nor operating systems: they provide an easy means of making operating system calls from application programs.
As used in this manual, system program refers to a program that is written in assembly language, makes calls to the Machine Language Interface, and adheres to a set of conventions, making it relatively easy to switch from one system program to another. System programs can be identified by their file type.
In short, it is the structure of a program, not its function, that makes a program a ProDOS system program.
The rules for organizing system programs are given in Chapter 5.
Use of Disk Drives
Although ProDOS is able to communicate with several different types of disk drives, the type of disk drive and the slot location of the drive need not be known by the system program: the MLI takes care of such details. Instead disks -- or, more accurately, volumes of information -- are identified by their volume names.
The information on a volume is divided into files. A file is an ordered collection of bytes, having a name, a type, and several other properties. One important type of file is the directory file: a directory file contains the names and location on the volume of other files. When a disk is formatted using the Format a Volume option of the ProDOS Filer program, a main directory file for the volume is automatically placed on the disk. It is called the disk's volume directory file, and it has the same name as the volume itself. Although it is initially empty, a volume directory file has a maximum capacity of 51 files.
Any file in the volume directory may itself be a directory file (called a subdirectory), and any file within a subdirectory can also be a subdirectory. Using directory files, you can arrange your files so that they can be most easily accessed and manipulated. This is especially useful when you are working with large capacity disk drives such as the ProFile. A sample directory structure is shown in Figure 1-2.
Directory structures are described in Chapter 2.
Figure 1-2. A Typical ProDOS Directory Structure
+---------------+
+-----------------+ +-->| VIDEOBALL |
+---->| PROGRAMS/ | | +---------------+
| |-----------------| |
| | VIDEOBALL |--+ +---------------+
| | DISKWARS |----->| DISKWARS |
| | | +---------------+
| +-----------------+
+-----------------+ |
| /PROFILE/ | |
|-----------------| | +---------------+
| PROGRAMS/ |--+ +-----------------+ +-->| MOM |
| LETTERS/ |------->| LETTERS/ | | +---------------+
| SYSTEMPROGRAMS/ |----+ |-----------------| |
| JUNK/ |--+ | | MOM |--+ +---------------+
+-----------------+ | | | DAD |----->| DAD |
| | | SPOT |--+ +---------------+
| | +-----------------+ |
| | | +---------------+
| | +-->| SPOT |
| | +---------------+
| |
| |
| | +---------------+
| | +-----------------+ +-->| BASIC.SYSTEM |
| +-->| SYSTEMPROGRAMS/ | | +---------------+
| |-----------------| |
| | BASIC.SYSTEM |--+ +---------------+
| | FILER |----->| FILER |
| | CONVERT |--+ +---------------+
| +-----------------+ |
| | +---------------+
| +-->| CONVERT |
| +---------------+
|
| +-----------------+
+---->| JUNK |
+-----------------+
The filing calls, described in Chapter 4, provide all functions necessary for the access and manipulation of files.
Volume and File Characteristics
Programs that make filing calls to the ProDOS Machine Language Interface can take advantage of the following features:
- Access to all ProDOS formatted disks; maximum capacity 32 megabytes on a volume.
- Files can be stored in up to 64 levels of readable directory and subdirectory files.
- A volume directory holds up to 51 entries.
- Subdirectories can hold as many files as needed; they become larger as files are added to them.
- There are over 60 distinct file identification codes; some are predefined, others can be defined by the system program. For compatibility, existing file types should be used.
- Up to eight files can be open for access simultaneously.
- A file can hold up to 16 megabytes of data.
- Disks can be accessed by block number as well as by file.
- If the data in a file is not sequential, the logical size of the file can be bigger than the amount of disk space used.
The use of files is described in Chapter 2; their format is given in Appendix B.
Use of Memory
ProDOS treats memory as a sequence of 256-byte pages. It represents the status of each page, used or unused, as a single bit in a portion of memory called the system bit map.
When ProDOS initializes itself, it marks all the pages in memory it needs to protect. Once running, it sets the corresponding bit in the bit map for each new page it uses; when it releases the page, it clears the bit.
If your program allows the user to read information into specific areas of memory, you can use the bit map to prevent ProDOS from overwriting the program.
The arrangement of ProDOS in memory is described in Chapter 3.
Use of Interrupt Driven Devices
Certain devices generate interrupts, signals that tell the controlling computer (in this case an Apple II), that the device needs attention.
ProDOS is able to handle up to four interrupting devices at a time. To add an interrupt driven device to your system:
1. Place an interrupt handling routine into memory. 2. Mark the block of memory as used. 3. Use the MLI call that adds interrupt routines to the system. 4. Enable the device.
This causes the routine to be called each time an interrupt occurs. If you install more than one routine, the routines will be called in the order in which they were installed.
To remove an interrupt handling routine:
1. Disable the device. 2. Unmark its block in memory 3. Use the MLI call that removes interrupt routines from the system.
Warning:
Failure to follow these procedures in sequence may cause system error. The use of interrupt driven devices is described in Chapter 6.
Use of Other Devices
Other than disks, ProDOS communicates only with clock/calendar cards. If your system has a clock/calendar card that follows ProDOS protocols (see Chapter 6), ProDOS automatically sets up a routine so that it can read from the clock before marking files with the time. If you have some other type of clock, you must write your own routine, place it in memory, and tell ProDOS where the routine is located.
Summary
Figure 1-3 illustrates the entire mechanism used by ProDOS and shows the interaction between the levels of ProDOS. A complete ProDOS system consists of the Machine Language Interface, a system program, and some external routines. If you wish your system to operate with interrupt driven devices, a clock/calendar card, or other external devices, you must supply routines that communicate with these devices.
The system program takes commands from the user and issues them to the Command Dispatcher portion of the Machine Language Interface or to independently controlled devices. The Command Dispatcher validates each command before passing it to the Block File Manager (which also manages memory) or to the Interrupt Receiver/Dispatcher. The Block File Manager calls a disk driver routine and the clock/calendar routine if necessary; the Interrupt Receiver/Dispatcher calls the interrupt handling routines.
Figure 1-3. The Levels of ProDOS
------
USER ( User ) IMA.USER
------
^
- - - - - - - - - - - - - - - - - - - - - - - | - - - - - - - - - - - - - - - - - - - - - - - - -
v
+----------------+
USER INTERFACE | System Program | xxx.SYSTEM
+----------------+
^ ^
| \
v \
+------------+ \
- - - - - - - - - - - - - - - - - - - - | Command | - \ - - - - - - - - - - - - - - - - - - - -
| Dispatcher | \
+------------+ \
^ ^ +-------------------+
| | |
+-----------------+ | |
| | |
v v |
+------------+ +---------------------+ | PRODOS
| Block File | | Interrupt | |
OPERATING | Manager | | Receiver/Dispatcher | |
SYSTEM +------------+ +---------------------+ |
^ ^ ^ |
| | +- - - - | - - - - - - - - - - - | - - - - - - - -
v v | v v
+-------------+ +----------------+ | +------------+ +-----------------+
| Disk Driver | | Clock/Calendar | | | Interrupt | | Other Device | User
| Routines | | Routine | | | Routine(s) | | Driver Routines | Installed
+-------------+ +----------------+ | +------------+ +-----------------+
^ ^ | ^ ^
- - - - - - - -|- - - - - - - - - | - - - - - -+- - - - | - - - - - - - - - | - - - - - - - - - -
v v v v
+---------+ +----------------+ +----------------+ +---------------+
HARDWARE | Disk II | | Clock/Calendar | | Interrupt | | Other Devices |
| ProFile | | Card | | Driven Devices | | |
+-----+ | +--------+ | +--------+ | +--------+ |
| | | | | | | |
+---+ +-------+ +-------+ +------+
The following chapters describe the implementation of this mechanism. After reading through Chapter 5, you will be ready to start writing your own system programs. After reading through Chapter 6, you will be able to write your own external routines.
Chapter 2 - File Use
Chapter 1 introduced you to the concepts of volumes and files. This chapter explains how files are named, how they are created and used and a little about how they are organized on disks. When you have finished reading this chapter you will be nearly ready to start using the ProDOS Machine Language Interface filing calls.
The technical details of file organization are given in Appendix B.
Using Files
A ProDOS filename or volume name is up to 15 characters long. It may contain capital letters (A-Z), digits (0-9), and periods (.), and it must begin with a letter. Lowercase letters are automatically converted to uppercase. A filename must be unique within its directory. Some examples are
By the Way: On the Apple II, an ASCII character is read from the keyboard and printed to the screen with its high bit set. ProDOS clears this high bit.
Pathnames
A ProDOS pathname is a series of filenames, each preceded by a slash (/). The first filename in a pathname is the name of a volume directory. Successive filenames indicate the path, from the volume directory to the file, that ProDOS must follow to find a particular file. The maximum length for a pathname is 64 characters, including slashes. Examples are
All calls that require you to name a file will accept either a pathname or a partial pathname. A partial pathname is a portion of a pathname that doesn't begin with a slash or a volume name. The maximum length for a partial pathname is 64 characters, including slashes. These partial pathnames are all derived from the sample pathnames above.
The partial pathnames are
ProDOS automatically adds the prefix to the front of partial pathnames to form full pathnames. The prefix is a pathname that indicates a directory; it is internally stored by ProDOS. To locate a file by its pathname, ProDOS must look through each file in the path. If you specify a partial pathname, however, ProDOS jumps straight to the prefix directory and starts searching from there. Thus disk accesses are faster when you set the prefix and use partial pathnames.
For the partial pathnames listed above to indicate valid files, the prefix should be set to /PROFILE/GAMES/, /PROFILE/, /PROFILE/, and /PROFILE/SYSTEMPROGRAMS/, respectively. The slashes at the end of these prefixes are optional; however, they are convenient reminders that prefixes indicate directory files.
The maximum length for a prefix is 64 characters. The minimum length for a prefix is zero characters, known as a null prefix. You set and read the prefix using the MLI calls, SET_PREFIX and GET_PREFIX, respectively. The 64 character limits for the prefix and partial pathname combine to create a maximum pathname of 128 characters.
Figure 2-1 illustrates a typical directory structure; it contains all the files mentioned above.
Figure 2-1. A Typical ProDOS Directory Structure
+---------------+
+-----------------+ +-->| VIDEOBALL |
+---->| PROGRAMS/ | | +---------------+
| |-----------------| |
| | VIDEOBALL -|--+ +---------------+
| | DISKWARS -|----->| DISKWARS |
| | | +---------------+
| +-----------------+
+-----------------+ |
| /PROFILE/ | |
|-----------------| | +---------------+
| PROGRAMS/ |--+ +-----------------+ +-->| MOM |
| LETTERS/ |------->| LETTERS/ | | +---------------+
| SYSTEMPROGRAMS/ |----+ |-----------------| |
| JUNK/ |--+ | | MOM -|--+ +---------------+
+-----------------+ | | | DAD -|----->| DAD |
| | | SPOT -|--+ +---------------+
| | +-----------------+ |
| | | +---------------+
| | +-->| SPOT |
| | +---------------+
| |
| |
| | +---------------+
| | +-----------------+ +-->| BASIC.SYSTEM |
| +-->| SYSTEMPROGRAMS/ | | +---------------+
| |-----------------| |
| | BASIC.SYSTEM -|--+ +---------------+
| | FILER -|----->| FILER |
| | CONVERT -|--+ +---------------+
| +-----------------+ |
| | +---------------+
| +-->| CONVERT |
| +---------------+
|
| +-----------------+
+---->| JUNK |
+-----------------+
Creating Files
A file is placed on a disk by the CREATE call. When you create a file, you assign it the following properties:
- A pathname. This pathname is a unique path by which the file can be identified and accessed. This pathname must place the file within an existing directory.
- An access byte. The value of this byte determines whether or not the file can be written to, read from, destroyed, or renamed.
- A file_type. This byte indicates to other system programs the type of information to be stored in the file. It does not affect, in any way, the contents of the file.
- A storage_type. This byte determines the physical format of the file on the disk. There are only two different formats: one is used for directory files, the other for non-directory files.
- A creation_date and a creation_time.
When you create a file, these properties are placed on the disk. The file's name can be changed using the RENAME call; other properties can be altered using the SET_FILE_INFO call. The disk storage format of these properties is given in Appendix B.
Once a file has been created, it remains on the disk until it is destroyed (using the DESTROY call).
Opening Files
Before you can read information from or write information to a file you must use the OPEN call to open the file for access. When you open a file you specify:
- A pathname. This pathname must indicate a previously created file that is on a disk mounted in a disk drive.
- The starting address in memory of an I/O buffer. Each open file requires its own 1024-byte buffer for the transfer of information to and from the file.
The OPEN call returns a reference number (ref_num). All subsequent references to the open file must use this reference number. The file remains open until you use the CLOSE call.
Each open file's I/O buffer is used by the system the entire time the file is open. Thus it is wise to keep as few files open as possible. A maximum of eight files can be open at a time.
When you open a file, some of the file's characteristics are placed into a region of memory called a file control block. Several of these characteristics -- the location in memory of the file's buffer, a pointer to the end of the file (the EOF), and a pointer to the current position in the file (the file's MARK) -- are accessible to system programs via MLI calls, and may be changed while the file is open.
It is important to be aware of the differences between a file on the disk and an open file in memory. Although some of the file's characteristics and some of its data may be in memory at any given time, the file itself still resides on the disk. This allows ProDOS to manipulate files that are much larger than the computer's memory capacity. As a system program writes to the file and changes its characteristics, new data and characteristics are written to the disk.
Warning
In is crucial that you close all files before turning off the computer or pressing [CONTROL]-[RESET]. This is the only way than you can ensure that all written data has been placed on the disk. See also the FLUSH call.
The EOF and MARK
To aid the tasks of reading from and writing to files, each open file has one pointer indicating the end of the file, the EOF, and another defining the current position in the file, the MARK. Both are moved automatically by ProDOS, but can also be independently moved by the system program.
The EOF is the number of readable bytes in the file. Since the first byte in a file has number 0, the EOF, when treated as a pointer, points one position past the last character in the file.
When a file is opened, the MARK is set to indicate the first byte in the file. In is automatically moved forward one byte for each byte written to or read from the file. The MARK, then, always indicates the next byte to be read from the file, or the next byte position in which to write new data. It cannot exceed the EOF.
Page 14
If during a write operation the MARK meets the EOF both the MARK and the EOF are moved forward one position for every additional byte written to the file. Thus, adding bytes to the end of the file automatically advances the EOF to accommodate the new information. Figure 2-2 illustrates the relationship between the MARK and the EOF.
Figure 2-2. Automatic Movement of EOF and MARK
EOF EOF Old EOF EOF
| | \ |
v v v v
+---------+ + +---------+ + +------------ +
| | | | | | | | | | | | | | | | | | | | | |
+---------+ + +---------+ + +------------ +
^ ^ ^ ^ ^
| | | | |
MARK Old MARK MARK Old MARK MARK
Beginning Position After Reading Two Bytes After Writing Two Bytes
A system program can place the EOF anywhere, from the current MARK position to the maximum possible byte position. The MARK can be placed anywhere from the first byte in the file to the EOF. These two functions can be accomplished using the SET_EOF and SET_MARK calls. The current values of the EOF and the MARK can be determined using the GET_EOF and GET_MARK calls.
Reading and Writing Files
READ and WRITE calls to the MLI transfer data between memory and a file. For both calls, the system program must specify three things:
- The reference number of the file (assigned when the file was opened).
- The location in memory of a buffer (data_buffer) that contains, or is to contain, the transferred data. Note that this cannot be the same buffer that was specified when the file was opened.
- The number of bytes to be transferred.
When the request has been carried out, the MLI passes back to the system program the number of bytes that it actually transferred. Page 15
A read or write request starts at the current MARK, and continues until the requested number of bytes has been transferred (or, on a read, until the end of file has been reached). Read requests can also terminate when a specified character is read. You turn on this feature and set the character(s) on which reads will terminate using the NEWLINE call. It is typically used for reading lines of text that are terminated by carriage returns.
By the Way: Neither a READ nor a WRITE call necessarily causes a disk access. It is only when a read or write crosses a 512-byte (block) boundary that a disk access occurs.
Closing and Flushing Files
When you finish reading from or writing to a file, you must use the CLOSE call to close the file. When you use this call, you specify * the reference number of the file (assigned when the file was opened).
CLOSE writes any unwritten data to the file, and it updates the file's size in the directory, if necessary. Then it frees the 1024-byte io_buffer for other uses and releases the file's reference number. Information in the file's directory, such as the file's size, is normally updated only when the file is closed. If you were to press [CONTROL]-[RESET] (typically halting the current program) while a file is open, data written to the file since it was opened could be lost and the integrity of the disk could be damaged. This can be prevented by using the FLUSH call. To use FLUSH you specify * the reference number of the file (assigned when the file was opened).
If you press [CONTROL]-[RESET] while an open but flushed file is in memory, there is no loss of data and no damage to the disk.
Both the CLOSE and FLUSH calls, when used with a reference number of 0, normally cause all open files to be closed or flushed. Specific groups of files can be closed or flushed using the system level. Page 16
File Levels
When a file is opened, it is assigned a level, according to the value of a specific byte in memory (the system level). If the system level is never changed, the CLOSE and FLUSH calls, when used with a reference number of 0, cause all open files to be closed or flushed. But if the level has been changed since the first file was opened, only the files having a file level greater than or equal to the current system level are closed or flushed.
The system level feature is used, for example, by the BASIC system program to implement the EXEC command. An EXEC file is opened with a level of 0, then the level is set to 7. A BASIC CLOSE command (intended to close all files opened within the EXEC program) closes all files at or above level 7, but the EXEC file itself remains open.
File Organization
This portion of the chapter describes in general terms the organization of files on a disk. It does not attempt to teach you everything about file organization: its purpose is to familiarize you with the terms and concepts required by the filing calls.
Appendix B elaborates on the subject of file organization.
Directory Files and Standard Files
Every ProDOS file is a named, ordered sequence of bytes that can be read from, and to which the rules of MARK and EOF apply. However, there are two types of files: directory files and standard files. Directory files are special files that describe and point to other files on the disk. They may be read from, but not written to (except by ProDOS). All nondirectory files are standard files. They may be read from and written to.
A directory file contains a number of similar elements, called entries. The first entry in a directory file is the header entry: it holds the name and other properties (such as the number of files stored in that directory) of the directory file. Each subsequent entry in the file describes and points to some other file on the disk. Figure 2-3 represents the structure of a directory file.
Page 17
Figure 2-3. Directory File Structure
Directory File Other Files +--------------+ +--------------+ | | +---->| File | | Header Entry | | +--------------+ | | | |--------------| | +--------------+ | | | +-->| File | | Entry -|--+ | +--------------+ | | | |--------------| | | -|----+ | -|---> | More Entries-|--> | -|---> +--------------+ | -|------->| File | |--------------| +--------------+ | | | Entry -|---+ +--------------+ | | +--->| File | |--------------| +--------------+ | | | Entry -|---+ +--------------+ | | +--->| File | +--------------+ +--------------+
The files described and pointed to by the entries in a directory file can be standard files or other directory files. A system program does not need to know the details of directory structure to access files with known names. Only operations on unknown files (such as listing the files in a directory) require the system program to examine a directory's entries. For such tasks, refer to Appendix B.
Standard files have no such predefined internal structure: the format of the data depends on the specific file type.
File Structure
Because directory files are generally smaller than standard files, and because they are sequentially accessed, ProDOS uses a simpler form of storage for directory files. Both types of files are stored as a set of 512-byte blocks, but the way in which the blocks are arranged on the disk differs.
A directory file is a linked list of blocks: each block in a directory file contains a pointer to the next block in the directory file as well as a pointer to the previous block in the directory. Figure 2-4 illustrates this structure.
Page 18
Figure 2-4. Block Organization of a Directory File
+------------+ +------------+ +------------+ | Key Block |<------| |<-...<-| Last Block | | |------>| |->...->| | | | | | | | | | | | | | | | | | | | +------------+ +------------+ +------------+
Data files, on the other hand, are often quite large, and their contents may be randomly accessed. It would be very slow to access such large files if they were organized sequentially. Instead ProDOS stores standard files using a tree structure. The largest possible standard file has a master index block that points to 128 index blocks. Each index block points to 256 data blocks and each data block can hold 512 bytes of data. The block organization of the largest possible standard file is shown in Figure 2-5.
Figure 2-5. Block Organization of a Standard File
+---------------------+
| Master Index |
| Block |
+---------------------+
| | | | | | | | | | |
| v v v v | v v v v |
+----------+ | +----------+
| | |
v v v
+-------------+ +-------------+ +-------------+
| Index | | Index | | Index |
| Block 0 | | Block n | | Block 127 |
+-------------+ +-------------+ +-------------+
| | | | | | | | | | | | | | | | | |
| v v v v | | v v v v | | v v v v |
| | | | | |
v v v v v v
+-------+ +-------+ +-------+ +-------+ +-------+ +-------+
| Data | | Data | | Data | | Data | | Data | | Data |
| Block | | Block | | Block | | Block | | Block | | Block |
| 0 | | 255 | | 0 | | 255 | | 0 | | 255 |
+-------+ +-------+ +-------+ +-------+ +-------+ +-------+
Most standard files do not have this exact organization. ProDOS only writes a subset of this structure to the file, depending on the amount of data written to the file. This technique produces three distinct forms of standard file: seedling, sapling, and tree files.
Appendix B describes the three forms of standard file.
Page 19
Sparse Files
In most instances a program writes data sequentially into a file. By writing data, moving the EOF and MARK, and then writing more data, a program can also write nonsequential data to a file. For example, a program can open a file, write ten characters of data, and then move the EOF and MARK (thereby making the file bigger) to $3FE0 before writing ten more bytes of data. The file produced takes up only three blocks on the disk (a total of 1536 bytes), yet over 16,000 bytes can be read from the file. Such files are known as sparse files.
Important!
The fact that more data can be read from the file than actually resides on the disk can cause a problem. Suppose that you were trying to copy a sparse file from one disk to another. If you were to read data from one file and write it to another, the new file would be much larger than the original because data that is not actually on the disk can be read from the file. Thus if your system program is going to transfer sparse files, you must use the information in Appendix B to determine which data segments should be copied, and which should not.
The ProDOS Filer automatically preserves the structure of sparse files on a copy.
Page 20
Chapter 3 - Memory Use
Page 21
This chapter explains the way the Machine Language Interface uses memory. It tells how much memory system programs have available to them, how system programs should manage this free memory, and it discusses the contents of important areas of memory while ProDOS is inn use.
Loading Sequence
When you start up your Apple II from a ProDOS startup disk -- one that contains both the MLI (ProDOS) and a system program (XXX.SYSTEM) -- a complex loading sequence is initiated.
A preliminary loading program is stored in the read-only memory (boot ROM) on a disk drive's controller card; the main part of the loader program, as it is called, resides in blocks 0 and 1 of every ProDOS-formatted disk.
When you turn on your computer, or use a PR# or IN# command to reference a disk drive from Applesoft, or otherwise transfer control to the ROM on the disk-drive controller card when a ProDOS startup disk is in the drive, this is what happens:
1. The program in the ROM reads the loader program from blocks 0 and 1 of the disk, places it into memory starting at location $800, and then executes it.
2. This loader program looks for the file with the name PRODOS and type $FF (containing the MLI) in the volume directory of the startup disk, loads it into memory starting at location $2000, and executes it.
3. The MLI ascertains the computer's memory size and moves itself to its final location, as shown in Figure 3-1. Next it determines what devices are in what slots and it sets up the system global page, described in the section "The System Global Page," for this system configuration.
4. The MLI then searches the volume directory of the boot disk for the first file with the name XXX.SYSTEM and type $FF, loads it into memory starting at $2000, and executes it.
If PRODOS cannot be found, the loader reports to the user that it is unable to load ProDOS. If no XXX.SYSTEM program is found, ProDOS displays the message UNABLE TO FIND A SYSTEM FILE.
The rules for system programs are described in Chapter 5.
Page 22
The MLI is entirely memory resident. Once it is in memory, it neither
moves, nor does it require any additional disk accesses (although the
system program might). The memory configuration that results from
this loading process is described in the section "Memory Map."
Volume Search Order
When a program or user requests access to a volume that ProDOS has not yet accessed, it must search through the volumes that are currently online for the requested volume. The order in which it searches the devices is determined during step 3 above.
The first volume checked is /RAM, if present, then the startup volume (generally slot 6, drive 1). The search then checks slots in descending slot order, starting with slot 7. In any slot, drive 1 is searched before drive 2.
For example, if there are two Disk II drives in slot 6, two Disk II drives in slot 5, and a ProFile in slot 7, the search order is:
/RAM
Slot 6, drive 1
Slot 6, drive 2
Slot 7
Slot 5, drive 1
Slot 5, drive 2
The startup volume is the volume in the highest numbered slot that can be identified by the system as a startup volume. This sequence is kept in the device list in the ProDOS global page and can be altered.
Note: If the startup volume is a hard disk, the search order is from slot 7 to slot 1.
Memory Map
ProDOS requires at least 64 kilobytes of memory. Figure 3-1 is the ProDOS memory map.
Page 23
Figure 3-1. Memory Map
Main Memory Auxiliary Memory
(IIc or 128K IIe only)
$FFFF+---------+$FFFF+---------+ $FFFF+---------+
|.Monitor.| |#########| |.........|
$F800|---------| |#########| |.........|
|.........| |#########| |.........|
|.........| |#########| |.........|
|.........| |#########| |.........|
|.........| |#########| |.........|
|.........| |#########| |.........|
|.........| |#ProDOS##| |.........|
|Applesoft| |#########|$DFFF+---------+$E000|---------|$DFFF+---------+
|.........| |#########| |.........| | | |.........|
|.........| |#########| |.........| | | |.........|
|.........| |#########|$D400|---------| | | |.........|
|.........| |#########| |#########| | | |.........|
|.........| |#########|$D100|---------| | |$D100|---------|
|.........| |#########| | | | | | |
$D000|---------| +---------+ +---------+$D000+---------+ +---------+
|..Other..|
$C100+---------+
^ $BFFF+---------+ $BFFF+---------+
| |#########| |.........|
This ROM area| $BF00|---------| $BF00|---------|
on IIc and IIe |\\\\\\\\\| | |
only! |\\\\\\\\\| | | +---------+
|\\\\\\\\\| | | |#########|
|\\\\\\\\\| | | +---------+
|\\\\\\\\\| | | Used by ProDOS
|\BASIC.\\| | |
|\SYSTEM\\| | |
|\\\\\\\\\| | | +---------+
|\\\\\\\\\| | | |\\\\\\\\\|
|\\\\\\\\\| | | +---------+
|\\\\\\\\\| | | Used by
|\\\\\\\\\| | | BASIC.SYSTEM
$9600|---------| | |
| | | |
| | | | +---------+
| | | | |.........|
| | | | +---------+
| | | | Other used or
| | | | reserved areas
| | | |
| | | |
| | | | +---------+
| | | | | |
| | | | +---------+
| | | | Free Space
| | | |
/\/\/\/\/\/ /\/\/\/\/\/
/\/\/\/\/\/ /\/\/\/\/\/
| | | |
| | | |
| | | |
| | | |
| | | |
$800|---------| $800|---------|
|.........| |.........|
|.........| |.........|
|.........| |.........|
|.........| $400|---------|
|.........| |#########|
$300|---------| |#########|
| | |#########|
$300|---------| |#########|
|.........| $200|---------|
|.........| | |
$100|---------| $100|---------|
| | |#########|
| | $80|---------|
$4F|---------| | |
|#Shared/#| | |
|####safe#| | |
$3A|---------| | |
| | | |
+---------+ +---------+
$00
Page 24
A system program as large as $8F00 (36608) bytes can be loaded into a
64K system. The total amount of space available to a system program
running on a 64K system is $B700 (46848) bytes.
Zero Page
The ProDOS Machine Language Interface uses zero-page locations $40-$4E, but it restores them before it completes a call. The disk-driver routines, called by the MLI, use locations $3A through $3F. These locations are not restored. See Chapter 4 for details.
The System Global Page
The $BF-page of memory, addresses $BF00 through $BFFF, contains the system's global variables. This section of memory is special because no matter what system ProDOS is booted on, the global page is always in the same location. Because of this it serves as the communication link between system programs and the operating system. The MLI places all information that might be useful to a system program in these locations. These locations are defined and described in Chapter 5.
The System Bit Map
ProDOS uses a simple form of memory management that allows it to protect itself and the user's data from being overwritten by ProDOS buffer allocation. It represents the lower 48K of the Apple II's random-access memory using twenty-four bytes of the system global page: one bit for each 256-byte page of RAM in the lower 48K of the Apple II. These twenty-four bytes are called the system bit map.
When ProDOS is started up, it protects the zero page, the stack, and the global page, by setting the bits that correspond to the used pages. If at all possible, a system program should not use pages of memory that are already used. If this is not possible, the system program must close all files and clear the bit map, leaving pages 0, 1, 4 through 7, and BF (zero page, stack, text, and ProDOS global page) protected. If an error occurs on the close, the program should ask the user to restart the system. See Chapter 5 for details.
Page 25
While a system program is using the MLI, there are only three calls
that affect the setting of the bit map: OPEN, CLOSE, and SET_BUF.
When the system program opens a file, it must specify the starting
address of a 1024-byte file buffer. As long as the file is open, this
buffer is a part of the system, and is marked off in the bit map. When
the file is closed, the buffer is released, and its bits are cleared.
In general, a system program requires the used pages of memory to be
contiguous, or touching. This leaves the maximum possible unbroken
memory space for the reading and manipulation of data. Suppose a
system program opens several files and then closes the one that was
opened first. In most cases, this causes a vacant 1K area to appear.
The GET_BUF and SET_BUF calls can be used to find this vacant
area, and to move another file's buffer into this space.
Refer to Chapter 5 for a specific example of using the system bit map.
Page 26 P8 Tech Ref Chapter 4
Chapter 5 - Writing a ProDOS System Program
Page 81
This chapter is about writing system programs that use the ProDOS MLI. It first explains the things that a program must do to qualify as a system program. Next it discusses some of the things that a system program must be aware of, particularly how it should use memory. The end of the chapter contains several programming hints.
System Program Requirements
A ProDOS system program is any program that makes calls to the ProDOS MLI and that adheres to a set of standard system program rules. Each system program must have * code to move the program from its load position to its final execution location, if necessary * a version number in the system global page * the ability to switch to another system program. All other aspects of the system program are up to you.
Placement in Memory
System programs are always loaded into memory starting at location $2000. When the system is first started up, the system program used is the first file on the startup disk with the name XXX.SYSTEM, and the $FF filetype. When one system program switches to another, it can load any file of type $FF. Figure 5-1 shows the portions of memory that are available to system programs. If BASIC is not being used, the area assigned to BASIC.SYSTEM (the BASIC command interpreter) is also available. A system program as large as $8F00 (36608) bytes can be loaded. The total space available to a system program is $B700 (46848) bytes. Page 82
Figure 5-1. Memory Map
Main Memory Auxiliary Memory
(IIc or 128K IIe only)
$FFFF+---------+$FFFF+---------+ $FFFF+---------+
|.Monitor.| |#########| |.........|
$F800|---------| |#########| |.........|
|.........| |#########| |.........|
|.........| |#########| |.........|
|.........| |#########| |.........|
|.........| |#########| |.........|
|.........| |#########| |.........|
|.........| |#ProDOS##| |.........|
|Applesoft| |#########|$DFFF+---------+$E000|---------|$DFFF+---------+
|.........| |#########| |.........| | | |.........|
|.........| |#########| |.........| | | |.........|
|.........| |#########|$D400|---------| | | |.........|
|.........| |#########| |#########| | | |.........|
|.........| |#########|$D100|---------| | |$D100|---------|
|.........| |#########| | | | | | |
$D000|---------| +---------+ +---------+$D000+---------+ +---------+
|..Other..|
$C100+---------+
^ $BFFF+---------+ $BFFF+---------+
| |#########| |.........|
This ROM area| $BF00|---------| $BF00|---------|
on IIc and IIe |\\\\\\\\\| | |
only! |\\\\\\\\\| | | +---------+
|\\\\\\\\\| | | |#########|
|\\\\\\\\\| | | +---------+
|\\\\\\\\\| | | Used by ProDOS
|\BASIC.\\| | |
|\SYSTEM\\| | |
|\\\\\\\\\| | | +---------+
|\\\\\\\\\| | | |\\\\\\\\\|
|\\\\\\\\\| | | +---------+
|\\\\\\\\\| | | Used by
|\\\\\\\\\| | | BASIC.SYSTEM
$9600|---------| | |
| | | |
| | | | +---------+
| | | | |.........|
| | | | +---------+
| | | | Other used or
| | | | reserved areas
| | | |
| | | |
| | | | +---------+
| | | | | |
| | | | +---------+
| | | | Free Space
| | | |
/\/\/\/\/\/ /\/\/\/\/\/
/\/\/\/\/\/ /\/\/\/\/\/
| | | |
| | | |
| | | |
| | | |
| | | |
$800|---------| $800|---------|
|.........| |.........|
|.........| |.........|
|.........| |.........|
|.........| $400|---------|
|.........| |#########|
$300|---------| |#########|
| | |#########|
$300|---------| |#########|
|.........| $200|---------|
|.........| | |
$100|---------| $100|---------|
| | |#########|
| | $80|---------|
$4F|---------| | |
|#Shared/#| | |
|####safe#| | |
$3A|---------| | |
| | | |
+---------+ +---------+
$00
Page 83
Relocating the Code
The final execution location(s) to which you can relocate your code depends on your system configuration. The memory locations $0800 through $BEFF are available to system programs.
Updating the System Global Page
The MLI global page resides in locations $BF00 through $BFFF. These are the locations whose values you must set: $BF58-$BF6F - The system bit map. $BFFD - The version number of your system program. In addition, there is other information in the global page that your program might find useful. These values are documented in the section "The System Global Page."
The System Bit Map
The system bit map occupies bytes $BF58 through $BF6F in the system global page and it represents the status of each 256-byte page of memory from $0000 through $BFFF, as shown in Figure 5-2.
Figure 5-2. Memory Representation in the System Bit Map
Bit Map Address Pages Represented
_____________
$BF58-$BF5F |_|_|_|_|_|_|_| $00-$3F
$BF60-$BF67 |_|_|_|_|_|_|_| $40-$7F
$BF68-$BF6F |_|_|_|_|_|_|_| $80-$BF
Within each byte, the bits are used in reverse order. Thus, bit 7 of byte $BF58 represents the first 256 bytes of memory, and bit 0 of byte $BF6F represents the last page before $C000.
You may have noticed that neither the Language Card area of memory nor the extended memory of an Apple IIe or Apple IIc is included in this map. This is because these regions of memory cannot be directly accessed by the MLI. You cannot read data into or out of these areas, and you cannot execute MLI calls from them. More information is given in this chapter in the sections "Using the Language Card" and "Using the Alternate 64K RAM Bank."
Page 84
Using the Bit Map
There are twenty-four bytes in the bit map: the high five bits of an address select which of these bytes contains a given page. Each byte represents eight 256-byte pages; the next three bits of an address form the complement of the bit number within that byte. Thus for page $00 in memory, the high five bits are zero: byte 0 of the bit map contains that page. The next three bits are zero, the complement of 000 (binary) is 111 (binary): bit 7 within byte zero contains that page. Figure 5-3 shows this relationship.
Figure 5-3. Page Number to Bit-Map Bit Conversion
BIT 7 6 5 4 3 2 1 0
+---------------------------------------------+
| Byte in Bit Map | Complement |
PAGE # | (only 0 through 23 valid) | of Bit in Byte |
+---------------------------------------------+
Here is a short routine that accepts the high byte of an address in the Accumulator. It returns with the carry clear if the memory page is free; the carry is set if the page is already used (or if the page is in the Language Card). It destroys the values in the A, X, and Y registers.
------------------------------------------------------------------------
SOURCE FILE #01 =>PFREE 0000: BF58 1 BITMAP EQU $BF58 ;the system bit map 0000: 2 * 0000: 0000 3 PFREE EQU * 0000:C9 C0 4 CMP #$C0 ;in language card? 0002:B0 17 001B 5 BCS NOTFREE ;yes, it's protected 0004:AA 6 TAX ;save page for bit in page 0005:4A 7 LSR A ;move byte number to right 0006:4A 8 LSR A 0007:4A 9 LSR A 0008:A8 10 TAY ;save byte number 0009:8A 11 TXA ;get bit in byte 000A:29 07 12 AND #$7 ;mask off byte number 000C:AA 13 TAX ;and save bit in byte 000D:A9 80 14 LDA #$80 ;bit 7 set for bit 0 in byte 000F:CA 15 LOOP DEX ;done shifting? 0010:30 04 0016 16 BMI CHKBIT ;yes, check bit value 0012:4A 17 LSR A ;else shift again 0013:4C 0F 00 18 JMP LOOP ;and continue 0016:39 58 BF 19 CHKBIT AND BITMAP,Y ;is selected bit set? 0019:F0 02 001D 20 BEQ ISFREE ;nope, page is free 001B:38 21 NOTFREE SEC ;flag page not free 001C:60 22 RTS 001D:18 23 ISFREE CLC ;page is free 001E:60 24 RTS
------------------------------------------------------------------------
Page 85
Switching System Programs
All system programs must use a standard way of starting and quitting.
Starting System Programs
System programs are started in one of two ways:
- The disk containing ProDOS and the system program is started up;
ProDOS loads and runs the first XXX.SYSTEM file of type SYS($FF).
The order of search is determined by the file entries in the startup volume directory.
- The program is loaded by another program (such as the ProDOS
FILER or the BASIC.SYSTEM) or by a program dispatcher or selector.
The system program is loaded and jumped to at $2000. The complete or partial pathname of the system program is stored at $280, starting with a length byte. The string is a full pathname if it starts with a slash. It is a partial pathname if it starts with a letter.
This pathname allows a system program to determine the directory where other needed files may reside. The program should never assume that the files are in a specific directory or subdirectory.
There is a way to pass a second pathname to interpreters -- for example, to language interpreters -- that like to run startup programs.
The ProDOS dispatcher does not support this mechanism but other more sophisticated program selectors may. It requires that the interpreter start a certain way:
$2000 is a jump instruction. $2003 and $2004 are $EE.
If the interpreter starts this way, byte $2005 is assumed to indicate the length of a buffer that starts at $2006 and holds the pathname (starting with a length byte) of the startup file.
Interpreters that support this mechanism should supply their own default string, which should be a standard choice for a startup program or a flag not to run a startup program.
Once gaining control, the system program sets the reset vector and fixes the power-up byte. Never assume the state of the machine to be anything that is not clearly documented.
Page 86
Important!
If your interpreter uses any location in the range $D100-$DFFF (the
dispatcher/selector area) in the second 4K bank of RAM, be sure that
the area is initially saved and then restored on exit.
Quitting System Programs
Here is how to quit system programs: 1. Do normal housekeeping. Close files, reinstall /RAM if you have disconnected it, and so on.
2. Invalidate the power-up byte at $3F4. The simplest way is either to increment or to decrement it, which will always make it an invalid check of the $3F2 vector.
3. Execute a ProDOS system call number $65 as follows:
EXIT JSR PRODOS ;Call the MLI ($BF00)
DFB $65 ;CALL TYPE = QUIT
DW PARMTABLE ;Pointer to parameter table
PARMTABLE DFB 4 ;Number of parameters is 4
DFB 0 ;0 is the only quit type
DW 0000 ;Pointer reserved for future use
DFB 0 ;Byte reserved for future use
DW 0000 ;Pointer reserved for future use
Even though most of the parameter table is reserved for future use it must all be present. It must consist of seven bytes: $04 followed by six nulls ($00).
ProDOS MLI call $65, the QUIT call, moves addresses $D100 through $D3FF from the second 4K bank of RAM of the language card to $1000, and executes a JMP to $1000. What initially resides in that area is Apple's dispatcher code.
The dispatcher, once executed, does the following: 1. Allows the user to enter the prefix and filename of the system program (interpreter) to be executed.
2. Stores the system program name at $280, starting with a length byte. Once the system program executes, it can find from where it was starred, and locate any files it needs for processing.
3. Closes any open files.
4. Clears the bit map, and protects the zero, stack, text, and ProDOS global pages.
5. Reads in the system file at $2000, and executes a JMP to $2000.
Page 87
To install your own QUIT code that loads your own selector program,
you must, at some point, store the system program name at $280, close
open files, clear the bit map, and protect the zero, stack, text, and
ProDOS global pages, as described above. In addition, the $D100 byte
must be a CLD ($D8) instruction, so that programs can tell whether
selector code or the ProDOS dispatcher code is resident.
In addition to just leaving the pathname at $280 for the interpreter's use, a method to enable a selector program to specify an accompanying startup program has been defined. Once active, an interpreter can immediately run that program. This involves reserving an area in the system file, which a selector program overwrites with the startup program's name. The interpreter then loads and executes that specified program.
Here is how the procedure works: the selector program looks at the first byte of the interpreter at $2000. If it is a JMP ($4C) instruction, and bytes $2003 and $2004 are both $EE, then byte $2005 is interpreted as a buffer size indicator with the buffer starting at $2006.
The string at $2006 would be the normal ProDOS pathname or partial pathname, starting with a length byte.
Byte Content
$2000-$2002 JMP CONT $2003 $EE $2004 $EE $2005 $41 $2006 $07 $2007-$200D Startup Code . . . $2047 CONT . . .
The two $EEs let the selector program know that this particular interpreter can run a startup program. The interpreters that support this feature will supply their own default string, which may be a startup program or a flag of your choice.
Page 88
Managing System Resources
This section describes the interaction between ProDOS and the various parts of memory.
Using the Stack
In the Apple II, the stack is stored in page $01 of memory, from the high byte of the page going down. When an interrupt occurs, the interrupt handler saves the low 16 bytes of the stack, but only if the stack is more than 3/4 full. For maximum interrupt efficiency, a system program should not use more than the upper 3/4 of the stack.
System programs should set the stack pointer to $FF at the warm-start entry point.
Using the Alternate 64K RAM Bank
When ProDOS is started up, it checks its environment. If it finds 128K of memory (Apple IIe with Extended 80-column Text card, or Apple IIc), the auxiliary 64K bank of memory is configured as a RAM disk named /RAM. Because the memory on the 80-column card is in slot 3, /RAM appears as slot 3 drive 2. Its unit number, as entered in the ProDOS global page's device list, is $BF.
Before using the auxiliary memory for any other purpose, you must protect your code from /RAM. The routines described here are examples only.
Note: These routines are examples; they are not being specified as suitable for any particular purpose.
Protecting Auxiliary Bank Hi-Res Graphics Pages
If your use involves hi-res graphics, you may protect those areas of auxiliary memory. If you save a dummy 8K file as the first entry in /RAM, it will always be saved at $2000 to $3FFF. If you then immediately save a second dummy 8K file to /RAM, it will be saved at $4000 to $5FFF. This protects the hi-res pages in auxiliary memory while maintaining /RAM as an online storage device.
Page 89
There is no formula for determining where the blocks of /RAM
physically reside in memory. Further, the logical blocks are not
physically contiguous. There is no guaranteed way to protect any other
fixed portions of auxiliary memory by the dummy file method.
Disconnecting /RAM
To protect all of the auxiliary memory that has not been reserved for use by Apple, you must disconnect /RAM. Note these three areas of the system global page:
- $BF10-$BF2F contains the disk device driver addresses.
- $BF31 contains the number of devices minus one.
- $BF32-$BF3F contains the list of disk device numbers.
Here is how to disconnect /RAM. It is suggested that you read block two on /RAM and check the FILE_COUNT field in the directory. If there are any files on /RAM, prompt the user either to continue with the disconnect or to cancel the process.
Check the MACHID byte at $BF96 to see if you have 128K. If not, there will be no /RAM to disconnect.
The slot 0 drive 1 disk-driver vector ($BF10) will point to the "No Device Connected" routine. The slot 0 vectors $BF10 and $BF20 are reserved for Apple's use: you cannot use these vectors if this convention is to work. If the slot 3 drive 2 vector also points to the same address, then /RAM is already disconnected.
If /RAM is on line, you are ready to remove it. (Note that the following steps can be adapted to disconnecting any device.) 1. Retrieve the slot 3 drive 2 device number you find in DEVLST, and save it.
2. Move any remaining device numbers forward in the DEVLST.
3. Retrieve the slot 3 drive 2 driver vector, and save it for later reinstallation.
4. Replicate the "No Device Connected" vector in slot 0 drive 1 into slot 3 drive 2.
5. Decrement the device count (DEVCNT).
/RAM is now disconnected. You are free to use the unreserved areas of auxiliary memory.
Note: If ProDOS has just been started up, /RAM is the last disk device installed. However, if the user has manually installed another device(s), the device number for /RAM will not be the last entry in the device list (DEVLST).
Page 90
How to Treat RAM Disks With More Than 64K
If there is a device in slot 3 drive 2 that is not /RAM, or is a RAM disk with a capacity of more than 64K, the following routine prevents it from being disconnected.
ORG $1000
DEVCNT EQU $BF31 ; GLOBAL PAGE DEVICE COUNT
DEVLST EQU $BF32 ; GLOBAL PAGE DEVICE LIST
MACHID EQU $BF98 ; GLOBAL PAGE MACHINE ID BYTE
RAMSLOT EQU $BF26 ; SLOT 3, DRIVE 2 IS /RAM'S DRIVER VECTOR
*
* NODEV IS THE GLOBAL PAGE SLOT ZERO, DRIVE 1 DISK DRIVE VECTOR.
* IT IS RESERVED FOR USE AS THE "NO DEVICE CONNECTED" VECTOR.
*
NODEV EQU $BF10
*
*
RAMOUT PHP ; SAVE STATUS AND
SEI ; MAKE SURE INTERRUPTS ARE OFF!
*
* FIRST THING TO DO IS TO SEE IF THERE IS A /RAM TO DISCONNECT!
*
LDA MACHID ; LOAD THE MACHINE ID BYTE
AND #$30 ; TO CHECK FOR A 128k SYSTEM
CMP #$30 ; IS IT 128k?
BNE DONE ; IF NOT THEN BRANCH SINCE NO /RAM!
*
LDA RAMSLOT ; IT IS 128K; IS A DEVICE THERE?
CMP NODEV ; COMPARE WITH LOW BYTE OF NODEV
BNE CONT ; BRANCH IF NOT EQUAL, DEVICE IS CONNECTED
LDA RAMSLOT+1 ; CHECK HI BYTE FOR MATCH
CMP NODEV+1 ; ARE WE CONNECTED?
BEQ DONE ; BRANCH, NO WORK TO DO; DEVICE NOT THERE
*
* AT THIS POINT /RAM (OR SOME OTHER DEVICE) IS CONNECTED IN
* THE SLOT 3, DRIVE 2 VECTOR. NOW WE MUST GO THRU THE DEVICE
* LIST AND FIND THE SLOT 3, DRIVE 2 UNIT NUMBER OF /RAM ($BF).
* THE ACTUAL UNIT NUMBERS, (THAT IS TO SAY 'DEVICES') THAT WILL
* BE REMOVED WILL BE $BF, $BB, $B7, $B3. /RAM'S DEVICE NUMBER
* IS $BF. THUS THIS CONVENTION WILL ALLOW OTHER DEVICES THAT
* DO NOT NECESSARILY RESEMBLE (OR IN FACT, ARE COMPLETELY DIFFERENT
* FROM) /RAM TO REMAIN INTACT IN THE SYSTEM.
*
*
CONT LDY DEVCNT ; GET THE NUMBER OF DEVICES ONLINE
LOOP LDA DEVLST,Y ; START LOOKING FOR /RAM OR FACSIMILE
AND #$F3 ; LOOKING FOR $BF, $BB, $B7, $B3
CMP #$B3 ; IS DEVICE NUMBER IN {$BF,$BB,$B7,$B3}?
BEQ FOUND ; BRANCH IF FOUND..
DEY ; OTHERWISE CHECK OUT THE NEXT UNIT #.
BPL LOOP ; BRANCH UNLESS YOU'VE RUN OUT OF UNITS.
BMI DONE ; SINCE YOU HAVE RUN OUT OF UNITS TO
FOUND LDA DEVLST,Y ; GET THE ORIGINAL UNIT NUMBER BACK
STA RAMUNITID ; AND SAVE IT OFF FOR LATER RESTORATION.
*
* NOW WE MUST REMOVE THE UNIT FROM THE DEVICE LIST BY BUBBLING
* UP THE TRAILING UNITS.
*
GETLOOP LDA DEVLST+1,Y ; GET THE NEXT UNIT NUMBER
STA DEVLST,Y ; AND MOVE IT UP.
BEQ EXIT ; BRANCH WHEN DONE(ZEROS TRAIL THE DEVLST)
INY ; CONTINUE TO THE NEXT UNIT NUMBER...
BNE GETLOOP ; BRANCH ALWAYS.
*
EXIT LDA RAMSLOT ; SAVE SLOT 3, DRIVE 2 DEVICE ADDRESS.
STA ADDRESS ; SAVE OFF LOW BYTE OF /RAM DRIVER ADDRESS
LDA RAMSLOT+1 ; SAVE OFF HI BYTE
STA ADDRESS+1 ;
*
LDA NODEV ; FINALLY COPY THE 'NO DEVICE CONNECTED'
STA RAMSLOT ; INTO THE SLOT 3, DRIVE 2 VECTOR AND
LDA NODEV+1 ;
STA RAMSLOT+1 ;
DEC DEVCNT ; DECREMENT THE DEVICE COUNT.
*
DONE PLP ; RESTORE STATUS
*
RTS ; AND RETURN
*
ADDRESS DW $0000 ; STORE THE DEVICE DRIVER ADDRESS HERE
RAMUNITID DFB $00 ; STORE THE DEVICE'S UNIT NUMBER HERE
*
Page 91
Reinstalling /RAM
Part of your exit procedure should include code to reinstall /RAM, making it available to the next application. Be sure /RAM has been disconnected before you reinstall it. Applications should not begin by reinstalling /RAM, because this would preclude passing files from one application to the next in /RAM.
Here is how to reinstall /RAM (or any general device): 1. Reinstall the device driver address you retrieved and saved as the slot 3 drive 2 vector.
2. Increment the device count (DEVCNT).
3. Reinstall the device number in the device list (DEVLST). It may be best to reinstall the device number as the first entry in the list. If the user has manually installed a disk driver, he may assume that because it was the last thing installed that it is still the last one in the list. It is recommended that you move all the entries in the list down one, and reinstall the /RAM device number as the first entry.
4. Set up the parameters for a format request and JSR to the device driver address you have reinstalled. The /RAM driver will set up a new directory and bit map.
Page 92
The following is an example of what the reinstallation code might look
like. These routines deal specifically with /RAM but can easily be
adapted to any disk driver routines.
* * THIS IS THE EXAMPLE /RAM INSTALL ROUTINE * RAMIN PHP ; SAVE STATUS SEI ; AND MAKE SURE INTERRUPTS ARE OFF! * LDY DEVCNT ; GET THE NUMBER OF DEVICES - 1. LOOP1 LDA DEVLST,Y ; LOAD THE UNIT NUMBER AND #$F0 ; CHECK FOR SLOT 3, DRIVE 2 UNIT. CMP #$B0 ; IS IT THE SLOT 3, DRIVE 2 UNIT? BEQ DONE1 ; IF SO BRANCH. DEY ; OTHERWISE SEARCH ON... BPL LOOP1 ; LOOP UNTIL DEVLST SEARCH IS COMPLETED LDA ADDRESS ; RESTORE THE DEVICE DRIVER ADDRESS STA RAMSLOT ; LOW BYTE.. LDA ADDRESS+1 ; NOW THE STA RAMSLOT+1 ; HI BYTE. INC DEVCNT ; AFTER INSTALLING DEVICE, INC DEVICE COUNT LDY DEVCNT ; USE Y FOR LOOP COUNTER.. LOOP2 LDA DEVLST-1,Y ; BUBBLE DOWN THE ENTRIES IN DEVICE LIST STA DEVLST,Y ; DEY ; NEXT BNE LOOP2 ; LOOP UNTIL ALL ENTRIES MOVED DOWN. * * NOW SET UP A /RAM FORMAT REQUEST * LDA #3 ; LOAD ACC WITH FORMAT REQUEST NUMBER. STA $42 ; STORE REQUEST NUMBER IN PROPER PLACE. * LDA RAMUNITID ; RESTORE THE DEVICE STA DEVLST ; UNIT NUMBER IN THE DEVICE LIST AND #$F0 ; STRIP THE DEVICE ID (ZERO LOW NIBBLE) STA $43 ; AND STORE THE UNIT NUMBER IN $43. * LDA #$00 ; LOAD LOW BYTE OF BUFFER POINTER STA $44 ; AND STORE IT. LDA #$20 ; LOAD HI BYTE OF BUFFER POINTER STA $45 ; AND STORE IT. * LDA $C08B ; READ & WRITE ENABLE LDA $C08B ; THE LANGUAGE CARD WITH BANK 1 ON. * * NOTE HOW THE DRIVER IS CALLED. YOU JSR TO AN INDIRECT JMP SO * CONTROL IS RETURNED BY THE DRIVER TO THE INSTRUCTION AFTER THE JSR. * JSR DRIVER ; NOW LET DRIVER CARRY OUT CALL. BIT $C082 ; NOW PUT ROM BACK ON LINE. * BCC DONE1 ; IF THE CARRY IS CLEAR --> NO ERROR JSR ERROR ; GO PROCESS THE ERROR * DONE1 PLP ; RESTORE STATUS RTS ; THAT'S ALL * DRIVER JMP (RAMSLOT) ; CALL THE /RAM DRIVER * ERROR BRK ; YOUR ERROR HANDLER CODE WOULD GO HERE RTS ;
Page 93
The System Global Page
The $BF page of memory, addresses $BF00 through $BFFF, contains the system's global variables. Some of them, such as the system bit map and the date and time locations, can be set and used by system programs. Others, such as the machine identification byte, are informational but are not to be changed. Still others are for internal use of the system only. Follow the rules described below.
The DFB assembler directive assigns a value to the current memory location. The DW directive assigns a two-byte address, low byte first, to the current location.
Rules for Using the System Global Page
MLI entry point. This is the only address in the global page that you should ever call:
BF00: BF00 2 ORG GLOBALS BF00: 3 * BF00:4C 4B BF 4 ENTRY JMP MLIENT1 ;MLI CALL ENTRY POINT
Other entry points. Do not use these:
BF03:4C F6 BF 5 JSPARE JMP SYS.RTS ;Jump Vector to cold
;start, selector program,
;etc.
BF06:60 42 D7 6 DATETIME DFB $60,$42,$D7 ;CLOCK CALENDAR ROUTINE.
BF09:4C F8 DF 7 SYSERR JMP SYSERR1 ;ERROR REPORTING HOOK.
BF0C:4C 04 E0 8 SYSDEATH JMP SYSDEATH1 ;SYSTEM FAILURE HOOK.
BF0F:00 9 SERR DFB $00 ;ERR CODE, 0=NO ERROR.
Disk device driver vectors:
BF10: 11 * BF10: 12 * DEVICE DRIVER VECTORS. BF10: 13 * BF10:AB DE 14 DEVADR01 DW GNODEV ;SLOT ZERO RESERVED BF12:AB DE 15 DW GNODEV ;SLOT 1, DRIVE 1 BF14:AB DE 16 DW GNODEV ;SLOT 2, DRIVE 1 BF16:AB DE 17 DW GNODEV ;SLOT 3, DRIVE 1 BF18:AB DE 18 DW GNODEV ;SLOT 4, DRIVE 1 BF1A:AB DE 19 DW GNODEV ;SLOT 5, DRIVE 1 BF1C:AB DE 20 DW GNODEV ;SLOT 6, DRIVE 1 BF1E:AB DE 21 DW GNODEV ;SLOT 7, DRIVE 1 BF20:AB DE 22 DW GNODEV ;SLOT ZERO RESERVED BF22:AB DE 23 DW GNODEV ;SLOT 1, DRIVE 2 BF24:AB DE 24 DW GNODEV ;SLOT 2, DRIVE 2 BF26:AB DE 25 DW GNODEV ;SLOT 3, DRIVE 2 BF28:AB DE 26 DW GNODEV ;SLOT 4, DRIVE 2 BF2A:AB DE 27 DW GNODEV ;SLOT 5, DRIVE 2 BF2C:AB DE 28 DW GNODEV ;SLOT 6, DRIVE 2 BF2E:AB DE 29 DW GNODEV ;SLOT 7, DRIVE 2
Page 94
List of all active disk devices by unit number. When access to an
unrecognized volume is requested, devices are searched from the end
of the list to the beginning. See also Sections 3.1, 3.2, and 4.4.6. The
lower half of each byte in DEVLST is a device identification:
0 = Disk II, 4 = ProFile, $F = /RAM.
BF30: 31 *
BF30: 32 * CONFIGURED DEVICE LIST BY DEVICE NUMBER
BF30: 33 * ACCESS ORDER IS LAST IN LIST FIRST.
BF30: 34 *
BF30:00 35 DEVNUM DFB $00 ;MOST RECENT ACCESSED
;DEVICE.
BF31:FF 36 DEVCNT DFB $FF ;NUMBER OF ON-LINE DEVICES
;(MINUS 1).
BF32:00 00 00 00 37 DEVLST DFB $0,0,0,0 ;UP TO 14 UNITS MAY BE
;ACTIVE.
BF36:00 00 00 00 38 DFB 0,0,0,0,0
BF3B:00 00 00 00 39 DFB 0,0,0,0,0
BF40:28 43 29 41 41 ASC "(C)APPLE'83"
Routines reserved for MLI and subject to change.
BF4B:08 42 MLIENT1 PHP
BF4C:78 43 SEI
BF4D:4C B7 BF 44 JMP MLICONT
BF50:8D 8B C0 45 AFTIRQ STA RAMIN
BF53:4C D8 FF 46 JMP FIX45 ;Restore $45 after
;Interrupt in Lang Card
BF56:00 47 OLD45 DFB 0
BF57:00 48 AFBANK DFB 0
Memory map of the lower 48K. Each bit represents one page (256 bytes) of memory. Protected areas are marked with a 1, uprotected with a 0. ProDOS disallows reading into or io_buffer allocation in protected areas. See Section 5.1.
BF58:C0 00 00 00 56 MEMTABL DFB $C0,$00,$00,$00,$00,$00,$00,$00 BF60:00 00 00 00 57 DFB $00,$00,$00,$00,$00,$00,$00,$00 BF68:00 00 00 00 58 DFB $00,$00,$00,$00,$00,$00,$00,$01
The addresses in this table are buffer addresses for open files.
These are informational only; they should not be changed except using the MLI call SET_BUF.
BF70:00 00 66 GL.BUFF DW $0000 ;FILE NUMBER 1 BF72:00 00 67 DW $0000 ;FILE NUMBER 2 BF74:00 00 68 DW $0000 ;FILE NUMBER 3 BF76:00 00 69 DW $0000 ;FILE NUMBER 4 BF78:00 00 70 DW $0000 ;FILE NUMBER 5 BF7A:00 00 71 DW $0000 ;FILE NUMBER 6 BF7C:00 00 72 DW $0000 ;FILE NUMBER 7 BF7E:00 00 73 DW $0000 ;FILE NUMBER 8
Page 95
Interrupt vectors are stored here. Again, these are informational and
should be changed only by a call to the MLI using
ALLOC_INTERRUPT. Values of the A, X, Y, stack, and status
registers at the time of the most recent interrupt are also stored
here. In addition, the address interrupted is preserved. These may be
used for performance studies and debugging, but should not be changed
by the user. The routines are polled in ascending order. See
Section 6.2.
BF80:00 00 85 INTRUPT1 DW $0000 ;INTERRUPT ROUTINE 1 BF82:00 00 86 INTRUPT2 DW $0000 ;INTERRUPT ROUTINE 2 BF84:00 00 87 INTRUPT3 DW $0000 ;INTERRUPT ROUTINE 3 BF86:00 00 88 INTRUPT4 DW $0000 ;INTERRUPT ROUTINE 4 BF88:00 89 INTAREG DFB $00 ;A-REGISTER BF89:00 90 INTXREG DFB $00 ;X-REGISTER BF8A:00 91 INTYREG DFB $00 ;Y-REGISTER BF8B:00 92 INTSREG DFB $00 ;STACK REGISTER BF8C:00 93 INTPREG DFB $00 ;STATUS REGISTER BF8D:01 94 INTBANKID DFB $01 ;ROM, RAM1, OR RAM2 ($D000 IN LC) BF8E:00 00 95 INTADDR DW $0000 ;PROGRAM COUNTER RETN ADDR
The following options can be changed before calls to the MLI:
BF90:00 00 101 DATELO DW $0000 ;BITS 15-9=YR, 8-5=MO, 4-0=DAY BF92:00 00 102 TIMELO DW $0000 ;BITS 12-8=HR, 5-0=MIN; LOW-HI FORMAT. BF94:00 103 LEVEL DFB $00 ;FILE LEVEL: USED IN OPEN, FLUSH, CLOSE. BF95:00 104 BUBIT DFB $00 ;BACKUP BIT DISABLE, SETFILEINFO ONLY. BF96:00 00 105 SPARE1 DFB $00,$00 ;RESERVED FOR MLI USE
The definition of MACHID at $BF98 is:
BF98: 107 * BF98: 108 * The following are informational only. MACHID BF98: 109 * identifies the System Attributes: BF98: 110 * (Bit 3 off) BITS 7,6- 00=II 01=II+ 10=IIe 11=/// EMULATION BF98: 111 * (Bit 3 on) BITS 7,6- 00=NA 01=NA 10=//c 11=NA BF98: 112 * BITS 5,4- 00=NA 01=48K 10=64K 11=128K BF98: 113 * BIT 3 - Modifier for MACHID Bits 7,6. BF98: 114 * BIT 2 - RESERVED FOR FUTURE DEFINITION. BF98: 115 * BIT 1=1- 80 Column card BF98: 116 * BIT 0=1- Recognizable Clock Card BF98: 117 * BF98: 118 * SLTBYT indicates which slots are determined to have BF98: 119 * ROMS. PFIXPTR indicates an active PREFIX if it is BF98: 120 * non-zero. MLIACTV indicates an MLI call in progress BF98: 121 * if it is non-zero. CMDADR is the address of the last BF98: 122 * MLI call's parameter list. SAVX and SAVY are the BF98: 123 * values of X and Y when the MLI was last called. BF98: 124 * BF98:00 125 MACHID DFB $00 ;MACHINE IDENTIFICATION. BF99:00 126 SLTBYT DFB $00 ;'1' BITS INDICATE ROM IN SLOT(BIT#) BF9A:00 127 PFIXPTR DFB $00 ;IF = 0, NO PREFIX ACTIVE.. BF9B:00 128 MLIACTV DFB $00 ;IF <> 0, MLI call in progress BF9C:00 00 129 CMDADR DW $0000 ;RETURN ADDRESS OF LAST CALL TO MLI. BF9E:00 130 SAVEX DFB $00 ;X-REG ON ENTRY TO MLI BF9F:00 131 SAVEY DFB $00 ;Y-REG ON ENTRY TO MLI
Page 96
The following space is reserved for Language Card bank-switching
routines. All routines and addresses are subject to change at any time
without notice and will, in fact, vary with system configuration. The
routines presented here are for 64K systems only:
BFA0:4D 00 E0 141 EXIT EOR $E000 ;TEST FOR ROM ENABLE. BFA3:F0 05 BFAA 142 BEQ EXIT1 ;BRANCH IF RAM ENABLED. BFA5:8D 82 C0 143 STA ROMIN ;ELSE ENABLE ROM & RETURN. BFA8:D0 0B BFB5 144 BNE EXIT2 ;BRANCH ALWAYS BFAA: 145 ** BFAA:AD F5 BF 146 EXIT1 LDA BNKBYT2 ;FOR ALT RAM (MOD BY MLIENT1) BFAD:4D 00 D0 147 EOR $D000 ;ENABLE. BFB0:F0 03 BFB5 148 BEQ EXIT2 ;BRANCH IF NOT ALT RAM. BFB2:AD 83 C0 149 LDA ALTRAM ;ELSE ENABLE ALT $D000 BFB5:68 150 EXIT2 PLA ;RESTORE RETURN CODE. BFB6:40 151 RTI ;RE-ENABLE INTERRUPTS & RETURN BFB7: 152 ** BFB7:38 153 MLICONT SEC BFB8:6E 9B BF 154 ROR MLIACTV ;INDICATE TO INTERRUPT ROUTINES MLI ACTIVE. BFBB:AD 00 E0 155 LDA $E000 ;PRESERVE LANGUAGE CARD / ROM BFBE:8D F4 BF 156 STA BNKBYT1 ; ORIENTATION FOR PROPER BFC1:AD 00 D0 157 LDA $D000 ; RESTORATION WHEN MLI EXITS... BFC4:8D F5 BF 158 STA BNKBYT2 BFC7:AD 8B C0 159 LDA RAMIN ;NOW FORCE RAM CARD ON BFCA:AD 8B C0 160 LDA RAMIN ; WITH RAM WRITE ALLOWED. BFCD:4C 00 DE 161 JMP ENTRYMLI
Interrupt exit and entry routines:
BFD0: 163 * BFD0: 164 * INTERRUPT EXIT/ENTRY ROUTINES BFD0: 165 *
BFD0:AD 8D BF 167 IRQXIT LDA INTBANKID ;DETERMINE STATE OF RAM CARD BFD3:F0 0D BFE2 168 IRQXIT0 BEQ IRQXIT2 ; IF ANY. BRANCH IF ENABLED. BFD5:30 08 BFDF 169 BMI IRQXIT1 ;BRANCH IF ALTERNATE $D000 ENABLED. BFD7:4A 170 LSR A ;DETERMINE IF NO RAM CARD PRESENT. BFD8:90 0D BFE7 171 BCC ROMXIT ;BRANCH IF ROM ONLY SYSTEM. BFDA:AD 81 C0 172 LDA ROMIN1 ;ELSE ENABLE ROM FIRST. BFDD:B0 08 BFE7 173 BCS ROMXIT ;BRANCH ALWAYS TAKEN... BFDF:AD 83 C0 174 IRQXIT1 LDA ALTRAM ;ENABLE ALTERNATE $D000. BFE2:A9 01 175 IRQXIT2 LDA #1 ;PRESET BANKID FOR ROM. BFE4:8D 8D BF 176 STA INTBANKID ;(RESET IF RAM CARD INTERRUPT) BFE7:AD 88 BF 177 ROMXIT LDA INTAREG ;RESTORE ACCUMULATOR... BFEA:40 178 RTI ; AND EXIT!
BFEB:2C 8B C0 180 IRQENT BIT RAMIN ;THIS ENTRY ONLY USED WHEN ROM BFEE:2C 8B C0 181 BIT RAMIN ; WAS ENABLED AT TIME OF INTERRUT. BFF1:4C 4D DF 182 JMP IRQRECEV ; A-REG IS STORED AT $45 IN ZPAGE. BFF4:00 183 BNKBYT1 DFB $00 BFF5:00 184 BNKBYT2 DFB $00 BFF6: 185 ** BFF6:2C 8B C0 186 SYS.RTS BIT RAMIN ;Make certain Language card is switched in BFF9:4C 02 E0 187 JMP SYS.END ;Or anywhere else we need to go
Each system program should set IVERSION to its own current version number. ProDOS sets KVERSION to its current version number.
BFFC:00 188 IBAKVER DFB $00 ;UNDEFINED: Reserved for future use BFFD:00 189 IVERSION DFB $00 ;Version # of currently running Interpreter BFFE:00 191 KBAKVER DFB $00 ;UNDEFINED: Reserved for future use BFFF:02 192 KVERSION DFB $2 ;VERSION NO. (RELEASE ID)
Page 97
General Techniques
The first part of this chapter discusses the things that a system program must do. This section of the manual describes some of the things that system programs commonly do, and it gives some techniques for implementing them.
Determining Machine Configuration
It is often useful for a system program to know what type of Apple II it is running on. The MACHID byte in the system global page identifies the machine type, the amount of memory, and whether an 80-column text card or clock/calendar card was detected.
MACHID byte: see Section 5.2.3.
Machine Type
Two bits distinguish an Apple II, an Apple II Plus, an Apple IIe, an Apple IIc, or an Apple III in Apple II emulation mode. This distinction is most useful for two reasons: 1. The Apple IIe and IIc always have lowercase available. Screen messages can be coded using uppercase and lowercase, and then made all uppercase if the machine is not an Apple IIe or IIc (or if it is a Apple II without an 80-column text card).
2. The Apple IIe and IIc have keys that are not available on earlier versions of the Apple II (most notably [UP], [DOWN], [OA], [SA], and [DELETE]). Software should be coded to use the keys most convenient for the system it is running on, and the screen messages should be adjusted accordingly.
Memory Size
The possible memory sizes are 64K and 128K. A system program can use these values when deciding where to relocate itself. Recall that the alternate 64K bank cannot contain code that makes calls to the MLI and it cannot be used for system buffers.
Page 98
80-Column Text Card
This bit is always set in the Apple IIc. It is set in an Apple IIe if an 80-column text card that follows the defined protocol is in slot 3 or in the auxiliary slot. This protocol guarantees that the features of the card can be turned on by a JSR to $C300, the beginning of the ROM on the card (note that this disconnects BASIC.SYSTEM).
80-column text cards -- and other Apple IIe features -- can be turned off using the following sequence of instructions:
LDA #$15 ;Character that turns off video firmware JSR $C300 ;Print it to the video firmware
Using the Date
A system program often has reason to use the current date: to mark files with a modification date, to use as identification on a listing, or just for display on the screen. Whatever the use, it is usually desirable to obtain the most current setting.
Save the system date and time locations ($BF90-BF93) for possible future use, and then clear them. Next use the GET_TIME call. If there is a clock/calendar card with an installed clock routine, then the system date and time locations will become nonzero. This is the date and time you should use. If the GET_TIME call has no effect, then you should either use the values that were previously in the date and time locations, or prompt the user for the current date and time. Since the date and time locations are set to 0 when the system is started (unless ProDOS recognizes a clock/calendar card), it is reasonable to use nonzero values of the date and time locations as a default date and time.
If there is no system time, and the call to GET_TIME returns nothing an alternative is to use the GET_FILE_INFO call and to use the last modified date and time as a default. If the user updates the time, and you place these values in the system date and time locations, a SET_FILE_INFO call will update the time for the next GET_FILE_INFO.
The system updates the date and time at every CREATE, DESTROY, RENAME SET_FILE_INFO CLOSE, and FLUSH operation.
Refer to the GET_TIME call in Chapter 4, and to the description of clock/calender routines in Chapter 6 for more details.
Page 99
System Program Defaults
Each file entry in a directory has a two-byte aux_type field. This field contains information such as load address for BASIC programs or binary files, and record length for text files; for system files it is unused. If your system program has a small amount of default information that you would like to preserve from one execution of the program to the next, this field is a good place to store it.
To alter the contents of this field, use the GET_FILE_INFO call to read the current contents of the file's entry, change the values in the aux_id field, then use the SET_FILE_INFO call with the same parameter list to save the modified values in the file's entry.
Finding a Volume
Since one does not always know the names of all the online volumes, it is sometimes necessary to allow users to specify volumes by slot and drive instead of by volume name. Before the slot and drive information can be used to access ProDOS files, it must be converted to a volume name. To convert slot and drive numbers to volume names, you can use the following steps:
1. Make the slot and drive numbers into a unit_num. This number is used to specify the desired device to the ON_LINE call. The format of a unit_num is given in Section 4.4.6.
2. Use the unit_num in the ON_LINE call. This call will return a count byte followed by the volume name. This volume name is not preceded by a slash. You must increase the count by one and insert a slash preceding the volume name before using this name in other ProDOS calls.
Page 100
Using the RESET Vector
In the Apple II, pressing [CONTROL]-[RESET] causes an unconditional jump to the RESET vector (at $3F2 in memory). Because the user can press [CONTROL]-[RESET] at any time -- including while files are open -- ProDOS cannot take responsibility for disk integrity after [RESET] has been pressed: the system program must do it.
Your program should place in the RESET vector the address of a routine that displays a message advising that it will be closing any open files, and then close the files. Once this is done, the program may take any action required by the application. It is preferable either to jump back to the beginning of the program or to jump directly to the quit routine.
ProDOS System Program Conventions
For the sake of consistency from one piece of software to the next follow the conventions used in this manual:
- Use the same terminology whenever possible. If your application
implements any of the functions used by the BASIC system program, the Filer, the Convert program, or the Editor/Assembler, try to use the same wording.
- Use the same catalog format in all software that displays a list of
files. It is not necessary to implement both the 40- and 80-column formats (see the CAT and CATALOG commands of the BASIC system program).
- If you choose to implement your own version of this command,
recognize the file types and display the three-letter abbreviations that are shown in the quick reference card of this manual.
- The standard Apple II "Air-raid" bell has been replaced with a
gentler tone. Use it to give users some aural feedback that they are using a ProDOS program. The code for it follows.
Page 101
SPKR EQU $C030 ;this clicks the speaker
*
LENGTH DS 1 ;duration of tone
*
* This is the wait routine from the Monitor ROM.
*
WAIT SEC
WAIT2 PHA
WAIT3 SBC #1
BNE WAIT3
PLA
SBC #1
BNE WAIT2
RTS
*
* Generate a nice little tone
* Exits with Z-flag set (BEQ) for branching
* Destroys the contents of the accumulator
*
BELL LDA #$20 ;duration of tone
STA LENGTH
BELL1 LDA #$2 ;short delay...click
JSR WAIT
STA SPKR
LDA #$20 ;long delay...click
JSR WAIT
STA SPKR
DEC LENGTH
BNE BELL1 ;repeat LENGTH times
RTS
Page 102
Chapter 6 - Adding Routines to ProDOS
Page 103
This chapter explains device-handling routines that can be used with
the ProDOS MLI. Because such routines are connected to and interact
with the MLI, they are essentially invisible to the BASIC system
program described in Appendix A of this manual and in BASIC
Programming With ProDOS.
Appendix A explains the rules for installing routines when the BASIC system program is active.
The types of routines described in this chapter are:
- clock/calendar routines
- interrupt handling routines
- disk driver routines.
Note: These routines must all begin with a CLD instruction and end with an RTS.
Clock/Calendar Routines
ProDOS has a built-in clock driver that queries a clock/calendar card for the date and time. After the routine stores that information in the ProDOS Global Page ($BF90-$BF93), either ProDOS or your own application programs can use it. See Figure 6-1.
Figure 6-1. ProDOS Date and Time Locations
49041 ($BF91) 49040 ($BF90)
7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
DATE: | year | month | day |
+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
TIME: | hour | | minute |
+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
49043 ($BF93) 49042 ($BF92)
You can cause ProDOS to call the clock driver and to update the date and time by issuing a GET_TIME call (see Section 4.6.1).
ProDOS calls the clock driver routine for every call that might need the date and time: CREATE, DESTROY, RENAME SET_FILE_INFO CLOSE, and FLUSH.
Page 104
The ProDOS clock driver expects the clock card's firmware to return
information in a certain way. The ROM on the clock card must also
follow Apple's identification convention if it is to be recognized by
ProDOS at startup.
The ProDOS clock driver expects the clock card to send an ASCII string to the GETLN input buffer ($200). This string must have the following format (including the commas):
mo,da,dt,hr,mn where mo is the month (01 = January...12 = December) da is the day of the week (00 = Sunday...06 = Saturday) dt is the date (00 through 31) hr is the hour (00 through 23) mn is the minute (00 through 59) For example:
07,04,14,22,46
would represent Thursday, July 14, 10:46 p.m. The year is looked up in a table in the clock driver.
When the ProDOS system file is executed, it installs the address of the clock routine at $BF07, $BF08 -- whether there is a recognized clock card or not.
ProDOS recognizes a clock card if the following bytes are present in the Cn00 ROM:
$Cn00 = $08 $Cn02 = $28 $Cn04 = $58 $Cn06 = $70
The address is preceded by a $4C (JMP) if a clock card is recognized, or by a $60 (RTS) if not.
The ProDOS clock driver uses the following addresses for its I/O to the clock:
Cn08 - READ entry point Cn0B - WRITE entry point
The accumulator is loaded with an #A3 before the JSR to the WRITE entry point. This value could be used to let the clock card's firmware know in what format to leave the time.
The ProDOS driver takes the ASCII values sent by the clock, converts them to binary, and stores them in the ProDOS Global Page.
Page 105
The driver uses zero page locations $3A through $3E. It also saves and
restores the peripheral RAM card location $F8+n, where n is the slot
where the card resides.
Other Clock/Calendars
To support clock cards that do not follow the ProDOS protocol defined above, you can locate your code in a number of places. The cleanest solution is to replace the ProDOS routines with your own, if they fit.
If you look at $BF07,$BF08, you will find the location to put your code.
There is room for 125 bytes.
To install your code, simply write-enable the language card area, and move your code. Your relocation code must justify the absolute addresses as part of the relocation procedure. Finally, restore any soft switches you have changed. (There is no guarantee as to the absolute location of the clock-driver code on future revisions of ProDOS, only that its location can be found by examining the global page.) All that your code needs to do is get the time from the clock card, convert it to the ProDOS format, and store it in the date and time locations in the global page.
Your installation routine can be called either from an application program, or as part of the STARTUP program.
Interrupt Handling Routines
To aid the development of software that can handle interrupts, the MLI provides a convention for interfacing interrupt driven devices.
To use interrupts, you must install from one to four interrupt receiving routines somewhere in memory. It is up to you to check and update the system bit map to be sure that the routines do not conflict with ProDOS or other concurrently executing programs.
Once a routine is installed, you must use the ALLOC_INTERRUPT call to inform the MLI of the starting address of the receiving routine. After this call has been successfully completed, you may enable the hardware for interrupts.
Page 106
When an interrupt occurs, the MLI's interrupt handler preserves the
6502's registers, zero page locations $FA thru $ff, and, if the stack is
more than 3/4 full, 16 bytes of the stack. Then it calls each receiving
routine (via JSR), one by one, in the order in which they were
installed. Each installed routine must begin with a CLD instruction.
When the routine that can process the interrupt is called, it should carry out its task, clear the interrupt on the hardware, and return (via an RTS) with the carry flag clear. When a routine that cannot process the interrupt is called, it should return (via an RTS) with the carry flag set so that the MLI knows to call the next routine in the list.
As mentioned above, all 6502 registers, locations $FA thru $FF and if the stack is more than 3/4 full, 16 bytes of the stack, are preserved.
The interrupt routine may use these resources freely for temporary data storage.
Note: There is no general way for an interrupt routine to identify whether or not its device was the source of the interrupt. This task depends on the specific characteristics of the device; in fact, some devices provide no mechanism for interrupt verification. It is necessary to service such a device after all others have been polled.
If no installed and allocated routine claims a pending interrupt, a SYSTEM FAILURE message will be displayed and program execution will be halted.
When finished with a interrupt driven device, a DEALLOC_INTERRUPT call should be made, but only after the device itself is disabled.
Warning
This Warning does not apply to the Apple IIc nor to Apple IIe's with enhanced ROMs. Because the Apple II Monitor program relies on a zero-page location ($45) that is overwritten when an interrupt occurs, you should disable interrupts while you are using the Monitor program. The system also uses location $7F8 to store the I/O slot location that was in use before an interrupt occurred; do not use this location.
Page 107
Interrupts During MLI Calls
The preceding section does not discuss what a program should do if an interrupt were to occur during the execution of an MLI call and your interrupt handling routine itself makes calls to the MLI.
The interrupt routine must allow the MLI to complete its current call before initiating a new call to the MLI. The mechanism for doing this consists of changing the globals so that the MLI completes its call and returns to your routine rather than to the the routine that originally called it. Then your routine can use the MLI as needed. When it is finished, it must restore the 6502 registers to the state they would have been in at completion of the MLI call had the interrupt not occurred, and then jump back to the proper address in the original routine.
To do this, the interrupt handling routine should first check the status of the MLI. If the flag MLIACTV ($BF9B) has the high bit set, then the MLI was in the middle of a call. Your routine should then:
1. Save the return address of the original caller (CMDADR, $BF9C), replacing it with the address to which the MLI should return on completion of the current call.
2. Claim the interrupt by disabling interrupts on the hardware, and clearing the carry flag.
3. RTS
4. The MLI's interrupt handler believes that the interrupt has been processed, so it completes the current MLI call and returns to the address in CMDADR, which is actually in your routine. Your routine should now do this:
5. Save the A, X, Y, and P registers as the return state for the routine whose call just completed.
6. Use the MLI as needed.
7. Restore the A, X, Y, and P registers.
8. Jump to the original CMDADR.
The original program sees only that its MLI call was successfully completed, and it continues execution.
Page 108
Sample Interrupt Routine
Here is a sample interrupt routine that reads the date from a clock/calender card, and displays it in the upper-right corner of the screen once per second. It assumes the card is in slot 2.
SOURCE FILE #01 =>SHOWTIME ----- NEXT OBJECT FILE NAME IS SHOWTIME.0 0300: 0300 1 ORG $300 0300: C20B 2 WTTCP EQU $C20B ;CLOCK WRITE ENTRY PT (SLOT 2) 0300: C208 3 RDTCP EQU $C208 ;CLOCK READ ENTRY PT (SLOT 2) 0300; C080 4 TCICR EQU $C080 ;INTERRUPT CONTROL REG (SLOT 2) 0300: C088 5 TCMR EQU $C088 ;MYSTERY REGISTER (SLOT 2) 0300: 6 * 0300: 0200 7 IN EQU $200 ;WHERE CLOCK LEAVES THE TIME 0300: 8 * 0300: 0412 9 UPRIGHT EQU $412 ;THE UPPER RIGHT OF THE SCREEN 0300: 047A 10 INTONI EQU $47A ;LEAVE INTERRUPTS ON (SLOT 2) 0300: 07FA 11 INTON2 EQU $7FA ;LEAVE INTERRUPTS ON (SLOT 2) 0300: 12 * 0300: BF00 13 MLI EQU $BF00 ;ENTRY POINT TO THE PRODOS MLI 0300: 14 * 0300: 15 * CALLING INTERRUPTS, CALLING INTERRUPTS 0300: 16 * 0300:20 7E 03 17 JSR ALLOC.INT ;HAVE MLI INSTALL INT ROUTINE 0303:60 18 RTS ;THAT'S ALL FOLKS 0304: 19 * 0304: 20 * 0304: 0304 21 SHOWTIME EQU * 0304:D8 22 CLD 0305:08 23 PHP 0306:78 24 SEI ;DISABLE INTERRUPTS 0307:A0 20 25 LDY #$20 ; FOR SLOT 2 O3O9;B9 80 C0 26 LDA TCICR,Y ;GET VAL OF INT CONTROL REG 03OC:29 20 27 AND #$20 ;CHK BIT 5 - IS INT FROM CLK? 030E:F0 3C 034C 28 BEQ NOTCLK ;IF BIT 5 OFF, INT NOT FROM CLK 0310:B9 88 C0 29 LDA TCMR,Y ;CLEAR MYSTERY REGISTER 0313:B9 80 C0 30 LDA TCICR,Y ;CLEAR INTERRUPT ON HARDWARE 0316:CE 4F 03 31 DEC COUNTER ;ONLY PRINT TIME EVERY SECOND 0319:D0 2E 0349 32 BNE EXITCLK ; NOT TIME TO PRINT YET 031B: 33 * 031B:A2 27 34 LDX #39 ;SAVE THE INPUT BUFFER 031D:BD 00 02 35 DOIN LDA IN,X ; SINCE THE CLOCK WRITES OVER 0320:9D 56 03 36 STA INBUF,X ; IT WHEN IT IS CALLED 0323:CA 37 DEX ; 0324:10 F7 031D 38 BPL DOIN ; 0326: 39 0326:A9 A5 40 LDA #$A5 ;SET APPLESOFT STRING INPUT 0328:20 0B C2 41 JSR WTTCP ; MODE & SEND IT TO THE CARD 032B:20 08 C2 42 JSR RDTCP ;READ TIME INTO INPUT BUFFER 032E: 43 032E:A2 15 44 LDX #21 0330:BD 01 02 45 GETNEXT LDA IN+1,X ;PRINT TIME TO SCREEN 0333:9D 12 04 46 STA UPRIGHT,X ;CHARS 0-22 OF INPUT BUFFER 0336:CA 47 DEX ; 0337:10 F7 0330 48 BPL GETNEXT ; 0339: 49 0339:A9 40 50 SETCNTR LDA #64 ;SET UP COUNTER FOR NEXT TIME
Page 109
033B:8D 4F 03 51 STA COUNTER ; 033E: 52 033E:A2 27 53 LDX #39 ;RESTORE THE INPUT BUFFER 0340:BD 56 03 54 DOIN2 LDA INBUF,X ; 0343:9D 00 02 55 STA IN,X ; 0346:CA 56 DEX ; 0347:10 F7 0340 57 BPI DOIN2 ; 0349: 58 * 0349:28 59 EXITCLK PLP 034A:18 60 CLC ;TELL MLI INT WAS PROCESSED 034B:60 61 RTS 034C:28 62 NOTCLK PLP 034D:38 63 SEC ;TELL MLI IT ISN'T OURS 034E:60 64 RTS 034F: 65 * 034F: 0001 66 COUNTER DS 1,0 ; 0350; 67 * 0350:02 00 68 AIPARMS DFB 2,0 ;PUT ALLOCATE AND DEALLOCATE 0352:04 03 69 DW SHOWTIME ; INTERRUPT PARAMETERS HERE, 0354: 70 * 0354:01 00 71 DIPARMS DFB 1,0 ; SO BOTH ROUTINES CAN USE THEM 0356: 72 * 0356: 0028 73 INBUF DS 40,0 ;SAVE 40 BYTES IN HERE 037E: 74 * ; FOR INPUT BUFFER SAVE/RESTORE
Note the important features of this routine:
1. The routine begins with a CLD instruction (line 22).
2. The routine checks to see if the IRQ interrupt is being caused by the clock/calendar card (lines 25-28). If not, it returns with the carry set (lines 62-64).
3. If the interrupt belongs to the clock/calendar card, it clears the inter- rupt hardware (lines 29-30).
4. When it is done with the interrupt task, it returns with carry clear (lines 59-61).
Page 110
The following routine adds the interrupt routine to ProDOS using the
ALLOC_INTERRUPT call. Having done this, it then activates interrupts
on the clock/calendar card. Then a CLI instruction is executed to allow
the 6502 to process interrupts.
03A0:A9 00 94 DEALLOC.INT LDA #0 ;DISABLE INTERRUPTS 03A2:8D 7A 04 95 STA INTON1 ; IN THE THUNDERCLOCK 03A5:8D FA 07 96 STA INTON2 03A8:Ao 20 97 LDY #$20 03AA;99 80 C0 98 STA TCICR,Y 03AD: 99 * 03AD:AD 51 03 100 LDA AIPARMS+1 ;GET INT_NUM 03B0:8D 55 03 101 STA DIPARMS+1 ; FOR DEALLOCATION 03B3:20 00 BF 102 JSR MLI ;CALL THE MLI TO 03B6:41 103 DFB $41 ; DEALLOCATE INT ROUTINE 03B7:54 03 104 DW DIPARMS 03B9:D0 01 03BC 105 BNE OOPS2 ;BREAK ON ERROR 03BB:60 106 RTS ;DONE 03BC: 107 * 03BC:00 108 OOPS2 BRK ;BREAK ON ERROR
The next routine disables interrupts on the clock/calendar card before removing the interrupt routine from ProDOS with a DEALLOC_INTERRUPT call.
037E: 75 037E:20 00 BF 76 ALLOC.INT JSR MLI ;CALL THE MLI TO 0381:40 77 DFB $40 ; ALLOCATE THE INTERRUPT 0382:50 03 78 DW AIPARMS ; 0384:D0 19 039F 79 BNE OOPS ;BREAK ON ERROR 0386: 80 * 0386:A0 20 81 LDY #$20 0388:A9 AC 82 LDA #$AC ;SET 64HZ INTERRUPT RATE 038A:20 0B C2 83 JSR WTTCP ; BY WRITING A ',' To CLOCK 038D:A9 40 84 LDA #$40 ;NOW ENABLE THE SOFTWARE 038F:8D 7A 04 85 STA INTON1 ; AND TELL IT NOT TO DISABLE 0392:8D FA 07 86 STA INTON2 ; INTERRUPTS AFTER READS 0395:99 80 C0 87 STA TCICR,Y 0398:A9 01 88 LDA #1 ;PRINT TIME IMMEDIATELY 039A:8D 4F 03 89 STA COUNTER ; ONCE PER SECOND LATER 039D:58 90 CLI ;ALLOW THE 6502 TO SEE THE 039E:60 91 RTS ; INTERRUPTS 039F: 92 * 039F:00 93 OOPS BRK ;BREAK ON ERROR
Page 111
Disk Driver Routines
If a disk drive supplied by another manufacturer is to work with ProDOS, it must look and act just like a disk drive supplied by Apple Computer, Inc. Its boot ROM must have certain things in certain locations, and its driver routine must use certain zero-page locations for its call parameters.
ROM Code Conventions
During startup, ProDOS searches for block storage devices. If it finds the following three bytes in the ROM of a particular slot, ProDOS assumes it has found a disk drive (n represents slot number):
$Cn01 = $20
$Cn03 = $00
$Cn05 = $03
If $CnFF = $00, ProDOS assumes it has found a Disk II with 16-sector ROMs and marks the device driver table in the ProDOS global page with the address of the Disk II driver routines. The Disk II driver routines support any drive that emulates Apple's 16-sector Disk II (280 blocks, single volume, and so on).
If $CnFF = $FF, ProDOS assumes it has found a Disk II with 13-sector ROMs, which ProDOS does not support.
If ProDOS finds a value other than $00 or $FF at $CnFF, it assumes it has found an intelligent disk controller. If the STATUS byte at $CnFE indicates that the device supports READ and STATUS requests, ProDOS marks the global page with a device-driver address whose high-byte is equal to $Cn and whose low-byte is equal to the value found at $CnFF.
Page 112
The only calls to the disk driver are STATUS, READ, WRITE, and
FORMAT. The STATUS call should perform a check to verify that the
device is ready for a READ or WRITE. If it is not, the carry should be
set and the appropriate error code returned in the accumulator. If the
device is ready for a READ or WRITE, then the driver should clear the
carry, place a zero in the accumulator, and return the number of
blocks on the device in the X-register (low-byte) and Y-register
(high-byte).
If you wish to interface a disk controller card with more than two drives (or a device with more than two volumes), additional device driver vectors for disk controllers plugged into slot 5 or 6 may be installed in slot 1 or 2 locations. There will be no conflict with character devices physically present in these slots.
Device numbers for four drives in slot 5 or 6 are listed below.
Physical Slot Five: S5,D1 = $50 S5,D2 = $D0 S1,D1 = $10 S1,D2 = $90 Physical Slot Six: S6,D1 = $60 S6,D2 = $E0 S2,D1 = $20 S2,D2 = $A0
Page 113
The special locations in the ROM code are:
$CnFC-$CnFD
The total number of blocks on the device. Used for writing the disk's bit map and directory header after formatting. (If this location is $0000, it indicates that the number of blocks must be obtained by making a STATUS request.)
$CnFE
The status byte (bits 0 and 1 must be set for ProDOS to install the driver vector.) bit 7 - Medium is removable. bit 6 - Device is interruptable. bit 5-4 - Number of volumes on the device (0-3). bit 3 - The device supports formatting. bit 2 - The device can be written to. bit 1 - The device can be read from (must be on). bit 0 - The device's status can be read -- (must be on). $CnFF The low-byte of entry to the driver routines. ProDOS will place $Cn + this byte in the global page.
Call Parameters
parameters are passed to the driver are: $42 Command: 0 = STATUS request 1 = READ request 2 = WRITE request 3 = FORMAT request
Note: The FORMAT code in the driver need only lay down address marks if required. The calling routine should write the virgin directory and bit map.
Page 114
$43
Unit Number:
7 6 5 4 3 2 1 0 +--+--+--+--+--+--+--+--+ |DR| SLOT | NOT USED | +--+--+--+--+--+--+--+--+
Note: The UNIT_NUMBER that appears in the device list (DEVLST) in the system globals will include the high nibble of the status byte ($CnFE) as an ID in its low nibble.
$44-$45 Buffer Pointer: Indicates the start of a 512-byte memory buffer for data transfer. $46-$47 Block Number: Indicates the block on the disk for data transfer. The device driver should report errors by setting the carry flag and loading the error code into the accumulator. The error codes that should be implemented are: $27 - I/O error $28 - No device connected $2B - Write protected
Page 115
Appendix A - The ProDOS BASIC System Program
Page 117
This appendix explains aspects of the BASIC system program
(BASIC.SYSTEM) that are beyond the scope of the manual BASIC
Programming With ProDOS. The primary subjects discussed in this
appendix are
- how the BASIC system program uses memory
- how a machine-language program can make calls to the BASIC system program
- useful locations in the BASIC system program
- how you can add commands to the BASIC system program.
A.1 - Memory Map
The arrangement of ProDOS in memory is decided when the system is started up, and it depends on your particular system configuration. Figure A-1 shows the memory organization for an Apple IIe (64K or 128K) or Apple IIc (128K).
Page 118
Figure A-1. Memory Map
Main Memory Auxiliary Memory
(IIc or 128K IIe only)
$FFFF+---------+$FFFF+---------+ $FFFF+---------+
|.Monitor.| |#########| |.........|
$F800|---------| |#########| |.........|
|.........| |#########| |.........|
|.........| |#########| |.........|
|.........| |#########| |.........|
|.........| |#########| |.........|
|.........| |#########| |.........|
|.........| |#ProDOS##| |.........|
|Applesoft| |#########|$DFFF+---------+$E000|---------|$DFFF+---------+
|.........| |#########| |.........| | | |.........|
|.........| |#########| |.........| | | |.........|
|.........| |#########|$D400|---------| | | |.........|
|.........| |#########| |#########| | | |.........|
|.........| |#########|$D100|---------| | |$D100|---------|
|.........| |#########| | | | | | |
$D000|---------| +---------+ +---------+$D000+---------+ +---------+
|..Other..|
$C100+---------+
^ $BFFF+---------+ $BFFF+---------+
| |#########| |.........|
This ROM area| $BF00|---------| $BF00|---------|
on IIc and IIe |\\\\\\\\\| | |
only! |\\\\\\\\\| | | +---------+
|\\\\\\\\\| | | |#########|
|\\\\\\\\\| | | +---------+
|\\\\\\\\\| | | Used by ProDOS
|\BASIC.\\| | |
|\SYSTEM\\| | |
|\\\\\\\\\| | | +---------+
|\\\\\\\\\| | | |\\\\\\\\\|
|\\\\\\\\\| | | +---------+
|\\\\\\\\\| | | Used by
|\\\\\\\\\| | | BASIC.SYSTEM
$9600|---------| | |
| | | |
| | | | +---------+
| | | | |.........|
| | | | +---------+
| | | | Other used or
| | | | reserved areas
| | | |
| | | |
| | | | +---------+
| | | | | |
| | | | +---------+
| | | | Free Space
| | | |
/\/\/\/\/\/ /\/\/\/\/\/
/\/\/\/\/\/ /\/\/\/\/\/
| | | |
| | | |
| | | |
| | | |
| | | |
$800|---------| $800|---------|
|.........| |.........|
|.........| |.........|
|.........| |.........|
|.........| $400|---------|
|.........| |#########|
$300|---------| |#########|
| | |#########|
$300|---------| |#########|
|.........| $200|---------|
|.........| | |
$100|---------| $100|---------|
| | |#########|
| | $80|---------|
$4F|---------| | |
|#Shared/#| | |
|####safe#| | |
$3A|---------| | |
| | | |
+---------+ +---------+
$00
Page 119
HIMEM
When ProDOS starts up the BASIC system program, it loads all the necessary programs and data into memory as shown in Figure A-1, leaves a 1K buffer on the highest available 1K boundary, and then sets HIMEM right below this buffer. This buffer is used as the file buffer for commands, such as CATALOG, that only need a temporary buffer.
Table A-1 shows the possible settings of HIMEM, and the maximum number of bytes available to a program running under such a system configuration.
Table A-1. HIMEM and Program Workspace
System Bytes Available Configuration HIMEM to Programs 64K 38400 ($9600) 36352 ($8E00) Applesoft in ROM
These settings are in effect immediately after you boot the BASIC system program. While a program is running, however, these figures may change. Each time a file is opened, ProDOS lowers HIMEM by 1K ($400), keeping the 1K temporary command buffer immediately above it, and places a buffer for the file where the old temporary buffer was. When a file is closed, ProDOS releases the file's buffer, and raises HIMEM by 1K. Figure A-2 illustrates this process.
Page 120
Figure A-2. The Movement of HIMEM
_______ _______ _______ _______ _______ _______ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |_______| |_______| |_______| |_______| |_______| |_______| | | |///////| | | | | | | | | | Free | 1K |/CAT's/| 1K | Free | 1K | DOG's | 1K | DOG's | 1K | Free | 1K |_______| |_______| |_______| |_______| |_______| |_______| | | | | | | | | | | | | | HIMEM | | HIMEM | | HIMEM | | Free | 1K | CAT's | 1K | HIMEM | | | | | | | |_______| |_______| | | | | | | | | | | | | | | | | | | | | | HIMEM | | HIMEM | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |_______| |_______| |_______| |_______| |_______| |_______|
No Files During CAT After CAT Open "DOG" During CAT Close "DOG" Open
Buffer Management
There are many times when you might want machine-language routines to coexist with ProDOS; for example, when using interrupt-driven devices, when using input/output devices that have no ROM, or when using commands that you have added to ProDOS.
BASIC.SYSTEM provides buffer management for file I/O. Those facilities can also be utilized from machine-language modules operating in the ProDOS/Applesoft environment to provide protected areas for code, data, and so on.
BASIC.SYSTEM resides from $9A00 upward, with a general-purpose buffer from $9600 (HIMEM) to $99FF. When a file is opened, BASIC.SYSTEM does garbage collection if needed, moves the general-purpose buffer down to $9200, and installs a file I/O buffer at $9600. When a second file is opened, the general-purpose buffer is moved down to $8E00 and a second file I/O buffer is installed at $9200. If an EXEC file is opened, it is always installed as the highest file I/O buffer at $9600, and all the other buffers are moved down.
Additional regular file I/O buffers are installed by moving the general-purpose buffer down and installing it below the lowest file I/O buffer. All file I/O buffers, including the general-purpose buffer, are 1K (1024 bytes) and begin on a page boundary.
Page 121
BASIC.SYSTEM may be called from machine language to allocate any
number of pages (256 bytes) as a buffer, located above HIMEM and
protected from Applesoft BASIC programs. The ProDOS bit map is not
altered, so that files can be loaded into the area without an error from
the ProDOS Kernel. If you subsequently alter the bit map to protect the
area, you must mark the area as free when you are finished --
BASIC.SYSTEM will not do it for you.
To allocate a buffer, simply place the number of desired pages in the accumulator and use JSR GETBUFR ($BEF5). If the carry flag returns clear, the allocation was successful and the accumulator will return the high byte of the buffer address. If the carry flag returns set, an error has occurred and the accumulator will return the error code.
Note that the X and Y registers are not preserved. The first buffer is installed as the highest buffer, just below BASIC.SYSTEM from $99FF downward, regardless of the number and type of file I/O buffers that are open. If a second allocation is requested, it is installed immediately below the first. Thus, it is possible to assemble code to run at known addresses-relocatable modules are not needed.
To de-allocate the buffers created by the above call and move the file buffers back up, just use JSR FREEBUFR ($BEF8). Although more than one buffer may be allocated by this call, they may not be selectively de-allocated.
Important!
All routines that are to be called by BASIC.SYSTEM should begin with the CLD instruction. This includes I/O routines accessed by PR# and IN# and clock/calendar routines. This allows ProDOS to spot accidental calls.
For tips on raising LOMEM to provide more memory for assembly-language routines, and protecting high-res graphics pages, see the Applesoft BASIC Programmer's Reference Manual.
Page 122
The BASIC Global Page
The BASIC system program has a specific area of memory, its global page, in which it keeps its current status. This page lies in the address range $BE00 through $BEFF (48640-48895). When BASIC.SYSTEM is active, its fields are defined as follows:
BE00: CI.ENTRY JMP WARMDOS ;Reenter ProDOS/Applesoft
BE03: DOSCMD JMP SYNTAX ;External entry for command string
BE06: EXTRNCMD JMP XRETURN ;Called for added CMD syntaxing
BE09: ERROUT JMP ERROR ;Handles ONERR or prints error
BE0C: PRINTERR JMP PRTERR ;Prints error message
;Number is in accumulator
BE0F: ERRCODE DFB 0 ;ProDOS error code stored here
;and $DE for Applesoft
Page 123
Default I/O vectors. These may be changed by the user to remap
slots for nondisk devices. When the system is booted, all slots not
containing a ROM are considered not connected and the default vector
is left to point at the appropriate error handling routine.
BE10: OUTVECT0 DW COUT1 ;Monitor video output routine BE12: OUTVECT1 DW NODEVERR ;Default $C100 when ROM present BE14: OUTVECT2 DW NODEVERR ;Default $C200 when ROM present BE16: OUTVECT3 DW NODEVERR ;Default $C300 when ROM present BE18: OUTVECT4 DW NODEVERR ;Default $C400 when ROM present BE1A: OUTVECT5 DW NODEVERR ;Default $C500 when ROM present BE1C: OUTVECT6 DW NODEVERR ;Default $C600 when ROM present BE1E: OUTVECT7 DW NODEVERR ;Default $C700 when ROM present BE20: INVECT0 DW CHIN1 ;Monitor keyboard input routine BE22: INVECT1 DW NODEVERR ;Default $C100 when ROM present BE24: INVECT2 DW NODEVERR ;Default $C200 when ROM present BE26: INVECT3 DW NODEVERR ;Default $C300 when ROM present BE28: INVECT4 DW NODEVERR ;Default $C400 when ROM present BE2A: INVECT5 DW NODEVERR ;Default $C500 when ROM present BE2C: INVECT6 DW NODEVERR ;Default $C600 when ROM present BE2E: INVECT7 DW NODEVERR ;Default $C700 when ROM present BE30: VECTOUT DW COUT1 ;Current character output routine BE32: VECTIN DW CHIN1 ;Current character input routine BE34: VDOSIO DW DOSOUT ;ProDOS char out intercept routine
Page 124
BE36: DW DOSINP ;ProDOS char in intercept routine
BE38: VSYSIO DW 0,0 ;Internal redirection of I/O
BE3C: DEFSLT DFB $06 ;Default slot, set by 'S' parm
BE3D: DEFDRV DFB $01 ;Default drive, set by 'D' parm
BE3E: PREGA DFB 0 ;Register save area
BE3F: PREGX DFB 0
BE40: PREGY DFB 0
BE41: DTRACE DFB 0 ;Applesoft trace enable
BE42: STATE DFB 0 ;0=Imm, >0=Def modes
BE43: EXACTV DFB 0 ;EXEC file active if bit 7 on
BE44: IFILACTV DFB 0 ;Input file active if bit 7 on
BE45: OFILACTV DFB 0 ;Output file active if bit 7 on
BE46: PFXACTV DFB 0 ;Prefix input active if bit 7 on
BE47: DIRFLG DFB 0 ;File being accessed is directory
BE48: EDIRFLG DFB 0 ;End of directory encountered
BE49: STRINGS DFB 0 ;Counter for free string space
BE4A: TBUFPTR DFB 0 ;Temporory buffered char count (WRITE)
BE4B: INPTR DFB 0 ;Input char count during kbd input
BE4C: CHRLAST DFB 0 ;Last character output (for error detect)
BE4D: OPENCNT DFB $00 ;Number of open file (except EXEC file)
BE4E: EXFILE DFB $00 ;Flag to indicate EXEC file being closed
BE4F: CATFLAG DFB $00 ;File being input is (translated) dir
BE50: XTRNADDR DW 0 ;Execution address of external cmd (0)
BE52: XLEN DFB 0 ;Length of command string-1, ('HELP'=3)
BE53: XCNUM DFB 0 ;BASIC cmd number (external cmd if =0)
Page 125
Command parameter PBITS/FBITS bit definitions:
BE54: PFIX EQU $80 ;Prefix needs fetching, pathname optional BE54: SLOT EQU $40 ;No parameters to be processed BE54: RRUN EQU $20 ;Command only valid during program BE54: FNOPT EQU $10 ;Filename is optional BE54: CRFLG EQU $08 ;CREATE allowed BE54: T EQU $04 ;File type BE54: FN2 EQU $02 ;Filename '2' for RENAME BE54: FN1 EQU $01 ;Filename expected
And for PBITS+1/FBITS+1 definitions:
BE54: AD EQU $80 ;Address BE54: B EQU $40 ;Byte BE54: E EQU $20 ;End address BE54: L EQU $10 ;Length BE54: LINE EQU $08 ;'@' line number BE54: SD EQU $04 ;Slot and drive numbers BE54: F EQU $02 ;Field BE54: R EQU $01 ;Record BE54: V EQU $00 ;Volume number ignored
When the BASIC system program recognizes one of its commands, it sets up PBITS to indicate which parameters (#S, #D, and so on) may be used with that command. Then it parses the command string, marking the found parameters in FBITS, and placing their values in locations $BE58-$BE6B. The meanings of the bit within PBITS and FBITS are discussed in the section "Adding Commands to the BASIC System Program."
BE54: PBITS DW 0 ;Allowed parameter bits BE56: FBITS DW 0 ;Found parameter bits
Page 126
The following locations hold the values of the parameters for the
BASIC commands. As the BASIC system program parses command
options, it sets the value of the corresponding command parameters.
Previously set parameters do not change.
BE58: PVALS EQU * BE58: VADDR DW 0 ;Parameter value for 'A' parm BE5A: VBYTE DFB 0,0,0 ;Parameter value for 'B' parm BE5D: VENDA DW 0 ;Parameter value for 'E' parm BE5F: VLNTH DW 0 ;Parameter value for 'L' parm BE61: VSLOT DFB 0 ;Parameter value for 'S' parm BE62: VDRIV DFB 0 ;Parameter value for 'D' parm BE63: VFELD DW 0 ;Parameter value for 'F' parm BE65: VRECD DW 0 ;Parameter value for 'R' parm BE67: VVOLM DFB 0 ;Parameter value for 'V' parm BE68: VLINE DW 0 ;Parameter value for '@' parm BE6A: PTYPE EQU *-PVALS BE6A: VTYPE DFB 0 ;Parameter value for 'T' parm BE6B: PIOSLT EQU *-PVALS BE6B: VIOSLT DFB 0 ;Parameter value for IN# or PR# BE6C: VPATH1 DW TXBUF-1 ;Pathname 1 buffer BE6E: VPATH2 DW TXBUF2 ;Pathname 2 buffer (RENAME)
Page 127
GOSYSTEM is used to make all MLI calls since errors must be
translated before returning to the calling routine. On entry the
Accumulator should contain the call number. The address of the
parameter table is looked up and set based on the call number. Only
file management calls can be made using this routine: $C0-$D3. The
original implementation of this BASIC system program contains only
these calls.
BE70: GOSYSTEM STA SYSCALL ;Save call number
BE73: STX CALLX ;Preserve X register
BE76: AND #$1F ;Strip high bits of call number
BE78: TAX ; and use as lookup index
BE79: LDA SYSCTBL,X ;Get low address of parm table
BE7C: STA SYSPARM
BE7F: LDX CALLX ;Restore X before calling
BE82: JSR MLIENTRY ;Call ProDOS MLI to execute request
BE85: SYSCALL DFB 0
BE86: SYSPARM DW * ;(High address should be same
; as parameter tables)
BE88: BCS BADCALL ;Branch if error encountered
BE8A: RTS
BADCALL converts MLI errors into BASIC system program error equivalents. Routines should be entered with error number in the Accumulator. The BADCALL routine should be used whenever a ProDOS MLI call returns an error and BASIC.SYSTEM will be used to print the error message. Returns BASIC system program error number in Accumulator. All unrecognized errors are mapped to I/O error.
X register is restored to its value before the call is made. Carry is set.
BE8B: BADCALL LDA #12 ;19 errors are mapped to BE8D: MLIERR1 CMP MLIERTBL,X ; other than I/O error BE90: BEQ MLIERR2 BE92: DEX BE93: BPL MLIERR1 BE95: LDX #$13 ;If not recognized, make it I/O error BE97: MLIERR2 LDA BIERRTBL,X ;return error in Accumulator BE9A: LDX CALLX ;Restore X register BE9D: SEC ;Set Carry to indicate error BE9E: XRETURN RTS BE9F: CISPARE1 DFB $00
Page 128
The following are the system-call parameter tables. These tables
must reside within the same page of memory. Only those parameters
that are subject to alterations have been labeled. SYSCTBL below
contains the low-order addresses of each parameter table. SYSCTBL
is used by GOSYSTEM to set up the address of the parameter table
for each call. (See GOSYSTEM.)
BEA0: SCREATE DFB $07
BEA1: DW TXBUF-1 ;Pointer to pathname
BEA3: CRACESS DFB $C3 ;$C1 if directory create
BEA4: CRFILID DFB $00
BEA5: CRAUXID DW $0000
BEA7: CRFKIND DFB 0
BEA8: DW 0 ;No predetermined date/time
BEAA: DW 0
BEAC: SSGPRFX EQU *
BEAC: SDSTROY DFB $01
BEAD: DW TXBUF-1 ;This call requires no modifications
BEAF: SRECNAME DFB $02
BEB0: DW TXBUF-1 ;No modifications needed
BEB2: DW TXBUF2
BEB4: SSGINFO DFB $00 ;P.CNT=7 if SET_FILE_INFO
;P.CNT=A if GET_FILE_INFO
BEB5: DW TXBUF-1
BEB7: FIACESS DFB $00 ;Access used by lock/unlock
BEB8: FIFILID DFB $00 ;FILE ID is type specifier
BEB9: FIAUXID DW $0000 ;Aux_id is used for load addr
; and record length
BEBB: FIFKIND DFB $00 ;Identifies trees vs. directories
BEBC: FIBLOKS DW $0000 ;Used by CAT commands for root dir
BEBE: FIMDATE DW $0000 ;Modification date & time
BEC0: DW $0000 ;should always be zeroed before call
BEC2: DW $0000 ;Create date and time ignored
BEC4: DW $0000
Page 129
BEC6: SONLINE EQU *
BEC6: SSETMRK EQU *
BEC6: SGETMRK EQU *
BEC6: SSETEOF EQU *
BEC6: SGETEOF EQU *
BEC6: SSETBUF EQU *
BEC6: SGETBUF EQU *
BEC6: DFB $02 ;Parameter count
BEC7: SBUFREF EQU *
BEC7: SREFNUM EQU *
BEC7: SUNITNUM EQU *
BEC7: DFB 0 ;Unit or reference number
BEC8: SDATPTR EQU *
BEC8: SMARK EQU *
BEC8: SEOF EQU *
BEC8: SBUFADR EQU *
BEC8: DFB 0,0,0 ;Some calls only use 2 bytes
;MRK & EOF use 3 bytes
BECB: SOPEN DFB $03
BECC: DW TXBUF-1
BECE: OSYSBUF DW $0000
BED0: OREFNUM DFB 0
BED1: SNEWLIN DFB $03
BED2: NEWLREF DFB $00 ;Reference number
BED3: NLINEBL DFB $7F ;Newline character is always CR
BED4: DFB $0D ; both $0D and $8D are recognized
BED5: SREAD EQU *
BED5: SWRITE EQU *
BED5: DFB $04
BED6: RWREFNUM DFB $00
BED7: RWDATA DW $0000 ;Pointer to data to be read/written
BED9: RWCOUNT DW $0000 ;Number of bytes to be read/written
BEDB: RWTRANS DW $0000 ;returned # of bytes read/written
Page 130
BEDD: SCLOSE EQU * BEDD: SFLUSH EQU * BEDD: DFB $01 BEDE: CFREFNUM DFB $00 BEDF: CCCSPARE DFB $00 BEE0: ASC 'COPYRIGHT APPLE, 1983' BEF5: GETBUFR JMP GETPAGES BEF8: FREBUFR JMP FREPAGES BEF8: RSHIMEM DFB 0, 0, 0, 0, 0
BASIC.SYSTEM Commands From Assembly Language
There are times when a routine wants to perform functions that are already implemented by the BASIC system program -- deleting and renaming files, displaying a directory, and so on. The DOSCMD vector serves just this function.
First a routine should place the desired BASIC command in the input buffer ($200). It should be an ASCII string with the high bits set, followed by a carriage return ($8D), exactly as the Monitor GETLN routine would leave a string. Next the routine should do a JSR to the DOSCMD entry point ($BE03).
BASIC.SYSTEM will parse the command, set up all the parameters, (as explained in Section A.3.3), and then execute the command. If there is an error, it will return the error code in the accumulator with the carry set. If it is 0, there was no error. Otherwise it contains a BASIC system program error number.
Note: The JSR DOSCMD must be executed in deferred mode (from a BASIC program), rather than in immediate mode. This applies also to the Monitor program: from the Monitor, you can't do a $xxxxG to execute the code that contains the JSR DOSCMD. This is because BASIC.SYSTEM checks certain state flags, which are set correctly only while in deferred mode.
There are certain commands that do not work as expected when initiated via DOSCMD: RUN -(dash command), LOAD, CHAIN, READ, WRITE, APPEND, and EXEC. Use them this way at your own risk.
Page 131
The commands that do work correctly are: CATALOG, CAT, PREFIX,
CREATE, RENAME, DELETE, LOCK, UNLOCK, SAVE, STORE,
RESTORE, PR#, IN#, FRE, OPEN, CLOSE, FLUSH, POSITION, BRUN,
BLOAD, and BSAVE.
The following are: 1. An example of a BASIC program that uses the BLOAD command to load an assembly-language routine that exercises the DOSCMD routine.
2. A listing of that assembly-language routine. 3. You should review them before writing your own routine.
10 REM YOU MUST CALL THE ROUTINE FROM INSIDE A BASIC PROGRAM 11 REM 12 REM 20 PRINT CHR$(4)"BLOAD/P/PROGRAMS/CMD.0" 30 CALL 4096 40 PRINT "BACK TO THE WONDERFUL WORLD OF BASIC!" 50 END
Page 132
1000: 1000 1 ORG $1000 1000: FD6F 2 GETLN1 EQU $FD6F ; MONITORS INPUT ROUTINE 1000: BE03 3 DOSCMD EQU $BE03 ; BASIC.SYSTEM GLBL PG DOS CMD ENTRY 1000: FDED 4 COUT EQU $FDED ; MONITORS CHAR OUT ROUTINE 1000: BE0C 5 PRERR EQU $BE0C ; PRINT THE ERROR 1000: 6 * 1000: 7 * 1000: 8 * 1000:A2 00 9 START LDX #0 ; DISPLAY PROMPT... 1002:BD 1F 10 10 L1 LDA PROMPT,X ; 1005:F0 06 100D 11 BEQ CONT ; BRANCH IF END OF STRING 1007:20 ED FD 12 JSR COUT ; 100A:E8 13 INX ; 100B:D0 F5 1002 14 BNE L1 ; LOOP UNTIL NULL TERMINATOR HIT 100D: 15 * 100D:20 6F FD 16 CONT JSR GETLN1 ; ACCEPT COMMAND FROM KB 1010:20 03 BE 17 JSR DOSCMD ; AND EXECUTE COMMAND 1013:2C 10 C0 18 BIT $C010 ; CLEAR STROBE 1016:B0 02 101A 19 BCS ERROR ; BRANCH IF ERROR DETECTED 1018:90 E6 1000 20 BCC START ; OTHERWISE RESTART 101A: 21 * 101A: 22 * 101A: 23 * NOTE: AFTER HANDLING YOUR ERROR YOU MUST CLEAR THE CARRY 101A: 24 * BEFORE RETURNING TO BASIC OR BASIC WILL DO 101A: 25 * STRANGE TO YOU. 101A: 26 * 101A:20 0C BE 27 ERROR JSR PRERR ; PRINT 'ERR' 101D:18 28 CLC ; 101E:60 29 RTS ; RETURN TO BASIC 101F: 30 * 101F: 31 MSB ON 101F: 32 * 101F:8D 33 PROMPT DB $8D ; OUTPUT A RETURN FIRST 1020:C5 CE D4 C5 34 ASC 'ENTER BASIC.SYSTEM COMMAND --> ' 103F:00 35 DB 0
Page 133
DOSCMD is merely a way to perform some BASIC.SYSTEM commands
from assembly language, and is not a substitute for performing the
commands in BASIC. Keep in mind the consequences of the command
you are executing. For example, when doing a BRUN or BLOAD, make
sure the code is loaded at proper addresses.
After you call DOSCMD, the carry bit will be set if an error has occurred. The accumulator will have the error number.
There are three ways to handle DOSCMD errors:
- Do a JSR ERROUT ($BE09). This returns control to your
BASIC ONERR routine, where you can handle the error.
- Do a JSR PRINTERR ($BE0C). This prints Out the error and
returns control to the point just after the JSR.
- Handle the error yourself. Be sure to clear the carry (CLC) before
returning control to BASIC.SYSTEM. If you don't, an error will be assumed, and the results are unpredictable.
Adding Commands to the BASIC System Program
The EXTRNCMD location in the global page allows you to add your own commands to the ProDOS command set. Once you attach a command, it is treated as if it were one of the BASIC.SYSTEM commands, except that the original commands have preference. To execute your command in immediate mode, just enter it. To execute it in deferred mode, preface it with PRINT CHR$(4).
Whenever BASIC.SYSTEM receives a command, it first checks its command list for a match. If the command is not recognized, BASIC.SYSTEM sends the command to the external command handlers, if any are connected. If no external command handler claims the command, BASIC.SYSTEM passes control to Applesoft, which returns an error if the command is not recognized.
If you have frequent need for special commands, you can write your own command handler and attach it to BASIC.SYSTEM through the EXTRNCMD jump vector. First, save the current EXTRNCMD vector (to JMP to if the command is not yours), and install the address of your routine in EXTRNCMD+1 and +2 (low byte first). Your routine must do three things:
Page 134
- It must check for the presence of your command(s) by inpecting the
GETLN input buffer. If the command is not yours, you must set the carry (SEC) and JMP to the initial EXTRNCMD vector you saved to continue the search.
- If the command is yours, you must zero XCNUM ($BE53) to indicate
an external command, and set XLEN ($BE52) equal to the length of your command string minus one.
- If there are no associated parameters (such as slot, drive, A$, and so
on) to parse, or if you're going to parse them yourself, you must set all 16 parameter bits in PBITS ($BE54,$BE55) to zero. And, if you're going to handle everything yourself before returning control to BASIC.SYSTEM, you must point XTRNADDR ($BE50,$BE51) at an RTS instruction. XRETURN ($BE9E) is a good location. Now, just fall through to your execution routines.
- If there are parameters to parse, it is easiest to let BASIC.SYSTEM
parse them for you (unless you want to use some undefined parameters). By setting up the bits in PBITS ($BE54,$BE55), and setting XTRNADDR ($BE50,$BE51) equal to the location where execution of your command begins, you can return control to BASIC.SYSTEM, with an RTS, and let it parse and verify the parameters and return them to you in the global page.
- It must execute the instructions expected of the command, and it
should RTS with the carry cleared.
Note: Having BASIC.SYSTEM parse your external command parameters was initially intended only for its own use. As it happens, not all parameters can be parsed separately. The low byte of PBITS ($BE54) must have a nonzero value to have BASIC.SYSTEM parse parameters.
This means that regardless of the parameters you need parsed, you must also elect to parse some parameter specified by the low byte of PBITS. For example, set PBITS to $10, filename optional (this parameter need not be known by the user).
The following are two sample routines, BEEP and BEEPSLOT. They can reside together as external commands. BEEP handles everything itself, while BEEPSLOT lets you pass a slot and drive parameter (,S#,D#) where the drive is ignored.
Page 135
A.3.2.1 - BEEP Example
**************************************************************
* *
* BRUN BEEP.0 TO INSTALL THE ROUTINE'S ADDRESS IN EXTRNCMD. *
* THEN TYPE BEEP AS AN IMMEDIATE COMMAND OR USE PRINT *
* CHR$(4);"BEEP" IN A PROGRAM. *
* *
**************************************************************
*
*
ORG $300
INBUF EQU $200 ;GETLN input buffer.
WAIT EQU $FCA8 ;Monitor wait routine.
BELL EQU $FF3A ;Monitor bell routine.
EXTRNCMD EQU $BE06 ;External cmd JMP vector.
XTRNADDR EQU $BE50 ;Ext cmd implementation addr.
XLEN EQU $BE52 ;length of command string-1.
XCNUM EQU $BE53 ;CI cmd no. (ext cmd - 0).
PBITS EQU $BE54 ;Command parameter bits.
XRETURN EQU $BE9E ;Known RTS instruction.
MSB ON ;Set high bit on ASCII
*
* FIRST SAVE THE EXTERNAL COMMAND ADDRESS SO YOU WON'T
* DISCONNECT ANY PREVIOUSLY CONNECTED COMMAND.
*
LDA EXTRNCMD+1
STA NXTCMD
LDA EXTRNCMD+2
STA NXTCMD+1
*
LDA #>BEEP ;Install the address of our
STA EXTRNCMD+1 ; command handler in the
LDA #<BEEP ; external command JMP
STA EXTRNCMD+2 ; vector.
RTS
*
BEEP LDX #0 ;Check for our command.
NXTCHR LDA INBUF,X ;Get first character.
CMP CMD,X ;Does it match?
BNE NOTOURS ;No, back to CI.
INX ;Next character
CPX #CMDLEN ;All characters yet?
BNE NXTCHR ;No, read next one.
*
LDA #CMDLEN-1 ;Our cmd! Put cmd length-1
STA XLEN ; in CI global XLEN.
LDA #>XRETURN ;Point XTRNADDR to a known
STA XTRNADDR ; RTS since we'll handle
LDA #<XRETURN ; at the time we intercept
Page 136
STA XTRNADDR+1 ; our command.
LDA #0 ;Mark the cmd number as
STA XCNUM ; zero (external).
STA PBITS ;And indicate no parameters
STA PBITS+1 ; to be parsed.
*
LDX #5 ;Number of desired beeps.
NXTBEEP JSR BELL ;Else, beep once.
LDA #$80 ;Set up the delay
JSR WAIT ; and wait.
DEX ;Decrement index and
BNE NXTBEEP ; repeat until X = 0.
*
CLC ;All done successfully.
RTS ; RETURN WITH THE CARRY CLEAR.
*
NOTOURS SEC ; ALWAYS SET CARRY IF NOT YOUR
JMP (NXTCMD) ; CMD AND LET NEXT COMMAND TRY
* ; TO CLAIM IT.
CMD ASC "BEEP" ;Our command
CMDLEN EQU *-CMD ;Our command length
*
NXTCMD DW 0 ; STORE THE NEXT EXT CMD'S
; ADDRESS HERE.
Page 137
BEEPSLOT Example
*************************************************************
* *
* BRUN BEEPSLOT.0 TO INSTALL THE ROUTINE'S ADDRESS IN *
* EXTRNCMD. THEN ENTER BEEPSLOT,S(n),D(n). ONLY A LEGAL *
* SLOT AND DRIVE NUMBERS ARE ACCEPTABLE. IF NO SLOT NUMBER *
* IT WILL USE THE DEFAULT SLOT NUMBER. ANY DRIVE NUMBER IS *
* SIMPLY IGNORED. THE COMMAND MAY ALSO BE USED IN A *
* PROGRAM PRINT CHR$(4) STATEMENT. *
* *
*************************************************************
*
*
ORG $2000
INBUF EQU $200 ;GETLN input buffer.
WAIT EQU $FCA8 ;Monitor wait routine.
BELL EQU $FF3A ;Monitor bell routine
EXTRNCMD EQU $BE06 ;External cmd JMP vector.
XTRNADDR EQU $BE50 ;Ext cmd implementation addr.
XLEN EQU $BE52 ;Length of command string-1.
XCNUM EQU $BE53 ;CI cmd no. (ext cmd = 0).
PBITS EQU $BE54 ;Command parameter bits.
VSLOT EQU $BE61 ;Verified slot parameter.
MSB ON ;Set high bit on ASCII.
*
* REMEMBER TO SAVE THE PREVIOUS COMMAND ADDRESS.
*
LDA EXTRNCMD+1
STA NXTCMD
LDA EXTRNCMD+2
STA NXTCMD+1
*
LDA #>BEEPSLOT ;Install the address of our
STA EXTRNCMD+1 ; command handler in the
LDA #<BEEPSLOT ; external command JMP
STA EXTRNCMD+2 ; vector.
RTS
*
BEEPSLOT LDX #0 ;Check for our command.
NXTCHR LDA INBUF,X ;Get first character.
CMP CMD,X ;Does it match?
BNE NOTOURS ;NO, SO CONTINUE WITH NEXT CMD.
INX ;Next character
CPX #CMDLEN ;All characters yet?
BNE NXTCHR ;No, read next one.
*
LDA #CMDLEN-1 ;Our cmd! Put cmd length-1
STA XLEN ; in CI global XLEN.
LDA #>EXECUTE ;Point XTRNADDR to our
Page 138
STA XTRNADDR ; command execution
LDA #<EXECUTE ; routine
STA XTRNADDR+1
LDA #0 ;Mark the cmd number as
STA XCNUM ; zero (external).
*
LDA #%00010000 ;Set at least one bit
STA PBITS ; in PBITS low byte!
*
LDA #%00000100 ;And mark PBITS high byte
STA PBITS+1 ; that slot & drive are legal.
CLC ;Everything is OK.
RTS ;Return to BASIC.SYSTEM
*
EXECUTE LDA VSLOT ;Get slot parameter.
TAX ;Transfer to index reg.
NXTBEEP JSR BELL ;Else, beep once.
LDA #$80 ;Set up the delay
JSR WAIT ; and wait.
DEX ;decrement index and
BNE NXTBEEP ; repeat until x = 0.
CLC ;All done successfully.
RTS ;Back to BASIC.SYSTEM.
*
* IT'S NOT OUR COMMAND SO MAKE SURE YOU LET BASIC
* CHECK WHETER OR NOT IT'S THE NEXT COMMAND.
*
NOTOURS SEC ;SET CARRY AND LET
JMP (NXTCMD) ; NEXT EXT CMD GO FOR IT.
*
CMD ASC "BEEPSLOT" ;Our command
CMDLEN EQU *-CMD ;Our command length
NXTCMD DW 0 ; STORE THE NEXT COMMAND'S
; ADDRESS HERE.
Page 139
Command String Parsing
First, the external command must tell the BASIC system program which parameters are allowed for the command. It does this by assigning the appropriate values to the two PBITS bytes, which have the following meanings:
Address: $BE54 $BE55
_______________________ _______________________
| | | | | | | | | | | | | | | | | |
PBITS: | | | | | | | | | | | | | | | | | |
|__|__|__|__|__|__|__|__| |__|__|__|__|__|__|__|__|
Bit #: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Bit # - Meaning
15 - Prefix needs fetching. Pathname is optional
14 - No parameters to be processed
13 - Command only valid during program execution
12 - Filename is optional
11 - Create allowed if file doesn't exist
10 - File type (Ttype) optional
9 - A second filename expected
8 - A first filename expected
7 - Address (A#) allowed
6 - Byte (B#) allowed
5 - End address (E#) allowed
4 - Length (L#) allowed
3 - Line number (@#) allowed
2 - Slot and Drive (S# and D#) allowed
1 - Field (F#) allowed
0 - Record (R#) allowed
Having done this, the routine should place the length of the recognized command word minus one into XLEN ($BE52). It should also place a $00 into XCNUM ($BE53), indicating that an external command was found, and it should place the address within the routine at which further processing of the parsed command will take place into XTRNADDR ($BE50). Then it should RTS back to the BASIC system program.
Page 140
The BASIC system program will see that the command was recognized,
and it will parse the string according to PBITS. For each parameter
that was used in the command, it will set the corresponding bit in
FBITS ($BE56) and update the value of that parameter in the global
page. Finally, it will do a JSR to the location indicated in
XTRNADDR ($BE50).
The routine can now process the command. All parameters are stored in the global page except the filenames which are stored in the locations indicated by VPATH1 and VPATH2.
The HELP command is such a routine. When you type -HELP, the help command is loaded into memory at $2000, it moves HIMEM down and places itself above HIMEM, then it marks itself in the bit map.
Finally it places the start address of the routine in the EXTRNCMD vector. The BASIC system program now recognizes a series of HELP commands as well as the NOHELP command.
The NOHELP command removes the help routine's address from the EXTRNCMD vector, unmarks the routine from the bit map, and moves HIMEM back up.
Page 141
Zero Page
Figure A-3 is a memory map that shows the locations used by the Monitor, Applesoft, the Device Drivers, and the ProDOS MLI. The owner of each location is shown by a letter: M, A, D, or P.
Figure A-3. Zero Page Memory Map Use by the Monitor (M), Applesoft (A), Disk Drivers (D), and ProDOS MLI (P) is shown.
Decimal---0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 , Hex---$0 $1 $2 $3 $4 $5 $6 $7 $8 $9 $A $B $C $D $E $F 0 $00 DA DA A A A A A A A A A A 16 $10 A A A A A A A A A A 32 $20 M M M M M M M M M M M M M M M M 48 $30 M M M M M M M M M M PMD PMD PMD PMD PMD DM 64 $40 PMD PMD PMD PMD PMD PMD PMD PM PM PM P P P P PM M 80 $50 MA MA MA MA MA MA A A A A A A A A A A 96 $60 A A A A A A A A A A A A A A A A 112 $70 A A A A A A A A A A A A A A A A 128 $80 A A A A A A A A A A A A A A A A 144 $90 A A A A A A A A A A A A A A A A 160 $A0 A A A A A A A A A A A A A A A A 176 $B0 A A A A A A A A A A A A A A A A 192 $C0 A A A A A A A A A A A A A A 208 $D0 A A A A A A A A A A A A A A 224 $E0 A A A A A A A A A A 240 $F0 A A A A A A A A A A
If you need many zero-page locations for your routines, choose a region of already-used locations, save them at the beginning of the routine, and then restore them at the end.
Page 142
The Extended 80-Column Text Card
The Apple IIe computer can optionally contain an Extended 80-Column Text Card, giving the computer access to an additional 64K of RAM.
(The Apple IIc has the equivalent of such a card built in.) ProDOS uses this extra RAM as a volume, just like a small disk volume. This volume is initially given the name /RAM, but it can be renamed.
The 64K of RAM on the card is logically partitioned into 127 512-byte blocks of information. The contents of these blocks are:
Blocks 00-01 - Unavailable Block 02 - Volume directory Block 03 - Volume bit map Blocks 04-07 - Unavailable Blocks 08-126 - Directories and files
A detailed description of the way these blocks are used on a disk volume is in Appendix B. The major differences between a disk volume and /RAM are:
- On a disk volume, blocks 0 and 1 are used for the loader program.
Since /RAM is not a bootable volume, these blocks are not used.
- On a disk volume, there are usually four blocks reserved for the
volume directory, with a maximum capacity of 51 files in the volume directory. On /RAM, there is only one block of volume directory: it can hold 12 files (any or all of them can be subdirectory files).
- Normal disk devices are associated with a given slot and drive.
/RAM is placed in the device list as slot 3, drive 2.
This arrangement gives you a total of 119 blocks of file storage.
Page 143
Appendix B - File Organization
Page 145
This appendix contains a detailed description of the way that ProDOS
stores files on disks. For most system program applications, the MLI
insulates you from this level of detail. However, you must use this
information if you want
- to list the files in a directory
- to copy a sparse file without increasing the file's size
- to compare two sparse files.
This appendix first explains the organization of information on volumes. Next, it shows the storage of volume directories, directories, and the various stages of standard files. Finally it presents a set of diagrams that summarize all the material in this appendix. You can refer to these diagrams as you read the appendix. They will become your most valuable tool for working with file organization.
Format of Information on a Volume
When a volume is formatted for use with ProDOS, its surface is partitioned into an array of tracks and sectors. In accessing a volume, ProDOS requests not a track and sector, but a logical block from the device corresponding to that volume. That device's driver translates the requested block number into the proper track and sector number; the physical location of information on a volume is unimportant to ProDOS and to a system program that uses ProDOS. This appendix discusses the organization of information on a volume in terms of logical blocks, numbered starting with zero, not tracks and sectors.
When the volume is formatted, information needed by ProDOS is placed in specific logical blocks. A loader program is placed in blocks 0 and 1 of the volume. This program enables ProDOS to be booted from the volume. Block 2 of the volume is the key block (the first block) of the volume directory file; it contains descriptions of (and pointers to) all the files in the volume directory. The volume directory occupies a number of consecutive blocks, typically four, and is immediately followed by the volume bit map, which records whether each block on the volume is used or unused. The volume bit map occupies consecutive blocks, one for every 4,096 blocks, or fraction thereof, on the volume. The rest of the blocks on the disk contain subdirectory file information, standard file information, or are empty.
The first blocks of a volume look something like Figure B-1.
Page 146
Figure B-1. Blocks on a Volume
+----------------------------------- ---------------------------------- ------------------- | | | Block 2 | | Block n | Block n + 1 | | Block p | | Block 0 | Block 1 | Volume | ... | Volume | Volume | ... | Volume | Other | Loader | Loader | Directory | | Directory | Bit Map | | Bit Map | Files | | | (Key Block) | | (Last Block) | (First Block) | | (Last Block) | +----------------------------------- ---------------------------------- -------------------
The precise format of the volume directory, volume bit map, subdirectory files and standard files are explained in the following sections.
Format of Directory Files
The format of the information contained in volume directory and subdirectory files is quite similar. Each consists of a key block followed by zero or more blocks of additional directory information. The fields in a directory's key block are: a pointer to the next block in the drectory; a header entry that describes the directory; a number of file entries describing, and pointing to, the files in that directory; and zero or more unused bytes. The fields in subsequent (non-key) blocks in a directory are: a number of entries describing, and pointing to, the files in that directory; and zero or more unused bytes. The format of a directory file is represented in Figure B-2.
Page 147
Figure B-2. Directory File Format
Key Block Any Block Last Block
/ +-------+ +-------+ +-------+
| | 0 |<---|Pointer|<--...<--|Pointer| Blocks of a directory:
| |-------| |-------| |-------| Not necessarily contiguous,
| |Pointer|--->|Pointer|-->...-->| 0 | linked by pointers.
| |-------| |-------| |-------|
| |Header | | Entry | ... | Entry |
| |-------| |-------| |-------| Header describes the
| | Entry | | Entry | ... | Entry | directory file and its
| |-------| |-------| |-------| contents.
One / / More / / More / / More /
Block \ /Entries/ /Entries/ /Entries/
| |-------| |-------| |-------| Entry describes
| | Entry | | Entry | ... | Entry | and points to a file
| |-------| |-------| |-------| (subdirectory or
| | Entry | | Entry | ... | Entry | standard) in that
| |-------| |-------| |-------| directory.
| |Unused | |Unused | ... |Unused |
\ +-------+ +-------+ +-------+
The header entry is the same length as all other entries. The only organizational difference between a volume directory file and a subdirectory file is in the header.
See the sections "Volume Directory Headers" and "Subdirectory Headers."
Pointer Fields
The first four bytes of each block used by a directory file contain pointers to the preceding and succeeding blocks in the directory file, respectively. Each pointer is a two-byte logical block number, low byte first, high byte second. The key block of a directory file has no preceding block: its first pointer is zero. Likewise, the last block in a directory file has no successor: its second pointer is zero.
By the Way: All block pointers used by ProDOS have the same format: low byte first, high byte second.
Volume Directory Headers
Block 2 of a volume is the key block of that volume's directory file.
The volume directory header is at byte position $0004 of the key block, immediately following the block's two pointers. Thirteen fields are currently defined to be in a volume directory header: they contain all the vital information about that volume. Figure B-3 illustrates the structure of a volume directory header. Following Figure B-3 is a description of each of its fields.
Page 148
Figure B-3. The Volume Directory Header
Field Byte of
Length Block
+----------------------------+
1 byte | storage_type | name_length | $04
|----------------------------|
| | $05
/ /
15 bytes / file_name /
| | $13
|----------------------------|
| | $14
/ /
8 bytes / reserved /
| | $1B
|----------------------------|
| | $1C
| creation | $1D
4 bytes | date & time | $1D
| | $1F
|----------------------------|
1 byte | version | $20
|----------------------------|
1 byte | min_version | $21
|----------------------------|
1 byte | access | $22
|----------------------------|
1 byte | entry_length | $23
|----------------------------|
1 byte | entries_per_block | $24
|----------------------------|
| | $25
2 bytes | file_count | $26
|----------------------------|
| | $27
2 bytes | bit_map_pointer | $28
|----------------------------|
| | $29
2 bytes | total_blocks | $2A
+----------------------------+
Page 149
storage_type and name_length (1 byte): Two four-bit fields are
packed into this byte. A value of $F in the high four bits (the
storage_type) identifies the current block as the key block of a volume
directory file. The low four bits contain the length of the volume's
name (see the file_name field, below). The name_length can be
changed by a RENAME call.
file_name (15 bytes): The first n bytes of this field, where n is specified by name_length, contain the volume's name. This name must conform to the filename (volume name) syntax explained in Chapter 2.
The name does not begin with the slash that usually precedes volume names. This field can be changed by the RENAME call.
reserved (8 bytes): Reserved for future expansion of the file system.
creation (4 bytes): The date and time at which this volume was initialized. The format of these bytes is described in Section B.4.2.2.
version (1 byte): The version number of ProDOS under which this volume was initialized. This byte allows newer versions of ProDOS to determine the format of the volume, and adjust their directory interpretation to conform to older volume formats. In ProDOS 1.0, version = 0.
min_version: Reserved for future use. In ProDOS 1.0, it is 0.
access (1 byte): Determines whether this volume directory can be read written, destroyed, and renamed. The format of this field is described in Section B.4.2.3.
entry_length (1 byte): The length in bytes of each entry in this directory. The volume directory header itself is of this length.
entry_length = $27.
entries_per_block (1 byte): The number of entries that are stored in each block of the directory file. entries_per_block = $0D.
file_count (2 bytes): The number of active file entries in this directory file. An active file is one whose storage_type is not 0. See Section B.2.4 for a description of file entries.
bit_map_pointer (2 bytes): The block address of the first block of the volume's bit map. The bit map occupies consecutive blocks, one for every 4,096 blocks (or fraction thereof) on the volume. You can calculate the number of blocks in the bit map using the total_blocks field, described below.
Page 150
The bit map has one bit for each block on the volume: a value of 1
means the block is free; 0 means it is in use. If the number of blocks
used by all files on the volume is not the same as the number
recorded in the bit map, the directory structure of the volume has been
damaged.
total_blocks (2 bytes): The total number of blocks on the volume.
Subdirectory Headers
The key block of every subdirectory file is pointed to by an entry in a parent directory; for example, by an entry in a volume directory (explained in Section B.2). A subdirectory's header begins at byte position $0004 of the key block of that subdirectory file, immediately following the two pointers.
Its internal structure is quite similar to that of a volume directory header. Fourteen fields are currently defined to be in a subdirectory.
Figure B-4 illustrates the structure of a subdirectory header. A description of all the fields in a subdirectory header follows Figure B-4.
Page 151
Figure B-4. The Subdirectory Header
Field Byte of
Length Block
+----------------------------+
1 byte | storage_type | name_length | $04
|----------------------------|
| | $05
/ /
15 bytes / file_name /
| | $13
|----------------------------|
| | $14
/ /
8 bytes / reserved /
| | $1B
|----------------------------|
| | $1C
| creation | $1D
4 bytes | date & time | $1D
| | $1F
|----------------------------|
1 byte | version | $20
|----------------------------|
1 byte | min_version | $21
|----------------------------|
1 byte | access | $22
|----------------------------|
1 byte | entry_length | $23
|----------------------------|
1 byte | entries_per_block | $24
|----------------------------|
| | $25
2 bytes | file_count | $26
|----------------------------|
| | $27
2 bytes | parent_pointer | $28
|----------------------------|
1 byte | parent_entry_number | $29
|----------------------------|
1 byte | parent_entry_length | $2A
+----------------------------+
Page 152
storage_type and name_length (1 byte): Two four-bit fields are
packed into this byte. A value of $E in the high four bits (the
storage_type) identifies the current block as the key block of a
subdirectory file. The low four bits contain the length of the
subdirectory's name (see the file_name field, below). The
name_length can be changed by a RENAME call.
file_name (15 bytes): The first name_length bytes of this field contain the subdirectory's name. This name must conform to the filename syntax explained in Chapter 2. This field can be changed by the RENAME call.
reserved (8 bytes): Reserved for future expansion of the file system.
creation (4 bytes): The date and time at which this subdirectory was created. The format of these bytes is described in Section B.4.2.2.
version (1 byte): The version number of ProDOS under which this subdirectory was created. This byte allows newer versions of ProDOS to determine the format of the subdirectory, and to adjust their directory interpretations accordingly. ProDOS 1.0: version = 0.
min_version (1 byte): The minimum version number of ProDOS that can access the information in this subdirectory. This byte allows older versions of ProDOS to determine whether they can access newer subdirectories. min_version = 0.
access (1 byte): Determines whether this subdirectory can be read, written, destroyed, and renamed, and whether the file needs to be backed up. The format of this field is described in Section B.4.2.3. A subdirectory's access byte can be changed by the SET_FILE_INFO call.
entry_length (1 byte): The length in bytes of each entry in this subdirectory. The subdirectory header itself is of this length.
entry_length = $27.
entries_per_block (1 byte): The number of entries that are stored in each block of the directory file. entries_per_block = $0D.
file_count (2 bytes): The number of active file entries in this subdirectory file. An active file is one whose storage_type is not 0. See Section "File Entries" for more information about file entries.
parent_pointer (2 bytes): The block address of the directory file block that contains the entry for this subdirectory. This two-byte pointer is stored low byte first, high byte second.
Page 153
parent_entry_number (1 byte): The entry number for this
subdirectory within the block indicated by parent_pointer.
parent_entry_length (1 byte): The entry_length for the directory that owns this subdirectory file. Note that with these last three fields you can calculate the precise position on a volume of this subdirectory's file entry. parent_entry_length = $27.
File Entries
Immediately following the pointers in any block of a directory file are a number of entries. The first entry in the key block of a directory file is a header; all other entries are file entries. Each entry has the length specified by that directory's entry_length field, and each file entry contains information that describes, and points to, a single subdirectory file or standard file.
An entry in a directory file may be active or inactive; that is, it may or may not describe a file currently in the directory. If it is inactive, the first byte of the entry (storage_type and name_length) has the value zero.
The maximum number of entries, including the header, in a block of a directory is recorded in the entries_per_block field of that directory's header. The total number of active file entries, not including the header, is recorded in the file_count field of that directory's header.
Figure B-5 describes the format of a file entry.
Page 154
Figure B-5. The File Entry
Field Entry
Length Offset
+----------------------------+
1 byte | storage_type | name_length | $00
|----------------------------|
| | $01
/ /
15 bytes / file_name /
| | $0F
|----------------------------|
1 byte | file_type | $10
|----------------------------|
| | $11
2 bytes | key_pointer | $12
|----------------------------|
| | $13
2 bytes | blocks_used | $14
|----------------------------|
| | $15
3 bytes | EOF |
| | $17
|----------------------------|
| | $18
| creation |
4 bytes | date & time |
| | $1B
|----------------------------|
1 byte | version | $1C
|----------------------------|
1 byte | min_version | $1D
|----------------------------|
1 byte | access | $1E
|----------------------------|
| | $1F
2 bytes | aux_type | $20
|----------------------------|
| | $21
| |
4 bytes | last mod |
| | $24
|----------------------------|
| | $25
2 bytes | header_pointer | $26
+----------------------------+
Page 155
storage_type and name_length (1 byte): Two four-bit fields are
packed into this byte. The value in the high-order four bits (the
storage_type) specifies the type of file pointed to by this file entry:
$1 = Seeding file
$2 = Sapling file
$3 = Tree file
$4 = Pascal area
$D = Subdirectory
Seedling, sapling, and tree files, the three forms of a standard file, are described in Section B.3. The low four bits contain the length of the file's name (see the file_name field, below). The name_length can be changed by a RENAME call.
file_name (15 bytes): The first name_length bytes of this field contain the file's name. This name must conform to the filename syntax explained in Chapter 2. This field can be changed by the RENAME call.
file_type (1 byte): A descriptor of the internal structure of the file.
Section B.4.2.4 contains a list of the currently defined values of this byte.
key_pointer (2 bytes): The block address of the master index block if a tree file, of the index block if a sapling file, and of the block if a seedling file.
blocks_used (2 bytes): The total number of blocks actually used by the file. For a subdirectory file, this includes the blocks containing subdirectory information, but not the blocks in the files pointed to. For a standard file, this includes both informational blocks (index blocks) and data blocks. Refer to Section B.3 for more information on standard files.
EOF (3 bytes): A three-byte integer, lowest bytes first, that represents the total number of bytes readable from the file. Note that in the case of sparse files, described in Section B.3.6, EOF may be greater than the number of bytes actually allocated on the disk.
creation (4 bytes): The date and time at which the file pointed to by this entry was created. The format of these bytes is described in Section B.4.2.2.
version (1 byte): The version number of ProDOS under which the file pointed to by this entry was created. This byte allows newer versions of ProDOS to determine the format of the file, and adjust their interpretation processes accordingly. In ProDOS 1.0, version = 0.
Page 156
min_version (1 byte): The minimum version number of ProDOS that
can access the information in this file. This byte allows older versions
of ProDOS to determine whether they can access newer files. In
ProDOS 1.0, min_version = 0.
access (1 byte): Determines whether this file can be read, written, destroyed, and renamed, and whether the file needs to be backed up.
The format of this field is described in Section B.4.2.3. The value of this field can be changed by the SET_FILE_INFO call. You cannot delete a subdirectory that contains any files.
aux_type (2 bytes): A general-purpose field in which a system program can store additional information about the internal format of a file. For example, the ProDOS BASIC system program uses this field to record the load address of a BASIC program or binary file, or the record length of a text file.
last_mod (4 bytes): The date and time that the last CLOSE operation after a WRITE was performed on this file. The format of these bytes is described in Section B.4.2.2. This field can be changed by the SET_FILE_INFO call.
header_pointer (2 bytes): This field is the block address of the key block of the directory that owns this file entry. This two-byte pointer is stored low byte first, high byte second.
Reading a Directory File
This section deals with the techniques of reading from directory files, not with the specifics. The ProDOS calls with which these techniques can be implemented are explained in Chapter 4.
Before you can read from a directory, you must know the directory's pathname. With the directory's pathname, you can open the directory file, and obtain a reference number (RefNum) for that open file.
Before you can process the entries in the directory, you must read three values from the directory header:
- the length of each entry in the directory (entry_length)
- the number of entries in each block of the directory (entries_per_block)
- the total number of files in the directory (file_count).
Page 157
Using the reference number to identify the file, read the first 512 bytes
from the file, and into a buffer (ThisBlock). The buffer contains
two two-byte pointers, followed by the entries; the first entry is the
directory header. The three values are at positions $1F through $22 in
the header (positions $23 through $26 in the buffer). In the example
below, these values are assigned to the variables EntryLength,
EntriesPerBlock, and FileCount.
Open(DirPathname, Refnum); {Get reference number }
ThisBlock := Read512Bytes(RefNum); {Read a block into buffer}
EntryLength := ThisBlock[$23]; {Get directory info }
EntriesPerBlock := ThisBlock[$24];
FileCount := ThisBlock[$25] + (256 * ThisBlock[$26]);
Once these values are known, a system program can scan through the entries in the buffer, using a pointer to the beginning of the current entry EntryPointer, a counter BlockEntries that indicates the number of entries that have been examined in the current block, and a second counter ActiveEntries that indicates the number of active entries that have been processed.
An entry is active and is processed only if its first byte, the storage_type and name_length, is nonzero. All entries have been processed when ActiveEntries is equal to FileCount. If all the entries in the buffer have been processed, and ActiveEntries doesn't equal FileCount, then the next block of the directory is read into the buffer.
EntryPoint := EntryLength + $04; {Skip header entry}
BlockEntries := $02; {Prepare to process entry two}
ActiveEntries := $00; {No active entries found yet }
while ActiveEntries < FileCount do begin
if ThisBlock[EntryPointer] <> $00 then begin {Active entry}
ProcessEntry(ThisBlock[EntryPointer]);
ActiveEntries := ActiveEntries + $01
end;
if ActiveEntries < FileCount then {More entries to process}
if BlockEntries = EntriesPerBlock
then begin {ThisBlock done. Do next one}
ThisBlock := Read512Bytes(RefNum);
BlockEntries := $01;
EntryPointer := $04
end
else begin {Do next entry in ThisBlock }
EntryPointer := EntryPointer + EntryLength;
BlockEntries := BlockEntries + $01
end
end;
Close(RefNum);
Page 158
This algorithm processes entries until all expected active entries have
been found. If the directory structure is damaged, and the end of the
directory file is reached before the proper number of active entries has
been found, the algorithm fails.
Format of Standard Files
Each active entry in a directory file points to the key block (the first block) of a file. As shown below, the key block of a standard file may have several types of information in it. The storage_type field in that file's entry must be used to determine the contents of the key block.
This section explains the structure of the three stages of standard file: seedling, sapling, and tree. These are the files in which all programs and data are stored.
Growing a Tree File
The following scenario demonstrates the growth of a tree file on a volume. This scenario is based on the block allocation scheme used by ProDOS 1.0 on a 280-block flexible disk that contains four blocks of volume directory, and one block of volume bit map. Larger capacity volumes might have more blocks in the volume bit map, but the process would be identical.
A formatted, but otherwise empty, ProDOS volume is used like this:
Blocks 0-1 - Loader
Blocks 2-5 - Volume directory
Block 6 - Volume bit map
Blocks 7-279 - Unused
Page 159
If you open a new file of a nondirectory type, one data block is
immediately allocated to that file. An entry is placed in the volume
directory, and it points to block 7, the new data block, as the key
block for the file. The key block is indicated below by an arrow.
The volume now looks like this:
Data Block 0
Blocks 0-1 Loader
Blocks 2-5 Volume directory
Block 6 Volume bit map
--> Block 7 Data block 0
Blocks 8-279 Unused
This is a seedling file: its key block contains up to 512 bytes of data.
If you write more than 512 bytes of data to the file, the file grows into a sapling file. As soon as a second block of data becomes necessary, an index block is allocated, and it becomes the file's key block: this index block can point to up to 256 data blocks (two-byte pointers). A second data block (for the data that won't fit in the first data block) is also allocated. The volume now looks like this:
Index Block 0
Data Block 0
Data Block 1
Blocks 0-1 Loader
Blocks 2-5 Volume directory
Block 6 Volume bit map
Block 7 Data block 0
--> Block 8 Index block 0
Block 9 Data block 1
Blocks 10-279 Unused
This sapling file can hold up to 256 data blocks: 128K of data. If the file becomes any bigger than this, the file grows again, this time into a tree file. A master index block is allocated, and it becomes the file's key block: the master index block can point to up to 128 index blocks and each of these can point to up to 256 data blocks. Index block G becomes the first index block pointed to by the master index block. In addition, a new index block is allocated, and a new data block to which it points.
Page 160
Here's a new picture of the volume:
Master Index Block
Index Block 0
Index Block 1
Data Block 0
Data Block 255
Data Block 256
Blocks 0-1 Loader
Blocks 2-5 Volume directory
Block 6 Volume bit map
Block 7 Data block 0
Block 8 Index block 0
Blocks 9-263 Data blocks 1-255
--> Block 264 Master index block
Block 265 Index block 1
Block 266 Data block 256
Blocks 267-279 Unused
As data is written to this file, additional data blocks and index blocks are allocated as needed, up to a maximum of 129 index blocks (one a master index block), and 32,768 data blocks, for a maximum capacity of 16,777,215 bytes of data in a file. If you did the multiplication, you probably noticed that a byte was lost somewhere. The last byte of the last block of the largest possible file cannot be used because EOF cannot exceed 16,777,216. If you are wondering how such a large file might fit on a small volume such as a flexible disk, refer to Section B.3.6 on sparse files.
This scenario shows the growth of a single file on an otherwise empty volume. The process is a bit more confusing when several files are growing -- or being deleted -- simultaneously. However, the block allocation scheme is always the same: when a new block is needed ProDOS always allocates the first unused block in the volume bit map.
Seedling Files
A seedling file is a standard file that contains no more than 512 data bytes ($0 <= EOF <= $200). This file is stored as one block on the volume, and this data block is the file's key block.
The structure of such a seedling file appears in Figure B-6.
Page 161
Figure B-6. Structure of a Seedling File
key_pointer ----> +-------+
| Data | Data Block
| Block | 512 bytes long
$0 <= EOF <= $200 +-------+
The file is called a seedling file because, if more than 512 data bytes are written to it, it grows into a sapling file, and thence into a tree file.
The storage_type field of an entry that points to a seedling file has the value $1.
Sapling Files
A sapling file is a standard file that contains more than 512 and no more than 128K bytes ($200 < EOF <= $20000). A sapling file comprises an index block and 1 to 256 data blocks. The index block contains the block addresses of the data blocks. See Figure B-7.
Figure B-7. Structure of a Sapling File
key_pointer ------> +-------------------+
| | | | | | Index Block:
|$00 $01 $FE $FF| Up to 256 2-Byte
|- Index Block -| Pointers to Data Blocks
$0 <= EOF <= $20000 | | | | | |
+-------------------+
| | | |
+---------------+ | | +-------------------+
| | | |
| +---+ +-------+ |
| | | |
v v v v
+-----------+ +-----------+ +-----------+ +-----------+
| Data | | Data | ..... | Data | | Data |
| Block $00 | | Block $01 | | Block $FE | | Block $FF |
+-----------+ +-----------+ +-----------+ +-----------+
The key block of a sapling file is its index block. ProDOS retrieves data blocks in the file by first retrieving their addresses in the index block.
The storage_type field of an entry that points to a sapling file has the value $2.
Page 162
Tree Files
A tree file contains more than 128K bytes, and less than 16M bytes ($20000 < EOF < $1000000). A tree file consists of a master index block, 1 to 128 index blocks, and 1 to 32,768 data blocks. The master index block contains the addresses of the index blocks, and each index block contains the addresses of up to 256 data blocks. The structure of a tree file is shown in Figure B-8.
Figure B-8. The Structure of a Tree File
key_pointer ------> +----------------------+
| | | | | | Master Index Block:
|- Master Index Block -| Up to 128 2-Byte Pointers
$20000 < EOF < $10000000 | | | | | | to Index Blocks
+----------------------+
| |
+------------+ +-+
| |
v v
+-------------------+ +-------------------+
| | | | | | | | | | | |
|- Index Block $00 -| ....... |- Index Block $7F -|
| | | | | | | | | | | |
+-------------------+ +-------------------+
| | | |
+---------+ +------+ ++ ++
| | | |
v v v v
+-----------+ +-----------+ +-----------+ +-----------+
| Data | .... | Data | | Data | ... | Data |
| Block $00 | | Block $FF | | Block $00 | | Block $FF |
+-----------+ +-----------+ +-----------+ +-----------+
The key block of a tree file is the master index block. By looking at the master index block, ProDOS can find the addresses of all the index blocks; by looking at those blocks, it can find the addresses of all the data blocks.
The storage_type field of an entry that points to a tree file has the value $3.
Using Standard Files
A system program or application program operates the same on all three types of standard files, although the storage_type in the file's entry can be used to distinguish between the three. A program rarely reads index blocks or allocates blocks on a volume: ProDOS does that.
The program need only be concerned with the data stored in the file, not with how they are stored.
All types of standard files are read as a sequence of bytes, numbered from 0 to EOF-1, as explained in Chapter 4.
Page 163
Sparse Files
A sparse file is a sapling or tree file in which the number of data bytes that can be read from the file exceeds the number of bytes physically stored in the data blocks allocated to the file. ProDOS implements sparse files by allocating only those data blocks that have had data written to them, as well as the index blocks needed to point to them.
For example, you can define a file whose EOF is 16K, that uses only three blocks on the volume, and that has only four bytes of data written to it. If you create a file with an EOF of $0, ProDOS allocates only the key block (a data block) for a seedling file, and fills it with null characters (ASCII $00).
If you then set the EOF and MARK to position $0565, and write four bytes, ProDOS calculates that position $0565 is byte $0165 ($0564-($0200*2)) of the third block (block $2) of the file. It then allocates an index block, stores the address of the current data block in position 0 of the index block, allocates another data block, stores the address of that data block in position 2 of the index block, and stores the data in bytes $0165 through $0168 of that data block. The EOF is $0569.
If you now set the EOF to $4000 and close the file, you have a 16K file that takes up three blocks of space on the volume: two data blocks and an index block. You can read 16384 bytes of data from the file, but all the bytes before $0565 and after $0568 are nulls.
Figure B-9 shows how the file is organized.
Page 164
Figure B-9. A Sparse File
0 1 2
key_pointer --> +--------------+
Key_Block | | | | |
+--------------+
| |
+---------+ +-------+ EOF = $4000
| | |
v Block $0 Block $1 v Block $2 Block $3 Block $1F v
Data +-------------------------------------------+ +-----------+
Blocks | | | | | | | | |
+-------------------------------------------+ +-----------+
$0 $1FF $400 ^ $5FF
|
Bytes $565..$568
Thus ProDOS allocates volume space only for those blocks in a file that actually contain data. For tree files, the situation is similar: if none of the 256 data blocks assigned to an index block in a tree file have been allocated, the index block itself is not allocated.
On the other hand, if you CREATE a file with an EOF of $4000 (making it 16K bytes, or 32 blocks, long), ProDOS allocates an index block and 32 data blocks for a sapling file, and fills the data blocks with nulls.
By the Way: The first data block of a standard file, be it a seedling, sapling, or tree file, is always allocated. Thus there is always a data block to be read in when the file is opened.
Page 165
Locating a Byte in a File
The algorithm for finding a specific byte within a standard file is given below.
The MARK is a three-byte value that indicates an absolute byte position within a file.
Byte # Byte 2 Byte 1 Byte 0
bit # 7 0 7 0 7 0
+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
MARK |Index Number |Data Block Number| Byte of Block |
+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
Used by: Tree only Tree and sapling All three
If the file is a tree file, then the high seven bits of the MARK determine the number (0 to 127) of the index block that points to the byte. The value of the seven bits indicate the location of the low byte of the index block address within the master index block. The location of the high byte of the index block address is indicated by the value of these seven bits plus 256.
Page 166
If the file is a tree file or a sapling file, then the next eight bits of the
MARK determine the number (0-255) of the data block pointed to by
the indicated index block. This 8-bit value indicates the location of the
low byte of the data block address within the index block. The high
byte of the index block address is found at this offset plus 256.
For tree, sapling, and seedling files, the low nine bits of the MARK are the absolute position of the byte within the selected data block.
Disk Organization
Figure B-10 presents an overall view of block organization on a volume.
Figure B-11 shows the complete structures of the three standard files types. Figure B-12 is a summary of header and entry field information.
Page 167
Figure B-10. Disk Organization
+--------------------+
| BLOCKS ON A VOLUME |
| Figure B-1 |
+--------------------+
|| ||
|| ||
|| ||
vv vv
+----------------------------------+
| BLOCKS OF A DIRECTORY FILE |
|=================| VOLUME DIRECTORY OR SUBDIRECTORY |
|| | Figure B-2 |
|| +----------------------------------+
|| || ||
|============================| ||
|| || ||
vv vv vv
+----------------------+ +----------------------+ +------------------------------------+
| HEADER | | HEADER | | FILE ENTRY |
| VOLUME DIRECTORY | | SUBDIRECTORY | | SUBDIRECTORY OR |
| Found in key block | | Found in key block | | STANDARD FILE |===>>to
| of volume directory. | | of subdirectory. | | Found in any directory file block. | Figure
| Figure B-3 | | Figure B-4 | | Figure B-5 | B-11
+----------------------+ +----------------------+ +------------------------------------+
Page 168
Standard Files
Figure B-11. Standard Files
+---------------+
|===>>| KEY BLOCK |
|| | Standard File |
|| +---------------+
||
|| +----------------------------------+
|===>>| SEEDLING FILE: storage_type = $1 |
|| | Figure B-6 |
|| +----------------------------------+
||
|| +----------------------------------+
|===>>| SAPLING FILE: storage_type = $2 |
|| | Figure B-7 |
|| +----------------------------------+
||
|| +----------------------------------+
|===>>| TREE FILE: storage_type = $3 |
|| | Figure B-8 |
|| +----------------------------------+
||
======|
from Figure B-10
Page 169
Header and Entry Fields
Figure B-12. Header and Entry Fields
+-------------+
| CREATE_DATE | Byte 1 Byte 0
| |
| MOD_DATE | 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0
+-------------+ ----> +---------------------------------------------------------------+
| | | | | | | | | | | | | | | | |
| Year | Month | Day |
| | | | | | | | | | | | | | | | |
+---------------------------------------------------------------+
+-------------+
| CREATE_TIME |
| |
| MOD_TIME |
+-------------+ ----> +---------------------------------------------------------------+
| | | | | | | | | | | | | | | | |
| 0 0 0 | Hour | 0 0 | Minute |
| | | | | | | | | | | | | | | | |
+---------------------------------------------------------------+
Byte 1 Byte 0
+-------- Write-Enable
| +---- Read-Enable
| |
+--------------+ +----------+ +-------------------------------+
| storage_type | | access | = | D | RN | B | Reserved | W | R |
| (4 bits) | | (1 byte) | +-------------------------------+
+--------------+ +----------+ | | |
| | +----------------------- Backup
$0 = inactive file entry | +---------------------------- Rename-Enable
$1 = seedling file entry +-------------------------------- Destroy-Enable
$2 = sapling file entry
$3 = tree file entry
$D = subdirectory file entry name_length = length of file_name ($1-$F)
$E = subdirectory header file_name = $1-$F ASCII characters: first = letters
$F = volume directory header rest are letters, digits, periods.
key_pointer = block address of file's key block
+-----------+ blocks_used = total blocks for file
| file_type | EOF = byte number for end of file ($0-$FFFFFF)
| (1 byte) | version, min_version = 0 for ProDOS 1.0
+-----------+ entry_length = $27 for ProDOS 1.0
entries_per_block = $0D for ProDOS 1.0
See section B.4.2.4 aux_type = defined by system program
file_count = total files in directory
bit_map_pointer = block address of bit map
total_blocks = total blocks on volume
parent_pointer = block address containing entry
parent_entry_number = number in that block
parent_entry_length = $27 for ProDOS 1.0
header pointer = block address of key block
of entry's directory
Page 170
The storage_type Attribute
The storage_type, the high-order four bits of the first byte of an entry, defines the type of header (if the entry is a header) or the type of file described by the entry.
$0 indicates an inactive file entry $1 indicates a seedling file entry (EOF <= 256 bytes) $2 indicates a sapling file entry (256 < EOF <= 128K bytes) $3 indicates a tree file entry (128K < EOF < 16M bytes) $4 indicates Pascal area $D indicates a subdirectory file entry $E indicates a subdirectory header $F indicates a volume directory header
The name_length, the low-order four bits of the first byte, specifies the number of characters in the file_name field.
ProDOS automatically changes a seedling file to a sapling file and a sapling file to a tree file when the file's EOF grows into the range for a larger type. If a file's EOF shrinks into the range for a smaller type, ProDOS changes a tree file to a sapling file and a sapling file to a seedling file.
The creation and last_mod Fields
The date and time of the creation and last modification of each file and directory is stored as two four-byte values, as shown in Figure B-13.
Figure B-13. Date and Time Format
Byte 1 Byte 0
7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0
+---------------------------------------------------------------+
| | | | | | | | | | | | | | | | |
| Year | Month | Day |
| | | | | | | | | | | | | | | | |
+---------------------------------------------------------------+
+---------------------------------------------------------------+
| | | | | | | | | | | | | | | | |
| 0 0 0 | Hour | 0 0 | Minute |
| | | | | | | | | | | | | | | | |
+---------------------------------------------------------------+
Byte 1 Byte 0
The values for the year, month, day, hour, and minute are stored as binary integers, and may be unpacked for analysis.
Page 171
The access Attribute
The access attribute field (Figure B-14) determines whether the file can be read from, written to, deleted, or renamed. It also contains a bit that can be used to indicate whether a backup copy of the file has been made since the file's last modification.
Figure B-14. The access Attribute Field
+-------- Write-Enable
| +---- Read-Enable
| |
+-------------------------------+
| D | RN | B | Reserved | W | R |
+-------------------------------+
| | |
| | +----------------------- Backup
| +---------------------------- Rename-Enable
+-------------------------------- Destroy-Enable
A bit set to 1 indicates that the operation is enabled; a bit cleared to 0 indicates that the operation is disabled. The reserved bits are always 0.
ProDOS sets bit 5, the backup bit, of the access field to 1 whenever the file is changed (that is, after a CREATE, RENAME, CLOSE after WRITE, or SET_FILE_INFO operation). This bit should be reset to 0 whenever the file is duplicated by a backup program.
Note: Only ProDOS may change bits 2-4; only backup programs should clear bit 5, using SET_FILE_INFO.
The file_type Attribute
The file_type attribute within an entry field identifies the type of file described by that entry. This field should be used by system programs to guarantee file compatibility from one system program to the next.
The values of this byte are shown in Table B-1.
Page 172
Table B-1. The ProDOS File_Types
The file types marked with a * apply to Apple III only; they are not
ProDOS compatible. For the file types used by Apple III SOS only, refer
to the SOS Reference Manual.
File Type Preferred Use $00 Typeless file (SOS and ProDOS) $01 Bad block file $02 * Pascal code file $03 * Pascal text file $04 ASCII text file (SOS and ProDOS) $05 * Pascal data file $06 General binary file (SOS and ProDOS) $07 * Font file $08 Graphics screen file $09 * Business BASIC program file $0A * Business BASIC data file $0B * Word Processor file $0C * SOS system file $0D,$0E * SOS reserved $0F Directory file (SOS and ProDOS) $10 * RPS data file $11 * RPS index file $12 * AppleFile discard file $13 * AppleFile model file $14 * AppleFile report format file $15 * Screen Library file $16-$18 * SOS reserved $19 AppleWorks Data Base file $1A AppleWorks Word Processor file $1B AppleWorks Spreadsheet file $1C-$EE Reserved $EF Pascal area $F0 ProDOS CI added command file $F1-$F8 ProDOS user defined files 1-8 $F9 ProDOS reserved $FA Integer BASIC program file $FB Integer BASIC variable file $FC Applesoft program file $FD Applesoft variables file $FE Relocatable code file (EDASM) $FF ProDOS system file
Page 173
DOS 3.3 Disk Organization
Both DOS 3.3 and ProDOS 140K flexible disks are formatted using the same 16-sector layout. As a consequence, the ProDOS READ_BLOCK and WRITE_BLOCK calls are able to access DOS 3.3 disks too. These calls know nothing about the organization of files on either type of disk.
When using READ_BLOCK and WRITE_BLOCK, you specify a 512-byte block on the disk. When using RWTS (the DOS 3.3 counterpart to READ_BLOCK and WRITE_BLOCK), you specify the track and sector of a 256-byte chunk of data, as explained in the DOS Programmer's Manual. You use READ_BLOCK and WRITE_BLOCK to access DOS 3.3 disks, you must know what 512-byte block corresponds to the track and sector you want.
Figure B-15 shows how to determine a block number from a given track and sector. First multiply the track number by 8, then add the Sector Offset that corresponds to the sector number. The half of the block in which the sector resides is determined by the Half-of-Block line (1 is the first half; 2 is the second).
Figure B-15. Tracks and Sectors to Blocks
Block = (8 * Track) + Sector Offset
Sector : 0 1 2 3 4 5 6 7 8 9 A B C D E F Sector Offset : 0 7 6 6 5 5 4 4 3 3 2 2 1 1 0 7 Half of Block: 1 1 2 1 2 1 2 1 2 1 2 1 2 1 2 2
Refer to the DOS Programmer's Manual for a description of the file organization of DOS 3.3 disks.
Page 174
Appendix C - ProDOS, the Apple III, and SOS
Page 175
This appendix explains the relationships between ProDOS, the
Apple III, and SOS. It should be helpful to those already familiar with
SOS and to those thinking about developing assembly-language
programs concurrently for SOS and ProDOS.
ProDOS, the Apple III, and SOS
As explained earlier in the manual, blocks 0 and 1 of a ProDOS-formatted disk contain the boot code -- the code that reads the operating system from the disk and runs it. Not explained was that this boot code runs on either an Apple II or an Apple III.
When you start up either an Apple II or an Apple III system with a ProDOS disk, the boot code is loaded at $800, and executed. The first thing it does is look to see whether it is running on an Apple II or Apple III. If it is running on an Apple II, it tries to load in the file PRODOS. If it is running on an Apple III, it tries to load in the file SOS.KERNEL. In either case, if the proper file is not found, it displays the appropriate error message.
This means that two versions of an application could be written, one for the Apple II, the other for the Apple III, and packaged together on the same disk. This single disk could be sold to both Apple II and Apple III owners.
File Compatibility
SOS and ProDOS use the same directory structure: no exceptions.
Every file on a ProDOS disk can be read by a SOS program and vice versa.
The file types that are used by both systems are directory files, text files, and binary files. These three types are adequate for the sharing of data between SOS and ProDOS versions of the same program.
File types that are intended for one system, but encountered on the other (as when you CATALOG a ProDOS disk using Business BASIC) are not inherently different from recognized file types; they just might cause a number to be displayed as their type instead of a name. The ProDOS BASIC system program, Filer, Conversion program, and Editor/Assembler all recognize and display names for all currently defined SOS file types. The abbreviations displayed when Apple III file types are encountered using ProDOS are shown in the quick reference section of this manual.
Page 176
Operating System Compatibility
Because of the larger amount of memory available to SOS, it is a much more complete operating system than is ProDOS. SOS has a complete and well defined file manager, device manager, memory manager, and interrupt and event handler. ProDOS has a file manager and simplified interrupt and memory calls.
Comparison of Input/Output
SOS communicates with all devices -- the console, printers, disk drives, and so on -- by making open, read, write, and close calls to the appropriate device; writing to one device is essentially the same as writing to another. ProDOS can perform these operations on files only.
Apple II peripherals generally have their driver code in ROM on the peripheral card. There is no consistent method for communicating with them. Thus the protocol for using any particular device must be known by the system program that is currently running.
Comparison of Filing Calls
The set of calls to the ProDOS operating system is essentially a subset of the calls to SOS. All filing calls shared by the two systems have the same call number and nearly identical sets of parameters. Some differences are:
- With ProDOS you don't specify the file size when you create a file.
Files are automatically extended when necessary.
- With SOS the GET_FILE_INFO call returns the size of the file in
bytes (the EOF). In ProDOS you must OPEN the file and then use the GET_EOF call.
Page 177
- The SOS VOLUME command corresponds to the ProDOS ON_LINE
command. When given a device name, VOLUME returns the volume name for that device. When given a unit number (derived from the slot and drive), ON_LINE returns the volume name.
- For SOS, SET_MARK and SET_EOF can use a displacement from
the current position. ProDOS uses only an absolute position in the file.
Memory Handling Techniques
SOS has a fairly sophisticated memory manager: a system program requests memory from SOS, either by location or by amount needed. If the request can be satisfied, SOS grants it. That portion of memory is then the sole responsibility of the requestor until it is released.
A ProDOS system program is responsible for its own memory management. It must find free memory, and then allocate it by marking it off in a memory bit map. If a page of memory is marked in the bit map, ProDOS will not write data into that page. ProDOS can thus prevent users from destroying protected areas of memory (presumably all data is brought into memory using the ProDOS READ call).
Comparison of Interrupts
In SOS, any device capable of generating an interrupt must have a device driver capable of handling the interrupt; the device driver and the interrupt handler are inseparable. ProDOS does not have device drivers; thus, interrupt handling routines are installed separately using the ALLOC_INTERRUPT call. Also, whereas SOS has a distinct interrupt priority for each device in the system, ProDOS must poll the routines one by one until someone claims the interrupt.
Page 178
Appendix D - The ProDOS Machine Language Exerciser
Page 179
The ProDOS Exerciser program is a menu-driven program that allows
you to practice calls to the ProDOS Machine Language Interface
without writing a system program. It is useful for learning how the
various ProDOS MLI calls work. Using it, you can test the behavior of
a ProDOS-based program before writing any code.
How to Use It
To start up the Exerciser program from BASIC, type -/EXERCISER/EXER.SYSTEM and press [RETURN].
This causes the Exerciser (which is a machine-language program, but not a system program) to be loaded at $2000, and then relocated to the highest available spot in memory. On a 64K system, it occupies memory from $7400 on.
The Exerciser main menu displays all the MLI calls and their call numbers, as well as a few other commands. To select an MLI call, simply type the call number followed by [RETURN]. To select one of the other commands, type the displayed letter followed by [RETURN].
When you select either a call or a command, a list of parameters for that call is displayed. The parameters for each MLI call are displayed almost exactly as they would have to be coded in a ProDOS-based application. The only difference is that a true parameter list would contain a two-byte pointer to a pathname, whereas the Exerciser displays the pathname itself. The meanings of the parameters for each ProDOS call are described in Chapter 4 in the section describing that call.
The default values for each of the parameters are displayed. The cursor pauses at each of the parameters that requires a value to be entered. You may accept the default value by pressing [RETURN] or change the value by typing the new value followed by [RETURN]. All values are displayed and entered in hexadecimal.
When you have entered values for all required parameters, press [RETURN]. The call is executed, values returned by the call are displayed, and an error message is displayed. If error $00 is indicated the call was successful. If the call was unsuccessful, the Apple II beeps as it displays the error message.
Errors are discussed at the end of Chapter 4.
Page 180
Modify Buffer
The Modify Buffer command can be used to examine or edit the Contents of memory. It asks you for a data buffer address; this is the address at which you wish to start editing. You can then page forward or backward through memory using [>] and [<], respectively.
Each screen displays the values of 256 consecutive bytes, arranged in 16 rows of eight bytes each. The ASCII characters associated with these bytes are displayed at the right of the screen (as printed with the high bits set). On a standard Apple II, lowercase ASCII codes are converted to the corresponding uppercase codes. Each row is preceded by the address of the first byte in that row (just like the LIST command in the Apple II Monitor).
To move the cursor to a different byte on the screen, use [I], [J], [K], and [M], or the arrow keys. To change a byte of memory, simply type the new value right over the old one. The value is updated in memory as well as on the screen. The Modify Buffer command remembers the original values of the last 16 bytes you changed. To restore up to sixteen changed bytes, press U (for Undo) once for each value to be restored.
If a memory page is marked in the system bit map as used by the system, the editor displays the message MEMORY PAGE PROTECTED and it does not allow you to change a value in that page.
Screen shot from front cover
+-----------------------------------------+ | * * * * * * * * * * * * * * * * * * * * | | * PRODOS * | | * MACHINE LANGUAGE INTERFACE * | | * SYSTEM CALL EXERCISER * | | * * * * * * * * * * * * * * * * * * * * | | | | $C0-CREATE $CB-WRITE | | $C1-DESTROY $CC-CLOSE | | $C2-RENAME $CD-FLUSH | | $C3-SET FILE INFO $CE-SET MARK | | $C4-GET FILE INFO $CF-GET MARK | | $C5-ON LINE $D0-SET EOF | | $C6-SET PREFIX $D1-GET EOF | | $C7-GET PREFIX $D2-SET BUF | | $C8-OPEN $D3-GET BUF | | $C9-NEWLINE $80-READ BLOCK | | $CA-READ $81-WRITE BLOCK | | _______________________________________ | | | | L - LIST DIRECTORY Q - QUIT | | M - MODIFY BUFFER | | | | SELECT COMMAND: $C0_ | +-----------------------------------------+
Page 181 Page 182
Index
Index A A register ... 96 access ... 150, 153, 157 byte ... 13 accumulator ... 29, 77, 85 Active Entries ... 158 ALLOC_INTERRUPT call ... 35, 170, 111, 178 alternate 64K RAM bank ... 89 APPEND command ... 131 Apple II ... xvi, 98 Apple II Plus ... 98 Apple II SOS ... 176 Apple IIc ... 98, 143 Apple IIe ... 98, 143 -- with extended 80-column text card ... 89 Apple III ... 98 file types ... 176 Applesoft ... 121, 134, 142 assembly language ... 131 aux_type ... 39, 46, 50, 100, 157 auxiliary bank hi-res graphics pages ... 89 B backup bit ... 63, 64, 172 BADCALL ... 128 bank-switching routines ... 97 BASIC.SYSTEM ... xv, 82, 121, 124, 176 BEEP example ... 136 BEEPSLOT example ... 138 binary files ... 176 bit map ... 84, 150 BLOAD command ... 132 Block Entries ... 158 Block File Manager (BFM) ... 7, 28, 31 block number ... 115, 146 blocks ... 18 blocks_used ... 50, 156 boot code ... 176 boot ROM ... 22 -- disk drives ... 112 booting ... 22 BRUN command ... 132 BSAVE command ... 132 buffer ... 15 -- allocation ... 25 -- pointer ... 115 byte, locating a specific ... 166 C C-flag 29, 77 calender card ... See clock/calender card calls -- filing ... 33, 56 -- housekeeping ... 32 -- system ... 35 carry flag ... 122 CAT command ... 132 CATALOG command ... 132 catalog format ... 101 CHAIN command ... 131 clock/calender card ... 2,6,71,99 CLOSE call ... 13, 16, 17, 26, 34, 99, 104, 132 CMDADR address ... 108 Command Dispatcher ... 7,28 command list ... 134 commands, adding ... 134 CONVERT.program ... 3, 176 CREATE call ... 13, 32, 99, 104, 132 create_date ... 39, 51 create_time ... 39, 51 creation ... 150, 153, 156 -- date ... 171 -- time ... 171 creation_date ... 13 creation_time ... 13 D dash (-) command ... 131 data blocks ... 19 data_buffer ... 15, 52, 55 data files ... 18 date and time, system ... 71 DEALLOC INTERRUPT call ... 35, 107, 112 defaults (system program) ... 100 DELETE call ... 132 DESTROY call ... 13, 32, 99, 104 device drivers ... 142 directory files ... 3,17,18,176 -- reading ... 157 -- structure ... 18 disconnecting /RAM ... 90 disk -- access ... 16 -- controller card ... 113 -- device driver vectors ... 94 -- devices ... 95 -- driver routines ... 28 -- operating system ... xv, 2 -- RAM ... 91 -- volume ... 143 Disk II driver ... 113 disk-drive controller card ... 22 dispatcher code ... 87 DOS 3.3 ... 174 -- disks ... 73 DOS ProDOS Conversion program ... xv, 3 DOSCMD vector ... 131, 134 Page 183 E 80-column text card ... 99 emulation mode ... 98 enable_mask ... 58 endtry_length ... 154 entries (directory file) ... 17 Entries Per Block ... 150, 153, 154, 158 entry field ... 43, 47 Entry Length variable ... 158 Entry Pointer variable ... 158 entry_length ... 150, 153 entry points ... 94 EOF ... 15, 20, 67, 156, 164, 171 -- See also individual calls error codes (ProDOS) ... 77 EXEC file ... 17, 131 EXERCISER program ... 31, 180 EXTRNCMD location ... 134 F FBITS ... 126, 141 fields, pointer ... 148 file(s) -- binary ... 176 -- buffer ... 26 -- closing ... 14, 16 -- control block ... 14, 56 -- creating ... 13 -- data ... 19 -- directory ... 18, 176 -- flushing ... 16 -- logical size ... 67 -- naming ... 10 -- opening ... 13 file_count ... 150, 153, 154 158 file_name ... 150, 150, 153, 156 file_type ... 13 filename ... 10 Filer, ProDOS ... 176 Filer Program ... xv filing calls ... 3, 5 -- ProDOS vs. SOS ... 177 FLUSH ... 16, 17, 34, 99, 104, 132 FORMAT call ... 113 FRE call ... 132 G GET_BUF call ... 26, 34 GET_EOF call ... 15, 34, 177 GET_FILE_INFO call ... 32, 43, 99, 100, 177 GET_MARK call ... 15, 34 GET_PREFIX call ... 11,33 GET_TIME call ... 35, 99, 104 GETLN input buffer ... 105, 135 global page ... 84, 104, 141 global variables ... 25 GOSYSTEM ... 127, 129 H header entry ... 147 header_pointer ... 157 headers (subdirectory) ... 151 HELP command ... 141 hi-res graphics ... 89 HIMEM command ... 141 housekeeping calls ... 3, 32, 36-54 I I/O buffer ... 14, 69 I/O vectors ... 123 IN# command ... 22, 132 index blocks ... 19, 160, 162, 163 input/output -- buffer ... 14, 69 -- vectors ... 123 -- ProDOS vs. SOS ... 177 int_num ... 72, 73 interrupt(s) ... 2, 72 -- routines ... 97 exit routines ... 97 handler ... 28 handling calls ... 3 Receiver/Dispatcher ... 7 vector(s) ... 96 -- table ... 72 interrupt-driven devices ... 121 io_buffer ... 16, 33 -- See also individual calls IVERSION ... 97 J jump to subroutine (JSR) ... 29 K key block ... 146, 147, 151, 159, 162, 164 key_pointer ... 156 key_pointer field ... 36 KVERSION ... 97 Page 184 L language card area ... 106 last_mod ... 157 level ... 56 linked list ... 36 LOAD command ... 131 loader program ... 22, 146 LOCK command ... 132 logical block ... 146 LOMEM command ... 122 M MACHID byte ... 96, 98 machine configuration ... 98 Machine Language Interface (MLI) ... 3 machine language routines ... xv, 121 MARK ... 14, 15, 20, 65, 66, 164, 166 master index block ... 19, 160, 163 memory ... 98 -- calls ... 3 -- handling (ProDOS vs. SOS) ... 178 -- management ... 2 -- map ... 24, 95 -- page ... 181 min_version ... 150, 153, 157 MLI (Machine Language Interface) ... 3, 5, 15, 22, 23, 25, 108, 180 -- entry point ... 94 -- issuing calls to ... 29 MLIATV flag ... 108 mod_date ... 46 mod_time ... 46, 50 Modify Buffer command ... 181 monitor ... 142 N name_length ... 150, 153, 154, 156, 158 new_pathname ... 42 NEWLINE call ... 15, 33 newline_char ... 58 NOHELP command ... 141 null prefix ... 11 null_field ... 46 O ON_LINE command ... 33, 178 OPEN call ... 26, 31, 33, 132, 177 P pages ... 5 param_count ... See individual calls parameter count ... 31 parent_entry_length ... 154 parent_entry_number ... 154 parent_pointer ... 153 parsing command ... 140 partial pathnames ... 10, 11 Pascal area ... 156 pathname ... 10, 11, 13 PBITS ... 126, 135, 141 peripheral cards ... xvii pointer ... 18, 31 POSITION command ... 132 PR# command ... 22, 132 prefix ... 11, 132 ProDOS BASIC Programming Examples disk ... 3 ProDOS ... xv -- Editor/Assembler ... 176 -- error codes ... 77 -- Filer ... 3, 20 -- Machine Language Interface ... 5, 142, 180 PRODOS program ... 22 ProDOS User's Disk ... 3 ProFile ... 4 program selectors ... 86 Q QUIT call ... 87 R /RAM ... 23, 89, 143 -- alternate 64K RAM bank ... 89 -- disconnecting ... 90 -- reinstalling ... 92 RAM disks ... 91 READ call ... 15, 33, 113, 131 READ_BLOCK call ... 35, 73, 174 ref_num ... 13 reference number ... 15, 16 register, stack ... 96 RENAME call ... 13, 32, 99, 104, 132, 150, 153, 156 request_count ... 62 -- See also individual calls RESET vector ... 101 RESTORE command ... 132 result command ... 31 RUN command ... 131 RWTS (DOS 3.3) ... 174 S sapling file ... 19, 156, 160, 164, 171 SAVE command ... 132 search order, volume ... 23 sectors ... 146 seedling file ... 19, 156, 160, 161 SET_BUF call ... 26 SET_EOF call ... 15, 34, 178 Page 185 SET_FILE_INFO call ... 13, 32, 47, 99, 100, 104, 157, 172 SET_MARK call ... 15, 34, 66, 178 SET_PREFIX call ... 11, 33 SHOWTIME program ... 109-112 16-sector ROMs ... 113 6502 machine language ... xv, xvi 6502 registers ... 107, 108 slot(s) ... xvii -- and drive ... 100 -- 5 ... 113 -- 6 ... 113 soft switches ... 106 SOS file ... 177 SOS KERNEL file ... 176 SOS volume command ... 178 sparse files ... 161 stack ... 25, 89, 107 register ... 96 standard files ... 17, 19, 159-166 starting up ... 22 startup disk ... 22 startup volume ... 23 STATUS call ... 113 status register ... 96 storage_type ... 13, 36, 39, 50, 150, 153, 154, 156, 158, 159, 162, 163 STORE command ... 132 strings ... 140 subdirectory ... 4 -- files ... 147 SYSCTBL ... 129 system -- bit map ... 5 -- date and time ... 71, 99 -- failure ... 79 -- global page ... 22 -- level ... 16 -- prefix ... 55 -- programs ... 2,3,25,82 ---- quitting ... 87 ---- starting ... 86 T 13-sector ROMs ... 113 tone, '''Warning''' ... 101 total_blocks ... 151 tracks ... 146 trans_count ... 62 -- See also individual calls tree files ... 19, 156, 159, 160, 164, 171 tree structure ... 19, 36 U unit_num ... 52 UNLOCK command ... 132 V value ... 31 variables (global) ... 25 version ... 150, 153, 156 volume(s) ... 146 -- bit map ... 146 -- directory ... 4, 147 -- directory file ... 146 -- finding ... 100 -- names ... 10, 51 -- search order ... 23 VPATH1 ... 141 VPATH2 ... 141 W WRITE command ... 15, 34, 113, 131 write buffer ... 64 WRITE_BLOCK call ... 35, 73, 174 X X register ... 96, 122 XCNUM ... 135, 141 XLEN ... 135, 141 XRETURN ... 135 XTRNADDR ... 135, 141 XXX.SYSTEM ... 22, 82 Y Y register ... 96, 122 Z zero page ... 107
Tell Apple
Apple uses comments and suggestions from Apple computer owners like you to improve existing products and develop new and better products. Now that you've used this product, we want to know your thoughts and suggestions about your experience. Please use this form to tell Apple what you think.
Rest of card omitted
ProDOS Technical Reference Manual Quick Reference Card
ASCII Tables
Binary
Dec ASCII Hex 76543210
0 NUL 00 00000000
1 SOH 01 00000001
2 STX 02 00000010
3 ETX 03 00000011
4 EOT 04 00000100
5 ENQ 05 00000101
6 ACK 06 00000110
7 BEL 07 00000111
8 BS 08 00001000
9 HT 09 00001001
10 LF 0A 00001010
11 VT 0B 00001011
12 FF 0C 00001100
13 CR 0D 00001101
14 50 0E 00001110
15 SI 0F 00001111
16 DLE 10 00010000
17 DC1 11 00010001
18 DC2 12 00010010
19 003 13 00010011
20 004 14 00010100
21 NAK 15 00010101
22 SYN 16 00010110
23 ETB 17 00010111
24 CAN 18 00011000
25 EM 19 00011001
26 SUB 1A 00011010
27 ESC 1B 00011011
28 FS 1C 00011100
29 GS 1D 00011101
30 RS 1E 00011110
31 US 1F 00011111
Binary
Dec ASCII Hex 76543210
32 SP 20 00100000
33 ! 21 00100001
34 " 22 00100010
35 # 23 00100011
36 $ 24 00100100
37 % 25 00100101
38 & 26 00100110
39 ' 27 00100111
40 ( 28 00101000
41 ) 29 00101001
42 * 2A 00101010
43 + 2B 00101011
44 , 2C 00101100
45 - 2D 00101101
46 . 2E 00101110
47 / 2F 00101111
48 0 30 00110000
49 1 31 00110001
50 2 32 00110010
51 3 33 00110011
52 4 34 00110100
53 5 35 00110101
54 6 36 00110110
55 7 37 00110111
56 8 38 00111000
57 9 39 00111001
58 . 3A 00111010
59 ; 3B 00111011
60 < 3C 00111100
61 = 3D 00111101
62 > 3E 00111110
63 ? 3F 00111111
Binary
Dec ASCII Hex 76543210
64 @ 40 01000000
65 A 41 01000001
66 B 42 01000010
67 C 43 01000011
68 D 44 01000100
69 E 45 01000101
70 F 46 01000110
71 G 47 01000111
72 H 48 01001000
73 I 49 01001001
74 J 4A 01001010
75 K 4B 01001011
76 L 4C 01001100
77 M 4D 01001101
78 N 4E 01001110
79 0 4F 01001111
80 P 50 01010000
81 Q 51 01010001
82 R 52 01010010
83 S 53 01010011
84 T 54 01010100
85 U 55 01010101
86 V 56 01010110
87 W 57 01010111
88 X 58 01011000
89 Y 59 01011001
90 Z 5A 01011010
91 [ 5B 01011011
92 / 5C 01011100
93 ] 5D 01011101
94 ^ 5E 01011110
95 _ 5F 01011111
Binary
Dec ASCII Hex 76543210
96 ` 60 01100000
97 a 61 01100001
98 b 62 01100010
99 C 63 01100011
100 d 64 01100100
101 e 65 01100101
102 f 66 01100110
103 g 67 01100111
104 h 68 01101000
105 i 69 01101001
106 j 6A 01101010
107 k 6B 01101011
108 I 6C 01101100
109 m 6D 01101101
110 n 6E 01101110
111 a 6F 01101111
112 p 70 01110000
113 q 71 01110001
114 r 72 01110010
115 s 73 01110011
116 t 74 01110100
117 u 75 01110101
118 v 76 01110110
119 w 77 01110111
120 x 78 01111000
121 y 79 01111001
122 z 7A 01111010
123 { 7B 01111011
124 | 7C 01111100
125 } 7D 01111101
126 7E 01111110
127 DEL 7F 01111111
File Types
file_type Preferred Use $00 Typeless file (SOS and ProDOS) $01 Bad block file $02 * Pascal code file $03 * Pascal text file $04 ASCII text file (SOS and ProDOS) $05 * Pascal data file $06 General binary file (SOS and ProDOS) $07 * Font file $08 Graphics screen file $09 * Business BASIC program file $0A * Business BASIC data file $0B * Word Processor file $0C * SOS system file $0D,$0E * SOS reserved $0F Directory file (SOS and ProDOS) $10 * RPS data file $11 * RPS index file $12 * AppleFile discard file $13 * AppleFile model file $14 * AppleFile report format file $15 * Screen library file $16-$18 * SOS reserved $19 AppleWorks Data Base file $1A AppleWorks Word Processor file $1B AppleWorks Spreadsheet file $1C-$EE Reserved $EF Pascal area $F0 ProDOS added command file $F1-$F8 ProDOS user defined files 1-8 $F9 ProDOS reserved $FA Integer BASIC program file $FB Integer BASIC variable file $FC Applesoft program file $FD Applesoft variables file $FE Relocatable code file (EDASM) $FF ProDOS system file
- Apple III SOS only; not used by ProDOS.
For the file_types used by Apple III SOS only, refer to the SOS Reference Manual.
MLI Error Codes
$00: No error $01: Bad system call number $04: Bad system call parameter count $25: Interrupt table full $27: I/O error $28: No device connected $2B: Disk write protected $2E: Disk switched $40: Invalid pathname $42: Maximum number of files open $43: Invalid reference number $44: Directory not found $45: Volume not found $46: File not found $47: Duplicate filename $48: Volume full $49: Volume directory full $4A: Incompatible file format, also a ProDOS directory $4B: Unsupported storage_type $4C: End of file encountered $4D: Position out of range $4E: File access error, also file locked $50: File is open $51: Directory structure damaged $52: Not a ProDOS volume $53: Invalid system call parameter $55: Volume Control Block table full $56: Bad buffer address $57: Duplicate volume $5A: File structure damaged
Refer to Section 4.8 for a more detailed description of these error codes.
ProDOS MLI Calls
4.4.1 CREATE ($C0)
7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+ 0 | param_count = 7 | +---+---+---+---+---+---+---+---+ 1 | pathname (low) | 2 | (2-byte pointer) (high) | +---+---+---+---+---+---+---+---+ 3 | access (1-byte value) | +---+---+---+---+---+---+---+---+ 4 | file_type (1-byte value) | +---+---+---+---+---+---+---+---+ 5 | aux_type (low) | 6 | (2-byte value) (high) | +---+---+---+---+---+---+---+---+ 7 | storage_type (1-byte value) | +---+---+---+---+---+---+---+---+ 8 | create_date (byte 0) | 9 | (2-byte value) (byte 1) | +---+---+---+---+---+---+---+---+ A | create_time (byte 0) | B | (2-byte value) (byte 1) | +---+---+---+---+---+---+---+---+
4.4.2 DESTROY ($C1)
7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+ 0 | param_count = 1 | +---+---+---+---+---+---+---+---+ 1 | pathname (low) | 2 | (2-byte pointer) (high) | +---+---+---+---+---+---+---+---+
4.4.3 RENAME ($C2)
7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+ 0 | param_count = 2 | +---+---+---+---+---+---+---+---+ 1 | pathname (low) | 2 | (2-byte pointer) (high) | +---+---+---+---+---+---+---+---+ 3 | new_pathname (low) | 4 | (2-byte pointer) (high) | +---+---+---+---+---+---+---+---+
4.4.4 SET_FILE_INFO ($C3)
7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+ 0 | param_count = 7 | +---+---+---+---+---+---+---+---+ 1 | pathname (low) | 2 | (2-byte pointer) (high) | +---+---+---+---+---+---+---+---+ 3 | access (1-byte value) | +---+---+---+---+---+---+---+---+ 4 | file_type (1-byte value) | +---+---+---+---+---+---+---+---+ 5 | aux_type (low) | 6 | (2-byte value) (high) | +---+---+---+---+---+---+---+---+ 7 | | 8 | null_field (3 bytes) | 9 | | +---+---+---+---+---+---+---+---+ A | mod_date (byte 0) | B | (2-byte value) (byte 1) | +---+---+---+---+---+---+---+---+ C | mod_time (byte 0) | D | (2-byte value) (byte 1) | +---+---+---+---+---+---+---+---+
4.4.5 GET_FILE_INFO ($C4)
7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+ 0 | param_count = $A | +---+---+---+---+---+---+---+---+ 1 | pathname (low) | 2 | (2-byte pointer) (high) | +---+---+---+---+---+---+---+---+ 3 | access (1-byte result) | +---+---+---+---+---+---+---+---+ 4 | file_type (1-byte result) | +---+---+---+---+---+---+---+---+ 5 | aux_type (low) | * 6 | (2-byte result) (high) | +---+---+---+---+---+---+---+---+ 7 | storage_type (1-byte result) | +---+---+---+---+---+---+---+---+ 8 | blocks used (low) | * 9 | (2-byte result) (high) | +---+---+---+---+---+---+---+---+ A | mod_date (byte 0) | B | (2-byte result) (byte 1) | +---+---+---+---+---+---+---+---+ C | mod_time (byte 0) | D | (2-byte result) (byte 1) | +---+---+---+---+---+---+---+---+ E | create_date (byte 0) | F | (2-byte result) (byte 1) | +---+---+---+---+---+---+---+---+ 10 | create_time (byte 0) | 11 | (2-byte result) (byte 1) | +---+---+---+---+---+---+---+---+
* When file information about a volume directory is requested, the total number of blocks on the volume is returned in the aux_type field and the total blocks for all files is returned in blocks_used.
4.4.6 ON_LINE ($C5)
7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+ 0 | param_count = 2 | +---+---+---+---+---+---+---+---+ 1 | unit_num (1-byte value) | +---+---+---+---+---+---+---+---+ 2 | data_buffer (low) | 3 | (2-byte pointer) (high) | +---+---+---+---+---+---+---+---+
4.4.7 SET_PREFIX ($C6)
7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+ 0 | param_count = 1 | +---+---+---+---+---+---+---+---+ 1 | pathname (low) | 2 | (2-byte pointer) (high) | +---+---+---+---+---+---+---+---+
4.4.8 GET_PREFIX ($C7)
7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+ 0 | param_count = 1 | +---+---+---+---+---+---+---+---+ 1 | data_buffer (low) | 2 | (2-byte pointer) (high) | +---+---+---+---+---+---+---+---+
4.5.1 OPEN ($C8)
7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+ 0 | param_count = 3 | +---+---+---+---+---+---+---+---+ 1 | pathname (low) | 2 | (2-byte pointer) (high) | +---+---+---+---+---+---+---+---+ 3 | io_buffer (low) | 4 | (2-byte pointer) (high) | +---+---+---+---+---+---+---+---+ 5 | ref_num (1-byte result) | +---+---+---+---+---+---+---+---+
4.5.2 NEWLINE ($C9)
7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+ 0 | param_count = 3 | +---+---+---+---+---+---+---+---+ 1 | ref_num (1-byte value) | +---+---+---+---+---+---+---+---+ 2 | enable_mask (1-byte value) | +---+---+---+---+---+---+---+---+ 3 | newline_char (1-byte value) | +---+---+---+---+---+---+---+---+
4.5.3 READ ($CA)
7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+ 0 | param_count = 4 | +---+---+---+---+---+---+---+---+ 1 | ref_num (1-byte value) | +---+---+---+---+---+---+---+---+ 2 | data_buffer (low) | 3 | (2-byte pointer) (high) | +---+---+---+---+---+---+---+---+ 4 | request_count (low) | 5 | (2-byte value) (high) | +---+---+---+---+---+---+---+---+ 6 | trans_count (low) | 7 | (2-byte result) (high) | +---+---+---+---+---+---+---+---+
4.5.4 WRITE ($CB)
7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+ 0 | param_count = 4 | +---+---+---+---+---+---+---+---+ 1 | ref_num (1-byte value) | +---+---+---+---+---+---+---+---+ 2 | data_buffer (low) | 3 | (2-byte pointer) (high) | +---+---+---+---+---+---+---+---+ 4 | request_count (low) | 5 | (2-byte value) (high) | +---+---+---+---+---+---+---+---+ 6 | trans_count (low) | 7 | (2-byte result) (high) | +---+---+---+---+---+---+---+---+
4.5.5 CLOSE ($CC)
7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+ 0 | param_count = 1 | +---+---+---+---+---+---+---+---+ 1 | ref_num (1-byte value) | +---+---+---+---+---+---+---+---+
4.5.6 FLUSH ($CD)
7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+ 0 | param_count = 1 | +---+---+---+---+---+---+---+---+ 1 | ref_num (1-byte value) | +---+---+---+---+---+---+---+---+
4.5.7 SET_MARK ($CE)
7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+ 0 | param_count = 2 | +---+---+---+---+---+---+---+---+ 1 | ref_num (1-byte value) | +---+---+---+---+---+---+---+---+ 2 | (low) | 3 | position (3-byte value) | 4 | (high) | +---+---+---+---+---+---+---+---+
4.5.8 GET_MARK ($CF)
7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+ 0 | param_count = 2 | +---+---+---+---+---+---+---+---+ 1 | ref_num (1-byte value) | +---+---+---+---+---+---+---+---+ 2 | (low) | 3 | position (3-byte result) | 4 | (high) | +---+---+---+---+---+---+---+---+
4.5.9 SET_EOF ($D0)
7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+ 0 | param_count = 2 | +---+---+---+---+---+---+---+---+ 1 | ref_num (1-byte value) | +---+---+---+---+---+---+---+---+ 2 | (low) | 3 | EOF (3-byte value) | 4 | (high) | +---+---+---+---+---+---+---+---+
4.5.10 GET_EOF ($D1)
7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+ 0 | param_count = 2 | +---+---+---+---+---+---+---+---+ 1 | ref_num (1-byte value) | +---+---+---+---+---+---+---+---+ 2 | (low) | 3 | EOF (3-byte result) | 4 | (high) | +---+---+---+---+---+---+---+---+
4.5.11 SET_BUF ($D2)
7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+ 0 | param_count = 2 | +---+---+---+---+---+---+---+---+ 1 | ref_num (1-byte value) | +---+---+---+---+---+---+---+---+ 2 | io_buffer (low) | 3 | (2-byte pointer) (high) | +---+---+---+---+---+---+---+---+
4.5.12 GET_BUF ($D3)
7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+ 0 | param_count = 2 | +---+---+---+---+---+---+---+---+ 1 | ref_num (1-byte value) | +---+---+---+---+---+---+---+---+ 2 | io_buffer (low) | 3 | (2-byte result) (high) | +---+---+---+---+---+---+---+---+
4.6.2 ALLOC_INTERRUPT ($40)
7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+ 0 | param_count = 2 | +---+---+---+---+---+---+---+---+ 1 | int_num (1-byte result) | +---+---+---+---+---+---+---+---+ 2 | int_code (low) | 3 | (2-byte pointer) (high) | +---+---+---+---+---+---+---+---+
4.6.3 DEALLOC_INTERRUPT ($41)
7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+ 0 | param_count = 1 | +---+---+---+---+---+---+---+---+ 1 | int_num (1-byte value) | +---+---+---+---+---+---+---+---+
4.7.1 READ_BLOCK ($80)
7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+ 0 | param_count = 3 | +---+---+---+---+---+---+---+---+ 1 | unit_num (1-byte value) | +---+---+---+---+---+---+---+---+ 2 | data_buffer (low) | 3 | (2-byte pointer) (high) | +---+---+---+---+---+---+---+---+ 4 | block_num (low) | 5 | (2-byte value) (high) | +---+---+---+---+---+---+---+---+
4.7.2 WRITE_BLOCK ($81)
7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+ 0 | param_count = 3 | +---+---+---+---+---+---+---+---+ 1 | unit_num (1-byte value) | +---+---+---+---+---+---+---+---+ 2 | data_buffer (low) | 3 | (2-byte pointer) (high) | +---+---+---+---+---+---+---+---+ 4 | block_num (low) | 5 | (2-byte value) (high) | +---+---+---+---+---+---+---+---+
Errors in this manual The following errors were noted in this manual and faithfully reproduced:
- page xi: two consecutive sections labeled B.4.2.3
- page 2: the caption for Figure 1-1 is missing
- page 24: memory map lists $300 twice
- page 28: "management" misspelled as "mangagement"
- page 60: param_count is missing "(1-byte value)"
- page 70: param_count is missing "(1-byte value)"
- page 83: memory map lists $300 twice
- page 95: "unprotected" misspelled as "uprotected"
- page 99: "calendar" misspelled as "calender"
- page 108: "the the" instead of "the"
- page 109: "calendar" misspelled as "calender"
- page 111: the two routines are in each other's position
- page 114: "interruptible" misspelled as "interruptable"
- page 114: some text appears to be missing after 6.3.2
- page 119: memory map lists $300 twice
- page 125: "Temporary" misspelled as "Temporory"
- page 131: address of RSHIMEM is BEF8 and should be BEFB
- page 135: "inspecting" misspelled as "inpecting"
- page 147: "directory" misspelled as "drectory"
- page 183: "calendar" misspelled as "calender" three times
- page 184: both "endtry_length" and "entry_length" with different page numbers
- Quick Reference Card: tilde (~) missing from ASCII table