P8 Tech Ref Appendix A - wiki.apple2.org

P8 Tech Ref Appendix A

Jump to: navigation, search

Appendix A - The ProDOS BASIC System Program

Page 117


This appendix explains aspects of the BASIC system program (BASIC.SYSTEM) that are beyond the scope of the manual BASIC Programming With ProDOS. The primary subjects discussed in this appendix are

  • how the BASIC system program uses memory
  • how a machine-language program can make calls to the BASIC system program
  • useful locations in the BASIC system program
  • how you can add commands to the BASIC system program.


A.1 - Memory Map

The arrangement of ProDOS in memory is decided when the system is started up, and it depends on your particular system configuration. Figure A-1 shows the memory organization for an Apple IIe (64K or 128K) or Apple IIc (128K).

Page 118


Figure A-1. Memory Map

             Main Memory                                 Auxiliary Memory
                                                      (IIc or 128K IIe only)

$FFFF+---------+$FFFF+---------+                $FFFF+---------+
     |.Monitor.|     |#########|                     |.........|
$F800|---------|     |#########|                     |.........|
     |.........|     |#########|                     |.........|
     |.........|     |#########|                     |.........|
     |.........|     |#########|                     |.........|
     |.........|     |#########|                     |.........|
     |.........|     |#########|                     |.........|
     |.........|     |#ProDOS##|                     |.........|
     |Applesoft|     |#########|$DFFF+---------+$E000|---------|$DFFF+---------+
     |.........|     |#########|     |.........|     |         |     |.........|
     |.........|     |#########|     |.........|     |         |     |.........|
     |.........|     |#########|$D400|---------|     |         |     |.........|
     |.........|     |#########|     |#########|     |         |     |.........|
     |.........|     |#########|$D100|---------|     |         |$D100|---------|
     |.........|     |#########|     |         |     |         |     |         |
$D000|---------|     +---------+     +---------+$D000+---------+     +---------+
     |..Other..|
$C100+---------+
             ^  $BFFF+---------+                $BFFF+---------+
             |       |#########|                     |.........|
This ROM area|  $BF00|---------|                $BF00|---------|
on IIc and IIe       |\\\\\\\\\|                     |         |
only!                |\\\\\\\\\|                     |         |     +---------+
                     |\\\\\\\\\|                     |         |     |#########|
                     |\\\\\\\\\|                     |         |     +---------+
                     |\\\\\\\\\|                     |         |     Used by ProDOS
                     |\BASIC.\\|                     |         |
                     |\SYSTEM\\|                     |         |
                     |\\\\\\\\\|                     |         |     +---------+
                     |\\\\\\\\\|                     |         |     |\\\\\\\\\|
                     |\\\\\\\\\|                     |         |     +---------+
                     |\\\\\\\\\|                     |         |     Used by
                     |\\\\\\\\\|                     |         |     BASIC.SYSTEM
                $9600|---------|                     |         |
                     |         |                     |         |
                     |         |                     |         |     +---------+
                     |         |                     |         |     |.........|
                     |         |                     |         |     +---------+
                     |         |                     |         |     Other used or
                     |         |                     |         |     reserved areas
                     |         |                     |         |
                     |         |                     |         |
                     |         |                     |         |     +---------+
                     |         |                     |         |     |         |
                     |         |                     |         |     +---------+
                     |         |                     |         |      Free Space
                     |         |                     |         |
                     /\/\/\/\/\/                     /\/\/\/\/\/

                     /\/\/\/\/\/                     /\/\/\/\/\/
                     |         |                     |         |
                     |         |                     |         |
                     |         |                     |         |
                     |         |                     |         |
                     |         |                     |         |
                 $800|---------|                 $800|---------|
                     |.........|                     |.........|
                     |.........|                     |.........|
                     |.........|                     |.........|
                     |.........|                 $400|---------|
                     |.........|                     |#########|
                 $300|---------|                     |#########|
                     |         |                     |#########|
                 $300|---------|                     |#########|
                     |.........|                 $200|---------|
                     |.........|                     |         |
                 $100|---------|                 $100|---------|
                     |         |                     |#########|
                     |         |                  $80|---------|
                  $4F|---------|                     |         |
                     |#Shared/#|                     |         |
                     |####safe#|                     |         |
                  $3A|---------|                     |         |
                     |         |                     |         |
                     +---------+                     +---------+
                  $00

Page 119


HIMEM

When ProDOS starts up the BASIC system program, it loads all the necessary programs and data into memory as shown in Figure A-1, leaves a 1K buffer on the highest available 1K boundary, and then sets HIMEM right below this buffer. This buffer is used as the file buffer for commands, such as CATALOG, that only need a temporary buffer.

Table A-1 shows the possible settings of HIMEM, and the maximum number of bytes available to a program running under such a system configuration.

Table A-1. HIMEM and Program Workspace

System                                          Bytes Available
Configuration           HIMEM                   to Programs

64K                     38400 ($9600)           36352 ($8E00)
Applesoft in ROM

These settings are in effect immediately after you boot the BASIC system program. While a program is running, however, these figures may change. Each time a file is opened, ProDOS lowers HIMEM by 1K ($400), keeping the 1K temporary command buffer immediately above it, and places a buffer for the file where the old temporary buffer was. When a file is closed, ProDOS releases the file's buffer, and raises HIMEM by 1K. Figure A-2 illustrates this process.

Page 120


Figure A-2. The Movement of HIMEM

 _______      _______      _______      _______      _______      _______
|       |    |       |    |       |    |       |    |       |    |       |
|       |    |       |    |       |    |       |    |       |    |       |
|       |    |       |    |       |    |       |    |       |    |       |
|       |    |       |    |       |    |       |    |       |    |       |
|_______|    |_______|    |_______|    |_______|    |_______|    |_______|
|       |    |///////|    |       |    |       |    |       |    |       |
| Free  | 1K |/CAT's/| 1K | Free  | 1K | DOG's | 1K | DOG's | 1K | Free  | 1K
|_______|    |_______|    |_______|    |_______|    |_______|    |_______|
|       |    |       |    |       |    |       |    |       |    |       |
| HIMEM |    | HIMEM |    | HIMEM |    | Free  | 1K | CAT's | 1K | HIMEM |
|       |    |       |    |       |    |_______|    |_______|    |       |
|       |    |       |    |       |    |       |    |       |    |       |
|       |    |       |    |       |    | HIMEM |    | HIMEM |    |       |
|       |    |       |    |       |    |       |    |       |    |       |
|       |    |       |    |       |    |       |    |       |    |       |
|       |    |       |    |       |    |       |    |       |    |       |
|       |    |       |    |       |    |       |    |       |    |       |
|       |    |       |    |       |    |       |    |       |    |       |
|_______|    |_______|    |_______|    |_______|    |_______|    |_______|
No Files     During CAT   After CAT    Open "DOG"   During CAT   Close "DOG"
  Open
  
  

Buffer Management

There are many times when you might want machine-language routines to coexist with ProDOS; for example, when using interrupt-driven devices, when using input/output devices that have no ROM, or when using commands that you have added to ProDOS.

BASIC.SYSTEM provides buffer management for file I/O. Those facilities can also be utilized from machine-language modules operating in the ProDOS/Applesoft environment to provide protected areas for code, data, and so on.

BASIC.SYSTEM resides from $9A00 upward, with a general-purpose buffer from $9600 (HIMEM) to $99FF. When a file is opened, BASIC.SYSTEM does garbage collection if needed, moves the general-purpose buffer down to $9200, and installs a file I/O buffer at $9600. When a second file is opened, the general-purpose buffer is moved down to $8E00 and a second file I/O buffer is installed at $9200. If an EXEC file is opened, it is always installed as the highest file I/O buffer at $9600, and all the other buffers are moved down.

Additional regular file I/O buffers are installed by moving the general-purpose buffer down and installing it below the lowest file I/O buffer. All file I/O buffers, including the general-purpose buffer, are 1K (1024 bytes) and begin on a page boundary.

Page 121


BASIC.SYSTEM may be called from machine language to allocate any number of pages (256 bytes) as a buffer, located above HIMEM and protected from Applesoft BASIC programs. The ProDOS bit map is not altered, so that files can be loaded into the area without an error from the ProDOS Kernel. If you subsequently alter the bit map to protect the area, you must mark the area as free when you are finished -- BASIC.SYSTEM will not do it for you.

To allocate a buffer, simply place the number of desired pages in the accumulator and use JSR GETBUFR ($BEF5). If the carry flag returns clear, the allocation was successful and the accumulator will return the high byte of the buffer address. If the carry flag returns set, an error has occurred and the accumulator will return the error code.

Note that the X and Y registers are not preserved. The first buffer is installed as the highest buffer, just below BASIC.SYSTEM from $99FF downward, regardless of the number and type of file I/O buffers that are open. If a second allocation is requested, it is installed immediately below the first. Thus, it is possible to assemble code to run at known addresses-relocatable modules are not needed.

To de-allocate the buffers created by the above call and move the file buffers back up, just use JSR FREEBUFR ($BEF8). Although more than one buffer may be allocated by this call, they may not be selectively de-allocated.

Important!

All routines that are to be called by BASIC.SYSTEM should begin with the CLD instruction. This includes I/O routines accessed by PR# and IN# and clock/calendar routines. This allows ProDOS to spot accidental calls.

For tips on raising LOMEM to provide more memory for assembly-language routines, and protecting high-res graphics pages, see the Applesoft BASIC Programmer's Reference Manual.

Page 122


The BASIC Global Page

The BASIC system program has a specific area of memory, its global page, in which it keeps its current status. This page lies in the address range $BE00 through $BEFF (48640-48895). When BASIC.SYSTEM is active, its fields are defined as follows:

BE00:  CI.ENTRY  JMP WARMDOS     ;Reenter ProDOS/Applesoft
BE03:  DOSCMD    JMP SYNTAX      ;External entry for command string
BE06:  EXTRNCMD  JMP XRETURN     ;Called for added CMD syntaxing
BE09:  ERROUT    JMP ERROR       ;Handles ONERR or prints error
BE0C:  PRINTERR  JMP PRTERR      ;Prints error message
                                 ;Number is in accumulator
BE0F:  ERRCODE   DFB 0           ;ProDOS error code stored here
                                 ;and $DE for Applesoft

Page 123


Default I/O vectors. These may be changed by the user to remap slots for nondisk devices. When the system is booted, all slots not containing a ROM are considered not connected and the default vector is left to point at the appropriate error handling routine.

BE10:  OUTVECT0  DW  COUT1       ;Monitor video output routine
BE12:  OUTVECT1  DW  NODEVERR    ;Default $C100 when ROM present
BE14:  OUTVECT2  DW  NODEVERR    ;Default $C200 when ROM present
BE16:  OUTVECT3  DW  NODEVERR    ;Default $C300 when ROM present
BE18:  OUTVECT4  DW  NODEVERR    ;Default $C400 when ROM present
BE1A:  OUTVECT5  DW  NODEVERR    ;Default $C500 when ROM present
BE1C:  OUTVECT6  DW  NODEVERR    ;Default $C600 when ROM present
BE1E:  OUTVECT7  DW  NODEVERR    ;Default $C700 when ROM present
BE20:  INVECT0   DW  CHIN1       ;Monitor keyboard input routine
BE22:  INVECT1   DW  NODEVERR    ;Default $C100 when ROM present
BE24:  INVECT2   DW  NODEVERR    ;Default $C200 when ROM present
BE26:  INVECT3   DW  NODEVERR    ;Default $C300 when ROM present
BE28:  INVECT4   DW  NODEVERR    ;Default $C400 when ROM present
BE2A:  INVECT5   DW  NODEVERR    ;Default $C500 when ROM present
BE2C:  INVECT6   DW  NODEVERR    ;Default $C600 when ROM present
BE2E:  INVECT7   DW  NODEVERR    ;Default $C700 when ROM present
BE30:  VECTOUT   DW  COUT1       ;Current character output routine
BE32:  VECTIN    DW  CHIN1       ;Current character input routine
BE34:  VDOSIO    DW  DOSOUT      ;ProDOS char out intercept routine

Page 124


BE36:            DW  DOSINP      ;ProDOS char in intercept routine
BE38:  VSYSIO    DW  0,0         ;Internal redirection of I/O
BE3C:  DEFSLT    DFB $06         ;Default slot, set by 'S' parm
BE3D:  DEFDRV    DFB $01         ;Default drive, set by 'D' parm
BE3E:  PREGA     DFB 0           ;Register save area
BE3F:  PREGX     DFB 0
BE40:  PREGY     DFB 0
BE41:  DTRACE    DFB 0           ;Applesoft trace enable
BE42:  STATE     DFB 0           ;0=Imm, >0=Def modes
BE43:  EXACTV    DFB 0           ;EXEC file active if bit 7 on
BE44:  IFILACTV  DFB 0           ;Input file active if bit 7 on
BE45:  OFILACTV  DFB 0           ;Output file active if bit 7 on
BE46:  PFXACTV   DFB 0           ;Prefix input active if bit 7 on
BE47:  DIRFLG    DFB 0           ;File being accessed is directory
BE48:  EDIRFLG   DFB 0           ;End of directory encountered
BE49:  STRINGS   DFB 0           ;Counter for free string space
BE4A:  TBUFPTR   DFB 0           ;Temporory buffered char count (WRITE)
BE4B:  INPTR     DFB 0           ;Input char count during kbd input
BE4C:  CHRLAST   DFB 0           ;Last character output (for error detect)
BE4D:  OPENCNT   DFB $00         ;Number of open file (except EXEC file)
BE4E:  EXFILE    DFB $00         ;Flag to indicate EXEC file being closed
BE4F:  CATFLAG   DFB $00         ;File being input is (translated) dir
BE50:  XTRNADDR  DW  0           ;Execution address of external cmd (0)
BE52:  XLEN      DFB 0           ;Length of command string-1, ('HELP'=3)
BE53:  XCNUM     DFB 0           ;BASIC cmd number (external cmd if =0)

Page 125


Command parameter PBITS/FBITS bit definitions:

BE54:  PFIX      EQU $80         ;Prefix needs fetching, pathname optional
BE54:  SLOT      EQU $40         ;No parameters to be processed
BE54:  RRUN      EQU $20         ;Command only valid during program
BE54:  FNOPT     EQU $10         ;Filename is optional
BE54:  CRFLG     EQU $08         ;CREATE allowed
BE54:  T         EQU $04         ;File type
BE54:  FN2       EQU $02         ;Filename '2' for RENAME
BE54:  FN1       EQU $01         ;Filename expected

And for PBITS+1/FBITS+1 definitions:

BE54:  AD        EQU $80         ;Address
BE54:  B         EQU $40         ;Byte
BE54:  E         EQU $20         ;End address
BE54:  L         EQU $10         ;Length
BE54:  LINE      EQU $08         ;'@' line number
BE54:  SD        EQU $04         ;Slot and drive numbers
BE54:  F         EQU $02         ;Field
BE54:  R         EQU $01         ;Record
BE54:  V         EQU $00         ;Volume number ignored

When the BASIC system program recognizes one of its commands, it sets up PBITS to indicate which parameters (#S, #D, and so on) may be used with that command. Then it parses the command string, marking the found parameters in FBITS, and placing their values in locations $BE58-$BE6B. The meanings of the bit within PBITS and FBITS are discussed in the section "Adding Commands to the BASIC System Program."

BE54:  PBITS     DW  0           ;Allowed parameter bits
BE56:  FBITS     DW  0           ;Found parameter bits

Page 126


The following locations hold the values of the parameters for the BASIC commands. As the BASIC system program parses command options, it sets the value of the corresponding command parameters.

Previously set parameters do not change.

BE58:  PVALS     EQU *
BE58:  VADDR     DW  0           ;Parameter value for 'A' parm
BE5A:  VBYTE     DFB 0,0,0       ;Parameter value for 'B' parm
BE5D:  VENDA     DW  0           ;Parameter value for 'E' parm
BE5F:  VLNTH     DW  0           ;Parameter value for 'L' parm
BE61:  VSLOT     DFB 0           ;Parameter value for 'S' parm
BE62:  VDRIV     DFB 0           ;Parameter value for 'D' parm
BE63:  VFELD     DW  0           ;Parameter value for 'F' parm
BE65:  VRECD     DW  0           ;Parameter value for 'R' parm
BE67:  VVOLM     DFB 0           ;Parameter value for 'V' parm
BE68:  VLINE     DW  0           ;Parameter value for '@' parm
BE6A:  PTYPE     EQU *-PVALS
BE6A:  VTYPE     DFB 0           ;Parameter value for 'T' parm
BE6B:  PIOSLT    EQU *-PVALS
BE6B:  VIOSLT    DFB 0           ;Parameter value for IN# or PR#
BE6C:  VPATH1    DW  TXBUF-1     ;Pathname 1 buffer
BE6E:  VPATH2    DW  TXBUF2      ;Pathname 2 buffer (RENAME)

Page 127


GOSYSTEM is used to make all MLI calls since errors must be translated before returning to the calling routine. On entry the Accumulator should contain the call number. The address of the parameter table is looked up and set based on the call number. Only file management calls can be made using this routine: $C0-$D3. The original implementation of this BASIC system program contains only these calls.

BE70:  GOSYSTEM  STA SYSCALL     ;Save call number
BE73:            STX CALLX       ;Preserve X register
BE76:            AND #$1F        ;Strip high bits of call number
BE78:            TAX             ; and use as lookup index
BE79:            LDA SYSCTBL,X   ;Get low address of parm table
BE7C:            STA SYSPARM
BE7F:            LDX CALLX       ;Restore X before calling
BE82:            JSR MLIENTRY    ;Call ProDOS MLI to execute request
BE85:  SYSCALL   DFB 0
BE86:  SYSPARM   DW  *           ;(High address should be same
                                 ; as parameter tables)
BE88:            BCS BADCALL     ;Branch if error encountered
BE8A:            RTS

BADCALL converts MLI errors into BASIC system program error equivalents. Routines should be entered with error number in the Accumulator. The BADCALL routine should be used whenever a ProDOS MLI call returns an error and BASIC.SYSTEM will be used to print the error message. Returns BASIC system program error number in Accumulator. All unrecognized errors are mapped to I/O error.

X register is restored to its value before the call is made. Carry is set.

BE8B:  BADCALL   LDA #12         ;19 errors are mapped to
BE8D:  MLIERR1   CMP MLIERTBL,X  ; other than I/O error
BE90:            BEQ MLIERR2
BE92:            DEX
BE93:            BPL MLIERR1
BE95:            LDX #$13        ;If not recognized, make it I/O error
BE97:  MLIERR2   LDA BIERRTBL,X  ;return error in Accumulator
BE9A:            LDX CALLX       ;Restore X register
BE9D:            SEC             ;Set Carry to indicate error
BE9E:  XRETURN   RTS
BE9F:  CISPARE1  DFB $00

Page 128


The following are the system-call parameter tables. These tables must reside within the same page of memory. Only those parameters that are subject to alterations have been labeled. SYSCTBL below contains the low-order addresses of each parameter table. SYSCTBL is used by GOSYSTEM to set up the address of the parameter table for each call. (See GOSYSTEM.)

BEA0:  SCREATE   DFB $07
BEA1:            DW  TXBUF-1     ;Pointer to pathname
BEA3:  CRACESS   DFB $C3         ;$C1 if directory create
BEA4:  CRFILID   DFB $00
BEA5:  CRAUXID   DW  $0000
BEA7:  CRFKIND   DFB 0
BEA8:            DW  0           ;No predetermined date/time
BEAA:            DW  0
BEAC:  SSGPRFX   EQU *
BEAC:  SDSTROY   DFB $01
BEAD:            DW  TXBUF-1     ;This call requires no modifications
BEAF:  SRECNAME  DFB $02
BEB0:            DW  TXBUF-1     ;No modifications needed
BEB2:            DW  TXBUF2
BEB4:  SSGINFO   DFB $00         ;P.CNT=7 if SET_FILE_INFO
                                 ;P.CNT=A if GET_FILE_INFO
BEB5:            DW  TXBUF-1
BEB7:  FIACESS   DFB $00         ;Access used by lock/unlock
BEB8:  FIFILID   DFB $00         ;FILE ID is type specifier
BEB9:  FIAUXID   DW  $0000       ;Aux_id is used for load addr
                                 ; and record length
BEBB:  FIFKIND   DFB $00         ;Identifies trees vs. directories
BEBC:  FIBLOKS   DW  $0000       ;Used by CAT commands for root dir
BEBE:  FIMDATE   DW  $0000       ;Modification date & time
BEC0:            DW  $0000       ;should always be zeroed before call
BEC2:            DW  $0000       ;Create date and time ignored
BEC4:            DW  $0000

Page 129


BEC6:  SONLINE   EQU *
BEC6:  SSETMRK   EQU *
BEC6:  SGETMRK   EQU *
BEC6:  SSETEOF   EQU *
BEC6:  SGETEOF   EQU *
BEC6:  SSETBUF   EQU *
BEC6:  SGETBUF   EQU *
BEC6:            DFB $02         ;Parameter count
BEC7:  SBUFREF   EQU *
BEC7:  SREFNUM   EQU *
BEC7:  SUNITNUM  EQU *
BEC7:            DFB 0           ;Unit or reference number
BEC8:  SDATPTR   EQU *
BEC8:  SMARK     EQU *
BEC8:  SEOF      EQU *
BEC8:  SBUFADR   EQU *
BEC8:            DFB 0,0,0       ;Some calls only use 2 bytes
                                 ;MRK & EOF use 3 bytes
BECB:  SOPEN     DFB $03
BECC:            DW  TXBUF-1
BECE:  OSYSBUF   DW  $0000
BED0:  OREFNUM   DFB 0
BED1:  SNEWLIN   DFB $03
BED2:  NEWLREF   DFB $00         ;Reference number
BED3:  NLINEBL   DFB $7F         ;Newline character is always CR
BED4:            DFB $0D         ; both $0D and $8D are recognized
BED5:  SREAD     EQU *
BED5:  SWRITE    EQU *
BED5:            DFB $04
BED6:  RWREFNUM  DFB $00
BED7:  RWDATA    DW  $0000       ;Pointer to data to be read/written
BED9:  RWCOUNT   DW  $0000       ;Number of bytes to be read/written
BEDB:  RWTRANS   DW  $0000       ;returned # of bytes read/written

Page 130


BEDD:  SCLOSE    EQU *
BEDD:  SFLUSH    EQU *
BEDD:            DFB $01
BEDE:  CFREFNUM  DFB $00
BEDF:  CCCSPARE  DFB $00
BEE0:            ASC 'COPYRIGHT APPLE, 1983'
BEF5:  GETBUFR   JMP GETPAGES
BEF8:  FREBUFR   JMP FREPAGES
BEF8:  RSHIMEM   DFB 0, 0, 0, 0, 0


BASIC.SYSTEM Commands From Assembly Language

There are times when a routine wants to perform functions that are already implemented by the BASIC system program -- deleting and renaming files, displaying a directory, and so on. The DOSCMD vector serves just this function.

First a routine should place the desired BASIC command in the input buffer ($200). It should be an ASCII string with the high bits set, followed by a carriage return ($8D), exactly as the Monitor GETLN routine would leave a string. Next the routine should do a JSR to the DOSCMD entry point ($BE03).

BASIC.SYSTEM will parse the command, set up all the parameters, (as explained in Section A.3.3), and then execute the command. If there is an error, it will return the error code in the accumulator with the carry set. If it is 0, there was no error. Otherwise it contains a BASIC system program error number.

Note: The JSR DOSCMD must be executed in deferred mode (from a BASIC program), rather than in immediate mode. This applies also to the Monitor program: from the Monitor, you can't do a $xxxxG to execute the code that contains the JSR DOSCMD. This is because BASIC.SYSTEM checks certain state flags, which are set correctly only while in deferred mode.

There are certain commands that do not work as expected when initiated via DOSCMD: RUN -(dash command), LOAD, CHAIN, READ, WRITE, APPEND, and EXEC. Use them this way at your own risk.

Page 131


The commands that do work correctly are: CATALOG, CAT, PREFIX, CREATE, RENAME, DELETE, LOCK, UNLOCK, SAVE, STORE, RESTORE, PR#, IN#, FRE, OPEN, CLOSE, FLUSH, POSITION, BRUN, BLOAD, and BSAVE.

The following are: 1. An example of a BASIC program that uses the BLOAD command to load an assembly-language routine that exercises the DOSCMD routine.

2. A listing of that assembly-language routine. 3. You should review them before writing your own routine.

10 REM YOU MUST CALL THE ROUTINE FROM INSIDE A BASIC PROGRAM
11 REM
12 REM
20 PRINT CHR$(4)"BLOAD/P/PROGRAMS/CMD.0"
30 CALL 4096
40 PRINT "BACK TO THE WONDERFUL WORLD OF BASIC!"
50 END

Page 132


1000:        1000    1           ORG   $1000
1000:        FD6F    2 GETLN1    EQU   $FD6F         ; MONITORS INPUT ROUTINE
1000:        BE03    3 DOSCMD    EQU   $BE03         ; BASIC.SYSTEM GLBL PG DOS CMD ENTRY
1000:        FDED    4 COUT      EQU   $FDED         ; MONITORS CHAR OUT ROUTINE
1000:        BE0C    5 PRERR     EQU   $BE0C         ; PRINT THE ERROR
1000:                6 *
1000:                7 *
1000:                8 *
1000:A2 00           9 START     LDX   #0            ; DISPLAY PROMPT...
1002:BD 1F 10       10 L1        LDA   PROMPT,X      ;
1005:F0 06   100D   11           BEQ   CONT          ; BRANCH IF END OF STRING
1007:20 ED FD       12           JSR   COUT          ;
100A:E8             13           INX                 ;
100B:D0 F5   1002   14           BNE   L1            ; LOOP UNTIL NULL TERMINATOR HIT
100D:               15 *
100D:20 6F FD       16 CONT      JSR   GETLN1        ; ACCEPT COMMAND FROM KB
1010:20 03 BE       17           JSR   DOSCMD        ; AND EXECUTE COMMAND
1013:2C 10 C0       18           BIT   $C010         ; CLEAR STROBE
1016:B0 02   101A   19           BCS   ERROR         ; BRANCH IF ERROR DETECTED
1018:90 E6   1000   20           BCC   START         ; OTHERWISE RESTART
101A:               21 *
101A:               22 *
101A:               23 * NOTE: AFTER HANDLING YOUR ERROR YOU MUST CLEAR THE CARRY
101A:               24 *       BEFORE RETURNING TO BASIC OR BASIC WILL DO
101A:               25 *       STRANGE TO YOU.
101A:               26 *
101A:20 0C BE       27 ERROR     JSR   PRERR         ; PRINT 'ERR'
101D:18             28           CLC                 ;
101E:60             29           RTS                 ; RETURN TO BASIC
101F:               30 *
101F:               31           MSB   ON
101F:               32 *
101F:8D             33 PROMPT    DB    $8D           ; OUTPUT A RETURN FIRST
1020:C5 CE D4 C5    34           ASC   'ENTER        BASIC.SYSTEM COMMAND --> '
103F:00             35           DB    0

Page 133


DOSCMD is merely a way to perform some BASIC.SYSTEM commands from assembly language, and is not a substitute for performing the commands in BASIC. Keep in mind the consequences of the command you are executing. For example, when doing a BRUN or BLOAD, make sure the code is loaded at proper addresses.

After you call DOSCMD, the carry bit will be set if an error has occurred. The accumulator will have the error number.

There are three ways to handle DOSCMD errors:

  • Do a JSR ERROUT ($BE09). This returns control to your

BASIC ONERR routine, where you can handle the error.

  • Do a JSR PRINTERR ($BE0C). This prints Out the error and

returns control to the point just after the JSR.

  • Handle the error yourself. Be sure to clear the carry (CLC) before

returning control to BASIC.SYSTEM. If you don't, an error will be assumed, and the results are unpredictable.

Adding Commands to the BASIC System Program

The EXTRNCMD location in the global page allows you to add your own commands to the ProDOS command set. Once you attach a command, it is treated as if it were one of the BASIC.SYSTEM commands, except that the original commands have preference. To execute your command in immediate mode, just enter it. To execute it in deferred mode, preface it with PRINT CHR$(4).

Whenever BASIC.SYSTEM receives a command, it first checks its command list for a match. If the command is not recognized, BASIC.SYSTEM sends the command to the external command handlers, if any are connected. If no external command handler claims the command, BASIC.SYSTEM passes control to Applesoft, which returns an error if the command is not recognized.

If you have frequent need for special commands, you can write your own command handler and attach it to BASIC.SYSTEM through the EXTRNCMD jump vector. First, save the current EXTRNCMD vector (to JMP to if the command is not yours), and install the address of your routine in EXTRNCMD+1 and +2 (low byte first). Your routine must do three things:

Page 134


  • It must check for the presence of your command(s) by inpecting the

GETLN input buffer. If the command is not yours, you must set the carry (SEC) and JMP to the initial EXTRNCMD vector you saved to continue the search.

  • If the command is yours, you must zero XCNUM ($BE53) to indicate

an external command, and set XLEN ($BE52) equal to the length of your command string minus one.

  • If there are no associated parameters (such as slot, drive, A$, and so

on) to parse, or if you're going to parse them yourself, you must set all 16 parameter bits in PBITS ($BE54,$BE55) to zero. And, if you're going to handle everything yourself before returning control to BASIC.SYSTEM, you must point XTRNADDR ($BE50,$BE51) at an RTS instruction. XRETURN ($BE9E) is a good location. Now, just fall through to your execution routines.

  • If there are parameters to parse, it is easiest to let BASIC.SYSTEM

parse them for you (unless you want to use some undefined parameters). By setting up the bits in PBITS ($BE54,$BE55), and setting XTRNADDR ($BE50,$BE51) equal to the location where execution of your command begins, you can return control to BASIC.SYSTEM, with an RTS, and let it parse and verify the parameters and return them to you in the global page.

  • It must execute the instructions expected of the command, and it

should RTS with the carry cleared.

Note: Having BASIC.SYSTEM parse your external command parameters was initially intended only for its own use. As it happens, not all parameters can be parsed separately. The low byte of PBITS ($BE54) must have a nonzero value to have BASIC.SYSTEM parse parameters.

This means that regardless of the parameters you need parsed, you must also elect to parse some parameter specified by the low byte of PBITS. For example, set PBITS to $10, filename optional (this parameter need not be known by the user).

The following are two sample routines, BEEP and BEEPSLOT. They can reside together as external commands. BEEP handles everything itself, while BEEPSLOT lets you pass a slot and drive parameter (,S#,D#) where the drive is ignored.

Page 135


A.3.2.1 - BEEP Example

**************************************************************
*                                                            *
*  BRUN BEEP.0 TO INSTALL THE ROUTINE'S ADDRESS IN EXTRNCMD. *
*  THEN TYPE BEEP AS AN IMMEDIATE COMMAND OR USE PRINT       *
*  CHR$(4);"BEEP" IN A PROGRAM.                              *
*                                                            *
**************************************************************
*
*
           ORG  $300
INBUF      EQU  $200     ;GETLN input buffer.
WAIT       EQU  $FCA8    ;Monitor wait routine.
BELL       EQU  $FF3A    ;Monitor bell routine.
EXTRNCMD   EQU  $BE06    ;External cmd JMP vector.
XTRNADDR   EQU  $BE50    ;Ext cmd implementation addr.
XLEN       EQU  $BE52    ;length of command string-1.
XCNUM      EQU  $BE53    ;CI cmd no. (ext cmd - 0).
PBITS      EQU  $BE54    ;Command parameter bits.
XRETURN    EQU  $BE9E    ;Known RTS instruction.
           MSB  ON       ;Set high bit on ASCII
*
* FIRST SAVE THE EXTERNAL COMMAND ADDRESS SO YOU WON'T
* DISCONNECT ANY PREVIOUSLY CONNECTED COMMAND.
*
           LDA  EXTRNCMD+1
           STA  NXTCMD
           LDA  EXTRNCMD+2
           STA  NXTCMD+1
*
           LDA  #>BEEP      ;Install the address of our
           STA  EXTRNCMD+1  ; command handler in the
           LDA  #<BEEP      ; external command JMP
           STA  EXTRNCMD+2  ; vector.
           RTS
*
BEEP       LDX  #0          ;Check for our command.
NXTCHR     LDA  INBUF,X     ;Get first character.
           CMP  CMD,X       ;Does it match?
           BNE  NOTOURS     ;No, back to CI.
           INX              ;Next character
           CPX  #CMDLEN     ;All characters yet?
           BNE  NXTCHR      ;No, read next one.
*
           LDA  #CMDLEN-1   ;Our cmd! Put cmd length-1
           STA  XLEN        ; in CI global XLEN.
           LDA  #>XRETURN   ;Point XTRNADDR to a known
           STA  XTRNADDR    ; RTS since we'll handle
           LDA  #<XRETURN   ; at the time we intercept

Page 136


           STA  XTRNADDR+1  ; our command.
           LDA  #0          ;Mark the cmd number as
           STA  XCNUM       ; zero (external).
           STA  PBITS       ;And indicate no parameters
           STA  PBITS+1     ; to be parsed.
*
           LDX  #5          ;Number of desired beeps.
NXTBEEP    JSR  BELL        ;Else, beep once.
           LDA  #$80        ;Set up the delay 
           JSR  WAIT        ; and wait.
           DEX              ;Decrement index and
           BNE  NXTBEEP     ; repeat until X = 0.
*
           CLC              ;All done successfully.
           RTS              ; RETURN WITH THE CARRY CLEAR.
*
NOTOURS    SEC              ; ALWAYS SET CARRY IF NOT YOUR
           JMP  (NXTCMD)    ; CMD AND LET NEXT COMMAND TRY
*                           ; TO CLAIM IT.
CMD        ASC  "BEEP"      ;Our command
CMDLEN     EQU  *-CMD       ;Our command length
*
NXTCMD     DW   0           ; STORE THE NEXT EXT CMD'S
                            ; ADDRESS HERE.

Page 137


BEEPSLOT Example

*************************************************************
*                                                           *
* BRUN BEEPSLOT.0 TO INSTALL THE ROUTINE'S ADDRESS IN       *
* EXTRNCMD.  THEN ENTER BEEPSLOT,S(n),D(n).  ONLY A LEGAL   *
* SLOT AND DRIVE NUMBERS ARE ACCEPTABLE.  IF NO SLOT NUMBER *
* IT WILL USE THE DEFAULT SLOT NUMBER.  ANY DRIVE NUMBER IS *
* SIMPLY IGNORED.  THE COMMAND MAY ALSO BE USED IN A        *
* PROGRAM PRINT CHR$(4) STATEMENT.                          *
*                                                           *
*************************************************************
*
*
           ORG  $2000
INBUF      EQU  $200       ;GETLN input buffer.
WAIT       EQU  $FCA8      ;Monitor wait routine.
BELL       EQU  $FF3A      ;Monitor bell routine
EXTRNCMD   EQU  $BE06      ;External cmd JMP vector.
XTRNADDR   EQU  $BE50      ;Ext cmd implementation addr.
XLEN       EQU  $BE52      ;Length of command string-1.
XCNUM      EQU  $BE53      ;CI cmd no. (ext cmd = 0).
PBITS      EQU  $BE54      ;Command parameter bits.
VSLOT      EQU  $BE61      ;Verified slot parameter.
           MSB  ON         ;Set high bit on ASCII.
*
* REMEMBER TO SAVE THE PREVIOUS COMMAND ADDRESS.
*
           LDA  EXTRNCMD+1
           STA  NXTCMD
           LDA  EXTRNCMD+2
           STA  NXTCMD+1
*
           LDA  #>BEEPSLOT ;Install the address of our
           STA  EXTRNCMD+1 ; command handler in the
           LDA  #<BEEPSLOT ; external command JMP
           STA  EXTRNCMD+2 ; vector.
           RTS
*
BEEPSLOT   LDX  #0         ;Check for our command.
NXTCHR     LDA  INBUF,X    ;Get first character.
           CMP  CMD,X      ;Does it match?
           BNE  NOTOURS    ;NO, SO CONTINUE WITH NEXT CMD.
           INX             ;Next character
           CPX  #CMDLEN    ;All characters yet?
           BNE  NXTCHR     ;No, read next one.
*
           LDA  #CMDLEN-1  ;Our cmd! Put cmd length-1
           STA  XLEN       ; in CI global XLEN.
           LDA  #>EXECUTE  ;Point XTRNADDR to our

Page 138


           STA  XTRNADDR   ; command execution
           LDA  #<EXECUTE  ; routine
           STA  XTRNADDR+1
           LDA  #0         ;Mark the cmd number as
           STA  XCNUM      ; zero (external).
*
           LDA  #%00010000 ;Set at least one bit
           STA  PBITS      ; in PBITS low byte!
*
           LDA  #%00000100 ;And mark PBITS high byte
           STA  PBITS+1    ; that slot & drive are legal.
           CLC             ;Everything is OK.
           RTS             ;Return to BASIC.SYSTEM
*
EXECUTE    LDA  VSLOT      ;Get slot parameter.
           TAX             ;Transfer to index reg.
NXTBEEP    JSR  BELL       ;Else, beep once.
           LDA  #$80       ;Set up the delay
           JSR  WAIT       ; and wait.
           DEX             ;decrement index and
           BNE  NXTBEEP    ; repeat until x = 0.
           CLC             ;All done successfully.
           RTS             ;Back to BASIC.SYSTEM.
*
* IT'S NOT OUR COMMAND SO MAKE SURE YOU LET BASIC
* CHECK WHETER OR NOT IT'S THE NEXT COMMAND.
*
NOTOURS    SEC             ;SET CARRY AND LET
           JMP  (NXTCMD)   ; NEXT EXT CMD GO FOR IT.
*
CMD        ASC  "BEEPSLOT" ;Our command
CMDLEN     EQU  *-CMD      ;Our command length
NXTCMD     DW   0          ; STORE THE NEXT COMMAND'S
                           ; ADDRESS HERE.

Page 139


Command String Parsing

First, the external command must tell the BASIC system program which parameters are allowed for the command. It does this by assigning the appropriate values to the two PBITS bytes, which have the following meanings:

Address:              $BE54                      $BE55
            _______________________    _______________________
           |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
PBITS:     |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
           |__|__|__|__|__|__|__|__|  |__|__|__|__|__|__|__|__|
Bit #:      15 14 13 12 11 10  9  8     7  6  5  4  3  2  1  0
Bit # - Meaning
15 - Prefix needs fetching. Pathname is optional
14 - No parameters to be processed
13 - Command only valid during program execution
12 - Filename is optional
11 - Create allowed if file doesn't exist
10 - File type (Ttype) optional
9 - A second filename expected 
8 - A first filename expected
7 - Address (A#) allowed
6 - Byte (B#) allowed
5 - End address (E#) allowed
4 - Length (L#) allowed
3 - Line number (@#) allowed
2 - Slot and Drive (S# and D#) allowed
1 - Field (F#) allowed
0 - Record (R#) allowed

Having done this, the routine should place the length of the recognized command word minus one into XLEN ($BE52). It should also place a $00 into XCNUM ($BE53), indicating that an external command was found, and it should place the address within the routine at which further processing of the parsed command will take place into XTRNADDR ($BE50). Then it should RTS back to the BASIC system program.

Page 140


The BASIC system program will see that the command was recognized, and it will parse the string according to PBITS. For each parameter that was used in the command, it will set the corresponding bit in FBITS ($BE56) and update the value of that parameter in the global page. Finally, it will do a JSR to the location indicated in XTRNADDR ($BE50).

The routine can now process the command. All parameters are stored in the global page except the filenames which are stored in the locations indicated by VPATH1 and VPATH2.

The HELP command is such a routine. When you type -HELP, the help command is loaded into memory at $2000, it moves HIMEM down and places itself above HIMEM, then it marks itself in the bit map.

Finally it places the start address of the routine in the EXTRNCMD vector. The BASIC system program now recognizes a series of HELP commands as well as the NOHELP command.

The NOHELP command removes the help routine's address from the EXTRNCMD vector, unmarks the routine from the bit map, and moves HIMEM back up.

Page 141


Zero Page

Figure A-3 is a memory map that shows the locations used by the Monitor, Applesoft, the Device Drivers, and the ProDOS MLI. The owner of each location is shown by a letter: M, A, D, or P.

Figure A-3. Zero Page Memory Map Use by the Monitor (M), Applesoft (A), Disk Drivers (D), and ProDOS MLI (P) is shown.

Decimal---0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
,   Hex---$0  $1  $2  $3  $4  $5  $6  $7  $8  $9  $A  $B  $C  $D  $E  $F
0   $00  DA  DA   A   A   A   A                   A   A   A   A   A   A
16  $10   A   A   A   A   A   A   A   A   A                           A
32  $20   M   M   M   M   M   M   M   M   M   M   M   M   M   M   M   M
48  $30   M   M   M   M   M   M   M   M   M   M  PMD PMD PMD PMD PMD DM
64  $40  PMD PMD PMD PMD PMD PMD PMD PM  PM  PM   P   P   P   P  PM   M
80  $50  MA  MA  MA  MA  MA  MA   A   A   A   A   A   A   A   A   A   A
96  $60   A   A   A   A   A   A   A   A   A   A   A   A   A   A   A   A
112 $70   A   A   A   A   A   A   A   A   A   A   A   A   A   A   A   A
128 $80   A   A   A   A   A   A   A   A   A   A   A   A   A   A   A   A
144 $90   A   A   A   A   A   A   A   A   A   A   A   A   A   A   A   A
160 $A0   A   A   A   A   A   A   A   A   A   A   A   A   A   A   A   A
176 $B0   A   A   A   A   A   A   A   A   A   A   A   A   A   A   A   A
192 $C0   A   A   A   A   A   A   A   A   A   A   A   A   A   A
208 $D0   A   A   A   A   A   A           A   A   A   A   A   A   A   A
224 $E0   A   A   A       A   A   A   A   A   A   A
240 $F0   A   A   A   A   A   A   A   A   A   A

If you need many zero-page locations for your routines, choose a region of already-used locations, save them at the beginning of the routine, and then restore them at the end.

Page 142


The Extended 80-Column Text Card

The Apple IIe computer can optionally contain an Extended 80-Column Text Card, giving the computer access to an additional 64K of RAM.

(The Apple IIc has the equivalent of such a card built in.) ProDOS uses this extra RAM as a volume, just like a small disk volume. This volume is initially given the name /RAM, but it can be renamed.

The 64K of RAM on the card is logically partitioned into 127 512-byte blocks of information. The contents of these blocks are:

Blocks 00-01 - Unavailable
Block 02 - Volume directory
Block 03 - Volume bit map
Blocks 04-07 - Unavailable
Blocks 08-126 - Directories and files

A detailed description of the way these blocks are used on a disk volume is in Appendix B. The major differences between a disk volume and /RAM are:

  • On a disk volume, blocks 0 and 1 are used for the loader program.

Since /RAM is not a bootable volume, these blocks are not used.

  • On a disk volume, there are usually four blocks reserved for the

volume directory, with a maximum capacity of 51 files in the volume directory. On /RAM, there is only one block of volume directory: it can hold 12 files (any or all of them can be subdirectory files).

  • Normal disk devices are associated with a given slot and drive.

/RAM is placed in the device list as slot 3, drive 2.

This arrangement gives you a total of 119 blocks of file storage.

Page 143

Content is available under Creative Commons Attribution-NonCommercial-ShareAlike unless otherwise noted.
Powered by MediaWiki