AOH :: PRODOS.TXT
This is a compilation of a whole bunch of Prodos 8 & 16 bit technical notes..som
|
Apple II
Technical Notes
_____________________________________________________________________________
Developer Technical Support
ProDOS 8
#1: The GETLN Buffer and a ProDOS Clock Card
Revised by: Matt Deatherage November 1988
Revised by: Pete McDonald November 1985
This Technical Note describes the effect of a clock card on the GETLN buffer.
_____________________________________________________________________________
ProDOS automatically supports a ThunderClock(TM) or compatible clock card when
the system identifies it as being installed. When programming under ProDOS,
always consider the impact of a clock card on the GETLN input buffer ($200 -
$2FF). ProDOS can support other clocks which may also use this space.
When ProDOS calls a clock card, the card deposits an ASCII string in the GETLN
input buffer in the form: 07,04,14,22,46,57. This string translates as the
following:
07 = The month, July (01=Jan,...,12=Dec)
04 = The day of the week, Thurs.(00=Sun,...,06=Sat)
14 = The date (00 to 31)
22 = The hour, 10 p.m. (00 to 23)
46 = The minute (00 to 59)
57 = The second (00 to 59)
ProDOS calls the clock card as part of many of its routines. Anything in the
first 17 bytes of the GETLN input buffer is subject to loss if a clock card is
installed and is called.
In general, it has been the practice of programmers to use the GETLN input
buffer for every conceivable purpose. Therefore, an application should never
store anything there. If your application has a future need to know about the
contents of the $200 - $2FF space, you should transfer it to some other
location to guarantee that it will remain intact, particularly under ProDOS,
where a clock card may regularly be overwriting the first 17 bytes.
The ProDOS 8 Technical Reference Manual contains more information on the clock
driver, including the necessary identification bytes, how the ProDOS driver
calls the card, and how you may replace this routine with your own.
Further Reference
o ProDOS 8 Technical Reference Manual
Apple II
Technical Notes
_____________________________________________________________________________
Developer Technical Support
ProDOS 8
#2: Porting DOS 3.3 Programs to ProDOS and BASIC.SYSTEM
Revised by: Matt Deatherage November 1988
Revised by: Pete McDonald November 1985
This Technical Note formerly described the DOSCMD vector of BASIC.SYSTEM.
_____________________________________________________________________________
This Note formerly described the DOSCMD vector of BASIC.SYSTEM, which can be
used to let BASIC.SYSTEM interpret ASCII strings as disk commands in much the
same way DOS 3.3 did. The ProDOS 8 Technical Reference Manual now contains
this information in Appendix A.
Further Reference
o ProDOS 8 Technical Reference Manual
Apple II
Technical Notes
_____________________________________________________________________________
Developer Technical Support
ProDOS 8
#3: Device Search, Identification, and Driver Conventions
Revised by: Matt Deatherage November 1988
Revised by: Pete McDonald November 1985
This Technical Note formerly described how ProDOS 8 searches for devices and
how it deals with devices which are not Disk II drives.
_____________________________________________________________________________
This Note formerly described how ProDOS 8 searches for devices and how it
deals with devices which are not Disk II drives; this information is now
contained in section 6.3 of the ProDOS 8 Technical Reference Manual.
Note: The information on slot mapping on page 113 of the manual
and on page 2 of the former edition of this Technical Note is
incorrect. ProDOS itself will mirror SmartPort devices from
slot 5 into slot 2 under certain conditions. Devices should not
be mirrored into slots other than slot 2. For more information,
see ProDOS 8 Technical Note #20, Mirrored Devices and SmartPort.
Further Reference
o ProDOS 8 Technical Reference Manual
o ProDOS 8 Technical Note #20, Mirrored Devices and SmartPort
Apple II
Technical Notes
_____________________________________________________________________________
Developer Technical Support
ProDOS 8
#4: I/O Redirection in DOS and ProDOS
Revised by: Matt Deatherage November 1988
Revised by: Pete McDonald November 1985
This Technical Note discusses I/O redirection differences between DOS 3.3 and
ProDOS.
_____________________________________________________________________________
Under DOS 3.3, all that is necessary to change the I/O hooks is installing
your I/O routine addresses in the character-out vector ($36-$37) and the key-
in vector ($38-$39) and notifying DOS (JSR $3EA) to take your addresses and
swap in its intercept routine addresses.
Under ProDOS, there is no instruction installed at $3EA, so what do you do?
You simply leave the ProDOS BASIC command interpreter's intercept addresses
installed at $36-$39 and install your I/O addresses in the global page at
$BE30-$BE33. The locations $BE30-$BE31 should contain the output address
(normally $FDF0, the Monitor COUT1 routine), while $BE32-$BE33 should contain
the input address (normally $FD1B, the Monitor KEYIN routine).
By keeping these vectors in a global page, a special routine for moving the
vectors is no longer needed, thus, no $3EA instruction. You install the
addresses at their destination yourself.
If you intend to switch between devices (i.e., the screen and the printer),
you should save the hooks you find in $BE30-$BE33 and restore them when you
are done. Blindly replacing the values in the global page could easily leave
you no way to restore input or output to the previous device when you are
done.
Apple II
Technical Notes
_____________________________________________________________________________
Developer Technical Support
ProDOS 8
#5: ProDOS Block Device Formatting
Revised by: Matt Deatherage November 1988
Revised by: Pete McDonald October 1985
This Technical Note formerly described the ProDOS FORMATTER routine.
_____________________________________________________________________________
The ProDOS 8 Update Manual now contains the information about the ProDOS
FORMATTER routine which this Note formerly described. This routine is
available from Apple Software Licensing at Apple Computer, Inc., 20525 Mariani
Avenue, M/S 38-I, Cupertino, CA, 95014 or (408) 974-4667.
Note: This routine does not work properly with network volumes on
either entry point. You cannot format a network volume with
ProDOS 8, nor can you make low-level device calls to it (as
FORMATTER does in ENTRY2 to determine the characteristics of a
volume). As a general rule, it is better to use GET_FILE_INFO to
determine the size of the volume since ProDOS MLI calls work with
network volumes.
Further Reference
o ProDOS 8 Update Manual
Apple II
Technical Notes
_____________________________________________________________________________
Developer Technical Support
ProDOS 8
#6: Attaching External Commands to BASIC.SYSTEM
Revised by: Matt Deatherage November 1988
Revised by: Pete McDonald December 1985
This Technical Note formerly described how to attach an external command to
BASIC.SYSTEM.
_____________________________________________________________________________
The ProDOS 8 Technical Reference Manual, Appendix A now documents the
information which this Note formerly covered about installing an external
command into BASIC.SYSTEM to be treated as a normal BASIC.SYSTEM command.
Further Reference
o ProDOS 8 Technical Reference Manual
Apple II
Technical Notes
_____________________________________________________________________________
Developer Technical Support
ProDOS 8
#7: Starting and Quitting Interpreter Conventions
Revised by: Matt Deatherage November 1988
Revised by: Pete McDonald December 1985
This Technical Note formerly described conventions for a ProDOS application to
start and quit.
_____________________________________________________________________________
Section 5.1.5 of the ProDOS 8 Technical Reference Manual now documents the
conventions a ProDOS application should follow when starting and quitting,
which were formerly covered in this Note as well as ProDOS 8 Technical Note
#14, Selector and Dispatcher Conventions.
Further Reference
o ProDOS 8 Technical Reference Manual
Apple II
Technical Notes
_____________________________________________________________________________
Developer Technical Support
ProDOS 8
#8: Dealing with /RAM
Revised by: Matt Deatherage November 1988
Written by: Kerry Laidlaw October 1984
This Technical Note formerly described conventions for dealing with the built-
in ProDOS 8 RAM disk, /RAM.
_____________________________________________________________________________
Section 5.2.2 of the ProDOS 8 Technical Reference Manual now documents the
conventions on how to handle /RAM, including how to disconnect it, how to
reconnect it, and precautions you should follow if doing either, which were
covered in this Note. The manual also includes sample source code.
Executing the sample code which comes with the manual to disconnect /RAM has
the undesired effect of decreasing the maximum number of volumes on-line when
used with versions of ProDOS 8 prior to 1.2. This side effect is because
earlier versions of ProDOS 8 do not have the capability to remove the volume
control block (VCB) entry which is allocated for /RAM when it is installed.
In later versions of ProDOS 8 (1.2 and later), this problem no longer exists,
and you should issue an ON_LINE call to a device after disconnecting it. This
call returns error $28 (no device connected), but it also erases the VCB entry
for the disconnected device.
Further Reference
o ProDOS 8 Technical Reference Manual
o ProDOS 8 Update Manual
Apple II
Technical Notes
_____________________________________________________________________________
Developer Technical Support
ProDOS 8
#9: Buffer Management Using BASIC.SYSTEM
Revised by: Matt Deatherage November 1988
Revised by: Pete McDonald October 1985
This Technical Note discusses methods for allocating buffers which will not be
arbitrarily deallocated in BASIC.SYSTEM.
_____________________________________________________________________________
Section A.2.1 of the ProDOS 8 Technical Reference Manual describes in detail
how an application may obtain a buffer from BASIC.SYSTEM for its own use. The
buffer will be respected by BASIC.SYSTEM, so if you choose to put a program or
other executable code in there, it will be safe.
However, BASIC.SYSTEM does not provide a way to selectively deallocate the
buffers it has allocated. Although it is quite easy to allocate space by
calling GETBUFR ($BEF5) and also quite easy to deallocate by calling FREEBUFR
($BEF8), it is not so easy to use FREEBUFR to deallocate a particular buffer.
In fact, FREEBUFR always deallocates all buffers allocated by GETBUFR. This
is fine for transient applications, but a method is needed to protect a static
code buffer from being deallocated by FREEBUFR for a static application.
Location RSHIMEM ($BEFB) contains the high byte of the highest available
memory location for buffers, normally $96. FREEBUFR uses it to determine the
beginning page of the highest (or first) buffer. By lowering the value of
RSHIMEM immediately after the first call to GETBUFR, and before any call to
FREEBUFR, we can fool FREEBUFR into not reclaiming all the space. So although
it is not possible to selectively deallocate buffers, it is still possible to
reserve space that FREEBUFR will not reclaim.
Physically, we place the code buffer between BASIC.SYSTEM and its buffers, in
the space from $99FF down.
After creating the protected static code buffer, we can call GETBUFR and
FREEBUFR to maintain temporary buffers as needed by our protected module.
FREEBUFR will not reclaim the protected buffer until after RSHIMEM is restored
to its original value.
The following is a skeleton example which allocates a two-page buffer for a
static code module, protects it from FREEBUFR, then deprotects it and restores
it to its original state.
START LDA #$02 ;get 2 pages
JSR GETBUFR
LDA RSHIMEM ;get current RSHIMEM
SEC ;ready for sub
SBC #$02 ;minus 2 pages
STA RSHIMEM ;save new val to fool FREEBUFR
JSR FREEBUFR ;CALL FREEBUFR to deallocate.
At this point, the value of RSHIMEM is the page number of the beginning of our
protected buffer. The static code may now use GETBUFR and FREEBUFR for
transient file buffers without fear of freeing its own space from RSHIMEM to
$99FF.
To release the protected space, simply restore RSHIMEM to its original value
and perform a JSR FREEBUFR.
END LDA RSHIMEM ;get current val
CLC ;ready for ADD
ADC #2 ;give back 2 pages
STA RSHIMEM ;tell FREEBUFR about it
JSR FREEBUFR ;DO FREEBUFR
RTS
You can reserve any number of pages using this method, as long as the amount
you reserve is within available memory limits.
Further Reference
o ProDOS 8 Technical Reference Manual
Apple II
Technical Notes
_____________________________________________________________________________
Developer Technical Support
ProDOS 8
#10: Installing Clock Driver Routines
Revised by: Matt Deatherage November 1988
Revised by: Pete McDonald November 1985
This Technical Note formerly described how to install a clock driver routine
other than the default.
_____________________________________________________________________________
Section 6.1.1 of the ProDOS 8 Technical Reference Manual documents how to
install a clock driver other than the default ThunderClock(TM) driver or the
Apple IIGS clock driver into ProDOS 8, which this Note formerly covered.
Further Reference
o ProDOS 8 Technical Reference Manual
o ProDOS 8 Technical Note #1, The GETLN Buffer and a ProDOS Clock Card
Apple II
Technical Notes
_____________________________________________________________________________
Developer Technical Support
ProDOS 8
#11: The ProDOS 8 MACHID Byte
Revised by: Matt Deatherage November 1988
Revised by: Pete McDonald November 1985
This Technical Note describes the machine ID byte (MACHID) which ProDOS
maintains to help identify different machine types.
_____________________________________________________________________________
ProDOS 8 maintains a machine ID byte, MACHID, at location $BF98 in the ProDOS
8 global page. Section 5.2.4 of the ProDOS 8 Technical Reference Manual
correctly documents the definition of this byte.
MACHID has become less robust through the years. Although it can tell you if
you are running on an Apple ][, ][+, IIe, IIc, or Apple /// in emulation mode,
it cannot tell you which version of an Apple IIe or IIc you are using, nor can
it identify an Apple IIGS (it thinks a IIGS is an Apple IIe). However, the
byte still provides a quick test for two components of the system which you
might wish to identify: an 80-column card and a clock card.
Bit 1 of MACHID identifies an 80-column card. ProDOS 8 Technical Note #15,
How ProDOS 8 Treats Slot 3 explains how this identification is determined.
Note that on an Apple IIGS, this bit is always set, even if the user selects
Your Card in the Control Panel for slot 3. The bit is set since ProDOS 8
versions 1.7 and later switch out a card in slot 3 in favor of the built-in
80-column firmware, unless the card in slot 3 is an 80-column card. ProDOS 8
behaves in the same manner on an Apple IIe as well.
Bit 0 of MACHID identifies a clock card. Note that on an Apple IIGS, this bit
is always set since the IIGS clock cannot be switched out of the system. Due
to these unchangeable settings, the value of MACHID on the Apple IIGS is
always $B3, as it is on any Apple IIe with an 80-column card and a clock card.
Further Reference
o ProDOS 8 Technical Reference Manual
o Apple IIGS Hardware Reference Manual
o ProDOS 8 Technical Note #15, How ProDOS 8 Treats Slot 3
o Miscellaneous Technical Note #7, Apple II Family Identification
Apple II
Technical Notes
_____________________________________________________________________________
Developer Technical Support
ProDOS 8
#12: Interrupt Handling
Revised by: Matt Deatherage November 1988
Revised by: Pete McDonald November 1985
This Technical Note clarifies some aspects of ProDOS 8 interrupt handlers.
_____________________________________________________________________________
Although the ProDOS 8 Technical Reference Manual (section 6.2) documents
interrupt handlers and includes a code example, there still remain a few
unclear areas on this subject matter; this Note clarifies these areas.
All interrupt routines must begin with a CLD instruction. Although not
checked in initial releases of ProDOS 8, this first byte will be checked in
future revisions to verify the validity of the interrupt handler.
Although your interrupt handler does not have to disable interrupts (ProDOS 8
does that for you), it must never re-enable interrupts with a 6502 CLI
instruction. Another interrupt coming through during a non-reentrant
interrupt handler can bring the system down.
If your application includes an interrupt handler, you should do the following
before exiting:
1. Turn off the interrupt source. Remember, 255 unclaimed interrupts
will cause system death.
2. Make a DEALLOC_INTERRUPT call before exiting from your
application. Do not leave a vector installed that points to a
routine that is no longer there.
Within your interrupt handler routines, you must leave all memory banks in the
same configuration you found them. Do not forget anything: main language
card, main alternate $D000 space, main motherboard ROM, and, on an Apple IIe,
IIc, or IIGS, auxiliary language card, auxiliary alternate $D000 space,
alternate zero page and stack, etc. This is very important since the ProDOS
interrupt receiver assumes that the environment is absolutely unaltered when
your handler relinquishes control. In addition, be sure to leave the language
card write-enabled.
If your handler recognizes an interrupt and services it, you should clear the
carry flag (CLC) immediately before returning (RTS). If it was not your
interrupt, you set set the carry (SEC) immediately before returning (RTS). Do
not use a return from interrupt (RTI) to exit; the ProDOS interrupt receiver
still has some housekeeping to perform before it issues the RTI instruction.
Further Reference
o ProDOS 8 Technical Reference Manual
Apple II
Technical Notes
_____________________________________________________________________________
Developer Technical Support
ProDOS 8
#13: Double High-Resolution Graphics Files
Revised by: Matt Deatherage November 1988
Revised by: Pete McDonald November 1985
This Technical Note formerly described a proposed file format for Apple II
double high-resolution graphics images.
_____________________________________________________________________________
The information formerly in this Note, the proposed file format for Apple II
double high-resolution graphics images, is now covered in the Apple II File
Type Notes, File Type $08.
Further Reference
o Apple II File Type Notes, File Type $08
Apple II
Technical Notes
_____________________________________________________________________________
Developer Technical Support
ProDOS 8
#14: Selector and Dispatcher Conventions
Revised by: Matt Deatherage November 1988
Revised by: Pete McDonald December 1985
This Technical Note formerly described conventions for a ProDOS application to
start and quit.
_____________________________________________________________________________
Section 5.1.5 of the ProDOS 8 Technical Reference Manual now documents the
conventions a ProDOS application should follow when starting and quitting,
which were formerly covered in this Note as well as ProDOS 8 Technical Note
#7, Starting and Quitting Interpreter Conventions.
Further Reference
o ProDOS 8 Technical Reference Manual
Apple II
Technical Notes
_____________________________________________________________________________
Developer Technical Support
ProDOS 8
#15: How ProDOS 8 Treats Slot 3
Revised by: Matt Deatherage November 1988
Revised by: Pete McDonald November 1985
This Technical Note describes how ProDOS 8 reacts to non-Apple 80-column cards
in slot 3 and how it identifies them.
_____________________________________________________________________________
The ProDOS 8 Update Manual now documents much of the information which was
originally covered in this Note about how ProDOS 8 reacts to non-Apple 80-
column cards in slot 3. However, since there is still some confusion on the
issue, we summarize it again in this Note.
On an Apple ][+, ProDOS 8 considers the following four Pascal 1.1 protocol ID
bytes sufficient to identify a card in slot 3 as an 80-column card and mark
the corresponding bit in the MACHID byte: $C305 = $38, $C307 = $18, $C30B =
$01, $C30C = $8x, where x represents the card's own ID value and is not
checked. On any other Apple II, the following fifth ID byte must also match:
$C3FA = $2C. This fifth ID byte assures ProDOS 8 that the card supports
interrupts on an Apple IIe. Unless ProDOS 8 finds all five ID bytes in an
Apple IIe or later, it will not identify the card as an 80-column card and
will enable the built-in 80-column firmware instead. In an Apple IIc or IIGS,
the internal firmware always matches these five bytes (see below).
If you are designing an 80-column card and wish to meet these requirements,
you must follow certain other considerations as well as matching the five
identification bytes; the ProDOS 8 Update Manual enumerates these other
considerations.
The ProDOS 8 Update Manual notes that an Apple IIGS does not switch in the 80-
column firmware if it is not selected in the Control Panel. However, due to a
bug in ProDOS 8 versions 1.6 and earlier, it switches in the 80-column
firmware unconditionally. ProDOS 8 cannot respect the Control Panel setting
for 80-column firmware in certain situations; it cannot operate in a 128K
machine in a 128K configuration (including /RAM) without the presence of the
80-column firmware, since it must utilize the extra 64K. This is just one of
the reasons ProDOS 8 does not recognize a card in slot 3 if it is not an 80-
column card, as outlined above.
With ProDOS 8 version 1.7 and later, an Apple IIGS behaves exactly like an
Apple IIe with respect to slot 3. If a card is slot 3 is selected in the
Control Panel, ProDOS 8 ignores it in favor of the built-in 80-column
firmware--unless the card matches the five identification bytes listed above.
This works the same on a Apple IIe.
Further Reference
o ProDOS 8 Technical Reference Manual
o ProDOS 8 Update Manual
o ProDOS 8 Technical Note #11, The ProDOS 8 MACHID Byte
Apple II
Technical Notes
_____________________________________________________________________________
Developer Technical Support
ProDOS 8
#16: How to Format a ProDOS Disk Device
Revised by: Matt Deatherage November 1988
Revised by: Pete McDonald November 1985
This Technical Note supplements the ProDOS 8 Technical Reference Manual in its
description of the low-level driver call that formats the media in a ProDOS
device.
_____________________________________________________________________________
The ProDOS 8 Technical Reference Manual describes the low-level driver call
that formats the media in a ProDOS device, but it neglects to mention the
following:
1. It does not work for Disk II drives or /RAM, both of which ProDOS
treats specially with built-in driver code.
2. ProDOS has no easy way to tell you whether a device is a Disk II
drive or /RAM.
Once ProDOS finishes building its device table, which it does when it boots,
it no longer cares about what kind of devices exist, so it does not keep any
information about the different types of devices available. ProDOS identifies
Disk II devices and installs a built-in driver for them. When it has
installed all devices which are physically present, ProDOS then installs /RAM,
in a manner similar to Disk II drives, by pointing to the driver code which is
within ProDOS itself. This method presents a problem for the developer who
wishes to format ProDOS disks since the Disk II driver and the /RAM driver
respond to the FORMAT request in non-standard ways, yet there is no
identification in the global page that tells you which devices are Disk II
drives or /RAM.
The Disk II driver does not support the FORMAT request, and the /RAM driver
responds by "formatting" the RAM disk and also writing to it a virgin
directory and bitmap; neither of these two cases is documented in the ProDOS 8
Technical Reference Manual. To write special-case code for these two device
types, you must be able to identify them, and the method for identification is
available in ProDOS 8 Technical Note #21: Identifying ProDOS Devices.
You should note, however, that AppleTalk network volumes cannot be formatted;
they return a DEVICE NOT CONNECTED error for the FORMAT and any low-level
device call. You may access AppleTalk network volumes through ProDOS MLI
calls only.
Also note that Apple licences a ProDOS 8 Formatter routine, which correctly
identifies and handles Disk II drives and /RAM. You should contact Apple
Software Licensing at Apple Computer, Inc., 20525 Mariani Avenue, M/S 38-I,
Cupertino, CA, 95014 or (408) 974-4667 if you wish to license this routine.
Further Reference
o ProDOS 8 Technical Reference Manual
o ProDOS 8 Update Manual
o ProDOS 8 Technical Note #21, Identifying ProDOS Devices
Apple II
Technical Notes
_____________________________________________________________________________
Developer Technical Support
ProDOS 8
#17: Recursive ProDOS Catalog Routine
Revised by: Keith Rollin & Matt Deatherage November 1988
Written by: Greg Seitz December 1983
This Technical Note presents an assembly language example of a recursive
directory reading routine which is AppleShare compatible.
_____________________________________________________________________________
This Note presents a routine in assembly language for recursively cataloging a
ProDOS disk, and if you apply this technique to the volume directory of a
disk, it will display the name of every file stored on the disk. The routine
displays the contents of a given directory, the volume directory in this case,
then displays the contents of every directory contained within the initial
directory.
Previous versions of the Note recommended reading the directory with
READ_BLOCK ProDOS calls. This method will still work in most cases, but Apple
Computer no longer endorses it since block-level access is not allowed to
AppleShare file servers under ProDOS. (A file server cannot handle one
machine connected to it changing files and directories on a block level while
it is trying to arbitrate usage between other machines at the file level. A
block-level change behind the server's back could easily mess things up
catastrophically.)
If you are willing to use a different approach, however, you can read the
directory just as easily using READ calls. Instead of using directory
pointers to decide which block to read next, we simply read the directory and
display filenames as we go, until we reach a subdirectory file. When we reach
a subdirectory, the routine saves the necessary variables, plunges down one
level of the tree structure, and catalogs the subdirectory. You repeat the
process if you find a subdirectory at the current level. When you reach the
EOF of any directory, the routine closes the current directory and pops back
up one level, and when it reaches the EOF of the initial directory, the
routine is finished.
The code example on the following pages includes a simple test of the ReadDir
routine, which is the actual recursive catalog routine. Note that the simple
test relies upon the GETBUFR routine in BASIC.SYSTEM to allocate a buffer;
therefore, as presented, the routine requires the presence of BASIC.SYSTEM.
The actual ReadDir routine requires nothing outside of the ProDOS 8 MLI.
01 RECURSIVE.S ProDOS Catalog Routine 27-AUG-88 16:20 PAGE 2
----- NEXT OBJECT FILE NAME IS CATALOG.OBJ
0800: 0800 2 org $800
0800: 3 *******************************************************
0800: 4 *
0800: 5 * Recursive ProDOS Catalog Routine
0800: 6 *
0800: 7 * by: Greg Seitz 12/83
0800: 8 * Pete McDonald 1/86
0800: 9 * Keith Rollin 7/88
0800: 10 *
0800: 11 * This program shows the latest "Apple Approved"
0800: 12 * method for reading a ProDOS directory. With
0800: 13 * the advent of AppleTalk for the Apple II, using
0800: 14 * _READBLOCK to read the directory will no longer
0800: 15 * work. This routine has been re-written to read
0800: 16 * directories by opening them as files, and
0800: 17 * performing simple _READ commands.
0800: 18 *
0800: 19 *******************************************************
0800: 20 *
0800: 21 * Equates
0800: 22 *
0800: 23 * Zero page locations
0800: 24 *
0800: 0080 25 dirName equ $80 ; pointer to directory name
0800: 0082 26 entPtr equ $82 ; ptr to current entry
0800: 27 *
0800: 28 *
0800: 29 * ProDOS command numbers
0800: 30 *
0800: BF00 31 MLI equ $BF00 ; MLI entry point
0800: BEF5 32 GetBufr equ $BEF5 ; BASIC.SYSTEM get buffer routine
0800: 33 *
0800: 00C7 34 GetPCmd equ $C7 ; Get Prefix
0800: 00C8 35 OpenCmd equ $C8 ; Open a file command
0800: 00CA 36 ReadCmd equ $CA ; Read a file command
0800: 00CC 37 CloseCmd equ $CC ; Close a file command
0800: 00CE 38 SetMCmd equ $CE ; Set File Position command
0800: 39 *
0800: 40 *
0800: 41 * Offsets into the directory
0800: 42 *
0800: 0000 43 oType equ $0 ; offset to file type byte
0800: 0023 44 oEntLen equ $23 ; length of each dir. entry
0800: 0024 45 oEntBlk equ $24 ; entries in each block
0800: 0025 46 oEntDir equ $25 ; entries in entire directory
0800: 47 *
0800: 48 *
0800: 49 * Monitor routines
0800: 50 *
0800: FDED 51 cout equ $FDED ; output a character
0800: FD8E 52 crout equ $FD8E ; output a RETURN
0800: 53 *
0800: 54 *******************************************************
0800: 55 *
0800: 0800 56 Start equ *
0800: 57 *
0800: 58 * Simple routine to test the recursive ReadDir
01 RECURSIVE.S ProDOS Catalog Routine 27-AUG-88 16:20 PAGE 3
0800: 59 * routine. It gets an I/O buffer for ReadDir, gets
0800: 60 * the current prefix, sets the depth of recursion
0800: 61 * to zero, and calls ReadDir to process all of the
0800: 62 * entries in the directory.
0800: 63 *
0800:A9 04 64 lda #4 ; get an I/O buffer
0802:20 F5 BE 65 jsr GetBufr
0805:B0 17 081E 66 bcs exit ; didn't get it
0807:8D DD 09 67 sta ioBuf+1
080A: 68 *
080A:20 00 BF 69 jsr MLI
080D:C7 70 db GetPCmd
080E:EE 09 71 dw GetPParms
0810:B0 0C 081E 72 bcs exit
0812: 73 *
0812:A9 00 74 lda #0
0814:8D D2 09 75 sta Depth
0817: 76 *
0817:A9 F1 77 lda #nameBuffer
0819:A2 0B 78 ldx #<nameBuffer
081B:20 1F 08 79 jsr ReadDir
081E: 80 *
081E: 081E 81 exit equ *
081E:60 82 rts
081F: 83 *
081F: 84 *******************************************************
081F: 85 *
081F: 081F 86 ReadDir equ *
081F: 87 *
081F: 88 * This is the actual recursive routine. It takes as
081F: 89 * input a pointer to the directory name to read in
081F: 90 * A,X (lo,hi), opens it, and starts to read the
081F: 91 * entries. When it encounters a filename, it calls
081F: 92 * the routine "VisitFile". When it encounters a
081F: 93 * directory name, it calls "VisitDir".
081F: 94 *
081F: 95 *******************************************************
081F: 96 *
081F:85 80 97 sta dirName ; save a pointer to name
0821:86 81 98 stx dirName+1
0823: 99 *
0823:8D DA 09 100 sta openName ; set up OpenFile params
0826:8E DB 09 101 stx openName+1
0829: 102 *
0829: 0829 103 ReadDir1 equ * ; recursive entry point
0829:20 54 08 104 jsr OpenDir ; open the directory as a file
082C:B0 1F 084D 105 bcs done
082E: 106 *
082E:4C 48 08 107 jmp nextEntry ; jump to the end of the loop
0831: 108 *
0831: 0831 109 loop equ *
0831:A0 00 110 ldy #oType ; get type of current entry
0833:B1 82 111 lda (entPtr),y
0835:C9 00 112 cmp #0 ; inactive entry?
0837:F0 0F 0848 113 beq nextEntry ; yes - bump to next one
0839:29 F0 114 and #$F0 ; look at 4 high bits
083B:C9 D0 115 cmp #$D0 ; is it a directory?
083D:F0 06 0845 116 beq ItsADir ; yes, so call VisitDir
01 RECURSIVE.S ProDOS Catalog Routine 27-AUG-88 16:20 PAGE 4
083F:20 9A 08 117 jsr VisitFile ; no, it's a file
0842:4C 48 08 118 jmp nextEntry
0845: 0845 119 ItsADir equ *
0845:20 A1 08 120 jsr VisitDir
0848: 0848 121 nextEntry equ *
0848:20 68 09 122 jsr GetNext ; get pointer to next entry
084B:90 E4 0831 123 bcc loop ; Carry set means we're done
084D: 084D 124 done equ *
084D: 125 *
084D:20 00 BF 126 jsr MLI ; close the directory
0850:CC 127 db CloseCmd
0851:E7 09 128 dw CloseParms
0853: 129 *
0853:60 130 rts
0854: 131 *
0854: 132 *******************************************************
0854: 133 *
0854: 0854 134 OpenDir equ *
0854: 135 *
0854: 136 * Opens the directory pointed to by OpenParms
0854: 137 * parameter block. This pointer should be init-
0854: 138 * ialized BEFORE this routine is called. If the
0854: 139 * file is successfully opened, the following
0854: 140 * variables are set:
0854: 141 *
0854: 142 * xRefNum ; all the refnums
0854: 143 * entryLen ; size of directory entries
0854: 144 * entPtr ; pointer to current entry
0854: 145 * ThisBEntry ; entry number within this block
0854: 146 * ThisEntry ; entry number within this dir.
0854: 147 * ThisBlock ; offset (in blocks) into dir.
0854: 148 *
0854:20 00 BF 149 jsr MLI ; open dir as a file
0857:C8 150 db OpenCmd
0858:D9 09 151 dw OpenParms
085A:B0 3D 0899 152 bcs OpenDone
085C: 153 *
085C:AD DE 09 154 lda oRefNum ; copy the refnum return-
085F:8D E0 09 155 sta rRefNum ; ed by Open into the
0862:8D E8 09 156 sta cRefNum ; other param blocks.
0865:8D EA 09 157 sta sRefNum
0868: 158 *
0868:20 00 BF 159 jsr MLI ; read the first block
086B:CA 160 db ReadCmd
086C:DF 09 161 dw ReadParms
086E:B0 29 0899 162 bcs OpenDone
0870: 163 *
0870:AD 14 0A 164 lda buffer+oEntLen ; init 'entryLen'
0873:8D D7 09 165 sta entryLen
0876: 166 *
0876:A9 F5 167 lda #buffer+4 ; init ptr to first entry
0878:85 82 168 sta entPtr
087A:A9 09 169 lda #<buffer+4
087C:85 83 170 sta entPtr+1
087E: 171 *
087E:AD 15 0A 172 lda buffer+oEntblk ; init these values based on
0881:8D D5 09 173 sta ThisBEntry ; values in the dir header
0884:8D D8 09 174 sta entPerBlk
01 RECURSIVE.S ProDOS Catalog Routine 27-AUG-88 16:20 PAGE 5
0887:AD 16 0A 175 lda buffer+oEntDir
088A:8D D3 09 176 sta ThisEntry
088D:AD 17 0A 177 lda buffer+oEntDir+1
0890:8D D4 09 178 sta ThisEntry+1
0893: 179 *
0893:A9 00 180 lda #0 ; init block offset into dir.
0895:8D D6 09 181 sta ThisBlock
0898: 182 *
0898:18 183 clc ; say that open was OK
0899: 184 *
0899: 0899 185 OpenDone equ *
0899:60 186 rts
089A: 187 *
089A: 188 *******************************************************
089A: 189 *
089A: 089A 190 VisitFile equ *
089A: 191 *
089A: 192 * Do whatever is necessary when we encounter a
089A: 193 * file entry in the directory. In this case, we
089A: 194 * print the name of the file.
089A: 195 *
089A:20 A7 09 196 jsr PrintEntry
089D:20 8E FD 197 jsr crout
08A0:60 198 rts
08A1: 199 *
08A1: 200 *******************************************************
08A1: 201 *
08A1: 08A1 202 VisitDir equ *
08A1: 203 *
08A1: 204 * Print the name of the subdirectory we are looking
08A1: 205 * at, appending a "/" to it (to indicate that it's
08A1: 206 * a directory), and then calling RecursDir to list
08A1: 207 * everything in that directory.
08A1: 208 *
08A1:20 A7 09 209 jsr PrintEntry ; print dir's name
08A4:A9 AF 210 lda #'/'|$80 ; tack on / at end
08A6:20 ED FD 211 jsr cout
08A9:20 8E FD 212 jsr crout
08AC: 213 *
08AC:20 B0 08 214 jsr RecursDir ; enumerate all entries in sub-dir.
08AF: 215 *
08AF:60 216 rts
08B0: 217 *
08B0: 218 *******************************************************
08B0: 219 *
08B0: 08B0 220 RecursDir equ *
08B0: 221 *
08B0: 222 * This routine calls ReadDir recursively. It
08B0: 223 *
08B0: 224 * - increments the recursion depth counter,
08B0: 225 * - saves certain variables onto the stack
08B0: 226 * - closes the current directory
08B0: 227 * - creates the name of the new directory
08B0: 228 * - calls ReadDir (recursively)
08B0: 229 * - restores the variables from the stack
08B0: 230 * - restores directory name to original value
08B0: 231 * - re-opens the old directory
08B0: 232 * - moves to our last position within it
01 RECURSIVE.S ProDOS Catalog Routine 27-AUG-88 16:20 PAGE 6
08B0: 233 * - decrements the recursion depth counter
08B0: 234 *
08B0:EE D2 09 235 inc Depth ; bump this for recursive call
08B3: 236 *
08B3: 237 * Save everything we can think of (the women,
08B3: 238 * the children, the beer, etc.).
08B3: 239 *
08B3:A5 82 240 lda entPtr
08B5:48 241 pha
08B6:A5 83 242 lda entPtr+1
08B8:48 243 pha
08B9:AD D3 09 244 lda ThisEntry
08BC:48 245 pha
08BD:AD D4 09 246 lda ThisEntry+1
08C0:48 247 pha
08C1:AD D5 09 248 lda ThisBEntry
08C4:48 249 pha
08C5:AD D6 09 250 lda ThisBlock
08C8:48 251 pha
08C9:AD D7 09 252 lda entryLen
08CC:48 253 pha
08CD:AD D8 09 254 lda entPerblk
08D0:48 255 pha
08D1: 256 *
08D1: 257 * Close the current directory, as ReadDir will
08D1: 258 * open files of its own, and we don't want to
08D1: 259 * have a bunch of open files lying around.
08D1: 260 *
08D1:20 00 BF 261 jsr MLI
08D4:CC 262 db CloseCmd
08D5:E7 09 263 dw CloseParms
08D7: 264 *
08D7:20 20 09 265 jsr ExtendName ; make new dir name
08DA: 266 *
08DA:20 29 08 267 jsr ReadDir1 ; enumerate the subdirectory
08DD: 268 *
08DD:20 56 09 269 jsr ChopName ; restore old directory name
08E0: 270 *
08E0:20 54 08 271 jsr OpenDir ; re-open it back up
08E3: 272 *
08E3: 273 * Restore everything that we saved before
08E3: 274 *
08E3:68 275 pla
08E4:8D D8 09 276 sta entPerBlk
08E7:68 277 pla
08E8:8D D7 09 278 sta entryLen
08EB:68 279 pla
08EC:8D D6 09 280 sta Thisblock
08EF:68 281 pla
08F0:8D D5 09 282 sta ThisBEntry
08F3:68 283 pla
08F4:8D D4 09 284 sta ThisEntry+1
08F7:68 285 pla
08F8:8D D3 09 286 sta ThisEntry
08FB:68 287 pla
08FC:85 83 288 sta entPtr+1
08FE:68 289 pla
08FF:85 82 290 sta entPtr
01 RECURSIVE.S ProDOS Catalog Routine 27-AUG-88 16:20 PAGE 7
0901: 291 *
0901:AD D6 09 292 lda ThisBlock ; reset last position in dir
0904:0A 293 asl a ; = to block # times 512
0905:8D EC 09 294 sta Mark+1
0908:A9 00 295 lda #0
090A:8D EB 09 296 sta Mark
090D:8D ED 09 297 sta Mark+2
0910: 298 *
0910:20 00 BF 299 jsr MLI ; reset the file marker
0913:CE 300 db SetMCmd
0914:E9 09 301 dw SetMParms
0916: 302 *
0916:20 00 BF 303 jsr MLI ; now read in the block we
0919:CA 304 db ReadCmd ; were on last.
091A:DF 09 305 dw ReadParms
091C: 306 *
091C:CE D2 09 307 dec Depth
091F:60 308 rts
0920: 309 *
0920: 310 *******************************************************
0920: 311 *
0920: 0920 312 ExtendName equ *
0920: 313 *
0920: 314 * Append the name in the current directory entry
0920: 315 * to the name in the directory name buffer. This
0920: 316 * will allow us to descend another level into the
0920: 317 * disk hierarchy when we call ReadDir.
0920: 318 *
0920:A0 00 319 ldy #0 ; get length of string to copy
0922:B1 82 320 lda (entPtr),y
0924:29 0F 321 and #$0F
0926:8D 53 09 322 sta extCnt ; save the length here
0929:8C 54 09 323 sty srcPtr ; init src ptr to zero
092C: 324 *
092C:A0 00 325 ldy #0 ; init dest ptr to end of
092E:B1 80 326 lda (dirName),y ; the current directory name
0930:8D 55 09 327 sta destPtr
0933: 328 *
0933: 0933 329 extloop equ *
0933:EE 54 09 330 inc srcPtr ; bump to next char to read
0936:EE 55 09 331 inc destPtr ; bump to next empty location
0939:AC 54 09 332 ldy srcPtr ; get char of sub-dir name
093C:B1 82 333 lda (entPtr),y
093E:AC 55 09 334 ldy destPtr ; tack on to end of cur. dir.
0941:91 80 335 sta (dirName),y
0943:CE 53 09 336 dec extCnt ; done all chars?
0946:D0 EB 0933 337 bne extloop ; no - so do more
0948: 338 *
0948:C8 339 iny
0949:A9 2F 340 lda #'/' ; tack "/" on to the end
094B:91 80 341 sta (dirName),y
094D: 342 *
094D:98 343 tya ; fix length of filename to open
094E:A0 00 344 ldy #0
0950:91 80 345 sta (dirName),y
0952: 346 *
0952:60 347 rts
0953: 348 *
01 RECURSIVE.S ProDOS Catalog Routine 27-AUG-88 16:20 PAGE 8
0953: 0001 349 extCnt ds 1
0954: 0001 350 srcPtr ds 1
0955: 0001 351 destPtr ds 1
0956: 352 *
0956: 353 *
0956: 354 *******************************************************
0956: 355 *
0956: 0956 356 ChopName equ *
0956: 357 *
0956: 358 * Scans the current directory name, and chops
0956: 359 * off characters until it gets to a /.
0956: 360 *
0956:A0 00 361 ldy #0 ; get len of current dir.
0958:B1 80 362 lda (dirName),y
095A:A8 363 tay
095B: 095B 364 ChopLoop equ *
095B:88 365 dey ; bump to previous char
095C:B1 80 366 lda (dirName),y
095E:C9 2F 367 cmp #'/'
0960:D0 F9 095B 368 bne ChopLoop
0962:98 369 tya
0963:A0 00 370 ldy #0
0965:91 80 371 sta (dirName),y
0967:60 372 rts
0968: 373 *
0968: 374 *******************************************************
0968: 375 *
0968: 0968 376 GetNext equ *
0968: 377 *
0968: 378 * This routine is responsible for making a pointer
0968: 379 * to the next entry in the directory. If there are
0968: 380 * still entries to be processed in this block, then
0968: 381 * we simply bump the pointer by the size of the
0968: 382 * directory entry. If we have finished with this
0968: 383 * block, then we read in the next block, point to
0968: 384 * the first entry, and increment our block counter.
0968: 385 *
0968:AD D3 09 386 lda ThisEntry ; dec total entries
096B:D0 05 0972 387 bne skip1
096D:CE D4 09 388 dec ThisEntry+1
0970:30 33 09A5 389 bmi DirDone ; done with this directory
0972:CE D3 09 390 skip1 dec ThisEntry
0975: 391 *
0975:CE D5 09 392 dec ThisBEntry ; dec count for this block
0978:F0 10 098A 393 beq ReadNext ; done w/this block, get next one
097A: 394 *
097A:18 395 clc ; else bump up index
097B:A5 82 396 lda entPtr
097D:6D D7 09 397 adc entryLen
0980:85 82 398 sta entPtr
0982:A5 83 399 lda entPtr+1
0984:69 00 400 adc #0
0986:85 83 401 sta entPtr+1
0988:18 402 clc ; say that the buffer's good
0989:60 403 rts
098A: 404 *
098A: 098A 405 ReadNext equ *
098A:20 00 BF 406 jsr MLI ; get the next block
01 RECURSIVE.S ProDOS Catalog Routine 27-AUG-88 16:20 PAGE 9
098D:CA 407 db ReadCmd
098E:DF 09 408 dw ReadParms
0990:B0 13 09A5 409 bcs DirDone
0992: 410 *
0992:A9 F5 411 lda #buffer+4 ; set entry pointer to beginning
0994:85 82 412 sta entPtr
0996:A9 09 413 lda #<buffer+4
0998:85 83 414 sta entPtr+1
099A: 415 *
099A:AD D8 09 416 lda entPerBlk ; re-init 'entries in this block'
099D:8D D5 09 417 sta ThisBEntry
09A0:CE D5 09 418 dec ThisBEntry
09A3:18 419 clc ; return 'No error'
09A4:60 420 rts
09A5: 421 *
09A5: 09A5 422 DirDone equ * ; return 'All Done!'
09A5:38 423 sec ; return 'an error occurred'
09A6:60 424 rts
09A7: 425 *
09A7: 426 *******************************************************
09A7: 427 *
09A7: 09A7 428 PrintEntry equ *
09A7: 429 *
09A7: 430 * Using the pointer to the current entry, this
09A7: 431 * routine prints the entry name. It also pays
09A7: 432 * attention to the recursion depth, and indents
09A7: 433 * by 1 space for every level.
09A7: 434 *
09A7:AD D2 09 435 lda Depth ; init counter for indenting
09AA:8D D1 09 436 sta PrntCnt
09AD:4C B5 09 437 jmp spcDec
09B0:A9 A0 438 spcloop lda #$A0 ; print a space for indenting
09B2:20 ED FD 439 jsr cout
09B5: 09B5 440 spcDec equ *
09B5:CE D1 09 441 dec PrntCnt ; any more indenting?
09B8:10 F6 09B0 442 bpl spcloop ; yes - keep going
09BA: 443 *
09BA:A0 00 444 ldy #0 ; get byte that has the length byte
09BC:B1 82 445 lda (entPtr),y
09BE:29 0F 446 and #$0F ; get just the length
09C0:8D D1 09 447 sta PrntCnt ; put it into our counter
09C3: 09C3 448 PrntLoop equ *
09C3:C8 449 iny ; bump to the next char.
09C4:B1 82 450 lda (entPtr),y ; get next char
09C6:09 80 451 ora #$80 ; COUT likes high bit set
09C8:20 ED FD 452 jsr cout ; print it
09CB:CE D1 09 453 dec PrntCnt ; printed all chars?
09CE:D0 F3 09C3 454 bne PrntLoop ; no - keep going
09D0:60 455 rts
09D1: 456 *
09D1: 0001 457 PrntCnt ds 1 ; counter for printing
09D2: 458 *
09D2: 459 *******************************************************
09D2: 460 *
09D2: 461 * Some global variables
09D2: 462 *
09D2: 0001 463 Depth ds 1 ; amount of recursion
09D3: 0002 464 ThisEntry ds 2 ; abs entry number
01 RECURSIVE.S ProDOS Catalog Routine 27-AUG-88 16:20 PAGE 10
09D5: 0001 465 ThisBEntry ds 1 ; entry in this block
09D6: 0001 466 ThisBlock ds 1 ; block with dir
09D7: 0001 467 entryLen ds 1 ; length of each directory entry
09D8: 0001 468 entPerBlk ds 1 ; entries per block
09D9: 469 *
09D9: 470 *******************************************************
09D9: 471 *
09D9: 472 * ProDOS command parameter blocks
09D9: 473 *
09D9: 09D9 474 OpenParms equ *
09D9:03 475 db 3 ; number of parms
09DA: 0002 476 OpenName ds 2 ; pointer to filename
09DC:00 00 477 ioBuf dw $0000 ; I/O buffer
09DE: 0001 478 oRefNum ds 1 ; returned refnum
09DF: 479 *
09DF: 09DF 480 ReadParms equ *
09DF:04 481 db 4 ; number of parms
09E0: 0001 482 rRefNum ds 1 ; refnum from Open
09E1:F1 09 483 dw buffer ; pointer to buffer
09E3:00 02 484 reqAmt dw 512 ; amount to read
09E5: 0002 485 retAmt ds 2 ; amount actually read
09E7: 486 *
09E7: 09E7 487 CloseParms equ *
09E7:01 488 db 1 ; number of parms
09E8: 0001 489 cRefNum ds 1 ; refnum from Open
09E9: 490 *
09E9: 09E9 491 SetMParms equ *
09E9:02 492 db 2 ; number of parms
09EA: 0001 493 sRefNum ds 1 ; refnum from Open
09EB: 0003 494 Mark ds 3 ; file position
09EE: 495 *
09EE: 09EE 496 GetPParms equ *
09EE:01 497 db 1 ; number of parms
09EF:F1 0B 498 dw nameBuffer ; pointer to buffer
09F1: 499 *
09F1: 0200 500 buffer ds 512 ; enough for whole block
0BF1: 501 *
0BF1: 0040 502 nameBuffer ds 64 ; space for directory name
01 SYMBOL TABLE SORTED BY SYMBOL 27-AUG-88 16:20 PAGE 11
09F1 BUFFER 095B CHOPLOOP 0956 CHOPNAME CC CLOSECMD
09E7 CLOSEPARMS FDED COUT 09E8 CREFNUM FD8E CROUT
09D2 DEPTH 0955 DESTPTR 09A5 DIRDONE 80 DIRNAME
084D DONE 09D8 ENTPERBLK 82 ENTPTR 09D7 ENTRYLEN
081E EXIT 0953 EXTCNT 0920 EXTENDNAME 0933 EXTLOOP
BEF5 GETBUFR 0968 GETNEXT C7 GETPCMD 09EE GETPPARMS
09DC IOBUF 0845 ITSADIR 0831 LOOP 09EB MARK
BF00 MLI 0BF1 NAMEBUFFER 0848 NEXTENTRY 24 OENTBLK
25 OENTDIR 23 OENTLEN C8 OPENCMD 0854 OPENDIR
0899 OPENDONE 09DA OPENNAME 09D9 OPENPARMS 09DE OREFNUM
00 OTYPE 09A7 PRINTENTRY 09D1 PRNTCNT 09C3 PRNTLOOP
CA READCMD 0829 READDIR1 081F READDIR 098A READNEXT
09DF READPARMS 08B0 RECURSDIR ?09E3 REQAMT ?09E5 RETAMT
09E0 RREFNUM CE SETMCMD 09E9 SETMPARMS 0972 SKIP1
09B5 SPCDEC 09B0 SPCLOOP 0954 SRCPTR 09EA SREFNUM
?0800 START 09D5 THISBENTRY 09D6 THISBLOCK 09D3 THISENTRY
08A1 VISITDIR 089A VISITFILE
** SUCCESSFUL ASSEMBLY := NO ERRORS
** ASSEMBLER CREATED ON 15-JAN-84 21:28
** TOTAL LINES ASSEMBLED 502
** FREE SPACE PAGE COUNT 81
Further Reference
o ProDOS 8 Technical Reference Manual
Apple II
Technical Notes
_____________________________________________________________________________
Developer Technical Support
ProDOS 8
#18: /RAM Memory Map
Revised by: Matt Deatherage " November 1988
Written by: Pete McDoncld " " " December 1986
This Technical Note describes the block to actual oeoory location oarping of
/RAM.
_____________________________________________________________________________
Blocks Address Range
______________________________
| $70-$7F | $E000-$EFFF |
______________________________
| $68-$6F | $D000-$DFFF | (Bank 2)
______________________________
| $60-$67 | $D000-$DFFF | (Bank 1)
______________________________
| $4E-$5C | $A200-$BFFF |
______________________________
| $3D-$4C | $8200-$A1FF |
______________________________
| $2C-$3B | $6200-$81FF |
______________________________
| $1B-$2A | $4200-$61FF |
______________________________
| $0A-$19 | $2200-$41FF |
______________________________
______________________________
| $5D-$5F | $1A00-$1FFF |
______________________________
| $4D | $1800-$19FF |
______________________________
| $3C | $1600-$17FF |
______________________________
| $2B | $1400-$15FF |
______________________________
| $1A | $1200-$13FF |
______________________________
| $09 | $1000-$11FF |
______________________________
| $08 | $2000-$21FF |
______________________________
| $02 | $0E00-$0FFF |
______________________________
______________________________
| $03 | Bitmap* |
______________________________
Notes:
* Synthesized.
1. Blocks 0, 1, 4, 5, 6, and 7 do not exist.
2. Block $7F contains the Reset, IRQ, and NMI vectors and is normally
marked as used.
3. The memory from $0C00 - $0DFF is a general purpose buffer used by the
/RAM driver.
Apple II
Technical Notes
_____________________________________________________________________________
Developer Technical Support
ProDOS 8
#19: File Auxiliary Type Assignment
Revised by: Matt Deatherage November 1988
Written by: Matt Deatherage May 1988
This Technical Note describes file auxiliary type assignments.
_____________________________________________________________________________
The information in a ProDOS file auxiliary type field depends upon its primary
file type. For example, the auxiliary type field for a text file (TXT, $04)
is defined as the record length of the file if it is a random-access file, or
zero if it is a sequential file. The auxiliary type field for an
AppleWorks(TM) file contains information about the case of letters in the
filename (see Apple II File Type Notes, File Types $19, $1A, and $1B). The
auxiliary type field for a binary file (BIN, $06) contains the loading address
of the file, if one exists.
Auxiliary types are now used to extend the limit of 256 file types in ProDOS.
Specific auxiliary types can be assigned to generic application file types.
For example, if you need a file type for your word-processing program, Apple
might assign you an auxiliary type for the generic file type of Apple II word
processor file, if it is appropriate.
An application can determine if a given file belongs to it by checking the
file type and the auxiliary type in the directory entry. Other programming
considerations include the following:
1. If your program displays auxiliary type information, it should
include all auxiliary types, not just selected ones. Try to
display the auxiliary type information stored in the directory
entry, just as you would display hex codes for file types for
which you do not have a more descriptive message to display.
2. Programs should not store information in an undefined auxiliary
type field. Storing the record length in a text file is fine, and
it is even encouraged, but storing the number of words in a text
file in that text file's auxiliary type field might cause problems
for those programs which expect to find a record length there.
Similarly, storing data in the auxiliary type field will cause
problems if your data matches an auxiliary type which is assigned.
To avoid these problems, only store defined items in a file's
auxiliary type field. If you do not know of a definition for a
particular file type's associated auxiliary type, do not store
anything in its field.
To request a file type and auxiliary type, please send Apple II Developer
Technical Support a description of your proposed file format, along with a
justification for not using existing file and auxiliary types. We will
publish this information publicly, unless you specifically prohibit it, since
we feel doing so enables the exchange of data for those applications who
choose to support other file formats.
Further Reference
o ProDOS 8 Technical Reference Manual
o ProDOS 16 Technical Reference
Apple II
Technical Notes
_____________________________________________________________________________
Developer Technical Support
ProDOS 8
#20: Mirrored Devices and SmartPort
Revised by: Matt Deatherage November 1988
Written by: Matt Deatherage May 1988
This Technical Note describes how ProDOS 8 reacts when more than two SmartPort
devices are connected, how applications using direct device access should
behave, and other related issues. This Note supersedes Section 6.3.1 of the
ProDOS 8 Technical Reference Manual.
_____________________________________________________________________________
Although SmartPort theoretically can handle up to 127 devices connected to a
single interface (in practice, electrical considerations curtail this
considerably), ProDOS 8 can handle only two devices per slot. This is because
ProDOS uses bit 7 of its unit_number is used to distinguish drives from each
other, and a single bit cannot distinguish more than two devices.
When it boots, ProDOS checks each interface card (or firmware equivalent in
the IIc or IIGS) for the ProDOS block-device signature bytes ($Cn01 = $20,
$Cn03 = $00, and $Cn05 = $03), so it can install the appropriate device-driver
address in the system global page. If the signature bytes match, ProDOS then
checks the SmartPort signature byte ($Cn07 = $00), and if that byte matches
and the interface is in slot 5 (or located at $C500 in the IIc or IIGS),
ProDOS does a SmartPort STATUS call to determine how many devices are
connected to the interface. If only one or two drives are connected to the
interface, ProDOS installs its block-device entry point (the contents of $CnFF
added to $Cn00) in the device-driver vector table, which starts at $BF10. In
this particular instance, ProDOS would put the vector at $BF1A for slot 5,
drive 1, and if two drives were found, at $BF2A for slot 5, drive 2 .
If the interface is in slot 5 and more than two devices are connected, ProDOS
copies the same block-device entry point that it uses for slot 5, drives 1 and
2 in the device driver table entry for slot 2, drive 1, and if four drives are
connected, for slot 2, drive 2. Further in the boot process, if ProDOS finds
the interface of a block device in slot 2 (not possible on a IIc), it replaces
the vectors copied from slot 5 with the proper device-driver vectors for slot
2; this is the reason mirroring is disabled if there is a ProDOS device in
slot 2. Note that non-ProDOS devices (i.e, serial cards and ports, etc.) do
not have vectors installed in the ProDOS device-driver table, so they do not
interfere with mirroring.
When ProDOS makes an MLI call with the unit_number of a mirrored device, it
sets up the call to the device driver then goes through the vector in the
device-driver table starting at $BF00. When the block device driver (located
on the interface card or in the firmware) gets this MLI call, it checks the
unit number which is stored at $43 and verifies if the slot number (bits four,
five, and six) is the same as that of the interface. If it is not, the ProDOS
block device driver of the interface realizes it is dealing with a mirrored
device, internally adds three to the slot number and two to the drive number,
then processes it, returning the desired information or data to ProDOS.
If an application must make direct device-driver calls (something which is
not encouraged), it should first check devlst (starting at $BF32) to verify
that the unit_number is from an active device. In addition, the application
should mask off or ignore the low nibble of entries in devlst and know that
one less than the number of devices in the list is stored at $BF31 (devcnt).
The application then should use the unit_number to get the proper device-
driver vector from the ProDOS global page; the application should not
construct the vector itself, because this vector would be invalid for a
mirrored device.
The following code fragment correctly illustrates this technique. It is
written in 6502 assembly language and assumes the unit_number is in the
accumulator.
devcnt equ $BF31
devlst equ $BF32
devadr equ $BF10
devget sta unitno ; store for later compare instruction
ldx devcnt ; get count-1 from $BF31
devloop lda devlst,x ; get entry in list
and #$F0 ; mask off low byte
devcomp cmp unitno ; compare to the unit_number we filled in
beq goodnum ;
dex
bpl devloop ; loop again if still less than $80
bmi badunitno ; error: bad unit number
goodnum lda unitno ; get good copy of unit_number
lsr a ; divide it by 8
lsr a ; (not sixteen because devadr entries are
lsr a ; two bytes wide)
tax
lda devadr,x ; low byte of device driver address
sta addr
lda devadr+1,x ; high byte of device driver address
sta addr+1
rts
addr dw 0 ; address will be filled in here by goodnum
unitno dfb 0 ; unit number storage
Similarly, applications which construct firmware entry points from user input
to "slot and drive" questions will not work with mirrored devices. If an
application wishes to issue firmware-specific calls to a device, it should
look at the high byte of the device-driver table entry for that device to
obtain the proper place to check firmware ID bytes. In the sample code above,
the high byte would be returned in addr+1. For devices mirrored to slot 2
from slot 5, this technique will return $C5, and ID bytes would then be
checked (since they should always be checked before making device-specific
calls) in the $C500 space. Applications ignoring this technique will
incorrectly check the $C200 space.
Further Reference
o ProDOS 8 Technical Reference Manual
o ProDOS 8 Technical Note #21, Identifying ProDOS Devices
Apple II
Technical Notes
_____________________________________________________________________________
Developer Technical Support
ProDOS 8
#21: Identifying ProDOS Devices
Written by: Matt Deatherage & Dan Strnad November 1988
This Technical Note describes how to identify ProDOS devices and their
characteristics given the ProDOS unit number.
_____________________________________________________________________________
There are various reasons why an application would want to identify ProDOS
devices. Although ProDOS itself takes great pains to treat all devices
equally, it has internal drivers for two types of devices--Disk II drives and
the /RAM drive provided on 128K or greater machines. Because all devices
really are not equal (i.e., some cannot format while others are read-only,
etc.),.an developer may need to know how to identify a ProDOS device.
Although the question of how much identification is subjective for each
developer, ProDOS 8 offers a fair level of identification; the only devices
which cannot be conclusively identified are those devices with RAM-based
drivers, and they could be anything. The vast majority of ProDOS devices can
be identified,however, so you could prompt the user to insert a disk in
UniDisk 3.5 #2, instead of Slot 2, Drive 2, which could be confusing if the
user has a IIc or IIGS.
Note that for the majority of applications, this level of identification is
unnecessary. Most applications simply prompt the user to insert a disk by its
name, and the user can place it in any drive which is capable of working with
the media of the disk. You should avoid requiring a certain disk to be in a
specific drive since doing so defeats much of the device-independence which
gives ProDOS 8 its strength.
When you do need to identify a device (i.e., if you need to format media in a
Disk II or /RAM device), however, the process is fairly straightforward. This
process consists of a series of tests, any one of which could end with a
conclusive device identification. It is not possible to look at a single ID
byte to determine a particular device type. You may determine rather quickly
that a device is a SmartPort device, or you may go all the way through the
procedure to identify a third-party network device. For those developers who
absolutely must identify devices, we present the following discussion.
Isn't There Some Kind of "ID Nibble?"
ProDOS 8 does not support an "ID nibble." Section 5.2.4 of the ProDOS 8
Technical Reference Manual states that the low nibble of each unit number in
the device list "is a device identification: 0 = Disk II, 4 = Profile, $F =
/RAM."
When ProDOS 8 finds a "smart" ProDOS block device while doing its search of
the slots and ports, it copies the high nibble of $CnFE (where n is the slot
number) into the low nibble of the unit number in the global page. The low
nibble then has the following definition:
Bit 3: Medium is removable
Bit 2: Device is interruptible
Bit 1-0: Number of volumes on the device (minus one)
As you can see, it is quite easy for the second definition to produce one of
the original values (e.g., 0, 4, or $F) in the same nibble for completely
different reasons. You should ignore the low nibble in the unit number in the
global page when identifying devices since the first definition is
insufficient to uniquely identify devices and the second definition contains
no information to specifically identify devices. Once you do identify a
ProDOS block device, however, you may look at $CnFE to obtain the information
in the second definition above, as well as information on reading, writing,
formatting, and status availability.
When identifying ProDOS devices, we start with a list of unit numbers for all
currently installed disk devices. As we progress through the identification
process, we will identify some devices while we will not know about others
until the end of the process.
Starting with the Unit Number
ProDOS unit numbers (unit_number) are bytes where the bits are arranged in the
pattern DSSS0000, where D = 0 for drive one and D = 1 for drive two, SSS is a
three-bit integer with values from one through seven indicating the device
slot number (zero is not a valid slot number), and the low nibble is ignored.
To obtain a list of the unit numbers for all currently installed ProDOS disk
devices, you can perform a ProDOS MLI ON_LINE call with a unit number of $00.
This call returns a unit number and a volume name for every device in the
device list. ProDOS stores the length of the volume name in the low nibble of
the unit number which ON_LINE returns; if an error occurs, the low nibble will
contain $0 and the byte immediately following the unit"number will contain an
error code. For more information on the ON_LINE call, see section 4.4.6 of
the ProDOS 8 Technical Reference Manual. We will discuss the error codes in
more"dgtail later in this Note.
To kdentify the devkces in the device"list, we need to know in which physical
slot the hardware resides, so we can look at the slot I/O ROM space and check
the device's identification bytes. Note that the slot-number portion of the
unit number does not always represent the physical slot of the device, rather,
it sometimes represents the logical slot where you can find the address of the
device's driver entry point in the ProDOS global page. For example, if a
SmartPort device interface in slot 5 has more than two connected devices, the
third and fourth devices will be mapped to slot 2; this mapping gives these
two devices unit numbers of $20 and $A0 respectively, but the device's driver
entry point will still be in the $C5xx address space.
ProDOS 8 Technical Note #20, Mirrored Devices and SmartPort, discusses this
kind of mapping in detail. It also presents a code example which gives you
the correct device-driver entry point (from the global page) given the unit
number as input. We repeat this code example below for your benefit. It
assumes the unit_number is in the accumulator.
devcnt equ $BF31
devlst equ $BF32
devadr equ $BF10
devget sta unitno ; store for later compare instruction
ldx devcnt ; get count-1 from $BF31
devloop lda devlst,x ; get entry in list
and #$F0 ; mask off low byte
devcomp cmp unitno ; compare to the unit_number we filled in
beq goodnum ;
dex
bpl devloop ; loop again if still less than $80
bmi badunitno ; error: bad unit number
goodnum lda unitno ; get good copy of unit_number
lsr a ; divide it by 8
lsr a ; (not sixteen because devadr entries are
lsr a ; two bytes wide)
tax
lda devadr,x ; low byte of device driver address
sta addr
lda devadr+1,x ; high byte of device driver address
sta addr+1
rts
addr dw 0 ; aldress will be(filled in
( ; here by goodnum
unitno dfb 0 (;(unit number storage
Warning:( Attempting to construct the device-driver entry point from
|hm unit(n}mber is(very langerou{.( Always use the technique
presented above.
Network Volumes
AppleTalk volumes present a special problem to some developers since they
appear as "phantom devices," or devices which do not always have a device
driver installed in the ProDOS global page. Fortunately, the ProDOS Filing
Interface (PFI) to AppleTalk provides us with a way to identify network
volumes through an MLI call. The ProDOS Filing Interface call FIListSessions
is used to retrieve a list of the current sessions being maintained through
PFI and any volumes mounted for those sessions. The following presents an
example:
Network JSR $BF00 ;ProDOS MLI
DFB $42 ;AppleTalk command number
DW ParamAddr ;Address of Parameter Table
BCS ERROR ;error occurred
ParamAddr DFB $00 ;Async Flag (0 means synchronous only)
;note there is no parameter count
DFB $2F ;command for FIListSessions
DW $0000 ;AppleTalk Result Code returned here
DW BufLength ;length of the buffer supplied
DW BufPointer ;low word of pointer to buffer
DW $0000 ;high word of pointer to buffer
;(THIS WILL NOT BE ZERO IF THE BUFFER IS
;NOT IN BANK ZERO!!!)
DFB $00 ;Number of entries returned here
If the FIListSessions call fails with a bad command error ($01), then
AppleShare is not installed; therefore, there are no networks volumes mounted.
If there is a network error, the accumulator will contain $88 (Network Error),
and the result code in the parameter block will contain the specific error
code. The list of current sessions is placed into the buffer (at the address
BufPointer in the example above), but if the buffer is not large enough to
hold the list, it will retain the maximum number of current sessions possible
and return an error with a result code of $0A0B (Buffer Too Small). The
buffer format is as follows:
SesnRef DFB $00 ;Sessions Reference number (result)
UnitNum DFB $00 ;Unit Number (result)
VolName DS 28 ;28 byte space for Volume Name
;(starts with a length byte)
VolumeID DW $0000 ;Volume ID (result)
This list is repeated for every volume mounted for each session (the number is
placed into the last byte of the parameter list you passed to the ProDOS MLI).
For example, if there are two volumes mounted for session one, then session
one will be listed two times. The UnitNum field contains the slot and drive
number in unit-number format, and note that bit zero of this byte is set if
the volume is a user volume (i.e., it contains a special "users" folder).
This distinction is unimportant for identifying a ProDOS device as a network
pseudo-device, but it is necessary for applications which need to know the
location of the user volume. Note that if you mount two servers or more with
each having its own user volume, the user volume found first in the list
(scanned top to bottom) returned by FIListSessions specifies the user volume
that an application should use. See the AppleShare Programmer's Guide for the
Apple IIGS (available from the Apple Programmer's and Developer's Association
(APDA)) for more information on programming for network volumes.
If you keep a list of all unit numbers returned by the ON_LINE call and mark
each one "identified" as you identify it, keep in mind that the unit numbers
returned by FIListSessions and ON_LINE have different low nibbles which should
be masked off before you make any comparisons.
Note: You should mark the network volumes as identified and not
try to identify them further with the following methods.
What Slot is it Really In?
Once you have the address of the device driver's entry point and know that the
device is not a network pseudo-device, you can determine in what physical slot
the device resides. If the high byte of the device driver's entry point is of
the form $Cn, then n is the slot number of the device. A SmartPort device
mirrored to slot 2 will have a device driver address of $C5xx, giving 5 as the
physical slot number.
If the high byte of the device driver entry point is not of the form $Cn, then
there are three other possibilities:
o The device is a Disk II with driver code inside ProDOS.
o The device is either /RAM with driver code inside ProDOS or a third-party
auxiliary-slot RAM disk device with driver code installed somewhere in
memory.
o The device is not a RAM disk but has a RAM-based device driver, like a
third-party network device.
Auxiliary-slot RAM disks are identified by convention. Any device in slot 3,
drive 2 (unit number $B0) is assumed to be an auxiliary-slot RAM disk since
ProDOS 8 will not recognize any card which is not an 80-column card in slot 3
(see ProDOS 8 Technical Note #15). There is a chance that some other kind of
device could be installed with unit number $B0, but it is not likely.
To identify various kinds of auxiliary-slot RAM disks, you must obtain the
unit number from the ProDOS global page. The list of unit numbers starts at
$BF32 (DEVLST) and is preceded by the number of unit numbers minus one
(DEVCNT, at $BF31). You should search through this list until you find a unit
number in the form $Bx; if the unit number is $B3, $B7, $BB, or $BF, you can
assume the device to be an auxiliary-slot RAM disk which uses the auxiliary
64K bank of memory present in a 128K Apple IIe or IIc, or a IIGS. If the unit
number is one of the four listed above, you must remove this device to safely
access memory in the auxiliary 64K bank, but if the unit number is not one of
the four listed above, you can assume the device to be an auxiliary-slot RAM
disk which does not use the normal bank of auxiliary memory. (Some third-
party auxiliary-slot cards contain more than one 64K auxiliary bank; the
normal use of this memory is as a RAM disk. If the RAM-based driver for this
kind of card does not use the normal auxiliary 64K bank for storage, it should
have a unit number other than one of the four listed above.) If the unit
number is not one of the four listed above, you may safely access the
auxiliary bank of memory without first removing this device.
Section 5.2.2.3 of the ProDOS 8 Technical Reference Manual contains a routine
which disconnects the appropriate RAM disk devices in slot 3, drive 2, without
removing those drivers which do not use that bank, to allow use of the
auxiliary 64K bank.
Note: Previous information from Apple indicated that /RAM could be
distinguished from third-party RAM disks by a driver address of
$FF00. Although the address has not changed, some third-party
drivers may have addresses of $FF00 as well, although this is
not supported. /RAM always has a driver address of $FF00 and
unit number $BF, although any third-party RAM disk could install
itself with similar attributes.
For Disk II devices, the three-bit slot number portion of the unit_number will
always be the physical slot number. Disk II devices can never be mirrored to
another slot (the Disk II driver does not support it); therefore, it will be
in the physical slot represented in the unit number which ProDOS assigns when
it boots.
If the high byte of the device driver's entry point is not of the form $Cn,
then you should assume that the slot number is the value SSS in the unit
number (this is equivalent to assuming the device is a Disk II) for the next
step, which is checking the I/O space for identification bytes.
What to Do With the Slot Number
Once you have the slot number, you can look at the slot I/O ROM space to
determine the kind of device it is. As described in the ProDOS 8 Technical
Reference Manual, ProDOS looks for the following ID bytes in ROM to determine
if a ProDOS device is in a slot:
$Cn01 = $20
$Cn03 = $00
$Cn05 = $03
If you use the slot number, n, you obtained above, and the three values listed
above are not present, then the device has a RAM-based driver and cannot
further be identified.
If the three values previously discussed are present, then examination of
$CnFF will give more information. If $CnFF = $00, the device is a Disk II.
If $CnFF is any value other than $00 or $FF ($FF signifies a 13-sector Disk
II, which ProDOS does not support), the device is a ProDOS block device.
For ProDOS block devices, the byte at $CnFE contains several flags which
further identify the device; these flags are discussed in section 6.3.1 of the
ProDOS 8 Technical Reference Manual.
SmartPort Devices
Many of Apple's ProDOS block devices follow the SmartPort firmware interface.
Through SmartPort, you can further identify devices. Existing SmartPort
devices include SCSI hard disks, 3.5" disk drives and CD-ROM drives, with many
more possible device types.
If $Cn07 = $00, then the device is a SmartPort device, and you can then make a
SmartPort call to get more information about the device, including a device
type and subtype. The SmartPort entry point is three bytes beyond the ProDOS
block device entry point, which you already determined above. The method for
making SmartPort calls is outlined in the Apple IIc Technical Reference Manual
and the Apple IIGS Firmware Reference.
The most useful SmartPort call to make for device identification is the STATUS
call with statcode = 3 for Return Device Information Block (DIB). This call
returns the ASCII name of the device, a device type and subtype, as well as
the size of the device. Some SmartPort device types and subtypes are listed
in the above manuals, with a more complete list located in the Apple IIGS
Firmware Reference. A list containing SmartPort device types only is provided
in SmartPort Technical Note #4, SmartPort Device Types.
RAM-Based Drivers
One fork of the identification tree comes to an end at this point. If the
high byte of the device driver entry point was not $Cn and the device was not
/RAM, we assumed it was a Disk II and used the slot number portion of the unit
number to examine the slot ROM space. If the ROM space for that slot number
does not match the three ProDOS block device ID bytes, it cannot be a Disk II.
Having ruled out other possibilities, it must be a device installed after
ProDOS finished building its device table. Perhaps it is a third-party RAM
disk driver or maybe a driver for an older card which does not match the
ProDOS block device ID bytes.
Whatever the function of the driver, you can identify it no further. It quite
literally could be any kind of device at all, and with neither slot ROM space
to identify nor a standard location to compare the device driver entry point
against, the best you can do is consider it a "generic device" and go on.
But Is It Connected, and Can I Read From It?
Just because a ProDOS device is in the table does not mean it is ready to be
used. There is always the possibility that the drive has no media in it.
Back in the beginning, we made an ON_LINE call with a unit number of $00. If
the volume name of a disk in that device could not be read, or another error
occurred, ProDOS 8 would return the error code to us in the ON_LINE buffer
immediately following the unit number. Those errors possible include:
$27 I/O error
$28 No Device Connected
$2B Write Protected
$2F Device off-line
$45 Volume directory not found
$52 Not a ProDOS disk
$55 Volume Control Block full
$56 Bad buffer address
$57 Duplicate volume on-line
Note that error $2F is not listed in the ProDOS 8 Technical Reference Manual.
By convention, we interpret I/O error to mean the disk in the drive is either
damaged or blank (not formatted). We interpret Device off-line to mean that
there is no disk in the drive. We interpret No Device Connected to mean the
drive really does not exist (for example, asking for status on a second Disk
II when only one is connected).
If no error occurred for a unit number in the ON_LINE call (the low nibble of
the unit number is not zero), the volume name of the disk in the drive follows
the unit number.
Further Reference
o ProDOS 8 Technical Reference Manual
o AppleShare Programmer's Guide for the Apple IIGS
o ProDOS 8 Technical Note #15, How ProDOS 8 Treats Slot 3
o ProDOS 8 Technical Note #20, Mirrored Devices and SmartPort
The entire AOH site is optimized to look best in Firefox® 3 on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986- AOH
We do not send spam. If you have received spam bearing an artofhacking.com email address, please forward it with full headers to abuse@artofhacking.com.