mirror of
https://github.com/iKarith/beneath-apple-dos.git
synced 2024-12-28 00:30:49 +00:00
850 lines
28 KiB
Plaintext
850 lines
28 KiB
Plaintext
CHAPTER 6 - USING DOS FROM ASSEMBLY LANGUAGE
|
|
|
|
CAVEAT
|
|
|
|
This chapter is aimed at the advanced
|
|
assembly language programmer who
|
|
wishes to access the disk without
|
|
resorting to the PRINT statement
|
|
scheme used with BASIC.
|
|
Accordingly, the
|
|
topics covered here may be beyond the
|
|
comprehension (at least for the
|
|
present) of a programmer who has
|
|
never used assembly language.
|
|
|
|
DIRECT USE OF DISK DRIVE
|
|
|
|
It is often desirable or necessary to
|
|
access the Apple's disk drives
|
|
directly from assembly language,
|
|
without the use of DOS. This is
|
|
done using a section of 16 addresses
|
|
that are latched toggles, interfacing
|
|
directly to the hardware. There are
|
|
eight two byte toggles that essentially
|
|
represent pulling a TTL line high or
|
|
low. Applications which could use
|
|
direct disk access range from a
|
|
user written operating system to DOS-independent
|
|
utility programs. The
|
|
device address assignments are given
|
|
in Figure 6.1.
|
|
|
|
ADDRESS LABEL DESCRIPTION
|
|
---------------------------------------------------------------
|
|
$C080 PHASEOFF Stepper motor phase 0 off.
|
|
$C081 PHASEON Stepper motor phase 0 on.
|
|
$C082 PHASE1OFF Stepper motor phase 1 off.
|
|
$C083 PHASE1ON Stepper motor phase 1 on.
|
|
$C084 PHASE2OFF Stepper motor phase 2 off.
|
|
$C085 PHASE2ON Stepper motor phase 2 on.
|
|
$C086 PHASE3OFF Stepper motor phase 3 off.
|
|
$C087 PHASE3ON Stepper motor phase 3 on.
|
|
$C088 MOTOROFF Turn motor off.
|
|
$C089 MOTORON Turn motor on.
|
|
$C08A DRV0EN Engage drive 1.
|
|
$C08B DRV1EN Engage drive 2.
|
|
$C08C Q6L Strobe Data Latch for I/O.
|
|
$C08D Q6H Load Data Latch.
|
|
$C08E Q7L Prepare latch for input.
|
|
$C08F Q7H Prepare latch for output.
|
|
|
|
Q7L followed by Q6L = Read
|
|
Q7L followed by Q6H = Sense Write Protect
|
|
Q7H followed by Q6L = Write
|
|
Q7H followed by Q6H = Load Write Latch
|
|
|
|
*** figure 6.1 ***
|
|
|
|
The addresses are slot dependent and
|
|
the offsets are computed by
|
|
multiplying the slot number by 16.
|
|
In hexadecimal this works out nicely
|
|
and we can add the value $s0 (where s
|
|
is the slot number) to the base
|
|
address. If we wanted to engage disk
|
|
drive number 1 in slot number 6, for
|
|
example, we would add $60 to $C08A
|
|
(device address assignment for
|
|
engaging drive 1) for a result of
|
|
$C0EA. However, since it is
|
|
generally desirable to write code
|
|
that is not slot dependent, one would
|
|
normally use $C08A,X (where the
|
|
X register contains the value $s0).
|
|
|
|
In general, the above addresses need
|
|
only be accessed with any valid 6502
|
|
instruction. However, in the case of
|
|
reading and writing bytes, care must
|
|
be taken to insure that the data will
|
|
be in an appropriate register. All
|
|
of the following would engage drive
|
|
number 1. (Assume slot number 6)
|
|
|
|
LDA $C0EA
|
|
BIT $C08A,X (where X-reg contains $60)
|
|
CMP $C08A,X (where X-reg contains $60)
|
|
|
|
Below are typical examples
|
|
demonstrating the use of the device
|
|
address assignments. For more
|
|
examples, see APPENDIX A. Slot 6 is
|
|
assumed and the X-register contains
|
|
$60.
|
|
|
|
STEPPER PHASE OFF/ON:
|
|
|
|
Basically, each of the four phases
|
|
(0-3) must be turned on and then off
|
|
again. Done in ascending order, this
|
|
moves the arm inward. In descending
|
|
order, this moves the arm outward.
|
|
The timing between accesses to these
|
|
locations is critical, making this a
|
|
non-trivial exercise. It is
|
|
recommended that the SEEK command in
|
|
RWTS be used to move the arm. See
|
|
the section on using RWTS immediately
|
|
following.
|
|
|
|
MOTOR OFF/ON:
|
|
|
|
LDA $C088,X Turn motor off.
|
|
|
|
LDA $C089,X Turn motor on.
|
|
|
|
NOTE: A sufficient delay should be
|
|
provided to allow the motor time to
|
|
come up to speed. Shugart recommends
|
|
one second, but DOS is able to reduce
|
|
this delay by watching the read latch
|
|
until data starts to change.
|
|
|
|
ENGAGE DRIVE 1/2:
|
|
|
|
LDA $C08A,X Engage drive 1.
|
|
|
|
LDA $C08B,X Engage drive 2.
|
|
|
|
READ A BYTE:
|
|
|
|
READ LDA $C08C,X
|
|
BPL READ
|
|
|
|
NOTE: $C08E,X must already have been
|
|
accessed to assure Read mode. The
|
|
loop is necessary to assure that the
|
|
accumulator will contain valid data.
|
|
If the data latch does not yet
|
|
contain valid data the high bit will
|
|
be zero.
|
|
|
|
SENSE WRITE PROTECT:
|
|
|
|
LDA $C08D,X
|
|
LDA $C08E,X Sense write protect.
|
|
BMI ERROR If high bit set, protected.
|
|
|
|
WRITE LOAD AND WRITE A BYTE
|
|
|
|
LDA DATA
|
|
STA $C08D,X Write load.
|
|
ORA $C08C,X Write byte.
|
|
|
|
NOTE: $C08F,X must already have been
|
|
accessed to insure Write mode and a
|
|
100 microsecond delay should be
|
|
invoked before writing.
|
|
|
|
Due to hardware constraints, data
|
|
bytes must be written in 32 cycle
|
|
loops. Below is an example for an
|
|
immediate load of the accumulator,
|
|
followed by a write. Timing is so
|
|
critical that different routines may
|
|
be necessary, depending on how the
|
|
data is to be accessed, and code can
|
|
not cross memory page boundaries
|
|
without an adjustment.
|
|
|
|
LDA #$D5 (3 cycles)
|
|
JSR WRITE9 (6)
|
|
LDA #$AA (3)
|
|
JSR WRITE9 (6)
|
|
.
|
|
.
|
|
.
|
|
WRITE9 CLC (2)
|
|
WRITE7 PHA (3)
|
|
PLA (4)
|
|
WRITE STA $C08D,X (5)
|
|
ORA $C08C,X (4)
|
|
RTS (6)
|
|
|
|
CALLING READ/WRITE TRACK/SECTOR (RWTS)
|
|
|
|
Read/Write Track/Sector (RWTS) exists
|
|
in every version of DOS as a
|
|
collection of subroutines, occupying
|
|
roughly the top third of the DOS
|
|
program. The interface to RWTS is
|
|
standardized and thoroughly documented by Apple
|
|
and may be called by a
|
|
program running outside of DOS.
|
|
|
|
There are two subroutines which must
|
|
be called or whose function must be
|
|
performed.
|
|
|
|
JSR $3E3 - When this subroutine is
|
|
called, the Y and A registers are
|
|
loaded with the address of the
|
|
Input/Output control Block (IOB) used
|
|
by DOS when accessing RWTS. The low
|
|
order part of the address is in Y and
|
|
the high order part in A. This
|
|
subroutine should be called to locate
|
|
the IOB and the results may be stored
|
|
in two zero page locations to allow
|
|
storing values in the IOB and
|
|
retrieving output values after a call
|
|
to RWTS. Of course, you may set up
|
|
your own IOB as long as the Y and A
|
|
registers point to your IOB upon
|
|
calling RWTS.
|
|
|
|
JSR $3D9 - This is the main entry to
|
|
the RWTS routine. Prior to making
|
|
this call, the Y and A registers must
|
|
be loaded with the address of an IOB
|
|
describing the operation to be
|
|
performed. This may be done by first
|
|
calling $3E3 as described above. The
|
|
IOB must contain appropriate
|
|
information as defined in the list
|
|
on the facing page (offsets are given in hexadecimal):
|
|
|
|
INPUT/OUTPUT CONTROL BLOCK - GENERAL FORMAT
|
|
|
|
BYTE DESCRIPTION
|
|
00 Table type, must be $01
|
|
01 Slot number times 16 (s0: s=slot. Example: $60)
|
|
02 Drive number ($01 or $02)
|
|
03 Volume number expected ($00 matches any volume)
|
|
04 Track number ($00 through $22)
|
|
05 Sector number ($00 through $0F)
|
|
06-07 Address (LO/HI) of the Device Characteristics Table
|
|
08-09 Address (LO/HI) of the 256 byte buffer for
|
|
READ/WRITE
|
|
0A Not used
|
|
0B Byte count for partial sector ($00 for 256 bytes)
|
|
0C Command code $00 = SEEK
|
|
$01 = READ
|
|
$02 = WRITE
|
|
$04 = FORMAT
|
|
0D Return code - The processor CARRY flag is set upon
|
|
return from RWTS if there is a
|
|
non-zero return code:
|
|
$00 = No errors
|
|
$08 = Error during initialization
|
|
$10 = Write protect error
|
|
$20 = Volume mismatch error
|
|
$40 = Drive error
|
|
$80 = Read error (obsolete)
|
|
0E Volume number of last access (must be initialized)
|
|
0F Slot number of last access*16 (must be initialized)
|
|
10 Drive number of last access (must be initialized)
|
|
|
|
DEVICE CHARACTERISTICS TABLE
|
|
|
|
BYTE DESCRIPTION
|
|
00 Device type (should be $00 for DISK II)
|
|
01 Phases per track (should be $01 for DISK II)
|
|
02-03 Motor on time count (should be $EFD8 for DISK II)
|
|
|
|
RWTS IOB BY CALL TYPE
|
|
|
|
SEEK Move disk arm to desired track
|
|
|
|
Input: Byte 00 - Table type ($01)
|
|
01 - Slot number * 16 (s0: s=slot)
|
|
02 - Drive number ($01 or $02)
|
|
04 - Track number ($00 through $22)
|
|
06/07 - Pointer to the DCT
|
|
0C - Command code for SEEK ($00)
|
|
0F - Slot number of last access * 16
|
|
10 - Drive number of last access
|
|
|
|
Output: Byte 0D - Return code (See previous definition)
|
|
0F - Current Slot number * 16
|
|
10 - Current Drive number
|
|
|
|
READ Read a sector into a specified buffer
|
|
|
|
Input: Byte 00 - Table type ($01)
|
|
01 - Slot number * 16 (s0: s=slot)
|
|
02 - Drive number ($01 or $02)
|
|
03 - Volume number ($00 matches any volume)
|
|
04 - Track number ($00 through $22)
|
|
05 - Sector number ($00 through $0F)
|
|
06/07 - Pointer to the DCT
|
|
08/09 - Pointer to 256 byte user data buffer
|
|
0B - Byte count per sector ($00)
|
|
0C - Command code for READ ($01)
|
|
0E - Volume number of last access
|
|
0F - Slot number of last access * 16
|
|
10 - Drive number of last access
|
|
|
|
Output: Byte 0D - Return code (See previous definition)
|
|
0E - Current Volume number
|
|
0F - Current Slot number * 16
|
|
10 - Current Drive number
|
|
|
|
WRITE Write a sector from a specified buffer
|
|
|
|
Input: Byte 00 - Table type ($01)
|
|
01 - Slot number * 16 (s0: s=slot)
|
|
02 - Drive number ($01 or $02)
|
|
03 - Volume number ($00 matches any volume)
|
|
04 - Track number ($00 through $22)
|
|
05 - Sector number ($00 through $0F)
|
|
06/07 - Pointer to the DCT
|
|
08/09 - Pointer to 256 byte user data buffer
|
|
0B - Byte count per sector ($00)
|
|
0C - Command code for WRITE ($02)
|
|
0E - Volume number of last access
|
|
0F - Slot number of last access * 16
|
|
10 - Drive number of last access
|
|
|
|
Output: Byte 0D - Return code (See previous definition)
|
|
0E - Current Volume number
|
|
0F - Current Slot number * 16
|
|
10 - Current Drive number
|
|
|
|
FORMAT Initialize the diskette (does not put DOS on disk,
|
|
create a VTOC/CATALOG, or store HELLO program)
|
|
|
|
Input: Byte 00 - Table type ($01)
|
|
01 - Slot number * 16 (s0: s=slot)
|
|
02 - Drive number ($01 or $02)
|
|
03 - Volume number ($00 will default to 254)
|
|
06/07 - Pointer to the DCT
|
|
0C - Command code for FORMAT ($04)
|
|
0E - Volume number of last access
|
|
0F - Slot number of last access * 16
|
|
10 - Drive number of last access
|
|
|
|
Output: Byte 0D - Return code (See previous definition)
|
|
0E - Current Volume number
|
|
0F - Current Slot number * 16
|
|
10 - Current Drive number
|
|
|
|
CALLING THE DOS FILE MANAGER
|
|
|
|
The DOS file manager exists in every
|
|
version of DOS as a collection of
|
|
subroutines occupying approximately
|
|
the central third of the DOS program.
|
|
The interface to these routines is
|
|
generalized in such a way that they
|
|
may be called by a program running
|
|
outside of DOS. The definition of
|
|
this interface has
|
|
never been published by APPLE (or
|
|
anyone else, for that manner) but
|
|
since the calls can be made through
|
|
fixed vectors, and, the format of the
|
|
parameter lists passed have not
|
|
changed in all the versions of DOS,
|
|
these routines may be relied upon as
|
|
"safe". Indeed, the new FID utility
|
|
program
|
|
uses these routines to process files
|
|
on the diskette.
|
|
|
|
There are
|
|
two subroutines which must be called
|
|
in order to access the file manager.
|
|
|
|
JSR $3DC - When this subroutine is
|
|
called, the Y and A registers are
|
|
loaded with the address of the file
|
|
manager parameter list. The low order
|
|
part of the address is in Y and the
|
|
high order part in A. This subroutine
|
|
must be called at least once to
|
|
locate this parameter list and the
|
|
results may be stored in two zero page
|
|
locations to allow the programmer to
|
|
set input values in the parameter
|
|
list and to locate output values
|
|
there after file manager calls.
|
|
|
|
JSR $3D6 - This is the main entry to
|
|
the file manager. Prior to making
|
|
this call the parameter list, located
|
|
using the call described
|
|
above, must be completed
|
|
appropriately, depending upon the
|
|
type of call, and the X register must
|
|
be set to either zero or non-zero as
|
|
follows:
|
|
|
|
X = 0 - If file is not found, allocate it
|
|
X # 0 - If file is not found, do not allocate one
|
|
|
|
Normally,
|
|
X should be zero on an OPEN call for a
|
|
new file and non-zero for all other
|
|
call types.
|
|
|
|
Three buffers must be provided to the
|
|
file manager by the programmer,
|
|
allocated by him in his memory. These
|
|
buffers, together, occupy 557 bytes
|
|
of RAM, and must be passed to the
|
|
file manager each time their
|
|
associated file is used. A separate
|
|
set of these buffers must be
|
|
maintained for each open file.
|
|
DOS maintains buffers for this
|
|
purpose, as described in earlier
|
|
chapters, in high RAM. These buffers
|
|
may be "borrowed" from DOS if care is
|
|
taken to let DOS know about it. A
|
|
method for doing this will be
|
|
outlined later.
|
|
|
|
A chart giving the required inputs
|
|
for each call type to the file
|
|
manager is given in Figure 6.2.
|
|
The general format of the file
|
|
manager parameter list is as follows:
|
|
|
|
FILE MANAGER PARAMETER LIST - GENERAL FORMAT
|
|
|
|
BYTE DESCRIPTION
|
|
00 Call type: 01=OPEN 05=DELETE 09=RENAME
|
|
02=CLOSE 06=CATALOG 0A=POSITION
|
|
03=READ 07=LOCK 0B=INIT
|
|
04=WRITE 08=UNLOCK 0C=VERIFY
|
|
01 Sub-call type for READ or WRITE:
|
|
00=No operation (ignore call entirely)
|
|
01=READ or WRITE one byte
|
|
02=READ or WRITE a range of bytes
|
|
03=POSITION then READ or WRITE one byte
|
|
04=POSITION then READ/WRITE a range
|
|
02-09 Parameters specific to the call type used. See
|
|
FILE MANAGER PARAMETER LIST BY CALL TYPE below.
|
|
0A Return code (note: not all return codes can occur
|
|
for any call type). The processor CARRY
|
|
flag is set upon return from the file
|
|
manager if there is a non-zero return code:
|
|
00=No errors
|
|
01=Not used ("LANGUAGE NOT AVAILABLE")
|
|
02=Bad call type
|
|
03=Bad sub-call type (greater than four)
|
|
04=WRITE PROTECTED
|
|
05=END OF DATA
|
|
06=FILE NOT FOUND (was allocated if X=0)
|
|
07=VOLUME MISMATCH
|
|
08=DISK I/O ERROR
|
|
09=DISK FULL
|
|
0A=FILE LOCKED
|
|
0B Not used
|
|
0C-0D Address of a 45 byte buffer which will be used by the
|
|
file manager to save its status between calls. This
|
|
area is called the file manager workarea and need not
|
|
be initialized by the caller but the space must be
|
|
provided and this two byte address field initialized.
|
|
(addresses are in low/high order format)
|
|
0E-0F Address of a 256 byte buffer which will be used by the
|
|
file manager to maintain the current Track/Sector List
|
|
sector for the open file. Buffer itself need not be
|
|
initialized by the caller.
|
|
10-11 Address of a 256 byte buffer which will be used by the
|
|
file manager to maintain the data sector buffer.
|
|
Buffer need not be initialized by the caller.
|
|
|
|
*** INSERT FIGURE 6.2 ***
|
|
|
|
FILE MANAGER PARAMETER LIST BY CALL TYPE
|
|
|
|
OPEN Locates or creates a file. A call to POSITION should
|
|
follow every OPEN.
|
|
|
|
Input: Byte 00 - 01
|
|
02/03 - Fixed record length or 0000 if variable
|
|
04 - Volume number or 00 for any volume
|
|
05 - Drive number to be used (01 or 02)
|
|
06 - Slot number to be used (01-07)
|
|
07 - File type (used only for new files)
|
|
$00 = TEXT
|
|
$01 = INTEGER BASIC
|
|
$02 = APPLESOFT BASIC
|
|
$04 = BINARY
|
|
$08 = RELOCATABLE
|
|
$10 = S TYPE FILE
|
|
$20 = A TYPE FILE
|
|
$40 = B TYPE FILE
|
|
08/09 - Address of file name (30 characters)
|
|
(Low/high format)
|
|
0C/0D - Address of file manager workarea buffer
|
|
0E/0F - Address of T/S List sector buffer
|
|
10/11 - Address of data sector buffer
|
|
|
|
Output: Byte 07 - File type of file which was OPENed
|
|
0A - Return code (see previous definitions)
|
|
|
|
CLOSE Write out final sectors, update the Catalog.
|
|
A CLOSE call is required eventually for every OPEN.
|
|
|
|
Input: Byte 00 - 02
|
|
0C/0D - Address of file manager workarea buffer
|
|
0E/0F - Address of T/S List sector buffer
|
|
10/11 - Address of data sector buffer
|
|
|
|
Output: Byte 0A - Return code
|
|
|
|
READ Read one or a range of bytes from the file to memory.
|
|
WRITE Write one or a range of bytes from memory to the file.
|
|
|
|
Input: Byte 00 - 03 (READ) 04 (WRITE)
|
|
01 - Subcode:
|
|
00 = No operation
|
|
01 = READ or WRITE one byte only
|
|
02 = READ or WRITE a range of bytes
|
|
03 = POSITION then READ/WRITE one byte
|
|
04 = POSITION then READ/WRITE range
|
|
02/03 - (Subcodes 03 or 04) Record number
|
|
04/05 - (Subcodes 03 or 04) Byte offset
|
|
06/07 - (Subcodes 02 or 04) Number of bytes in
|
|
range to be read or written. (Note: for
|
|
WRITE, this length must be one less
|
|
than the actual length to be written)
|
|
08/09 - (Subcodes 02 or 04) Address of range of
|
|
bytes to be written or address of
|
|
buffer to which bytes are to be read.
|
|
08 - (WRITE, Subcodes 01 or 03) Single byte
|
|
to be written.
|
|
0C/0D - Address of file manager workarea buffer
|
|
0E/0F - Address of T/S List sector buffer
|
|
10/11 - Address of data sector buffer
|
|
|
|
Output: Byte 02/03 - Record number of current file position
|
|
04/05 - Byte offset of current position in file
|
|
08 - (READ, Subcodes 01 or 03) Byte read
|
|
0A - Return code
|
|
|
|
DELETE Locate and delete a file, freeing its sectors.
|
|
|
|
Input: Byte 00 - 05
|
|
(remainder are the same as with OPEN call type)
|
|
|
|
Output: Byte 0A - Return code
|
|
|
|
CATALOG Produce a catalog listing on the output device.
|
|
|
|
Input: Byte 00 - 06
|
|
05 - Drive
|
|
06 - Slot
|
|
0C/0D - Address of file manager workarea buffer
|
|
0E/0F - Address of T/S List sector buffer
|
|
10/11 - Address of data sector buffer
|
|
|
|
Output: Byte 0A - Return code
|
|
|
|
LOCK Lock a file.
|
|
|
|
Input: Byte 00 - 07
|
|
(remainder are the same as with OPEN call type)
|
|
|
|
Output: Byte 0A - Return code
|
|
|
|
UNLOCK Unlock a file.
|
|
|
|
Input: Byte 00 - 08
|
|
(remainder are the same as with OPEN call type)
|
|
|
|
Output: Byte 0A - Return code
|
|
|
|
RENAME Rename a file.
|
|
|
|
Input: Byte 00 - 09
|
|
02/03 - Address of new file name (30 bytes)
|
|
(remainder are the same as with OPEN call type)
|
|
|
|
Output: Byte 0A - Return code
|
|
|
|
POSITION Calculate the location of a record and/or byte
|
|
offset in the file. Position such that next READ or
|
|
WRITE will be at that location in the file. A call
|
|
to POSITION (either explicitly or implictly using
|
|
subcodes of READ or WRITE) is required prior to the
|
|
first READ or WRITE. Bytes 02 through 05 should be
|
|
set to zeros for a normal position to the beginning
|
|
of the file.
|
|
|
|
Input: Byte 00 - 0A
|
|
02/03 - Relative record number for files with a
|
|
fixed length record size or zero. First
|
|
record of file is record 0000.
|
|
04/05 - Relative byte offset into record or of
|
|
entire file if record number is zero.
|
|
0C/0D - Address of file manager workarea buffer.
|
|
0E/0F - Address of T/S List sector buffer.
|
|
10/11 - Address of data sector buffer.
|
|
|
|
Output: Byte 0A - Return code
|
|
|
|
INIT Initialize a slave diskette. This function formats a
|
|
diskette and writes a copy of DOS onto tracks 0-2.
|
|
A VTOC and Catalog are also created. A HELLO program
|
|
is not stored, however.
|
|
|
|
Input: Byte 00 - 0B
|
|
01 - First page of DOS image to be copied to
|
|
the diskette. Normally $9D for a 48K
|
|
machine.
|
|
04 - Volume number of new diskette.
|
|
05 - Drive number (01 or 02)
|
|
06 - Slot number (01-07)
|
|
0C/0D - Address of file manager workarea buffer.
|
|
0E/0F - Address of T/S List sector buffer.
|
|
10/11 - Address of data sector buffer.
|
|
|
|
Output: Byte 0A - Return code
|
|
|
|
VERIFY Verify that there are no bad sectors in a file by
|
|
reading every sector.
|
|
|
|
Input: Byte 00 - 0C
|
|
(remainder are the same as the OPEN call type)
|
|
|
|
Output: Byte 0A - Return code
|
|
|
|
DOS BUFFERS
|
|
|
|
Usually it is desirable to use one of DOS's buffers when
|
|
calling the file manager to save memory. DOS buffers consist of
|
|
each of the three buffers used by the file manager (file
|
|
manager workarea, T/S List sector, and data sector) as well as
|
|
a 30 byte file name buffer and some link pointers. All together
|
|
a DOS buffer occupies 595 bytes of memory. The address of the
|
|
first DOS buffer is stored in the first two bytes of DOS ($9D00
|
|
on a 48K APPLE II). The address of the next buffer is stored in
|
|
the first and so on in a chain of linked elements. The link
|
|
address to the next buffer in the last buffer is zeros. If the
|
|
buffer is not being used by DOS, the first byte of the file
|
|
name field is a hex 00. Otherwise, it contains the first
|
|
character of the name of the open file. The assembly language
|
|
programmer should follow these conventions to avoid having DOS
|
|
reuse the buffer while he is using it. This means that the
|
|
name of the file should be stored in the buffer to reserve it
|
|
for exclusive use (or at least a non-zero byte stored on the
|
|
first character) and later, when the user is through with the
|
|
buffer, a 00 should be stored on the file name to return it
|
|
to DOS's use. If the later is not done, DOS will eventually
|
|
run out of available buffers and will refuse even to do a
|
|
CATALOG command. A diagram of the DOS
|
|
buffers for MAXFILES 3 is given in
|
|
Figure 6.3 and
|
|
the format of a DOS buffer is given below.
|
|
|
|
*** INSERT FIGURE 6.3 ***
|
|
|
|
DOS BUFFER FORMAT
|
|
|
|
BYTE DESCRIPTION
|
|
000/0FF Data sector buffer (256 bytes in length)
|
|
100/1FF T/S List sector buffer (256 bytes in length)
|
|
200/22C File manager workarea buffer (45 bytes in length)
|
|
22D/24A File name buffer (30 bytes in length)
|
|
First byte indicates whether this DOS buffer is
|
|
being used. If hex 00, buffer is free for use.
|
|
24B/24C Address (Lo/High) of file manager workarea buffer
|
|
24D/24E Address of T/S List sector buffer
|
|
24F/250 Address of data sector buffer
|
|
251/252 Address of the file name field of the next buffer on
|
|
the chain of buffers. If this is the last buffer on
|
|
the chain then this field contains zeros.
|
|
|
|
THE FILE MANAGER WORKAREA
|
|
|
|
The file manager workarea contains
|
|
the variables which, taken together,
|
|
constitute all of the information the
|
|
file manager needs to deal with an
|
|
open file. Each time the file manager
|
|
finishes processing a call, it copies
|
|
all of its important variables into
|
|
the file manager workarea buffer
|
|
provided by the caller. Each
|
|
subsequent time the file manager is
|
|
called, the first thing it does is to
|
|
copy the contents of the file manager
|
|
workarea buffer back into its
|
|
variables so that it may resume
|
|
processing for the file where it left
|
|
off on the previous call.
|
|
Ordinarily, the programmer will have
|
|
no need to worry about the contents
|
|
of this workarea, since most of the
|
|
useful information is present in the
|
|
parameter list anyway. Occasionally,
|
|
it is handy to know more about the
|
|
open file. For these cases, the
|
|
format of the file manager workarea
|
|
is given below:
|
|
|
|
FILE MANAGER WORKAREA FORMAT
|
|
|
|
BYTE DESCRIPTION
|
|
00/01 Track/Sector of first T/S List for file
|
|
02/03 Track/Sector of current T/S List for file
|
|
04 Flags:
|
|
80=T/S List buffer changed and needs writing
|
|
40=Data buffer has been changed and needs writing
|
|
02=Volume freespace map changed and needs writing
|
|
05/06 Track/Sector of current data sector
|
|
07 Sector offset into catalog to entry for this file
|
|
08 Byte offset into catalog sector to entry for file
|
|
09/0A Maximum data sectors represented by one T/S List
|
|
0B/0C Offset of first sector in current T/S List
|
|
0D/0E Offset of last sector in current T/S List
|
|
0F/10 Relative sector number last read
|
|
11/12 Sector size in bytes (256)
|
|
13/14 Current position in sectors (relative)
|
|
15 Current byte offset in this sector
|
|
16 Not used
|
|
17/18 Fixed record length
|
|
19/1A Current record number
|
|
1B/1C Byte offset into current record
|
|
1D/1E Length of file in sectors
|
|
1F Next sector to allocate on this track
|
|
20 Current track being allocated
|
|
21/24 Bit map of available sectors on this track (rotated)
|
|
25 File type (80=locked) 0,1,2,4=T,I,A,B
|
|
26 Slot number times 16 (example: $60=slot 6)
|
|
27 Drive number (01 or 02)
|
|
28 Volume number (complemented)
|
|
29 Track
|
|
2A/2C Not used
|
|
|
|
COMMON ALGORITHMS
|
|
|
|
Given below are several pieces of code
|
|
which are used when working with DOS:
|
|
|
|
LOCATE A FREE DOS BUFFER
|
|
|
|
The following subroutine may be used
|
|
to locate an unallocated DOS buffer
|
|
for use with the DOS file manager.
|
|
|
|
FBUFF LDA $3D2 LOCATE DOS LOAD POINT
|
|
STA $1
|
|
LDY #0
|
|
STY $0
|
|
*
|
|
GBUF0 LDA ($0),Y LOCATE NEXT DOS BUFFER
|
|
PHA
|
|
INY
|
|
LDA ($0),Y
|
|
STA $1
|
|
PLA
|
|
STA $0
|
|
BNE GBUF GOT ONE
|
|
LDA $1
|
|
BEQ NBUF NO BUFFERS FREE
|
|
*
|
|
GBUF LDY #0 GET FILENAME
|
|
LDA ($0),Y
|
|
BEQ GOTBUF ITS FREE
|
|
LDY #36 ITS NOT FREE
|
|
BNE GBUF0 GO GET NEXT BUFFER
|
|
*
|
|
GOTBUF CLC INDICATE-GOT A FREE BUFFER
|
|
RTS RETURN TO CALLER
|
|
NBUF SEC INDICATE-NO FREE BUFFERS
|
|
RTS RETURN TO CALLER
|
|
|
|
IS DOS IN THE MACHINE?
|
|
|
|
The following series of instructions
|
|
should be used prior to attempting to
|
|
call RWTS or the file manager to
|
|
insure that DOS is present on this
|
|
machine.
|
|
|
|
LDA $3D0 GET VECTOR JMP
|
|
CMP #$4C IS IT A JUMP?
|
|
BNE NODOS NO, DOS NOT LOADED
|
|
|
|
WHICH VERSION OF DOS IS ACTIVE?
|
|
|
|
In case the program has version dependent code, a check of
|
|
the DOS version may be required:
|
|
|
|
CLC
|
|
LDA #0 ADD $16BE TO DOS LOAD POINT
|
|
ADC #$BE
|
|
STA $0
|
|
LDA $3D2
|
|
ADC #$16
|
|
STA $1
|
|
LDY #0
|
|
LDA ($0),Y GET DOS VERSION NUMBER (2 OR 3)
|
|
|
|
WHICH BASIC IS SELECTED?
|
|
|
|
Some programs depend upon either the
|
|
INTEGER BASIC ROM or the APPLESOFT
|
|
ROM. To find out which is active and
|
|
select the one desired, the following
|
|
subroutine can be called. First the A
|
|
register is loaded with a code to
|
|
indicate which BASIC is desired. $20
|
|
is used for INTEGER BASIC and $4C is
|
|
used for APPLESOFT. To set up for
|
|
APPLESOFT, for example:
|
|
|
|
LDA #$4C CODE FOR APPLESOFT
|
|
JSR SETBSC CALL SUBROUTINE
|
|
BNE ERROR LANGUAGE NOT AVAILABLE
|
|
.
|
|
.
|
|
.
|
|
SETBSC CMP $E000 CORRECT BASIC ALREADY THERE?
|
|
BEQ RTS YES
|
|
STA $C080 NO, SELECT ROM CARD
|
|
CMP $E000 NOW DO WE HAVE IT?
|
|
BEQ RTS YES
|
|
STA $C081 NO, TRY ROM CARD OUT
|
|
CMP $EOOO GOT IT NOW?
|
|
RTS RTS IN ANY CASE, EXIT TO CALLER
|
|
|
|
SEE IF A BASIC PROGRAM IS IN EXECUTION
|
|
|
|
To determine if there is a BASIC program running or
|
|
if BASIC is in immediate command mode, use the following
|
|
statements:
|
|
|
|
..IF INTEGER BASIC IS ACTIVE...
|
|
LDA $D9
|
|
BMI EXEC PROGRAM EXECUTING
|
|
BPL NOEXEC PROGRAM NOT EXECUTING
|
|
|
|
..IF APPLESOFT BASIC IS ACTIVE...
|
|
LDX $76 GET LINE NUMBER
|
|
INX
|
|
BEQ NOEXEC PROGRAM NOT EXECUTING
|
|
LDX $33 GET PROMPT CHARACTER
|
|
CPX #$DD PROMPT IS A "]"?
|
|
BEQ NOEXEC YES, NOT EXECUTING
|
|
BNE EXEC ELSE, PROGRAM IS EXECUTING
|
|
|
|
.nx ch7
|