T. Joseph Carter c904963f86 Chapter 8 cleanup
Mostly just dot commands here as this entire chapter is a formatted reverse
engineering of the DOS 3.3 RWTS.  Which is an amazingly useful resource, but not
one I'm doing anything with at this stage.  :)
2017-07-21 05:32:14 -07:00

2343 lines
93 KiB

This chapter will take a detailed look at the operation of the DOS program
itself to aid the APPLE user in understanding it and to help him to make
intelligent use of its facilities. Each subroutine and group of variables or
constants will be covered separately by storage address. The enterprising
programmer may wish to create a disassembly of DOS on his printer and transfer
the annotations given here directly to such a listing. Addresses used will be
for DOS 3.3 and for a 48K master diskette version of DOS. Slot 6 is assumed.
Unless specifically indicated by a $ character, lengths are given in decimal,
addresses in hexadecimal (base 16).
C600-C65B This routine is the first code executed when a disk
is to be booted. It receives control via PR#6 or
C600G or 6 control-P.
Dynamically build a translate table for converting
disk codes to six bit hex at location $356-$3FF.
Call an RTS instruction in the monitor ROM and
extract the return address from the stack to find out
the address of this controller card ROM.
Use this address to determine the slot number of this
drive by shifting $Csxx.
Save the slot number times 16 ($s0)
Clear disk I/O latches, set read mode, select drive
1, turn disk drive on.
Pull disk arm back over 80 tracks to recalibrate the
arm to track zero.
Set up parms to read sector zero on track zero to
location $800.
Execution falls through into a general sector read
subroutine at C65C.
C65C-C6FA This subroutine reads the sector number stored at
$3D on the track indicated by $41 to the address
stored at $26,$27.
Look for D5/AA/96 sector address header on the disk.
If D5/AA/AD is found and sector data was wanted, go
to C6A6.
C683 Handle a sector address block.
Read three double bytes from the disk and combine
them to obtain the volume, track, and sector number
of the sector being read from the disk at this time.
Store the track at $40.
Compare the sector found to the sector wanted and the
track found to the track wanted.
If no match, go back to C65C.
Otherwise, if sector is correct, go to C65D to find
the sector data itself.
C6A6 Handle sector data block.
Read the 85 bytes of secondary data to $300-$355.
Read 256 bytes of primary data to the address stored
at $26,$27.
Verify that the data checksum is valid.
If not, start over at C65C.
"Nibbilize" the primary and secondary data together
into the primary data buffer ($26,$27).
Increment $27 (address page of read data) and $3D
(sector number to be read) and check against $800
to see if additional sectors need to be read.
If so, reload slot*16 and go back to C65C to read
next sector. (This feature is not used when loading
DOS but is used when loading from a BASICS diskette.)
Otherwise, go to $801 to begin executing the second
stage of the bootstrap.
0801-084C This routine loads the second RAM loader, Boot 2,
including RWTS, into memory and jumps to it.
If this is not the first entry to Boot 1, go to $81F.
Get slot*16 and shift down to slot number.
Create the address of the ROM sector read subroutine
(C65C in our case) and store it at $3E,$3F.
Pick up the first memory page in which to read Boot 2
from location $8FE, add the length of Boot 2 in
sectors from $8FF, and set that value as the first
address to which to read (read last page first).
081F Get sector to read, if zero, go to $839.
Translate theoretical sector number into physical
sector number by indexing into skewing table at $84D.
Decrement theoretical sector number (8FF) for next
iteration through.
Set up parameters for ROM subroutine (C65C) and
jump to it. It will return to $801 when the sector
has been read.
0839 Adjust page number at 8FE to locate entry point of
Boot 2.
Perform a PR#0 and IN#0 by calling the monitor.
Initialize the monitor (TEXT mode, standard window,
Get slot*16 again and go to Boot 2 ($3700 for a
master disk, $B700 in its final relocated location).
9D00-9D0F Relocatable address constants
9D00 Address of first DOS buffer at its file name field.
9D02 Address of the DOS keyboard intercept routine.
9D04 Address of the DOS video intercept routine.
9D06 Address of the primary file name buffer.
9D08 Address of the secondary (RENAME) file name buffer.
9D0A Address of the range length parameter used for LOAD.
9D0C Address of the DOS load address ($9D00).
9D0E Address of the file manager parameter list.
9D10-9D1C DOS video (CSWL) intercept's state handler address
table. States are used to drive the handling of DOS
commands as they appear as output of PRINT statements
and this table contains the address of the routine
which handles each state from state 0 to state 6.
9D1E-9D55 Command handler entry point table. This table
contains the address of a command handler subroutine
for each DOS command in the following standard order:
MON A233
PR# A229
IN# A22E
9D56-9D61 Active BASIC entry point vector table. The addresses
stored here are maintained by DOS such that they
apply to the current version of BASIC running.
9D56 Address of CHAIN entry point to BASIC.
9D58 Address of RUN.
9D5A Address of error handler.
9D5C Address of BASIC coldstart.
9D5E Address of BASIC warmstart.
9D60 Address of BASIC relocate (APPLESOFT only).
9D62-9D6B Image of the entry point vector for INTEGER BASIC.
This image is copied to 9D56 if INTEGER BASIC is made
9D6C-9D77 Image of the entry point vector for the ROM version
9D78-9D83 Image of the entry point vector for the RAM version
9D84-9DBE DOS coldstart entry routine.
Get the slot and drive numbers and store as default
values for command keywords.
vector into current BASIC entry point vector.
Remember which BASIC is active.
Go to 9DD1.
9DBF-9DE9 DOS warmstart entry routine.
Get the remembered BASIC type and set the ROM card
as necessary (calls A5B2).
9DD1 Remember whether entry is coldstart or warmstart
Call A851 to replace DOS keyboard and video
Set video intercept handler state to 0.
Coldstart or warmstart the current BASIC (exit DOS).
(DOS will next gain control when BASIC prints its
input prompt character)
9DEA-9E50 First entry processing for DOS. This routine is
called by the keyboard intercept handler when the
first keyboard input request is made by BASIC after
a DOS coldstart.
If RAM APPLESOFT is active, copy its entry point
vector to the active BASIC entry point vector and
blank out the primary file name buffer so that no
HELLO file will be run.
Set MAXFILES to 3 by default.
Call A7D4 to build the DOS file buffers.
If an EXEC was active, close the EXEC file
Set the video intercept state to 0 and indicate
warmstart status by calling A75B.
If the last command executed was not INIT (this DOS
was not just booted), go to 9E45.
Otherwise, copy an image of the DOS jump vector to
Point $3F2,$3F3 to DOS warmstart routine.
Set the AUTOSTART ROM power-up byte since the RESET
handler address was changed.
Set the command index for RUN (to run the HELLO file)
and go to A180 to execute it.
9E45 See if there is a pending command.
If so, go to A180 to execute it. Otherwise, return
to caller.
9E51-9E7F An image of the DOS 3-page jump vector which the
above routine copies to $3D0-$3FF. See Chapter 5 for
a description of its contents.
9E81-9EB9 DOS keyboard intercept routine.
Call 9ED1 to save the registers at entry to DOS.
If not coldstarting or reading a disk file,
go to 9E9E.
Get value in A register at entry and echo it on the
screen (erases flashing cursor).
If in read state (reading a file) go to A626 to get
next byte from disk file.
Otherwise, call 9DEA to do first entry processing.
Put cursor on screen in next position.
If EXECing, call A682 to get the next byte from the
EXEC file.
Set the video intercept state to 3 (input echo).
Call 9FBA to restore the registers at entry to DOS.
Call the true keyboard input routine.
Save the input character so that it will be restored
with the registers in the A register.
Do the same with the new X register value.
Exit DOS via 9FB3.
9EBA-9EBC A jump to the true KSWL handler routine.
9EBD-9ED0 DOS video intercept routine.
Call 9ED1 to save the registers at entry to DOS.
Get the video intercept state and, using it as an
index into the state handler table (9D11), go to
the proper handler routine, passing it the character
being printed.
9ED1-9EEA Common intercept save registers routine.
Save the A, X, Y, and S registers at AA59-AA5C.
While in DOS, restore the true I/O handlers (KSWL and
CSWL) to $36-$39.
Return to caller.
9EEB-9F11 State 0 output handler. --start of line--
If a RUN command was interrupted (by loading RAM
APPLESOFT) go to 9F78 to complete it.
If read flag is on (file being read) and output is a
"?" character (BASIC INPUT), go to state 6 to skip
If read flag is on and output is prompt character
($33) go to state 2 to ignore the line.
Set state to 2 (ignore non-DOS command) just in case.
If output character is not a control-D, go to
state 2.
Otherwise, set state to 1 (collect possible DOS
command), set line index to zero, and fall through
to state 1.
9F12-9F22 State 1 output handler. --collect DOS command--
Using line index, store character in input buffer at
Increment line index.
If character is not a carriage return, exit DOS
via 9F95 (echo character on screen if MON I).
Otherwise, go to command scanner at 9FCD.
9F23-9F2E State 2 output handler. --non-DOS command ignore--
If the character is not a carriage return, exit DOS
via 9FA4 (echo character on screen).
Otherwise, set state back to 0 and exit DOS via
9F2F-9F51 State 3 output handler. --INPUT statement handler--
Set state to 0 in case INPUT ends.
If character is not a carriage return, echo it on
screen as long as EXEC is not in effect with NOMON I
but exit DOS in any case. (KSWL will set state=3)
Otherwise, call A65E to see if BASIC is executing a
program or is in immediate mode. If EXEC is running
or if BASIC is in immediate mode, go to state 1 to
collect the possible DOS command.
Otherwise, exit DOS, echoing the character as
9F52-9F60 State 4 output handler. --WRITE data to a file--
If the character is a carriage return, set state to
5 (start of write data line).
Call A60E to write the byte to the disk file.
Exit DOS with echo on screen if MON O.
9F61-9F70 State 5 output handler. --Start of WRITE data line--
If the character is a control-D, go to state 0 to
immediately exit write mode.
If the character is a line feed, write it and exit,
staying in state 5.
Otherwise, set the state to 4 and go to state 4.
9F71-9F77 State 6 output handler. --Skip prompt character--
Set state to 0.
Exit DOS via 9F9D (echo if MON I).
9F78-9F82 Finish RUN command, interrupted by APPLESOFT RAM LOAD
Reset the "RUN interrupted" flag.
Call A851 to replace the DOS CSWL/KSWL intercepts.
Go to A4DC to complete the RUN command.
9F83-9F94 DOS command scanner exit to BASIC routine.
If first character of command line is control-D,
go to echo exit (9F95).
Otherwise, set things up so BASIC won't see the DOS
command by passing a zero length line (only a
carriage return). Fall through to echo exit.
9F95-9FB0 Echo character on screen (conditionally) and exit DOS
9F95 Echo only if MON C set, otherwise, go to 9FB3.
9F99 Echo only if MON O set, otherwise, go to 9FB3.
9F9D Echo only if MON I set, otherwise, go to 9FB3.
9FA4 Always echo character.
Call 9FBA to restore registers at entry to DOS.
Call 9FC5 to echo character on screen.
Save contents of the registers after echoing.
Fall through to DOS exit routine.
9FB3-9FC4 DOS exit routine and register restore.
Call A851 to put back DOS KSWL/CSWL intercepts.
Restore S (stack) register from entry to DOS.
9FBA DOS register restore subroutine.
Restore registers from first entry to DOS and return
to caller.
9FC5-9FC7 A jump to the true CSWL routine.
9FC8-9FCC Skip a line on the screen.
Load a carriage return into the A register and
call 9FC5 to print it.
9FCD-A179 DOS command parse routine.
Set the command index to -1 (none).
Reset the pending command flag (none pending).
9FD6 Add one to command index.
If first charcater is a control-D, skip it.
Flush to a non-blank (call A1A4).
Compare command to command name in command name table
at A884 for the current command index.
If it doesn't match and if there are more entries
left to check, go back to 9FD6.
If it does match, go to A01B.
Otherwise, if command was not found in the table,
check to see if the first character was a control-D.
If so, go to A6C4 to print "SYNTAX ERROR".
Otherwise, call A75B to reset the state and warmstart
flag and go to 9F95 to echo the command and exit.
(the command must be for BASIC, not DOS)
A01B Compute an index into the operand table for the
command which was entered.
Call A65E to see if a BASIC program is executing.
If not, and the command is not a direct type command,
(according to the operand table) go to A6D2 to print
Otherwise, if the command is RUN, make the prompt
character ($33) non-printing.
Check the operand table to see if a first filename
is a legal operand for this command.
If not, go to A0A0.
Otherwise, clear the filename buffer (call A095).
Flush to the next non-blank (call A1A4) and copy
the filename operand to the first filename buffer.
Skip forward to a comma if one was not found yet.
If a second filename is legal for this command, use
the code above to copy it into the second filename
Check both filenames to see if they are blank.
If one was required by the command but not given,
give a syntax error or pass it through to BASIC.
(As in the case of LOAD with no operands)
If all is well, go to A0D1 to continue.
A095 A subroutine to blank both filename buffers.
A0A0 Indicate no filename parsed.
Check operand table to see if a positional operand
is expected.
If not, go to A0D1 to continue.
Otherwise, call A1B9 to convert the numeric operand.
If omitted, give syntax error.
If number converted exceeds 16, give "RANGE ERROR"
If number is supposed to be a slot number, give
"RANGE ERROR" if it exceeds 7.
If number is not a slot number, give "RANGE ERROR" if
it is zero. (MAXFILES 0 is a no-no)
A0D1 Set defaults for the keyword operands (V=0,L=0,B=0)
A0E8 Get the line offset index and flush to the next
non-blank, skipping any commas found.
If we are not yet to the end of the line, go to A10C.
Check to see if any keywords were given which were
not allowed for this command.
If not, go to A17A to process the command.
A10C Lookup the keyword found on the command line in the
table of valid keywords (A940)
If not in table, give "SYNTAX ERROR" message.
Get its bit position in the keywords-given flag.
If the keyword does not have an operand value, go to
Otherwise, indicate keyword found in flag.
Convert the numeric value associated with keyword.
Give "SYNTAX ERROR" message if invalid.
Check to see if the number is within the acceptable
range as given in the keyword valid range table at
Save the value of the keyword in the keyword values
table starting at AA66.
Go parse the next keyword. go to A0E8.
A164 Indicate C, I, or O keywords were parsed.
Update the MON value in the keyword value table
Go parse the next keyword. go to A0E8.
A17A-A17F Call A180 to process the command, then exit via echo
at 9F83.
A180-A192 Do command.
Reset the video intercept state to zero.
Clear the file manager parameter list.
Using the command index, get the address of the
command handling routine from the command handler
routine table at 9D1E and go to it.
Command handler will exit to caller of this routine.
A193-A1A3 Get next character on command line and check to see
if it is a carriage return or a comma.
A1A4-A1AD Flush command line characters until a non-blank is
A1AE-A1B8 Clear the file manager parameter list at B5BA to
A1B9-A1D5 Convert numeric operand from command line. Call
either A1D6 (decimal convert) or A203 (hex convert)
depending upon the presence or lack thereof of a
dollar sign ($).
A1D6-A202 Decimal convert subroutine.
A203-A228 Hexadecimal convert subroutine.
A229-A22D PR#n command handler.
Load the parsed numeric value and exit via FE95 in
the monitor ROM.
A22E-A232 IN#n command handler.
Load the parsed numeric value and exit via FE8B in
the monitor ROM.
A233-A23C MON command handler.
Add new MON flags to old in AA5E and exit.
A23D-A250 NOMON command handler.
If C was given, put out a carriage return since this
line was echoed but its CR was not.
Turn off the proper bits in AA5E and exit.
A251-A262 MAXFILES command handler.
Turn off any EXEC file which is active.
Close all open files (call A316).
Set the new MAXFILES number at AA57.
Go to A7D4 to rebuild the DOS file buffers and exit.
A263-A270 DELETE command handler.
Load the delete file manager opcode (05).
Call the file manager open driver (A2AA) to perform
the delete.
Find the file buffer used to do the delete and free
it (call A764).
Exit to caller.
A271-A274 LOCK command handler.
Load the lock file manager opcode (07) and go to
A275-A27C UNLOCK command handler.
Load the unlock file manager opcode (08).
A277 Call the file manager open driver (A2AA) to perform
the desired function.
Exit to the caller via close (A2EA).
A27D-A280 VERIFY command handler.
Load the verify file manager opcode (0C) and go to
A277 to perform function.
A281-A297 RENAME command handler.
Store address of second file name in file manager
parameter list.
Load the rename file manager opcode (09).
Call the file manager driver at A2C8.
Exit via close (A2EA).
A298-A2A2 APPEND command handler.
Call A2A3 to OPEN the file.
Read the file byte by byte until a zero is found.
If append flag is on, add one to record number
and turn flag off.
Exit via a call to POSITION.
A2A3-A2A7 OPEN command handler.
Set file type as TEXT.
Go to A3D5 to open file.
A2A8-A2E9 Command handler common file management code.
Set opcode to OPEN.
A2AA If no L value was given on the command, use 0001 and
store record length value in file manager parmlist.
A2C8 Close file if already open.
Is there an available file buffer?
If not, issue "NO FILE BUFFERS AVAILABLE" message.
Point $40,$41 at the free file buffer.
Copy filename to file buffer (allocates the buffer)
Copy buffer pointers to file manager parmlist (A74E).
Finish filling in the file manager parmlist (A71A).
Set operation code in parmlist.
Exit through the file manager driver.
A2EA-A2FB CLOSE command handler.
If no filename was given as part of command,
go to A316 to close all files.
Otherwise, find the open file buffer for filename
If no such file open, exit to caller.
Otherwise, close file and free buffer (A2FC).
Go back through CLOSE command handler to make sure
there are not more open buffers for the same file.
A2FC-A315 Close a file and free its file buffer.
Find out if this buffer is EXEC's (A7AF).
If so, turn EXEC flag off.
Release the buffer by storing a $00 on its filename
Copy file buffer pointers to the file manager
Set file manager opcode to CLOSE.
Exit through the file manager driver routine.
A316-A330 Close all open files.
Point to first file buffer (A792).
Go to A320.
A31B Point to next file buffer on chain (A79A).
If at end of chain, exit to caller.
A320 Is this file buffer EXEC's?
If so, skip it and go to A31B.
Is it not in use (open)?
If so, skip it and go to A31B.
Otherwise, close it and free it (A2FC).
Go to A316 to start all over.
A331-A35C BSAVE command handler.
Insure that the A and L keywords were present on the
If not, issue "SYNTAX ERROR" message.
Open and verify a B type file (A3D5).
Write the A keyword value as the first two bytes of
the file.
Write the L keyword value as the next two bytes of
the file.
Use the A value to exit by writing a range of bytes
from memory to the file.
A35D-A38D BLOAD command handler.
Open the file, ignoring its type.
Insure the type is B.
If not, issue "FILE TYPE MISMATCH" message.
Otherwise, open B type file and test file type (A3D5)
Read the A value from the first two bytes of file.
If A keyword was not given, use the value just read.
Read L value as next two bytes in file.
Go to A471 to read range of bytes to memory from file
A38E-A396 BRUN command handler.
Call BLOAD command handler to load file into memory.
Replace DOS intercepts.
Exit DOS by jumping to the A address value to begin
execution of the binary program.
A397-A3D4 SAVE command handler.
Get the active BASIC type (AAB6).
If INTEGER, go to A3BC.
If APPLESOFT, test $D6 flag to see if program is
If so, issue "PROGRAM TOO LARGE" message.
Otherwise, open and test for A type file (A3D5).
Compute program length (PGMEND-LOMEM).
Write this two byte length to file.
Exit by writing program image from LOMEM as a range
of bytes (A3FF).
A3BC Open and test for I type file (A3D5).
Compute program length (HIMEM-PGMSTART).
Write this two byte length to file.
Exit by writing program image from PGMSTART as a
range of bytes (A3FF).
A3D5-A3DF Open and test file type.
Set file type wanted in file manager parmlist.
Call A2A8 to open file.
Go to A7C4 to check file type.
A3E0-A3FE Write a 2 byte value to the open file.
Store value to be written in file manager parmlist.
Set write one byte opcodes.
Call file manager driver.
Call it again to write second byte and exit to caller
A3FF-A40F Read/write a range of bytes.
Set the address of the range in file manager parmlist
Set subcode to read or write a range of bytes.
Call the file manager driver.
Close the file.
Exit through the VERIFY command handler to insure
data was written ok.
A410-A412 Issue "FILE TYPE MISMATCH" message.
A413-A479 LOAD command handler.
Close all files (A316).
Open the file in question.
Is it an A or I type file?
If not, issue "FILE TYPE MISMATCH" message.
Which BASIC is active?
If INTEGER, go to A450.
Select APPLESOFT BASIC (A4B1). This call could result
in DOS losing control if the RAM version must be
Read first two bytes of file as length of program.
Add length to LOMEM (program start) to compute
program end.
Is program end beyond HIMEM?
If so, close file and issue "PROGRAM TOO LARGE".
Set program end and start of variables pointers.
Read program as range of bytes to program start.
Replace DOS intercepts (A851).
Go to BASIC's relocation routine to convert a RAM
APPLESOFT program to ROM and vice versa as needed.
A450 Select INTEGER BASIC (A4B1).
Read length of program (first two bytes in file).
Compute program start (HIMEM-LENGTH).
If zero or less than LOMEM, issue "PROGRAM TOO LARGE"
message and close file.
Set program start pointers.
Read program into memory as a range of bytes.
Exit to caller.
A47A-A4AA Read two bytes from file (Address or Length).
Set up parmlist to read two bytes to range length
field (AA60).
Call file manager driver.
Store value read as range length in file manager
parmlist just in case it was a length.
A4AB-A4B0 Close file and issue "PROGRAM TOO LARGE" message.
A4B1-A4D0 Select desired BASIC.
If desired BASIC is already active, exit to caller.
Save current command index in case we must RUN
If INTEGER, go to A59E to select it.
Otherwise, copy primary file name to secondary
buffer to save it in case RAM APPLESOFT is needed.
Go to A57A to set APPLESOFT.
A4D1-A4E4 RUN command handler.
If APPLESOFT is active, set RUN intercepted flag so
that RUN can complete after APPLESOFT is loaded.
Call LOAD command handler to load the program.
Skip a line on the screen.
Put DOS intercepts back.
Go to the RUN entry point in the current BASIC.
A4E5-A4EF INTEGER BASIC RUN entry point intercept.
Delete all variables (CLR equivalent).
Go to the CHAIN entry point in INTEGER BASIC.
A4F0-A4FB CHAIN command handler.
Call the LOAD command handler to load the program.
Skip a line.
Replace DOS intercepts.
Go to current BASIC's CHAIN entry point.
A4FC-A505 APPLESOFT ROM RUN entry point intercept.
Call APPLESOFT to clear variables.
Reset ONERR.
Go to RUN entry point.
A506-A50D APPLESOFT RAM RUN entry point intercept.
Call APPLESOFT to clear variables.
Reset ONERR.
Go to RUN entry point.
A510-A51A WRITE command handler.
Call READ/WRITE common code (A526).
Set CSWL state to 5 (WRITE mode line start).
Exit DOS (9F83).
A51B-A525 READ command handler.
Call READ/WRITE common code (A526).
Set READ mode flag in status flags (AA51).
Exit DOS (9F83).
A526-A54E READ/WRITE common code.
Locate the open file buffer for this file (A764).
If not open, open it.
Copy file buffer addresses to file manager parmlist.
If R or B were given on command, copy to parmlist
and issue a POSITION call to file manager.
Exit to caller.
A54F-A56D INIT command handler.
If V was given, use it. Otherwise, use 254.
Store first page number of DOS in file manager
Call file manager driver to INIT diskette.
Exit through SAVE to store greeting program on disk.
A56E-A579 CATALOG command handler.
Call file manager with CATALOG opcode.
Set new V value as default for future commands.
Exit to caller.
A57A-A59D FP command handler.
Set ROM card, if any, for APPLESOFT (A5B2).
If successful, coldstart DOS (9D84).
Otherwise, set status flag to indicate INTEGER BASIC
is active.
Set primary filename buffer to "APPLESOFT".
Set flags to indicate RAM APPLESOFT and coldstart.
Go to RUN command handler.
A59E-A5B1 INT command handler.
Set ROM card, if any, for INTEGER BASIC (A5B2).
If not successful, issue "LANGUAGE NOT AVAILABLE".
Otherwise, clear RUN intercepted flag.
Coldstart DOS (9D84).
A5B2-A5C5 Set ROM to desired BASIC.
(This routine is passed a $4C for APPLESOFT or a $20
for INTEGER, since these bytes appear at $E000 in
these BASICs. It will work regardless of which
BASIC is onboard)
If desired BASIC is already available, exit.
Try selecting ROM card.
If desired BASIC is now available, exit.
Try selecting onboard ROM.
If desired BASIC is now available, exit.
Otherwise, exit with error return code.
A5C6-A5DC EXEC command handler.
Open the file (A2A3).
Copy file buffer address to EXEC's buffer pointer at
Set EXEC active flag (AAB3).
Jump into POSITION command handler to skip R lines.
A5DD-A60D POSITION command handler.
Locate the open file buffer (A764).
If not found, open one as a TEXT file.
Copy buffer pointers to file manager parmlist.
If R was not given on command, exit.
A5F2 Otherwise, test R value for zero and exit if so.
Decrement R value by one.
Read file byte by byte until a carriage return (end
of line - $8D) is reached.
If at end of file, issue "END OF FILE" message.
Otherwise, go to A5F2 to skip next record.
A60E-A625 Write one data byte to file.
Insure that BASIC is running a program (A65E).
If not, close file and warmstart DOS.
Set up file manager parmlist to write the data byte
to the open file.
Call file manager and exit.
A626-A65B Read one data byte from file.
Insure that BASIC is running a program (A65E).
If not, close file and warmstart DOS.
Set CSWL intercept state to 6 (skip prompt character)
A630 Read next file byte (A68C).
If not at end of file, go to A644.
Otherwise, close file.
If state is not 3 (EXEC) issue "END OF DATA" message.
Exit to caller.
A644 If data byte is lower case character, turn its most
significant bit off to fool GETIN routine in monitor.
Store data byte in A register saved at entry to DOS.
Using line index, turn high bit back on in previous
data byte stored at $200 (input line buffer) to make
it lower case if necessary.
Exit DOS (9FB3).
A65E-A678 Test to see if BASIC is running a program or is in
immediate command mode.
If active BASIC is INTEGER, go to A672.
If line number is greater than 65280 and prompt is
"]" then APPLESOFT is in immediate mode.
Otherwise, it is executing a program.
Exit to caller with appropriate return code.
A672 Check $D9 to determine whether BASIC is executing a
program and exit with proper return code.
A679-A681 Close current file and warmstart DOS.
A682-A68B EXEC read one byte from file.
Select EXEC file buffer.
Copy file buffer addresses to file manager parmlist.
Set state to 3 (input echo).
Go to A62D to read a file byte.
A68C-A69C Read next text file byte.
Set up file manager parmlist to read one byte.
Call file manager driver.
Return to caller with the data byte.
A69D-A6A7 Set $40,$41 to point to EXEC file buffer.
A6A8-A6C3 File manager driver routine.
Call the file manager itself (AB06).
If no errors, exit to caller.
Otherwise, point $40,$41 at file buffer.
If found, release it by storing a zero on the file
name field.
If error was not "END OF DATA", print error message.
Otherwise, pretend a $00 was read and return to
A6C4-A6D4 Miscellaneous error messages.
A6D5-A701 Error handler.
Set warmstart flag and clear status (BFE6).
If APPLESOFT ONERR is active, go to A6EF.
Otherwise, print RETURN BELL RETURN.
Print text of error message (A702).
Print another RETURN.
A6EF Replace DOS intercepts.
If a BASIC program is in execution, pass error code
to BASIC's error handler.
Otherwise, warmstart BASIC.
A702-A719 Print text of error message.
Using the error number as an index, print the message
text from the message table (A971) byte by byte.
Last character has most significant bit on.
A71A-A742 Complete file manager parameter list.
Copy Volume value to parmlist.
Copy Drive value to parmlist.
Copy Slot value to parmlist.
Copy address of primary filename buffer to parmlist.
Save file buffer address in $40,$41.
Return to caller.
A743-A74D Copy primary filename to file buffer filename field.
A74E-A75A Copy current buffer pointers to file manager parmlist
Copy file manager workarea buffer pointer.
Copy T/S List sector buffer pointer.
Copy data sector buffer address.
Copy next file buffer link address.
Return to caller.
A75B-A763 Reset state to 0 and set warmstart flag.
A764-A791 Locate an open or free file buffer.
Assume there are no free file buffers by zeroing $45.
Point $40,$41 at first buffer on chain.
Go to A773.
A76E Point $40,$41 at next buffer on chain.
If at end of chain, exit with file not open code.
A773 Get first byte of filename field.
If zero (file buffer free), save file buffer address
at $44,$45 as an available buffer and go to A76E.
Otherwise, see if name in primary filename buffer
matches the name in this file buffer.
If not, go to A76E to get next buffer.
If so, return to caller with open file found code.
A792-A799 Point $40,$41 at first file buffer on chain.
A79A-A7A9 Point $40,$41 at next file buffer on chain.
A7AA-A7AE Get first byte of file name in file buffer.
A7AF-A7C3 See if current buffer belongs to EXEC.
Is EXEC active?
If not, exit.
If so, does current buffer address match EXEC's?
Return to caller with appropriate code.
A7C4-A7D3 Check file type.
Does file type of open file match desired file type?
If so, exit.
Otherwise, turn lock bit off and test again.
If ok, exit.
Otherwise, close file and issue "FILE TYPE MISMATCH".
A7D4-A850 Initialize (build) DOS file buffer chain.
Set $40,$41 to point to first buffer.
Set counter to MAXFILES value.
A7E5 Store zero on filename field to mark as free.
Set up link pointers in buffer to point to file
manager workarea (45 bytes prior to filename field).
Set up link pointer to T/S List sector buffer (-256
bytes from file manager workarea buffer).
Set up link pointer to data sector buffer 256 bytes
before that.
Decrement counter.
If zero, go to A82D to set HIMEM.
Otherwise, set link to next file buffer as 38 bytes
prior to data sector buffer.
Go to A7E5 to set up next buffer.
A82D Set link of last buffer to $0000.
If INTEGER BASIC is active, go to A846.
pointers in zeropage to point just below the last
Exit to caller.
to point just below the last buffer.
Exit to caller.
A851-A883 Replace DOS keyboard/video intercept vectors.
Is DOS keyboard (KSWL) vector still set?
If so, go to A86A.
Otherwise, save current KSWL vector ($38,$39) at
AA55,AA56 and replace with DOS intercept routine's
A86A Is DOS video (CSWL) vector still set?
If so, exit to caller.
Otherwise, save current CSWL vector ($36,$37) at
AA53,AA54 and replace with DOS intercept routine's
Exit to caller.
A884-A908 DOS command name text table.
This table consists of the ASCII name for each DOS
command in order of command index values, with the
last character of each indicated by the MSB being
on. Commands in order are:
Example: INIT is $49 $4E $49 $D4 (I N I T)
A909-A940 Command valid keywords table.
This table is used to determine which keywords are
required or may be given for any DOS command.
Each command has a two byte entry with 16 flags,
indicating which keywords may be given. The flag
bit settings are as follows:
0 Filename legal but optional
1 Command has no positional operand
2 Filename #1 expected
3 Filename #2 expected
4 Slot number positional operand expected
5 MAXFILES value expected as positional operand
6 Command may only be issued from within a program
7 Command may create a new file if file not found
8 C, I, O keywords legal
9 V keyword legal
10 D keyword legal
11 S keyword legal
12 L keyword legal
13 R keyword legal
14 B keyword legal
15 A keyword legal
Thus, for a typical command, OPEN, where the value
is $2378, bits 2, 6, 7, 9, 10, 11, and 12 are set so
the command has one filename operand, may only be
issued from within a program, may create a new file,
and the V, D, S, and L keywords are legal.
The command entries are:
INIT 2170
RUN A070
CHAIN 2070
LOCK 2070
CLOSE 6000
READ 2206
EXEC 2074
WRITE 2206
OPEN 2378
MON 4080
NOMON 4080
PR# 0800
IN# 0800
FP 4070
INT 4000
BSAVE 2179
BLOAD 2071
BRUN 2071
A941-A94A Keyword name table.
This table contains all the ASCII names of the DOS
keywords in standard order. Each keyword name
occupies one byte:
A94B-A954 Keyword flag bit positions table.
This table gives the bit positions for each keyword
into the second byte of the command valid keyword
table above and in the flag (AA65) which indicates
which keywords were present on the command line.
The bit positions are:
V - 40
D - 20
S - 10
L - 08
R - 04
B - 02
A - 01
C - C0 ...
I - A0 ... not used in valid keyword table
O - 90 ...
A955-A970 Keyword value valid range table.
This table indicates the range any keyword value
may legally have. Each keyword has a four byte entry,
two bytes of minimum value, and two bytes of maximum
value. Values are:
V 0 254
D 1 2
S 1 7
L 1 32767
R 0 32767
B 0 32767
A 0 65535
C, I, and O do not appear in this table since they
do not have numeric values.
A971-AA3E Error message text table.
This table contains the text for each error code in
order of error code number:
2 "RANGE ERROR" (Bad file manager opcode)
3 "RANGE ERROR" (Bad file manager subcode)
AA3F-AA4F Error message text offset index table.
This table contains the offset in bytes to the text
of any given error message in the table above.
Entries are one byte each for each error code number.
AA4F-AA65 DOS main routines variables.
AA4F Current file buffer address (2 bytes).
AA51 Status flags: $01=READ state, $00=Warmstart,
$80=Coldstart, $40=APPLESOFT RAM
AA52 DOS CSWL intercept state number.
AA53 Address of true CSWL handler (2 bytes).
AA55 Address of true KSWL handler (2 bytes).
AA57 MAXFILES value.
AA59 Save area for S, X, Y, and A registers when DOS is
entered (4 bytes).
AA5D Command line index value (offset into line).
AA5E MON flags: (C=$40, I=$20, O=$10)
AA5F Index of last command times 2.
AA60 Range length for LOAD and BLOAD (2 bytes).
AA62 Index of pending command, if any.
AA63 Scratch variable (counter, message index, etc.)
AA64 Index of current keyword.
AA65 Keywords present on command line flags.
AA66-AA74 Keyword values parsed from command and defaulted.
AA66 Volume (2 bytes)
AA68 Drive (2 bytes)
AA6A Slot (2 bytes)
AA6C Length (2 bytes)
AA6E Record (2 bytes)
AA70 Byte (2 bytes)
AA72 Address (2 bytes)
AA74 MON value (one byte)
AA75-AA92 Primary file name buffer
AA93-AAB0 Secondary (RENAME) file name buffer
AAB1-AAC0 DOS main routines constants and variables.
AAB1 MAXFILES default ($03).
AAB2 Control-D ($84).
AAB3 EXEC file active flag ($00=not active).
AAB4 EXEC file buffer address (2 bytes).
AAB7 RUN intercepted flag.
AAB8 "APPLESOFT" characters in ASCII (9 bytes)
AAC1-AAC8 File manager constants.
AAC1 Address of RWTS paramter list (B7E8).
AAC3 Address of VTOC sector buffer (B3BB).
AAC5 Address of directory sector buffer (B4BB).
AAC7 Address of last byte of DOS plus one. (C000)
AAC9-AAE4 File manager function routine entry point table.
This table contains a two byte function handler
routine address for each of the 14 file manager
opcodes in opcode order.
AAE5-AAF0 File manager read subcode handler entry point table.
This table contains a two byte function handler
routine address for each of the 6 read subcodes.
AAF1-AAFC File manager write subcode handler entry point table.
This table contains a two byte function handler
routine address for each of the 6 write subcodes.
AAFD-AB05 File manager external entry point (from $3D6).
Is X register zero?
If so, allow new files by simulating an INIT command
Otherwise, require old file by simulating a LOAD
command index.
Fall through to main file manager entry point.
AB06-AB1E File manager main entry.
Save S register at B39B.
Restore file manager workarea from file buffer (AE6A)
Make sure opcode does not exceed 13.
If it does, return with code=2 (invalid opcode).
Use opcode as index into file manager function
routine entry point table and go to proper handler
via RTS.
AB1F-AB21 Return with return code=2 (bad opcode).
AB22-AB27 OPEN function handler.
Call common open code (AB28).
Exit file manager.
AB28-ABDB Common open routine.
Initialize file manager workarea by resetting
variables to their defaults (ABDC).
Set sector length to 256.
Insure record length is non-zero. If zero, use 1.
Store record length in file manager workarea.
Locate or allocate a directory entry for the file
If file already exists, go to ABA6.
Otherwise, save directory index for free entry.
Using last command index and valid keywords table,
determine whether current command may create a new
If so, go to AB64.
Otherwise, if running "APPLESOFT", set return code
If not running "APPLESOFT" set return code to "FILE
NOT FOUND" and exit.
AB64 Set sector count in directory entry to 1 (there will
only be a T/S List sector initially).
Allocate a sector for a T/S List (B244).
Store sector number of this sector in directory
entry and in first and current T/S List sector number
in file manager workarea.
Store track number in both places also.
Move file type desired to directory entry.
Write directory sector back to catalog (B037).
Select T/S List buffer (AF0C).
Zero it (B7D6).
And write it back (AF3A).
Set return code to 6 ("FILE NOT FOUND").
ABA6 Place track/sector of T/S List in directory entry in
first T/S List variable in file manager workarea.
Copy file type from directory to parmlist to pass it
back to caller and to file manager workarea.
Copy number of sectors in file to workarea.
Save directory offset to entry in workarea.
Set end of data pointer to "infinity".
Set number of data bytes represented by one T/S List
sector to 122*256 (30.5K) in workarea.
Go read first T/S List sector (AF5E).
ABDC-AC05 Initialize file manager workarea.
Zero entire 45 bytes of workarea.
Save complemented volume number in workarea.
Save drive number in workarea.
Save slot*16 in workarea.
Set track number to $11 (catalog track).
Return to caller.
AC06-AC39 CLOSE function handler.
Checkpoint data buffer to disk if needed (AF1D).
Checkpoint T/S List buffer if needed (AF34).
Release any sectors which were preallocated but not
used (B2C3).
If VTOC does not need to be re-read, exit.
Otherwise, re-read VTOC sector (AFF7).
Flush through directory sectors in the catalog until
we reach the one which contains the entry for this
Get the index to the entry.
Update the sector count in the entry to reflect the
new file's length.
Checkpoint the directory sector back to the disk.
Exit file manager.
AC3A-AC57 RENAME function handler.
Call common code to locate/open the file.
If file is locked, exit with "FILE LOCKED" return
Set $42,$43 to point to new name.
Copy new name to directory entry.
Write back directory sector to disk.
Exit file manager.
AC58-AC69 READ function handler.
Insure subcode does not exceed 5. If so, exit with
return code=3.
Use subcode as index into READ subcode handler entry
point table.
Go to proper handler of subcode.
AC6A-AC6C Return code = 3, subcode bad
AC6D-AC6F "FILE LOCKED" error return
AC70-AC86 WRITE function handler.
If file is locked, exit with "FILE LOCKED" error.
Insure subcode does not exceed 5. If so, exit with
return code=3.
Use subcode as index into WRITE subcode handler entry
point table.
Go to proper handler of subcode.
AC87-AC89 POSITION AND READ ONE BYTE subcode handler
Call position routine.
Fall through to next subcode handler.
AC8A-AC92 READ ONE BYTE subcode handler.
Read next file byte (ACA8).
Store in parmlist for pass back to caller.
Exit the file manager.
Call position routine.
Fall through to next subcode handler.
AC96-ACA7 READ A RANGE OF BYTES subcode handler.
Decrement and check length (B1B5).
Read a byte (ACA8).
Point $42,$43 at range address and add one to address
Store byte read at address.
Loop back to AC96. (length check will exit file
manager when length is zero.)
ACA8-ACB8 Read a data byte.
Read next data sector if necessary (B0B6).
If at end of file, exit with "END OF DATA" error.
Otherwise, load data byte from data sector buffer.
Increment record number/byte offset into file (B15B).
Increment file position offset (B194).
Return with data byte read.
Call position routine.
Fall through to next subcode handler.
ACBE-ACC6 WRITE ONE BYTE subcode handler.
Find data byte to be written.
Write it to file (ACDA).
Exit file manager.
Call position routine.
Fall through to next subcode handler.
Copy and advance range address pointer.
Get next byte to write.
Write it to file (ACDA).
Test and decrement length (B1B5).
Loop back to AACA.
ACDA-ACEC Write a data byte.
Read the proper data sector (if necessary) (B0B6).
Store data byte to be written in sector buffer.
Flag data sector buffer as requiring rewrite.
Increment record number/byte offset into file (B15B).
Exit via file position offset increment routine
ACEF-ACF5 LOCK function handler.
Set mask byte to $80 (lock).
Go to common code (ACFB).
ACF6-ACFA UNLOCK function handler.
Set mask byte to $00 (unlock).
Fall through to common code.
ACFB-AD11 LOCK/UNLOCK common code.
Locate/open file (AB28).
Get index into directory to entry.
Update file type byte to lock ($8X) or unlock ($0X).
Write directory sector back to disk.
Exit file manager.
AD12-AD17 POSITION function handler.
Call position routine.
Exit file manager.
AD18-AD2A VERIFY function handler.
Locate/open file (AB28).
AD1B Read next data sector.
If at end of file, exit file manager.
Otherwise, increment sector position.
And loop back to AD1B.
AD2B-AD88 DELETE function handler.
Locate/open file (AB28).
Using directory index, determine if file is locked.
If so, exit with "FILE LOCKED" error code.
Copy T/S List sector's track number from directory to
workarea and to last character of file name in the
directory entry itself.
Store a $FF over T/S List sector's track number in
directory entry to mark file deleted.
Copy T/S List sector's sector number to workarea.
Write directory sector back to disk.
AD54 Read next T/S List sector (AF5E).
If no more exist, write VTOC and exit file manager.
Otherwise, select T/S List buffer (AF0C).
Index to first T/S pair.
AD5E If track number is zero or minus, skip it.
Otherwise, free the data sector by updating the VTOC
bit map (AD89).
Index to next T/S pair.
If more, go to AD5E.
Get T/S of next T/S List sector from this one.
Free this T/S List sector (AD89).
Go process next one, if any (go to AD54).
Otherwise, write VTOC and exit file manager.
AD89-AD97 Free a sector.
Call B2DD to deallocate sector in VTOC bit map.
Zero the sector allocation area of the workarea.
Return to caller.
AD98-AE2E CATALOG function handler.
Initialize file manager workarea (ABDC).
Set V value to zero (complimented=$FF).
Read the VTOC sector (AFF7).
Set up a counter for 22 lines before waiting for
the keyboard.
Skip 2 lines on the screen.
Convert Volume number and print it (AE42).
Skip 2 more lines.
ADCA Read next directory sector.
If no more exist, exit file manager.
Set index to first entry.
ADD1 Get track number.
If zero, exit file manager.
If minus, skip entry (deleted file).
Print "*" if file is locked (check file type byte).
Use file type as index into file type name table at
B3A7 and print single character found there.
Print a blank.
Convert and print the number of sectors in the file.
Print a blank.
Index to filename.
Print file name.
Skip to next line.
Advance index to next directory entry.
If there are more, go to ADD1.
If not, go to ADCA to read next directory sector.
Exit when finished.
AE2F-AE41 Skip a line on CATALOG printout.
Output a carriage return.
Decrement line counter.
If still nonzero, exit.
Otherwise, wait for keyboard keypush.
Then reset counter to 21 lines.
And return to caller.
AE42-AE69 Convert the number stored at $44 to a three character
printable number and print it.
AE6A-AE7D Restore file manager workarea from file buffer.
Select file manager workarea buffer.
Set return code in parmlist to zero initially.
Copy 45 byte saved image of file manager workarea in
file buffer to real file manager workarea.
Exit to caller.
AE7E-AE8D Save file manager workarea in file buffer.
Select file manager workarea buffer.
Copy 45 byte workarea to file buffer.
Exit to caller.
AE8E-AF07 INIT function handler.
Initialize the file manager workarea (ABDC).
Call RWTS to format the diskette (B058).
Copy V value to VTOC buffer.
Start track to allocate next value at $11.
And direction of allocation as $01 (forward).
Zero VTOC bit map (all sectors in use).
Skipping the first three tracks and track $11, copy
the 4 byte bit mask (B3A0) to each track entry in
the VTOC bit map to free the sectors. This leaves the
first three tracks and the catalog track marked in
Zero the directory sector buffer.
Point to directory sector buffer.
Set track $11 in RWTS parmlist.
Set up link from this directory sector to next (track
$11, sector-1).
Call RWTS to write directory sector.
Write each sector on track in this way except for
sector zero.
On last sector (sector 1) zero link pointer.
Point RWTS parms at DOS load point (B7C2).
Write DOS image onto tracks 0-2 (B74A).
Exit file manager.
AF08-AF1C Select a buffer by setting $42,$43 to point to it.
AF08 Select file manager workarea buffer in file buffer.
AF0C Select T/S List sector buffer in file buffer.
AF10 Select data sector buffer in file buffer.
Exit to caller when $42,$43 are set.
AF1D-AF33 Checkpoint write data sector buffer to disk.
Test flag to see if buffer was changed since last
If not, exit to caller.
Otherwise, set up RWTS pointer (AFE4).
Call RWTS to write sector.
Reset flag to indicate data sector no longer in need
of a checkpoint.
Exit to caller.
AF34-AF4A Checkpoint write T/S List sector buffer to disk.
Test flag to see if buffer was changed since last
If not, exit to caller.
Otherwise, set up RWTS pointer (AF4B).
Call RWTS to write sector.
Reset flag to indicate T/S List sector no longer in
need of checkpoint.
Exit to caller.
AF4B-AF5D Prepare for RWTS call with a T/S List sector.
Copy address of T/S List buffer to RWTS parmlist.
Get track/sector of sector.
Exit to caller.
AF5E-AFDB Read a T/S List sector to file buffer.
(CARRY flag is set at entry to indicate whether the
first T/S List for the file is wanted (C=0) or the
next (C=1).
Memorize carry flag entry code.
Checkpoint current T/S List sector if necessary.
Set up for RWTS (AF4B).
Select T/S List buffer (AF0C).
Is first or next wanted?
If first, go to AFB5 to continue.
Otherwise, get link to next T/S List from this one.
If link is non-zero, use it to find next one and go
to AFB5.
Otherwise, we are out of T/S Lists for this file.
If we are reading file, exit with error code.
Otherwise, allocate a new sector (B244).
Point old T/S List sector to new one's track/sector.
Write old T/S List sector back to disk.
Zero the buffer to form new T/S List sector.
Compute and store the relative sector number of the
first sector listed in this sector at +5,+6 into the
Set RWTS opcode to write new T/S List sector to disk.
AFB5 Set RWTS opcode to read old T/S List (unless we just
allocated it above).
Set track and sector and call RWTS to read old list
or write new list.
Compute relative sector number of last sector (plus
one) in this list and store in workarea.
Exit to caller with normal return code.
AFDC-AFE3 Read a data sector.
Set up for RWTS (AFE4).
Set RWTS READ opcode and go to RWTS driver to do it.
AFE4-AFF6 Prepare for RWTS with data sector.
Copy address of data sector buffer to RWTS parmlist.
Get its track/sector.
And exit to caller.
AFF7-B010 Read/write the VTOC buffer.
AFF7 Read VTOC entry, go to AFFD.
AFFB Write VTOC entry, fall through.
AFFD Common code.
Copy VTOC sector buffer address to RWTS parmlist.
Get its track number and use sector $00.
Exit through RWTS driver.
B011-B036 Read a directory sector.
(If CARRY flag is zero on entry, read first directory
sector. If CARRY is one, read next)
Memorize entry code.
Set buffer pointers (B045).
First or next?
If first, get track/sector of directory sector from
VTOC at offset +1,+2.
Otherwise, get track/sector from directory sector at
offset +1,+2. If track is zero, exit with error code
(end of directory).
Call RWTS to read sector.
Exit with normal return code.
B037-B044 Write directory sector.
Set buffer pointers.
Find its track/sector in workarea.
Exit through RWTS to write it.
B045-B051 Prepare for RWTS for directory buffer.
Copy directory buffer address to RWTS parmlist.
Exit to caller.
B052-B0B3 Read/Write Track/Sector (RWTS) driver.
Set track/sector in RWTS parmlist.
B058 Set command code (read,write,etc.)
If writing, set flag (B5D5).
Set volume number expected in parmlist.
Set slot*16 in parmlist.
Set drive in parmlist.
Set sector size in parmlist.
Set IOB type in parmlist ($01).
Call RWTS, passing parmlist pointer.
Copy true volume found to file manager parmlist.
Reset volume expected field in RWTS parmlist.
If an error did not occur, exit to caller.
Otherwise, get return code.
Translate vol mismatch to rc=7, write protected to
rc=4 and all other errors to rc=8 (I/O error).
Exit file manager now.
B0B6-B133 Read next data sector (if necessary).
Is the current file position in the current data
sector now in memory?
If so, go to B12C.
Otherwise, checkpoint data sector buffer.
Is the current file position prior to or after this
T/S List's domain?
If not, go to B0F3.
Otherwise, read each T/S List for the file, starting
with the first, until the proper one is found.
If it is never found, exit with error (ran off end of
file reading).
B0F3 Data is in this T/S List sector.
Compute the displacement to the proper entry in this
T/S List sector.
Select the T/S List buffer.
Get the track of the data sector wanted.
If non-zero, go to B114.
Otherwise, if not writing, exit with error (no data
to read there).
If writing, allocate a new sector and store its
track/sector location in the list at this point
Go to B120.
B114 Read old data sector, using the track/sector found
in the T/S List entry.
B120 Save number of sector last read in workarea.
B12C Select data buffer.
Get byte offset and exit normally to caller.
B134-B15A Add a new data sector to file.
Allocate a sector (B244).
Put track/sector numbers in T/S List entry.
Select data buffer and zero it.
Set flags to indicate that the T/S List sector and
the data sector buffer require checkpoints.
Exit to caller.
B15B-B193 Increment record number and byte offset into file.
Copy current record number and byte offset to file
manager parameter list to pass back to caller.
Increment byte offset in workarea.
If byte offset equals record length, set byte offset
back to zero and increment record number.
Return to caller.
B194-B1A1 Increment file position offset.
Increment byte offset into current sector by one.
If at end of sector, increment sector number by one.
Return to caller.
B1A2-B1B4 Copy and advance range address.
Copy range address from file manager parmlist to $42.
Increment range address in parmlist for next time
Return to caller.
B1B5-B1C8 Decrement range length.
Decrement range length in file manager parmlist by
If zero, exit file manager.
Otherwise, exit to caller.
B1C9-B21B Locate or allocate a directory entry in the catalog.
Read the VTOC sector (AFF7).
Set $42,$43 to point to file name we are looking for.
Set pass number to one (locate file).
B1D8 Initialize directory sector offset (first sector).
B1E1 Increment sector offset.
Read directory sector.
If at end of directory, go to B23A.
Set entry index to first file entry.
B1EB Get track.
If deleted, skip entry, go to B217.
If empty, end of directory, go to B212.
Advance index to filename in directory.
Compare against filename wanted.
If they match, return entry index and exit.
If not, advance index to next entry in sector and
loop back to B1EB.
If at end of sector, go to B1E1 to get next sector.
B212 If pass number is one, go to B1D8 to start second
B217 If pass number is one, go to B20B to skip entry.
If second pass, fall through to allocate entry.
B21C-B22F Copy file name to directory entry.
Advance index to file name field in directory entry.
Copy 30 byte filename to directory entry.
Reload directory index and return to caller.
B230-B239 Advance index to next directory entry in sector.
Add 35 (length of entry) to index.
Test for end of sector and return to caller.
B23A-B243 Switch to second pass in directory scan.
If on pass one, switch to pass 2 and go to B1D8.
If on pass two, exit file manager with "DISK FULL"
B244-B2C2 Allocate a disk sector.
Is there a track currently allocated to this file?
If not, go to B26A to find a track with free sectors.
B249 Otherwise, decrement sector number to get next
possible free sector number.
If there are no more sectors on this track, go to
B265 to find a new track.
Otherwise, rotate the track bit mask by one position
and get the bit for this sector.
If the sector is in use, loop back to B249.
Otherwise, add one to file's sector count.
Pass back sector number (track number is at B5F1).
And return to caller.
B265 Indicate no track is being used at present.
B26A Reset allocation flag to allow at least one complete
search of all tracks for some space.
Read VTOC sector.
B272 Get last track allocated from and add direction value
to get next track to examine (+1 or -1).
Are we back to track 0?
If so, go to B284.
Otherwise, are we past track 34?
If so, reverse direction and go to B28E.
B284 Is this the second time we have come to track 0 ?
(check allocation flag).
If so, exit with "DISK FULL" error.
Otherwise, set allocation flag to remember this.
Set direction to forward (+1).
B28E Begin at directory track (17 + or - 1).
Compute bit map index (tracknumber*4).
Copy track bit map from VTOC to workarea, watching
to see if all four bytes are zero (track is full).
In any case, set all four bytes in VTOC to zero
(allocate all sectors).
If no free sectors in the track, go to B272 to try
next track.
Otherwise, write VTOC to disk to insure file's
Set sector number to last sector in track.
Go to B249 to allocate one of its free sectors to
the file.
B2C3-B2DC Release pre-allocated sectors in current track and
checkpoint the VTOC.
Has a track been allocated to the file?
If not, exit to caller.
Otherwise, read VTOC.
Get next sector which could have been used (number
of times track map was shifted during allocation).
Call B2DD to shift track bit map back and merge it
back into the VTOC bit map.
Indicate no track has been allocated.
Exit to caller.
B2DD-B2FF Free one or more sectors by shifting mask in file
manager's allocation area back into VTOC bit map.
(If CARRY is set, current sector is freed also)
Rotate entire 4 byte track bit mask once.
Repeat for as many sectors as were allocated.
Compute index into VTOC for this track's map.
If zero, exit.
Merge ("OR") file manager's bits with those already
in VTOC, freeing sectors which were never used by
the file.
Return to caller.
B300-B35E Calculate file position.
Set record number passed in file manager parmlist
in workarea and in sector offsets.
Clear sector offset high part.
Perform a 16 bit multiply as follows:
3 byte file position = record number times record
Add the byte offset from the parmlist into the three
byte file position value (B5E4,B5E5,B5E6).
Return to caller.
B35F-B37D Error exits.
B363 RC=2 "RANGE ERROR" (bad opcode)
B367 RC=3 "RANGE ERROR" (bad subcode)
B377 RC=9 "DISK FULL" (all files closed)
B37F-B396 Exit file manager.
B37F Exit with no errors.
Get return code of zero.
Clear carry flag and go to B386.
B385 Set carry flag to indicate error.
B386 Save return code in parmlist.
Clear monitor status register ($48) after RWTS has
probably tromped on it.
Save file manager workarea to file buffer (AE7E).
Restore processor status and stack register.
Exit to original caller of file manager.
B397-B3A3 File manager scratch space.
B397 Track/sector of current directory sector (2 bytes).
B39B S register save area.
B39C Directory index.
B39D Catalog line counter/Directory lookup flag/Etc.
B39E LOCK/UNLOCK mask/Allocation flag/Etc.
B3A0 Four byte mask used by INIT to free an entire track
in the VTOC bit map.
B3A4-B3A6 Decimal conversion table (1,10,100).
B3A7-B3AE File type name table used by CATALOG.
File types are: T,I,A,B,S,R,A,B, corresponding to
hex values: $00, $01, $02, $04, $08, $10, $20, and
$40 respectively.
B3AF-B3BA ASCII text "DISK VOLUME " backwards. Used by CATALOG.
B3BB-B4BA VTOC sector buffer.
B3BC Track/sector of first directory sector.
B3BE DOS release number (1, 2, or 3).
B3C1 Volume number of diskette.
B3E2 Number of entries in each T/S List sector.
B3EB Track to allocate next.
B3EC Direction of track allocation (+1 or -1)
B3EF Number of tracks on a disk.
B3F0 Number of sectors on a disk.
B3F1 Sector size in bytes (2 bytes)
B3F3 Track 0 bit map
B3F7 Track 1 bit map
B47B Track 34 bit map
B4BB-B5BA DIRECTORY sector buffer.
B4BC Track/sector of next directory sector.
B4C6 First directory entry and
Track of T/S List
B4C7 Sector of T/S List
B4C8 File type and lock bit
B4C9 Filename field (30 bytes)
B4E7 Size of file in sectors (including T/S List(s)).
B5BB-B5D0 File manager parameter list.
B5BB Opcode
B5BC Subcode
B5BD Eight bytes of variable parameters depending on
B5C5 Return code.
B5C7 Address of file manager workarea buffer.
B5C9 Address of T/S List sector buffer.
B5CB Address of data sector buffer.
B5CD Address of next DOS buffer on chain (not used).
B5D1-B5FD File manager workarea.
B5D1 1st T/S List sector's track/sector.
B5D3 Current T/S List sector's track/sector.
B5D5 Flags: 80=T/S List needs checkpoint
40=Data sector needs checkpoint
20=VTOC sector needs checkpoint
02=Last operation was write
B5D6 Current data sector's track/sector.
B5D8 Directory sector index for file entry.
B5D9 Index into directory sector to directory entry for
B5DA Number of sectors described by one T/S List.
B5DC Relative sector number of first sector in list.
B5DE Relative sector number +1 of last sector in list.
B5E0 Relative sector number of last sector read.
B5E2 Sector length in bytes.
B5E4 File position (3 bytes) sector offset, byte offset
into that sector.
B5E8 Record length from OPEN.
B5EA Record number.
B5EC Byte offset into record.
B5EE Number of sectors in file.
B5F0 Sector allocation area (6 bytes).
Next sector to allocate (shift count)
Track being allocated
Four byte bit map of track being allocated, rotated
to next sector to allocate.
B5F6 File type.
B5F7 Slot number times 16.
B5F8 Drive number.
B5F9 Volume number (complemented).
B5FA Track number.
B5FE-B5FF Not used.
B600-B6FF Start of Boot 2/RWTS image.
B600 Boot 1 image which can be written to INITed disks
on track 0, sector 0.
B65D DOS 3.3 patch area.
B65D APPEND patch flag.
B65E APPEND patch. Come here when file manager driver
gets an error other than end of data.
Locate and free the file buffer.
Clear the APPEND flag.
Get the error number and go print error (A6D2).
B671 APPEND patch. Come here from APPEND command handler
to increment record number if APPEND flag is set and
to clear the flag. Exit through POSITION.
B686 VERIFY patch. Come here from I/O a range of bytes
routine to exit through VERIFY after SAVE or BSAVE.
B692 APPEND patch. Come here from file manager driver if
return code was END OF DATA.
Test the file position for zero.
If non-zero, set APPEND flag on and return to caller.
If zero (at start of file), copy record number and
byte offset to file manager parmlist and return a
zero data byte to caller.
B6FE Page address of first page in Boot 2.
B6FF Number of sectors (pages) in Boot 2.
B700-B749 DOS 2nd stage boot loader.
Set RWTS parmlist to read DOS from disk.
Call Read/Write group of pages ($B793).
Create new stack.
Call SETVIC ($FE93) and SETKBD ($FE89).
Exit to DOS coldstart ($9D84).
B74A-B78C Put DOS on tracks 0-2.
Set RWTS parmlist to write DOS to disk.
Call Read/Write group of pages ($B793).
Exit to caller.
B78D-B792 Unused.
B793-B7B4 Read/Write a group of pages.
call RWTS through external entry point ($B7B5).
Exit to caller.
B7B5-B7C1 Disable interrupts and call RWTS.
B7C2-B7D5 Set RWTS parameters for writing DOS.
B7D6-B7DE Zero current buffer.
Zero 256 bytes pointed to by $42,$43.
Exit to caller.
B7DF-B7E7 DOS 2nd stage boot loader parmlist.
B7DF Unused.
B7E0 Number of pages in 2nd DOS load.
B7E1 Number of sectors to read/write.
B7E2 Number of pages in 1st DOS load.
B7E3 INIT DOS page counter.
B7E4 Pointer to RWTS parmlist (2 bytes).
B7E6 Pointer to 1st stage boot location (2 bytes).
B7E8-B7F8 RWTS parmlist.
B7E8 Table type. Must be $01.
B7E9 Slot number times 16.
B7EA Drive number ($01 or $02).
B7EB Volume number expected (0 matches any volume).
B7EC Track number ($00 to $22).
B7ED Sector number ($00 to $0F).
B7EE Pointer to Device Characteristics Table (2 bytes).
B7F0 Pointer to user data buffer for READ/WRITE (2 bytes).
B7F2 Unused.
B7F3 Byte count for partial sector (use $00 for 256).
B7F4 Command code: 0=SEEK, 1=READ, 2=WRITE, 4=FORMAT.
B7F5 Error code:(valid if carry set) $10=Write protect,
$20=Volume mismatch, $40=Drive error, $80=Read error.
B7F6 Volume number found.
B7F7 Slot number found.
B7F8 Drive number found.
B7F9-B7FA Unused.
B7FB-B7FE Device Characteristics Table (DCT).
B7FB Device type (should be $00).
B7FC Phases per track (should be $01).
B7FD Motor on time count (2 bytes - should be $EF, $D8).
B7FF Unused.
B800-B829 PRENIBBLE routine.
Converts 256 (8 bit) bytes to 342 (6 bit) "nibbles"
of the form 00XXXXXX.
Pointer to page to convert stored at $3E,$3F.
Data stored at primary and secondary buffers.
On entry: $3E,$3F contain pointer to user data.
On exit: A-reg:unknown
Carry set
Exit to caller.
B82A-B8B7 WRITE routine.
Writes prenibbilized data from primary and secondary
buffers to disk.
Calls Write a byte subroutine.
Writes 5 bytes autosync, starting data marks
($D5/$AA/$AD), 342 bytes data, one byte checksum, and
closing data marks ($DE/$AA/$EB).
Uses Write Translate Table ($ba29).
On entry: X-reg:Slot number times 16
On exit: Carry set if error
If no error:
Carry clear
Uses $26,$27,$678
Exit to caller.
B8B8-B8C1 Write a byte subroutine.
Timing critical code used to write bytes at 32 cycle
Exit to caller.
Converts 342 (6 bit) "nibbles" of the form 00XXXXXX
to 256 (8 bit) bytes.
Nibbles stored at primary and secondary buffers.
Pointer to data page stored at $3E,$3F.
On entry: X-reg:Slot number times 16
$36,$37:pointer to user data
$26:byte count in secondary buffer ($00)
On exit: A-reg:unknown
Y-reg:byte count in secondary buffer
Carry set
Exit to caller.
B8DC-B943 READ routine.
Read a sector of data from disk and store it at
primary and secondary buffers. (First uses secondary
buffer high to low, then primary low to high)
On entry: X-reg:Slot times 16
Read mode (Q6L,Q7L)
On exit: Carry set if error.
If no error:
Carry clear
Uses $26
Exit to caller.
B944-B99F RDADR routine.
Read an Address Field.
Reads starting address marks ($D5/$AA/$96), address
information (volume/track/sector/checksum), and
closing address marks ($DE/$AA).
On entry: X-reg:Slot number times 16
Read mode (Q6L,Q7L)
On exit: Carry set if error.
If no error:
Carry clear
$2F: Volume number found
$2E: Track number found
$2D: Sector number found
$2C: Checksum found
Uses $26,$27
Exit to caller.
B9A0-B9FC SEEKABS routine.
Move disk arm to desired track.
Calls arm move delay subroutine ($B9FD).
On entry: X-reg:Slot number times 16
A-reg:Desired track (halftrack for single
phase disk).
$478:Current track.
On exit: A-reg:unknown
$2A and $478:Final track
$27:Prior track (if seek needed)
Uses: $26,$27,$2A,$2B
Exit to caller.
B9FD-BA10 Arm move delay subroutine.
Delays a specified number of 100 Usec intervals.
On entry: A-reg:number of 100 Usec intervals.
$46,$47:Should contain motor on time count
($EF,$D8) from Device Characteristics Table
$478:Current track.
On exit: A-reg:$00
Carry set
Exit to caller.
BA11-BA28 Arm move delay table.
Contains values of 100 Usec intervals used during
Phase-on and Phase-off of stepper motor.
BA29-BA68 Write Translate Table.
Contains 6 bit "nibbles" used to convert 8 bit bytes.
Values range from $96 to $FF.
Codes with more than one pair of adjacent zeros or
with no adjacent ones are excluded.
BA69-BA95 Unused.
BA96-BAFF Read Translate Table.
Contains 8 bit bytes used to convert 6 bit "nibbles".
Values range from $96 to $FF.
Codes with more than one pair of adjacent zeros or
with no adjacent ones are excluded.
BB00-BBFF Primary Buffer.
BC00-BC55 Secondary Buffer.
BC56-BCC3 Write Address Field during initialization.
Calls Write double byte subroutine.
Writes number of autosync bytes contained in Y-reg,
starting address marks ($D5/$AA/$96), address
information (volume/track/sector/checksum), closing
address marks ($DE/$AA/$EB).
On entry: X-reg:Slot number times 16
Y-reg:number of autosync to write
$3E: $AA
$3F: sector number
$41: volume number
$44: track number
On exit: A-reg:unknown
Carry set
Exit to caller.
BCC4-BCDE Write double byte subroutine.
Timing critical code that encodes address information
into even and odd bits and writes it at 32 cycle
Exit to caller.
BD00-BD18 Main entry to RWTS.
Upon entry, store Y-reg and A-reg at $48,$49 as
pointers to the IOB.
Initialize maximum number of recals at 1 and seeks
at 4.
Check if the slot number has changed. If not,
branch to SAMESLOT at $BD34.
BD19-BD33 Update slot number in IOB and wait for old drive
to turn off.
Enter read mode and read with delays to see if disk
is spinning.
Save result of test and turn on motor just in case.
BD54-BD73 Move pointers in IOB to zero page for future use.
Device Characteristics Table pointer at $3C,$3D
and data buffer pointer at $3E,$3F.
Set up $47 (motor on time) with $D8 from DCT.
Check if the drive number has changed. If not,
branch to $BD74.
If so, change test results to show drive off.
BD74-BD8F Select appropriate drive and save drive being used
as high bit of $35. 1=drive 1, 0=drive 2.
Get test results. If drive was on, branch to $BD90.
Wait for capacitor to discharge using MSWAIT
subroutine at $BA00.
BD90-BDAA Get destination track and go to it using MYSEEK
subroutine at $BE5A.
Check test result again and if drive was on,
branch to TRYTRK at $BDAB.
Delay for motor to come up to speed.
Get command code.
If null, exit through ALLDONE at $BE46, turning drive
off and returning to caller.
If =4, branch to FORMDSK at $BE0D.
Otherwise, move low bit into carry (set=read,
clear=write) and save value on status reg.
If write operation, data is prenibbilized via a call
to PRENIB16 at $B800.
BDBC-BDEC Initialize maximum retries at 48 and read an
Address Field via RDADR16 at $B944.
If read was good, branch to RDRIGHT at $BDED.
If bad read, decrement retries, and, if still some
left try again. Else, prepare to recalibrate.
Decrement recal count. If no more, then indicate
drive error via DRVERR at $BE04.
Otherwise, reinitialize reseeks at 4 and recalibrate
arm. Move to desired track and try again.
Verify on correct track. If so branch to RTTRK
at $BE10.
If not, set correct track via SETTRK subroutine at
$BE95 and decrement reseek count.
If not zero then reseek track. If zero, then recal.
Clean up stack and status reg.
Load A-reg with $40 (drive error)
Goto HNDLERR at $BE48.
BE0B-BE0C Used to branch to ALLDONE at $BE46.
Jump to DSKFORM at $BEAF.
Check volume number found against volume number
If no volume was specified, then no error.
If specified volume doesn't match, load A-reg with
$20 (volume mismatch error) and exit via HNDLERR
at $BE48.
Check to see if sector is correct.
Use ILFAV table at $BFB8 for software sector
If wrong sector, try again by branching back to
If sector correct, find out what operation to do.
If write, branch to WRIT at $BE51.
Otherwise, read data via READ16 ($B8DC).
If read is good, then postnibble data via POSTNB16
($B8C2) and return to caller with no error.
Skip over set carry instruction in HNDLERR.
Set carry.
Store A-reg in IOB as return code.
Turn off motor.
Return to caller.
Write a sector using WRITE16 ($B82A).
If the write was good, exit via ALLDONE ($BE46).
If bad write, load A-reg with $10 (write protect
error) and exit via HNDLERR ($BE48).
Provides necessary housekeeping before going to
SEEKABS routine.
Determines number of phases per track and stores
track information in appropriate slot dependent
BE8E-BE94 XTOY routine.
Put slot in Y-reg by transferring X-reg divided
by 16 into Y-reg.
BE95-BEAE Set track number.
BEAF-BF0C INIT command handler
Provides setup for initializing a disk.
Get the desired volume number from the IOB.
Zero both the primary and secondary buffers.
Recalibrate the disk arm to track 0.
Set the number of sync bytes to be written between
sectors to $28 (40.).
Call TRACK WRITE routine for the actual formatting.
Allow 48 retries during initialization.
Double check that the first sector found is zero
after calling TRACK WRITE.
Increment the track number after successfully
formatting a track.
Loop back until 35 tracks are done.
BF0D-BF61 TRACK WRITE routine.
Start with sector zero.
Preceed it with 128 self-sync bytes.
Follow them with sectors 0 through 15 in sequence.
Set retry count for verifying the track at 48.
Fill the sector initilization map with positive
Loop through a delay period to bypass most of the
initial self-sync bytes.
Read the first Address Field found.
If the read is good and sector zero was found,
enter the VERIFY TRACK routine.
Decrement the sync count by 2 (until it reaches 16
at which time it is decremented by 1).
If sync count is greater than or equal to 5, exit
via $BF71.
If not, set carry and return to caller.
BF62-BF87 VERIFY TRACK routine.
This routine reads all 16 sectors from the track that
was just formatted.
If an error occurs during the read of either the
Address Field or the Data Field, the number of
retries is decremented.
The routine continues reading until retries is zero.
Calls Sector Map routine ($BF88).
BF88-BFA7 Sector Map routine.
This routine marks the sector initialization map as
each sector is verified.
If an error occurs, the routine exits through $BF6C,
which decrements the number of retries and continues
if that value is greater than zero.
Upon completion of track zero, the sync count is
decremented by two if it is at least 16.
BFA8-BFB7 Sector Initialization Map used to mark sectors as
they are initialized.
Contains a $30 prior to initialization of a track.
Value changed to $FF as each sector is completed.
BFB8-BFC7 Sector Translate Table
Sector interleaving done with software.
BFC8-BFD6 Patch area starts here.
Patch from $B741 to zero language card during boot.
Call SETVID ($FE93).
Unprotect Language Card (if present).
Store $00 at $E000.
Exit through SETKBD ($FE89) and DOS coldstart.
BFD9-BFDB Unused.
BFDC-BFE5 Patch called from $A0E2.
Set three additional defaults (Byte offset=0).
Return to caller.
BFE6-BFEC Patch called from $A6D5.
Call $A75B to reset state and set warmstart flag.
Mark RUN not interrupted.
Return to caller.
BFED-BFFF Patch called from $B377.
Call $AE7E to save file manager workarea.
Restore stack.
Close all open files ($A316).
Save stack again.
Exit through $B385 ("DISK FULL ERROR").
24 Cursor horizontal (DOS)
26,27 Sector read buffer address (ROM)
Scratch space (RWTS)
2A Segment merge counter (ROM,BOOT)
Scratch space (RWTS)
2B BOOT slot*16 (ROM)
Scratch space (RWTS)
2C Checksum from sector header (RWTS)
2D Sector number from sector header (RWTS)
2E Track number from sector header (RWTS)
2F Volume number from sector header (RWTS)
33 Prompt character (DOS)
35 Drive number in high bit (RWTS)
3C Workbyte (ROM)
Merge workbyte (BOOT)
Device characteristics table address (RWTS)
3D Sector number (ROM)
Device characteristics table address (RWTS)
3E,3F Address of ROM sector-read subroutine (BOOT)
Buffer address (RWTS)
40,41 DOS image address (BOOT)
File buffer address (DOS)
41 Format track counter (RWTS)
42,43 Buffer address (DOS)
44,45 Numeric operand (DOS)
46,47 Scratch space (RWTS)
48,49 IOB address (RWTS)
Format diskette workspace (RWTS)
76 APPLESOFT BASIC line number high (DOS)
D8,D9 INTEGER BASIC line number (DOS)