Pro A system program is simply an assembly-language program, requiring the resources of GS/OS or ProDOS 8, that communicates directly with users. It is generally a primary application like a word processor, spreadsheet, or telecommunications program or a programming environment for languages like C, BASIC, or Pascal. Under ProDOS 8, a system program takes control of the entire Apple II memory space, except for the portion ProDOS 8 uses, and is responsible for managing it properly. This space includes the 64K main memory bank in all Apple IIs and the 64K auxiliary memory bank in a IIc, IIcs, or lIe with an extended 80-column text card. Under GS/OS, a system program must use the 1Ics Memory Manager to allocate blocks of memory it may need. Since the Memory Manager allocates only blocks that are not in use, the system program will peacefully co-exist with other programs that may be in memory at the same time. The operating system identifies a system program by inspecting its file type code. A ProDOS 8 system program has a file type code of $FF and a directory mnemonic of SYS. A GS/OS system program has a file type code of $B3 and a directory mnemonic of 516. But assigning a file type code of $B3 or $FF to a program file is not enough to convert it to a true system program. As we see, a system program must also follow certain software conventions and take care not to interfere with memory areas used by the operating system or other co-resident programs. In this chapter, we review the features of well-designed GS/OS and ProDOS 8 system programs. We then examine one very common, and very important, ProDOS 8 system program, BASIC.SYSTEM. The discussion of BASIC.SYSTEM is quite de- tailed: We see how it installs itself in the system, how it calls ProDOS 8 commands, how its command set can be extended, and how it handles errors. We also take a close look at the global page it uses to manage the communication between ProDOS 8 and Applesofi programs. The analysis of BASIC.SYSTEM should assist you in creating your own ProDOS 8 system programs. 219 THE STRUCTURE OF A GS/OS SYSTEM PROGItAM To be considered a true GS/OS system program, a program must possess four - properties. 1. The executable code for the program must be in 65816/6502 assembly' and it must be stored to disk as a load file in Apple's object module format This is not to say you cannot use a high-level language like C, Pascal, or r: a create a system program. You can as long as the language compiler creates assembly-language object code. The Apple Programmer's Workshop linker care of creating load files for you, as does the linker for Merlin 8/16. 2. The program must have a file type code of $B3. You can use the Apple mer's Workshop FILETYPE command to set the file type after compiling linking an application. By assigning the $B3 file type code, you can execute programs directly from the Apple Itcs Finder. 3. The program must use the IIcs toolbox's Memory Manager tool set to allocate blocks of memory it may need. By using the Memory Manager, the program avoid overwriting memory areas used by other co-resident programs, such as accessories, printer drivers, or interrupt handlers. 4. The program must end using the GS/OS Quit command. It can use the command to return to the system program that called it (usually the Finder) or call another system program as if it were a subroutine, regaining control when other system program ends. (See Chapter 4 for a discussion of the Quit command.) In general, you can assign any valid name to a system program. If you want to create a disk that automatically boots and rnns the system program, you should assign it a name that ends in .SYS16, place the program file in the root directory of the disk, and delete the START program from the SYSTE M/ subdirectory. Alternatively, you can name the system program START and put it in the SYSTEM/ subdirectory. Entry Conditions GS/OS launches a system program by first loading it into memory using the System Loader tool set's InitialLoad function. It then uses the Memory Manager to allocate a direct page/stack space for use by the system program. The size of the direct page/stack space depends on whether the program includes a direct page/stack object segment. If it doesn't (the usual case for most applications you re likely to develop), GS/OS uses the Memory Manager's NewHandle function to allocate a 4096-byte space in bank $00, which begins on a page boundary. (The other important Memory Manager attributes of the block are: locked, fixed, purge level 1, may use special memory, and no fixed starting address.) 220 System Programs If the program file does include a direct page/stack object segment, GS/OS allo- cates a direct page/stack space that is the same size as the object segment. (See Chapter 7 of the Apple II&s Programmer's Workshop Reference for how to create a direct page/stack object segment.) In either situation, GS/OS sets the A (accumulator), D (direct page), and SP (stack pointer) registers to the following values before passing control to the program: A = the User ID the System Loader assigns to the program. D = the address of the first byte in the direct page/stack space. SP = the address of the last byte in the direct page/stack space. Note that the stack occupies the upper end of the direct page/stack space. Since the stack grows downward in memory, it may eventually collide with the portion of the space used for direct page storage. It is the responsibility of the application to ensure it allocates enough direct page/stack space to prevent such a collision. The direct page/stack space that the System Loader automatically sets up is made purgeable when the system program ends by calling the Quit command. This means the application does not have to explicitly release this memory with the DisposeHandle function before ending. Your system program can also allocate a direct page/stack space on the fly at execution time. To do this, it should first call DisposeHandle to free up the space the System Loader allocates. Use FindHandle to determine the handle to this space; the high word of the long address that FindHandle requires is $0000; the low word is the value stored in the D or SP register. Here is a piece of code that will do the trick: PHA Space for result (long) PHA PEA $0000 High word of addr is always zero PHD ;Low word of addr in dp/stack space FindHandle ;(leave handle on stack) DisposeHandle The program must then use NewHandle to allocate the direct page/stack space it requires (the Memory Manager attributes for this space should be as described earlier in this section), and then put the starting address of the block in the D register and the ending address in the SP register. Here is a subroutine that performs these chores (UserID is a variable that holds the program's master user ID): DP_Hndl GEQU $00 PHA PHA PushLong #$8O0 PushWord UserID ;(Assume $00 is free) Space for result ;2K space ;Use program's user ID The Structure of a GS/OS System Program 221 PushWord #$C105 ;Attributes PushLong #$O0O0OO00 ;(Any bank $00 address) NewHandle PLA ;Pop handle STA DP Hndl PLA STA DP Hndl+2 LDA [DP_Hndl] ;Get absolute address TCD Set up new direct page CLC ;Calculate address of ADC #$800 ;the last byte in space DEC A TAX TXS Set up new stack ptr RTS Note that the user ID for the direct page/stack memory block should be set to the system program's master user ID so that the block will be automatically discarded when the system program ends. The master user ID is in the A register when the system program starts up; the Memory Manager's MMStartup function returns the same value. THE STRUCTURE OF A PRODOS 8 SYSTEM PROGRAM A properly designed ProDOS 8 system program is an executable assembly-language program adhering to certain conventions and protocols that relate to its internal structure and the way it takes control of the system. First, a system program must be designed to be loaded and executed beginning at location $2000 in main memory although it can later relocate itself anywhere else in memory not used by ProDOS 8 or system Monitor routines. The load address of $2000 is mandatory. You can use the BASIC.SYSTEM - (dash) command to execute a system program. It is also possible to automatically execute a system program when ProDOS 8 first starts up by giving the program a name of the form xxxxxxxx.SYSTEM and ensuring it is the first entry in the volume directory with such a name. Some system programs follow an optional auto-run protocol that allows a ProDOS 8 selector program to pass the name of a file to them. (Recall from Chapter 4 that a selector program gets control when an application calls the QUIT command.) The standard ProDOS 8 selector program does not allow for filename passing, but many independent selectors, such as ProSel and RunRun, do. The description of the QUIT command in Chapter 4 includes instructions on how to write your own selector. The auto-run protocol is quite simple. If the first byte of the system program ($2000) is $4C (a JMP opcode) and the fourth and fifth bytes ($2003 and $2004) are both $EE, the sixth byte ($2005) holds the size of a buffer that begins at the very next 222 System Programs byte. This buffer begins with a name length byte and is followed by the standard ASCII codes for the characters in the name of a file the system file is to work with when it first starts up. (A system program file usually has a default filename stored here.) Thus if the selector program detects the presence of the three identification bytes, it could prompt the user to enter the name of a data file, load the system program, store the length and name of the data file beginning at $2006, and then execute the system program by jumping to $2000. The BASIC.SYSTEM system program adheres to the auto-run protocol. Here is what the first part of that program looks like: JMP START1 DFB $EE DFB $EE DFB $41 DFB $07 ASC 'STARTUP' START1 Must be a JMP instruction Identification byte 1 Identification byte 2 Size of following buffer Length of filename Name of auto-run file Main program entry point As you can see, BASIC.SYSTEM defines a default auto-run file called STARTUP. This is the name of the Applesoft program BASIC.SYSTEM loads and runs whenever it starts up unless the selector passes a different name. The selector program ensures that when a system program gets control, its path- name or partial pathname is stored at $281; location $280 contains the length of the name. This permits the system program to deduce the precise directory it is located in. This is helpful for loading subsidiary programs or data files located in the same directory as the system program itself. Often, a system program defines an interpretive programming environment in which application programs can be written and executed. (BASIC.SYSTEM is the best example of such a program.) In this case, the code for the interpreter should be tucked away in a safe place that will not conflict with memory areas the application program can use. The best position for the code is in a contiguous block at the upper end of main RAM memory, just below the ProDOS 8 global page at $BF00; this leaves the space from $800 to the start of the code free for use as a work area. The system program can protect the code space by setting to 1 those bits in the system bit map corresponding to the pages in use. If this is done, the ProDOS 8 command interpreter will not allow these areas to be inadvertently used as file buffers or 1/0 buffers. (See Chapter 3 for a discussion of the system bit map.) When a system program first gets control, it should perform several preliminary housekeeping chores. z Initialize the microprocessor stack pointer. To ensure the maximum amount of stack space is available to the system program, the stack pointer should be The Structure of a ProDOS 8 System Program 223 set to the bottom of the stack. This can be done with the following two - structions: LDX #$FF TXS You should ensure that no more than three quarters of the stack is used at given time. z Initialize the reset vector. When reset is pressed on an Apple II, ultimately passes to the subroutine whose address is stored in the reset - at SOFTEV ($3F2-$3F3) but only if the number stored at PWREDUP ($3F4) the same as the number generated by logically exclusive-ORing the number stored at SOFTEV + 1 with the constant $A5. If PWREDUP is not set up properly, the system reboots when reset is pressed. To point the reset vector to a subroutine called RTBAP within the system program and fix up PWREDUP, execute the following code: LDA #RTRAP ;Address high STA SOFTEV+1 ;$3F3 EOR #$AS ;twiddle the bits STA PWREDUP ;$3F4 A general-purpose RTBAP subroutine should close all open files and then jump to the cold start entry point of the system program. It is not safe to do anything else because it is impossible for the reset subroutine to determine the state of the system just before the reset condition becomes active. z Initialize the version numbers in the ProDOS 8 global page. IBAKVER ($BFFC) must be set equal to the earliest version of ProDOS 8 the system program will work with; store a 0 here if any version will do. 1VERSION ($BFFD) must be set equal to the version number of the system program being used. When these chores have been completed, the system program can begin its main duties. If the system program adheres to the auto-run protocol, it must start working with the file whose name (preceded by a length byte) is stored beginning at $2005. The system program is then free to do almost anything it wants as long as it does not overwrite the ProDOS 8 system global page (page $BF) or data areas in other pages used by ProDOS 8 or system Monitor subroutines the system program might call. (See Chapter 3 for a discussion of ProDOS 8 memory usage.) If a system program wants to create special classes of files, it can use any of the user-definable file type codes, $F1-$F8. All other codes are reserved. (See Table 2-5 in Chapter 2 for a description of the file type codes ProDOS uses for standard data files.) When a system program creates a file, it can use the 2-byte auxiliary type code in its directory entry (at relative bytes $1F and $20; see Chapter 2) to hold miscellaneous 224 System Programs information about the file. This code is saved to disk when you first create the file with the CREATE command; you can change it with the SET FILE - INFO command. Here is the meaning of the auxiliary type code for each type of file BASIC. SYSTEM uses: BIN default loading address TXT record length (0 for sequential files) BAS default loading address (usually $0801) VAR starting address of a block of variables When the time comes for the system program to quit, the system program should first scramble the PWREDUP byte by decrementing it; this causes the system to reboot if reset is pressed. It should then close all open files and reconnect /RAM if it was earlier disconnected. (See Chapter 7 for instructions on how to do this.) Finally, it should pass control to another system program with the QUIT command. As we saw in Chapter 4, this causes the standard ProDOS 8 selector program to be executed. Here is what the code will look like: [close all open files] [restore /RAM] DEC $3F4 JSR $BF00 DFB $65 DA PARMTBL BCS ERROR BRK PARMTBL DFB 4 DFB 0 DA 0 DFB 0 DA 0 Scramble PWREDUP byte ;Call the MLI ;QUIT ;(shouldn't get here) ;4 parameters The selector code is responsible for passing control to another system program in an orderly manner. The standard ProDOS 8 selector asks you to enter the prefix and pathname of the next system program to be loaded and executed. If your ProDOS 8 application is running on a Ilcs, and the bootup operating system was GS/OS, you can also use QUIT to transfer control directly to another ProDOS 8 or GS/OS system program. (See the discussion of the QUIT command in Chapter 4 for how to do this.) THE BASIC.SYSTEM INTERPRETER The BASIC.SYSTEM interpreter is probably the most commonly used ProDOS 8 system program. It is the program loaded whenever an Applesoft programming The BASIC. SYSTEM Interpreter 225 environment is going to be used; it extends the Applesoft command set by ~ group of 32 disk commands an Applesoft program can use. BASIC.SYSTEM itself by storing the addresses of its internal character input and output subrou the system Monitor's input link (KSW: $38-$39) and output link (CSW: (The subroutines whose addresses are stored in these links are called 1 character input or output operation is to be performed.) The BASIC.SYSTEM input subroutine normally reads input from the current device (usually the keyboard) and will identify and execute any valid disk c - entered while the system is in Applesoft command mode. But if a file has pre - been opened for read operations, it gets its input from the file instead. Similarly, the BASIC.SYSTEM output subroutine normally sends output to the output device (usually the video screen) unless a file has been opened to receive output instead. It is also always on the lookout for argnments of PRINT statements begin with a [Control-D] code; such argnments are assumed to be BASIC.SYSTEM commands, and BASIC.SYSTEM tries to interpret them as such. The output "L= can spot these PRINT statements because BASIC.SYSTEM always operates with sofi trace mode on; this means line numbers will be sent to the output subroutine the line is actually executed, giving BASIC. SYSTEM a chance to check any PRINT ments on that line. (By the way, the line numbers generated in trace mode are not played by BASIC.SYSTEM unless the Applesofi TRACE command has been Fignre 5-1 shows a BASIC.SYSTEM memory map. When BASIC.SYSTEM is loaded, it relocates its command interpreter to the high end of main RAM memory $9A0~$BEFF &ust below the ProDOS 8 system global page), reserves a 1K purpose file buffer from $9600 to $99FF, and then sets the Applesofi HIMEM pointer $7~$74 to $9600. (H1MEM represents the upper limit for storage of Applesofi string variables.) This leaves the space from $0800 to $95FF free for Applesofi program ~ variable storage. BASIC.SYSTEM also uses the area between $3D0 and $3EC for storage of position-independent vectors to some of its internal subroutines. We examine how BASIC.SYSTEM uses page three in more detail later in this chapter. The BASIC.SYSTEM interpreter, becausc of its intimate connection to the Apple- soft ROM interpreter, can also be said to use all those RAM areas used by Applesofi itself. This includes the input buffer at $200-$2FF (BASIC.SYSTEM also uses most of this page as a temporary data buffer when it executes certain disk commands), the microprocessor stack at $10~$1FF, and several locations in zero page. (See Chapter 4 of Inside the Apple lIe for a detailed description of how Applesoft uses these areas.) Other areas, such as the video RAM area from $400 to $7FF and the system vector area from $3ED to $3FF, are also reserved for use in a BASIC.SYSTEM environment. The BAS1C.SYSTEM Commands Most of the BASIC.SYSTEM disk commands provide convenient access to files for 1/0 operations (OPEN, READ, POSITION, WRITE, APPEND, FLUSH, and CLOSE), general file management (CAT, CATALOG, CREATE, DELETE, LOCK, PREFIX, 226 System Programs FigureS-I BASIC. SYSTEM memory map $BFFF ~EFOOOC HIMEM $9600 $0800 $0400 0300 0200 0100 0000 (ProDOS 8 global page) BASIC.$YSTEM global page ~ BAS1C.SYSTEM interpreter ~ General-purpose file buffer (moves clown by $400 bytes 'v'nen a file is opened; moves up v'1ien a file is closed.) Applesoft program and variable space Video RAM ~ $3D0..$3EC used for vectors Input buffer + data area 6~02 stack (Much of zero page used) RENAME, UNLOCK, and VERIFY), or program file loading and execution (-, BLOAD, BRUN, BSAVE, EXEC, LOAD, RUN, and SAVE). There are also com- mands for effecting 1/0 redirection (IN# and PR#), to perform garbage collection of Applesofi string variables (FRE), to save and load Applesoft variables to and from files (STORE and RESTORE), to transfer control from one Applesoft program to another without destroying existing variables (CHAIN), and to disconnect BASIC.SYSTEM and run another ProDOS 8 system program (BYE). One command (NOMON) is allowed but does nothing; it is included to maintain compatability with programs running under DOS 3.3 that use NOMON to disable the display of disk commands and 1/0 operations. To use a BASIC.SYSTEM command from within a program, you must use the PRINT statement to print a [Control-D] character, the BASIC.SYSTEM command, the command parameters, and then a carriage return. For example, to list all the files in the /RAM volume on an Apple IIc, you would execute a line that looks something like this: 100 PRINT CHR$(4);"CATALOG/RAM" The BASIC. SYSTEM Interpreter 227 In this example, the CHR$(4) statement generates the [Control-D] character, the SYSTEM command is CATALOG, and the command parameter is /RAM (a The required carriage return is automatically generated by the PRINT statement. If you're entering a BASIC.SYSTEM command directly from the keyboard in sofr command mode, you don't have to worry about the [Control-D]. All you have to type in the command followed by the command arguments. The keyboard equi\ the CATALOG command is simply CATALOG /RAM You should be aware, however, that BASIC.SYSTEM does not permit all its mands to be entered from the keyboard in this way. Most BASIC.SYSTEM commands support, or require, several parameters for _ ifying such things as the pathname for the file to be acted on, loading addresses, lengths. Table 5-1 gives brief descriptions of the 13 different parameters by BASIC.SYSTEM. The letter parameters shown in Table 5-1 (,A#, ,B#, and so on, where # 1 the value of a parameter) can be specified in any order by appending them to the of the command line. The snum and pathname parameters cannot appear in the command line. When one of these parameters is specified, it must be placed ately after the command name. The exception is the RENAME command, requires two pathnames; the second pathname must appear right after the first one. Note that most BASIC.SYSTEM commands may be entered with slot (,S#) and - (,D#) parameters that specif' the physical location of the disk to be accessed. It is not necessary to use these parameters if the pathname specified is a full pathname or if a prefix is active because BASIC.SYSTEM will automatically search all installed disk drives for the file. But if a filename or partial pathname is specified, and no prefix has yet been defined or either the ,S# or ,D# parameter is used, BASIC.SYSTEM automatically uses the name of the volume directory specified by the slot and drive parameters (or their de- fanlts) to create the full pathname. BASIC.SYSTEM's ability to use slot and drive param- eters allows Applesofi programs to maintain greater compatibility with a DOS 3.3 environ- ment where the slot and drive must be specified to access disks in the nondefault drive. Let's now take a quick look at each of the 32 BASIC.SYSTEM commands. Table 5-2 summarizes the command syntax for each of these commands. (See Apple's BASIC Programming with ProDOS for detailed information on these commands; see the bibliography in Appendix III.) These commands can be divided into four distinct categories: file management commands, file loading and execution commands, file input/output commands, and miscellaneous commands. File Management Commands CAT. This command displays a list of the names of the files on the disk. Only the names of the files in the directory specified in the pathname parameter following the 228 System Programs