****************************************************************** * * * RUN Command Handler * * * ****************************************************************** * * * DOS's RUN command loads an Integer or Applesoft file and * * then attempts to execute it. If the specified file is not on * * the disk, a file-not-found error message is printed. If the * * file type code of the specified file is not compatible with * * the currently active language, the computer attempts to select * * the correct basic before LOADing the file. * * * ****************************************************************** * On entry - CUMLOPTN ($AA65) has been updated * to reflect parsed option words. * (Only volume (VOLPRSD), drive (DRVPRSD) * and slot (SLOTPRSD) parameters are * allowed with the DOS RUN command.) * - the validity of the options issued * with the command (and their numeric * values) have been checked. * - if a legal file name was issued, it has * been parsed & placed in the primary file * name buffer (PRIMFNBF, $AA75). - if no filename was issued with the RUN * comand, then execution doesn't get this far. * Instead, the DOS interpreter preceives the * "RUN" as a BASIC command & therefore sends * it along to the basic interpreter where it * attempts to RUN a program currently in memory. (A4D1) CMDRUN LDA ACTBSFLG ;Check which basic is current. ;(Int=$00, A(ROM)=$40, A(RAM0=$80) (A4D4) BEQ LOAD4RUN ;Branch if using integer. (A4D6) STA RUNTRUPT ;Set the RUN intercept flag to siganl that ;we are about to interrupt the RUN command ;to do a LOAD. ($40=A(ROM), $80=A(RAM).) * GO LOAD THE PROGRAM. * NOTE: THE "JSR" INSTRUCTION SHOWN BELOW IS * ACTUALLY A PLACEBO because after the file is * loaded, execution goes into basic and then * re-enters DOS. Once DOS gets its mitts back * into things, the RUNTRUPT flag is tested, THE * STACK IS RESET and then execution flows to the * next instruction (at RUNFPINT, $A4DC)). (A4D9) LOAD4RUN JSR CMDLOAD (A413) CMDLOAD . . (See dis'mbly below.) . . (RTS) (A4DC) RUNFPINT JSR CRVIADOS * Print a carriage return via DOS and the monitor. (9FC8) CRVIADOS LDA #$8D ;Carriage return. (9FCA) JMP GODSPLY ;Print char thru true output handler. ------------ (9FC5) GODSPLY JMP (CSW) ;CSW points to the true output handler (normally COUT1). ------------ (FDF0) COUT1 . . (Monitor ROM's screen output routine.) (See dis'mbly in APPLE II REFERENCE MANUAL.) . . (RTS) (A4DF) JSR INITIOHK * Initialize the I/O hooks so that DOS * intercepts all input and output. For * instance, if a routine encounters a * "COUT JMP (CSW)" then execution will * actually flow to DOS's output handler * routine (OPUTINCP, $9EBD). Similarly, * any routine that refers to "RDKEY JMP (KSW)" * will actually jump to DOS's input routine * (INPTINCP, $9E81). * The true (ie. normal) hooks are saved, ex: * KSW: KEYIN --> KSWTRUE: KEYIN. * CSW: COUT1 --> CSWTRUE: COUT1. * The intercepts are then set as follows: * ADINPTCP: INPTINCP --> KSW: INPTINCP. * ADOPUTCP: OPUTINCP --> CSW: OPUTINCP. * Check if input hook needs to be reset. (A851) INITIOHK LDA KSW+1 CMP ADINPTCP+1 (A856) BEQ CKOUTHK ;Input hook already points to DOS's ;input handler so go check output hook. * Reset input hook to point to DOS. (A858) STA KSWTRUE+1 ;KSW: KEYIN --> KSWTRUE: KEYIN. LDA KSW STA KSWTRUE LDA ADINPTCP ;ADINPTCP: INPTINCP --> KSW: INPTINCP. STA KSW LDA ADINPTCP+1 (A868) STA KSW+1 * Check if output hook needs to be reset. (A86A) CKOUTHK LDA CSW+1 CMP ADOPUTCP+1 (A86F) BEQ SETHKRTN ;Output hook already points to DOS's ;output handler routine, so exit. * Reset output hook to point to DOS. (A871) STA CSWTRUE+1 ;CSW: COUT1 --> CSWTRUE: COUT1. LDA CSW STA CSWTRUE LDA ADOPUTCP ;ADOPUTCP: OPUTINCP --> CSW: OPUTINCP. STA CSW LDA ADOPUTCP+1 STA CSW+1 SETHKRTN RTS (A883) (A4E2) JMP (RUNTRY) ;Go execute the program. ------------ ;(RUNTRY points to RUNFPROM if using A(ROM) ;or RUNFPRAM if using A(RAM).) (A4FC) RUNFPROM JSR SETZPTRS (D665) SETZPTRS JSR SETXTPT * Set TXTPTR to approximate beginning of * program (ie. TXTPTR: TXTTAB-1, normally $800). (D697) SETXTPT CLC LDA TXTTAB ;Add negative 1 to low byte. ADC #$FF STA TXTPTR LDA TXTTAB+1 ;Add zero to hi byte if carry set. ADC #$FF ;Else add neg 1 to hi byte if carry clr. STA TXTPTR+1 (D6A4) RTS * Simulate a "CLEAR" statement. * (Reset variable & string pointers.) (D668) LDA #0 CLEAR BNE CLRTS CLEARC LDA MEMSIZ LDY MEMSIZ+1 STA FRETOP ;FRETOP: MEMSIZ STY FRETOP+1 LDA VARTAB ;ARYTAB: VARTAB LDY VARTAB+1 STA ARYTAB STY ARYTAB+1 STA STREND ;STREND: VARTAB STY STREND+1 (D680) JSR RESTORE * Simulate a RESTORE statement. That is, reset * the pointer which points to bytes in DATA * statement (DATPTR: TXTTAB-1). (D849) RESTORE SEC LDA TXTTAB SBC #1 LDY TXTTAB+1 BCS SETDA DEY SETDA STA DATPTR ;Otherwise, points to addr STY DATPTR+1 ;of current DATA statement. (D857) RTS * Re-initialize stk while preserving return addr. (D683) STKINI LDX # = (MEMSIZ), a program-too-large error * * message is generated. If enough space is available, the * * end-of-program (PRGEND, $AF) and start-of-variable-space * * (VARTAB, $67) pointers are set. * * The file is then read into free memory at the location * * defined by the start-of-program pointer (TXXTTAB, $67). As * * the program is read in, LENADRBF is used as a byte counter. * * Once the entire program is in place, the file is closed and * * the I/O hooks are reset to point to DOS. Execution then jumps * * to the address pointed to by RLOCNTRY ($9D60). * * When Applesoft is being used, RLOCNTRY points to Applesoft* * basic's relocation handler (SETLINKS, $D4F2). It is this * * routine that reconfigures Applesoft programs and enables them * * to be relocatable. Unfortunately, SETLINKS also has a darker * * side to its personality. Because it clears all variable, * * string and data pointers, it prevents Applesoft programs from * * being "chainable." * * After all of the Applesoft program's line links are * * adjusted to their new location, execution flows into Applesoft * * basic's RESTART routine ($D43C). However, the pattern of * * program flow depends upon the nature of the caller. If the * * RUN command was interrupted to do a LOAD, the run interrupt * * flag (RUNTRUPT, $AAB7) is turned off and execution jumps to * * RUNFPINT ($A4DC) to complete the RUN command. If the LOAD was * * not called from the RUN command, a normal RESTART is done. * * (See formatted disassembly given in the file titled * * DOSWARMSTART.) * * * * Note that the start-of-program pointer (TXTTAB, $67-$68) * * defines the load address. Normally, this pointer contains an * * $801. However, by simply zapping TXTTAB with a different value* * prior to issuing the LOAD command, an Applesoft program can be * * read into a non-standard location. This techniques is often * * used to load a program above the graphics screen. * * The indirect jump at $A44D represents an opportunity to * * divert the load routine to a user-installed patch. For * * instance, you can simulate an Applesoft version of the CHAIN * * command by pointing RLOCNTRY at a patch that adjusts program * * line pointers and perserves all variables. * * If the exact file structure is known, it is sometimes a * * simple matter to modify the LOAD routine to accommodate certain* * commercial programs that use A-type files. * * * ****************************************************************** * On entry - CUMLOPTN ($AA65) has been updated * to reflect parsed option words. * (Only volume (VOLPRSD), drive (DRVPRSD) * and slot (SLOTPRSD) parameters are * allowed with the DOS LOAD command.) * - the validity of the options issued * with the command (and their numeric * values) have been checked. * - if a legal file name was issued, it has * been parsed & placed in the primary file * name buffer (PRIMFNBF, $AA75). - if no filename was issued with the LOAD * comand, then execution doesn't get this far. * Instead, the DOS interpreter preceives the * "LOAD" as a BASIC command & therefore sends * it along to the basic interpreter where it * is used to load the next sequential program * from a CASSETTE tape. (A413) CMDLOAD JSR CLOSEALL * CLOSE ALL FILES (EXCEPT AN ACTIVE EXEC FILE). (A316) CLOSEALL JSR GETFNBF1 ;Enter here when direct call or if 1rst char ;in primary filename field was a space. * Put address of 1rst DOS name buffer * (chain) in the A3L/H pointer. (A792) GETFNBF1 LDA ADOSFNB1 ;First link to chain of DOS buffers LDX ADOSFNB1+1 ;(ie. pt to 1rst filename buffer in chain). (A798) BNE SETNXPTR ;ALWAYS. (A7A4) SETNXPTR STX A3L+1 ;Put addr of 1rst filename buffer in ptr STA A3L ;(ie. highest name buffer in chain). TXA ;Get hi-byte of addr back in (a). GETNXRTN RTS (A7A9) (A319) BNE CKIFEXEC ;ALWAYS. (A31B) CHKNXBUF JSR GETNXBUF * Get addr of next filename buffer in chain * from chain pointers buffer offset 37 & 36 * bytes from 1rst char of present filename * buffer. (A79A) GETNXBUF LDY #37 ;Point ptr at chain buffer. LDA (A3L),Y ;Pick up hi byte of addr of nxt filename buffer. BEQ GETNXRTN ;If hi-byte is 0 then link zeroed out. TAX ;Save hi-byte in (x). DEY ;Pick up low-byte. LDA (A3L),Y SETNXPTR STX A3L+1 ;Stick addr of filename buffer in ptr. STA A3L TXA ;Condition z-flg in relation to hi byte . GETNXRTN RTS (A7A9) (A31E) BEQ CLOSERTS ;Link zeroed out, so now all files closed. (A320) ;Exit CLOSEALL via this route. CKIFEXEC JSR CKEXCBUF * Check if current filename buffer * belongs to an EXEC file. (A7AF) CKEXCBUF LDA EXECFLAG ;Check to see if EXECing. BEQ NOTEXCBF ;No sweat - not running exec file. LDA EXECBUFF ;We are EXECing, there4 chk if addr of CMP A3L ;current filename buffer same as that BNE CKEXCRTN ;for buffer belonging to EXEC. LDA EXECBUFF+1 ;Maybe - low-bytes matched, now chk hi bytes. CMP A3L+1 BEQ CKEXCRTN ;Exec buffer = current buffer. NOTEXCBF DEX ;Not EXECing, there4 reduce (X) to make sure z-flag off. (A7C2) ;(P.S. (x) was orig conditioned to a large non-zero ;value on entry to GETFNBF1. There4, if now DEX then (A7C3) ;can be sure z-flag will be off.) CKEXCRTN RTS ;If execing, rtn with z-flag on. (A323) BEQ CHKNXBUF ;EXEC WAS ACTIVE SO DON'T CLOSE ITS BUFFER ;OUT OR WILL END UP IN NEVER-NEVER-LAND. ;After all, don't want to close buffer ;if we are using it to exec (ie. would ;be like burying ourselves alive)!!! (A325) JSR GETFNBY1 ;Get first char of filename from buf in chain. * Get first byte from DOS name buffer. (A7AA) GETFNBY1 LDY #0 ;Buffer is free if 1rst byte = $00. LDA (A3L),Y ;If buffer is occuppied, the 1rst byte (A7AE) RTS ;in buf = 1rst char in name of file which ;owns the buffer. (A328) BEQ CHKNXBUF ;This file is already closed, so go back ;to close rest of files. (A32A) JSR CLOSEONE * CLOSE THE OPEN FILE. (A2FC) CLOSEONE JSR CKEXCBUF * Check if current filename buffer * belongs to an EXEC file. (A7AF) CKEXCBUF LDA EXECFLAG ;Check to see if EXECing. BEQ NOTEXCBF ;No sweat - not running exec file. LDA EXECBUFF ;We are EXECing, there4 chk if addr of CMP A3L ;current filename buffer same as that BNE CKEXCRTN ;for buffer belonging to EXEC. (A7BB) LDA EXECBUFF+1 ;Maybe - low-bytes matched, ;so now check hi bytes. (A7BE) CMP A3L+1 BEQ CKEXCRTN ;Exec buffer = current buffer. NOTEXCBF DEX ;Not EXECing, DEX to make sure z-flag off. (A7C2) ;(P.S. (x) orig conditioned to a large ;non-zero value on entry to GETFNBF1. ;There4, if now DEX then can be sure (A7C3) ;z-flag will be off.) CKEXCRTN RTS ;Exit with z-flag = 1 if execing. ; = 0 if not execing. (A2FF) BNE FREEBUFF ;ALWAYS BRANCH IF CLOSEONE IS ACCESSED VIA CLOSEALL. LDA #0 ;Shut exec flag off. (A303) STA EXECFLAG ;NOTE: THIS INSTRUCTION IS NEVER CARRIED ;OUT IF ACCESSED VIA CLOSEALL. (An active exec file ;was already detected and skipped by the "BEQ CHKNXBUF" (A306) ;instruction at $A323.) FREEBUFF LDY #0 TYA ;Free up the DOS buffer by poking a $00 in the STA (A3L),Y ;1rst byte of the filename field. (A30B) JSR BUFS2PRM * GET addresses of the DOS buffers from chain * buffer & put them in FM parameter list. (A74E) BUFS2PRM LDY #30 ;Get addresses of FM Work buffer, ADRINPRM LDA (A3L),Y ;T/S list buffer, Data sec buffer and STA WRKBUFFM-30,Y ;NEXT filename buf from chain ptr INY ;buf & put them in FM parameter list. CPY #38 ;(P.S. addr of NEXT filename buffer not BNE ADRINPRM ;used by DOS.) (A75A) RTS (A30E) LDA #2 ;Stick opcode for CLOSE function STA OPCODEFM ;in the FM parameter list. (A313) JMP FMDRIVER ;Get ready to do the function. ------------ (A6A8) FMDRIVER JSR FILEMGR ;Call the file manager ;to execute the CLOSE function. (AB06) FILEMGR TSX ;Save stk pointer so can rtn to caller. STX STKSAV (AB0A) JSR RSTRFMWA ;Copy FM work buffer (in DOS chain) ;to FM work area (not in buffer chain). (AE6A) RSTRFMWA JSR SELWKBUF ;Find FM work buf. * Get adr of FM wrk buf * from FM parm list & * put it in A4L/H ptr. (AF08) SELWKBUF LDA #0 (AF0A) BEQ PT2FMBUF (AF12) PT2FMBUF LDA WRKBUFFM,X STA A4L LDA WRKBUFFM+1,X STA A4L+1 (AF1C) RTS (AE6D) LDY #0 ;Zero-out return code (AE6F) STY RTNCODFM ;in FM parm list to (AE72) ;signal no errors. STORFMWK LDA (A4L),Y ;Copy FM work buf STA FMWKAREA,Y ;(in chain) to FM INY ;wrk area (not in CPY #45 ;DOS buf chain). BNE STORFMWK CLC ;Why????? (AE7D) RTS (AB0D) LDA OPCODEFM ;Chk if opcode is legal. CMP #13 ;(Must be less than 13.) BCS TOERROP ;Opcode too large, go to range error. ASL ;Double val of opcode & get addr of TAX ;appropriate function handler from table. LDA FMFUNCTB+1,X ;Stick adr on stack (hi byte first) PHA ;& then do a "stack jump" to the appropriate LDA FMFUNCTB,X ;function handler. PHA (AB1E) RTS (AC06) FNCLOSE . . . (See dis'mbly of CLOSE function.) . . - if necessary, free up any sectors that were previously allocated to the file but not needed. - also updates the file size, fixes up links & updates data, VTOC, T/S list & directory sectors if necessary. . . (RTS) ============ TOERROP JMP RNGERROP ;To $B363 - see dis'mbly of errors. (AB1F) ------------ * Return here after doing the CLOSE function * (Cause after @ function is done, use stack * to get back to original caller.) (A6AB) AFTRFUNC BCC FMDRVRTN ;(c) = 0 = no errors. LDA RTNCODFM ;Get error code from FM parameter list. CMP #5 ;End-of-data error? (A6B2) BEQ TOAPPTCH ;Yes - got a zeroed-out T/S link or a ;zeroed-out data pair values listed in ;a T/S list. (Not applicable to the ;close function.) (A6B4) JMP OTHRERR ;No. See dis'mbly of errors. ------------ (A6C3) FMDRVRTN RTS (A32D) JMP CLOSEALL ;Goes to next instruction (CLOSERTS) via CLOSEALL. ------------ (A330) CLOSERTS RTS ============ (A416) OPENLOAD JSR HNDLCMD ;Go open the file. * OPEN THE FILE. * On entry from LOAD command, LENPRSD = 0. * * Common file manager command handler code. (A2A8) HNDLCMD LDA #1 ;1 = open opcode. HNDLCMD1 STA TEMPBYT ;Store opcode in temporary location. LDA LENPRSD ;Get L-parameter from parsed table. BNE SAVLENFM ;Was a non-zero L-parm issued with cmd? LDA LENPRSD+1 BNE SAVLENFM LDA #1 ;Length was 0 so make it 1 instead. STA LENPRSD SAVLENFM LDA LENPRSD ;Put length in FM parm list. STA RECLENFM LDA LENPRSD+1 STA RECLENFM+1 CLSLOCBF JSR CMDCLOSE ;Close file if it's already open. (A2C8) (A2EA) CMDCLOSE . . (See dis'mbly of CMDCLOSE .) . . - Because CLOSEALL was just used to close all open files, this call to CMDCLOSE is only used for its reference to GETBUFF to locate a free DOS buffer. . . - If necessary, the CLOSE FUNCTION updates the data sector, T/S list sector & the VTOC. It also fixes up links in the directory sectors and updates the file size if needed. . . (RTS) (A2CB) LDA A5L+1 ;Hi byte of A5L/H pointer which points at the highest ;numbered (lowest in memory) free DOS name buffer (in chain). (A2CD) BNE SAVFNPTR ;Branch if found a free buffer. (A2CF) JMP NOBUFERR ;Go issue an out-of-buffers message. ------------ ;(See dis'mbly of errors.) (A2D2) SAVFNPTR STA A3L+1 ;Reset A3L/H to point at DOS buffer that we LDA A5L ;will use for file name field buffer (chain). STA A3L (A2D8) JSR CPYPFN * NOTE: This (re)assigns a DOS buffer to the file * we want to OPEN/LOAD. The buffer may or may not * be the same one that was just released by the * CLOSE cmd above. The highest numbered (lowest in * memory) free DOS buffer is used. (A743) CPYPFN LDY #29 ;30 bytes to copy (0 to 29). CPYPRIM LDA PRIMFNBF,Y ;Copy the name of the file wanted from STA (A3L),Y ;the primary filename buffer into the DEY ;filename field buffer (in DOS chain). BPL CPYRIM ;More chars to get. (A74D) RTS (A2DB) JSR BUFS2PRM * Get addresses of the various DOS buffers from the * chain buffer & put them in the FM parameter list. (A74E) BUFS2PRM LDY #30 ;Get addr of FM work buf, T/S list ADRINPRM LDA (A3L),Y ;buf, data sector buf & next DOS STA WRKBUFFM-30,Y ;filename buf from chain INY ;pointer buffer & put them in FM parm list. CPY #38 ;(P.S. Adr of next DOS file name buf is BNE ADRINPRM ;not used by DOS.) (A75A) RTS (A2DE) JSR CPY2PARM * Put volume, drive, & slot values plus the * address of the primary filename buffer * in the FM parameter list. (A71A) CPY2PARM LDA VOLPRSD ;From parsed table. STA VOLFM LDA DRVPRSD ;From parsed table. STA DRVFM LDA SLOTPRSD ;From parsed table. STA SLOTFM LDA ADRPFNBF ;Get the adr of the primary file STA FNAMBUFM ;name buf from the constants tbl LDA ADRPFNBF+1 ;and put it in the FM parm list. STA FNAMBUFM+1 LDA A3L ;Save adr of current DOS file name STA CURFNADR ;buf in table of DOS variables. LDA A3L+1 STA CURFNADR+1 (A742) RTS (A2E1) LDA TEMPBYT ;Get open opcode back from temporary buffer STA OPCODEFM ;and put it in the FM parameter list. (A2E7) JMP FMDRIVER ------------ * USE THE FILE MANAGER DRIVER * TO DO THE OPEN FUNCTION. (A6A8) FMDRIVER JSR FILEMGR ;Call the file manager to do the function. * File manager proper. (AB06) FILEMGR TSX ;Save stk pointer so can later rtn to caller of FM. STX STKSAV (AB0A) JSR RSTRFMWA * Copy FM work buf (in DOS chain) to * FM work area (not in DOS chain). (AE6A) RSTRFMWA JSR SELWKBUF ;Point A4L/H at FM work buf. * Get addr of FM work buff from * the FM parm list & put it in * the A4L/H pointer. (AF08) SELWKBUF LDX #0 ;Offset to select ;work buffer. (AF0A) BEQ PT2FMBUF ;ALWAYS. (AF12) PT2FMBUF LDA WRKBUFFM,X STA A4L LDA WRKBUFFM+1,X STA A4L+1 (AF1C) RTS (AE6D) LDY #0 ;Zero out return code in FM parm list to STY RTNCODFM ;signal no errors as default condition. STORFMWK LDA (A4L),Y ;Copy FM work buf to FM work area. STA FMWKAREA,Y INY CPY #45 ;45 bytes to copy (0 to 44). BNE STORFMWK CLC ;WHY????? (AE7D) RTS (AB0D) LDA OPCODEFM ;Check if opcode is legal. CMP #13 ;(Must be less than 13.) BCS TOERROP ;Opcode too large so got range error. ASL ;Double val of opcode & put it in (x) TAX ;so it indexes tables of adrs. LDA FMFUNCTB+1,X ;Stick adr of appropriate function PHA ;handler on stack (hi byte first). LDA FMFUNCTB,X PHA (AB1E) RTS ;DO STACK JUMP TO FUNCTION ENTRY POINT. . . (AB22) FNOPEN . . (See dis'mbly of OPEN function.) . . - uses part of COMNOPEN routine. - reads in VTOC to get link to 1rst directory. - reads directory secs in & looks for file description entry with matching filename. - if matching name found, reads in the 1rst T/S list sector belonging to the file. - if no match found, issues a "file not found" message cause LOAD cmd can't create a new file. - reads T/S list back into T/S list buf. . . (RTS) ============ TOERROP JMP RNGERROP ;Go handle range error. (AB1F) ------------ ;(See dis'mbly of errors.) * Return here after doing the OPEN FUNCTION. * (Cause after @ function is done, use stack * to get back to the original caller.) (A6AB) AFTRFUNC BCC FMDRVRTN ;(c) = 0 = no errors. LDA RTNCODFM ;Get error code from FM parameter list. CMP #5 ;End-of-data error? (A6B2) BEQ TOAPPTCH ;Yes - got a zeroed-out T/S link or a ;zeroed-out data pair values listed in ;a T/S list. (Not applicable to the ;open function.) (A6B4) JMP OTHRERR ;No. See dis'mbly of errors. ------------ (A6C3) FMDRVRTN RTS * Restrict LOAD command to Applesoft ($02), * Integer ($01) or A-type ($20) files. (A419) LDA #$23 AND FILTYPFM ;Type found (via OPEN function). BEQ TOTYPMIS ;Err - not one of the above file types. STA FILTYPFM ;Save type wanted in FM parameter list. (A423) LDA ACTBSFLG ;Check which basic is active: ; INT=$00, FP=$40 & A(RAM)=$80. (A426) BEQ LODINTGR ;Branch if Integer is active language. ;(See linear disassembly.) (A428) LDA #2 ;Code for Applesoft (ie. FP). (A42A) JSR SELCTBSC ;Check if type wanted is Applesoft. * Check if desired basic is up or not. * Switch basic if necessary. (A4B1) SELCTBSC CMP FILTYPFM ;Basic wanted = basic found? (A4B4) BEQ SELBSRTN ;Yes - basic wanted is active. * Type of file wanted is not compatible * with current active language. (A4B6) LDX NDX2CMD ;Save index to current command in case (A4B9) STX NEXTCMD ;we are using integer & must load integer ;file called "APPLESOFT" in order to load A(RAM). (A4BC) LSR ;Shift type wanted in order to see which basic to switch into. BEQ SWTCH2FP (A4BF) JMP CMDINT ;Switch from FP to Integer. ------------ * Switching from Integer to Applesoft * so copy name of file from primary * to secondary name buffer in case we * have to use RAM-based Applesoft. (A4C2) SWTCH2FP LDX #29 ;30 bytes to copy (0 to 29). PRIM2SND LDA PRIMFNBF,X ;Get byte from primary. STA SCNDFNBF,X ;Copy it to secondary. DEX (A4CB) BPL PRIM2SND ;Branch if more bytes to copy. * Execute the FP command. (A4CD) JMP CMDFP ;See dis'mbly of FP command. --------- * Type of basic required (ie. compatible * with file type wanted) is currently active. (A4D0) SELBSRTN RTS ;Desired basic was active. (A42D) JSR RDADRLEN * READ THE LENGTH OF THE FP PRGM * FROM THE FIRST TWO BYTES OF THE FILE. (A47A) RDADRLEN LDA ADLENADR ;Get adr of two-byte input buffer (LENADRBF, STA CURIOBUF ;$AA60) from relocatable constants table and LDA ADLENADR+1 ;designate it as the I/O buffer in the FM STA CURIOBUF+1 ;parameter list. LDA #0 ;Designate length to read as 2 bytes STA LEN2RDWR+1 ;(ie. want to read load length which is LDA #2 ;stored as the 1rst 2 bytes of the file). STA LEN2RDWR LDA #3 ;Set FM parm list to read a range of bytes. STA OPCODEFM LDA #2 STA SUBCODFM (A49A) JSR FMDRIVER * USE THE FILE MANAGER DRIVER * TO READ IN THE LOAD LENGTH. (A6A8) FMDRIVER JSR FILEMGR ;Call the file manager to do the function. * File manager proper. (AB06) FILEMGR TSX ;Save the stack pointer so can later STX STKSAV ;return to the caller of the FM. (AB0A) JSR RSTRFMWA * Copy FM work buf (in DOS chain) to * FM work area (not in DOS chain). (AE6A) RSTRFMWA JSR SELWKBUF ;Find FM work buf. * Get addr of FM * work buff from * the FM parm list * & put it in the * A4L/H pointer. (AF08) SELWKBUF LDX #0 (AF0A) BEQ PT2FMBUF (AF12) PT2FMBUF LDA WRKBUFFM,X STA A4L LDA WRKBUFFM+1,X STA A4L+1 (AF1C) RTS (AE6D) LDY #0 ;Zero out return (AE6F) STY RTNCODFM ;code in FM parm ;list to assume ;no errors as (AE72) ;default condition. STORFMWK LDA (A4L),Y ;Copy FM work buf STA FMWKAREA,Y ;to FM work area. INY CPY #45 ;45 bytes to copy BNE STORFMWK ;(0 to 44). CLC ;WHY????? (AE7D) RTS (AB0D) LDA OPCODEFM ;Check if opcode is legal. CMP #13 ;(Must be less than 13.) BCS TOERROP ;Opcode too large so got range error. ASL ;Double val of opcode & put it in (x) TAX ;so it indexes tables of adrs. LDA FMFUNCTB+1,X ;Stick adr of appropriate function PHA ;handler on stack (hi byte first). LDA FMFUNCTB,X PHA (AB1E) RTS ;DO STACK JUMP TO FUNCTION ENTRY POINT. . . (AC58) FNREAD . . (See dis'mbly of READ function and read-a-range (READRNG, $AC96) subfunction.) . . - reads in first two bytes of file to get length of file in bytes. - On entry: LEN2RDWR: 2, FILPTSEC: $FFFF, RELFIRST: 0, RELASTP1: $7A, RELPREV: 0, RECNMBWA:0, RECNMBFM: 0, BYTOFFWA: 0, BYTOFFFM: 0, RECLENFM: 1, RECLENWA 1 and CURIOBUF = LENADRBF addr (normally $AA62). . . (RTS) ============ TOERROP JMP RNGERROP ;Go handle range error. (AB1F) ------------ ;(See dis'mbly of errors.) * Return here after doing the READ FUNCTION. * (Cause after @ function is done, use stack * to get back to the original caller.) * Note that (c) = 0 if a byte from a data sector was * just read -- even if that byte was a $00. (A6AB) AFTRFUNC BCC FMDRVRTN ;(c) = 0 = no errors. LDA RTNCODFM ;Get error code from FM parameter list. CMP #5 ;End-of-data error? (A6B2) BEQ TOAPPTCH ;Yes - got a zeroed-out T/S link or a ;zeroed-out data pair values listed in ;a T/S list. (A6B4) JMP OTHRERR ;No. See dis'mbly of errors. TOAPPTCH JMP APNDPTCH ;(See dis'mbly of errors.) NOP BK2FMDRV JSR CKIFAPND ;Note: APNDPTCH returns here. (A6BB) * Check if using the append command. (BA69) CKIFAPND LDX CMDINDEX ;Get command index. CPX #$1C ;Are we APPENDing? BEQ RTNCKAPN ;Yes - leave flag on. LDX #0 ;No - turn off append flag. STX APPNDFLG RTNCKAPN RTS (BA75) (A6BE) LDX #0 ;Zero out the one-data byte parameter in FM parm list. STX ONEIOBUF ;(Also referred to as low byte of CURIOBUF.) FMDRVRTN RTS (A6C3) * Prepare to read in file. (A49D) LDA LENADRBF+1 ;Get hi byte of length just read from disk. (A4A0) STA LEN2RDWR+1 ;Put length val just read into buffer so know how ;much to read when read in main body of file. (A4A3) TAY ;Save hi byte in (y). LDA LENADRBF ;Do likewise with low byte. STA LEN2RDWR (A4AA) RTS * Check to see if there is encough room * between the program start position and * MEMSIZ to accomodate file. (A430) CLC ;Add length of file to start of (A431) ADC TXTTAB ;program position (normally $801, ;but FP prgm can be loaded at a ;non-standard pos'n by first ;zapping TXTTAB accordingly). (A433) TAX ;Save low byte of prgm end in (x). TYA ;Retrieve hi byte of length from (y). ADC TXTTAB+1 CMP MEMSIZ+1 (A439) BCS TOTOOLRG ;Branch if not enough room. ;(Go issue program-too-large error message.) * Program is short enough to be * accomodated in free memory space. * * Set zero-page pointers. (A43B) STA PRGEND+1 ;Set end of program pointer. STA VARTAB+1 ;Set start of variable space. STX PRGEND ;PRGEND: val in TXTTAB + length. STX VARTAB ;VARTAB: val in TXTTAB + length. LDX TXTTAB LDY TXTTAB+1 (A447) JSR LODINTFP ;Designate where in free memory to ;load program and then go load it. * GO DO THE ACTUAL LOAD. * (Code common to both FP * and Integer load commands.) (A471) LODINTFP STX CURIOBUF ;Designate load addr as I/O buffer STY CURIOBUF+1 ;in the FM parameter list. (A477) JMP CLOSEFM ;Use file manager to load the program ------------ ;and then close the file. * Load the program & then close the file. (A40A) CLOSEFM JSR FMDRIVER ;Use file manager to load main body of file. * USE THE FILE MANAGER DRIVER * TO READ IN THE FILE. (A6A8) FMDRIVER JSR FILEMGR ;Call the file manager to do the function. * File manager proper. (AB06) FILEMGR TSX ;Save the stack pointer so can later STX STKSAV ;return to the caller of the FM. (AB0A) JSR RSTRFMWA * Copy FM work buf (in DOS chain) to * FM work area (not in DOS chain). (AE6A) RSTRFMWA JSR SELWKBUF ;Find FM work buf. * Get addr of FM * work buff from * the FM parm list * & put it in the * A4L/H pointer. (AF08) SELWKBUF LDX #0 (AF0A) BEQ PT2FMBUF (AF12) PT2FMBUF LDA WRKBUFFM,X STA A4L LDA WRKBUFFM+1,X STA A4L+1 (AF1C) RTS (AE6D) LDY #0 ;Zero out return (AE6F) STY RTNCODFM ;code in FM parm ;list to assume ;no errors as (AE72) ;default condition. STORFMWK LDA (A4L),Y ;Copy FM work buf STA FMWKAREA,Y ;to FM work area. INY CPY #45 ;45 bytes to copy BNE STORFMWK ;(0 to 44). CLC ;WHY????? (AE7D) RTS (AB0D) LDA OPCODEFM ;Check if opcode is legal. CMP #13 ;(Must be less than 13.) BCS TOERROP ;Opcode too large so got range error. ASL ;Double val of opcode & put it in (x) TAX ;so it indexes tables of adrs. LDA FMFUNCTB+1,X ;Stick adr of appropriate function PHA ;handler on stack (hi byte first). LDA FMFUNCTB,X PHA (AB1E) RTS ;DO STACK JUMP TO FUNCTION ENTRY POINT. . . (AC58) FNREAD . . (See dis'mbly of READ function and read-a-range (READRNG, $AC96) subfunction.) . . - reads file into free memory starting at address designated in TXTTAB (normally $801). - On entry: LEN2RDWR: contents of LENADRBF (val read off disk). FILPTSEC: 0, RELPREV:0, FILPTBYT:2, RECNMBWA: 2, RECNMBFM: 1, BYTOFFWA: 0, BYTOFFFM: 0 and CURIOBUF = TXTTAB = free memory target addr (normally $801). . . (RTS) ============ TOERROP JMP RNGERROP ;Go handle range error. (AB1F) ------------ ;(See dis'mbly of errors.) * Return here after doing the READ FUNCTION. * (Cause after @ function is done, use stack * to get back to the original caller.) * Note that (c) = 0 if a byte from a data sector was * just read -- even if that byte was a $00. (A6AB) AFTRFUNC BCC FMDRVRTN ;(c) = 0 = no errors. LDA RTNCODFM ;Get error code from FM parameter list. CMP #5 ;End-of-data error? (A6B2) BEQ TOAPPTCH ;Yes - got a zeroed-out T/S link or a ;zeroed-out data pair listed in a T/S list. (A6B4) JMP OTHRERR ;No. See dis'mbly of errors. TOAPPTCH JMP APNDPTCH ;(See dis'mbly of errors.) NOP BK2FMDRV JSR CKIFAPND ;Note: APNDPTCH returns here. (A6BB) * Check if using the append command. (BA69) CKIFAPND LDX CMDINDEX ;Get command index. CPX #$1C ;Are we APPENDing? BEQ RTNCKAPN ;Yes - leave flag on. LDX #0 ;No - turn off append flag. STX APPNDFLG RTNCKAPN RTS (BA75) (A6BE) LDX #0 ;Zero out the one-data byte parameter in FM parm list. STX ONEIOBUF ;(Also referred to as low byte of CURIOBUF.) FMDRVRTN RTS (A6C3) (A40D) JMP CMDCLOSE ;Go close the file. ------------ (A2EA) CMDCLOSE . . (See dis'mly of CLOSE command.) . . (RTS) (A44A) JSR INITIOHK ;Point the I/O hooks at DOS. * Initialize the I/O hooks so that DOS * intercepts all input and output. For * instance, if a routine encounters a * "COUT JMP (CSW)" then execution will * actually flow to DOS's output handler * routine (OPUTINCP, $9EBD). Similarly, * any routine that refers to "RDKEY JMP (KSW)" * will actually jump to DOS's input routine * (INPTINCP, $9E81). * The true (ie. normal) hooks are saved, ex: * KSW: KEYIN --> KSWTRUE: KEYIN. * CSW: COUT1 --> CSWTRUE: COUT1. * The intercepts are then set as follows: * ADINCPTCP: INPTINCP --> KSW: INPTINCP. * ADOPUTCP: OPUTINCP --> CSW: OPUTINCP. * Check if input hook needs to be reset. (A851) INITIOHK LDA KSW+1 CMP ADINPTCP+1 (A856) BEQ CKOUTHK ;Input hook already points to DOS's ;input handler so go check output hook. * Reset input hook to point to DOS. (A858) STA KSWTRUE+1 ;KSW: KEYIN --> KSWTRUE: KEYIN. LDA KSW STA KSWTRUE LDA ADINPTCP ;ADINPTCP: INPTINCP --> KSW: INPTINCP. STA KSW LDA ADINPTCP+1 (A868) STA KSW+1 * Check if output hook needs to be reset. (A86A) CKOUTHK LDA CSW+1 CMP ADOPUTCP+1 (A86F) BEQ SETHKRTN ;Output hook already points to DOS's ;output handler routine, so exit. * Reset output hook to point to DOS. (A871) STA CSWTRUE+1 ;CSW: COUT1 --> CSWTRUE: COUT1. LDA CSW STA CSWTRUE LDA ADOPUTCP ;ADOPUTCP: OPUTINCP --> CSW: OPUTINCP. STA CSW LDA ADOPUTCP+1 STA CSW+1 SETHKRTN RTS (A883) (A44D) JMP (RLOCNTRY) ;Equivalent to "JMP SETLINKS". ;**************** NOTE ******************** ;* This is a hacker's dream. If you want * ;* to get fancy & do intelligent tasks * ;* (like preserving variables for the * ;* prgm being loaded), you can zap * ;* RLOCNTRY ($9D60) to point to your own * ;* customized load-handling routines. * ;****************************************** * CAUTION: ENTERING APPLESOFT ROM. * * Set important zero-page pointers and * clear out any variables. * Adjust stack while retaining the * return address. * Fix links (ptrs to next line) in * each line of Applesoft program. * Clear all variables & establish forward * links. (Note: "0 " is equivalent * to "JSR SETLINKS"). (D4F2) SETLINKS JSR SETZPTRS (D665) SETZPTRS JSR SETXTPT * Set TXTPTR to approximate beginning of * program (ie. TXTPTR: TXTTAB-1, normally $800). (D697) SETXTPT CLC LDA TXTTAB ;Add negative 1 to low byte. ADC #$FF STA TXTPTR LDA TXTTAB+1 ;Add zero to hi byte if carry set. ADC #$FF ;Else add neg 1 to hi byte if carry clr. STA TXTPTR+1 (D6A4) RTS * Simulate a "CLEAR" statement. * (Reset variable & string pointers.) (D668) LDA #0 CLEAR BNE CLRTS CLEARC LDA MEMSIZ LDY MEMSIZ+1 STA FRETOP ;FRETOP: MEMSIZ STY FRETOP+1 LDA VARTAB ;ARYTAB: VARTAB LDY VARTAB+1 STA ARYTAB STY ARYTAB+1 STA STREND ;STREND: VARTAB STY STREND+1 (D680) JSR RESTORE * Simulate a RESTORE statement. That is, reset * the pointer which points to bytes in DATA * statement (DATPTR: TXTTAB-1). (D849) RESTORE SEC LDA TXTTAB SBC #1 LDY TXTTAB+1 BCS SETDA DEY SETDA STA DATPTR ;Otherwise, points to addr STY DATPTR+1 ;of current DATA statement. (D857) RTS * Re-initialize stk while preserving return addr. (D683) STKINI LDX #