996 lines
69 KiB
Plaintext
996 lines
69 KiB
Plaintext
******************************************************************
|
|
* *
|
|
* BRUN Command Handler *
|
|
* *
|
|
*----------------------------------------------------------------*
|
|
* *
|
|
* The BRUN command handler (CMDBRUN, $A38E) loads a binary *
|
|
* file into memory, resets the I/O hooks to point to DOS and *
|
|
* then begins executing the file. *
|
|
* A file name must be issued with the command. Address, *
|
|
* drive and slot parameters are optional. If no address is *
|
|
* issued with the command, the load address is read off the *
|
|
* disk. This default address represents the A-parameter that *
|
|
* was originally used with the BSAVE command. It was stored as *
|
|
* the first two bytes of the file. *
|
|
* *
|
|
******************************************************************
|
|
|
|
|
|
* On entry - CUMLOPTN ($AA65) has been updated
|
|
* to reflect parsed option words.
|
|
* - the validity of the options & their
|
|
* numeric values have been checked.
|
|
* (Only volume, drive, slot & address
|
|
* parameters are allowed with the BRUN
|
|
* command. Their parsed values are stored
|
|
* in VOLPRSD ($AA66-67), DRVPRSD ($AA68-69),
|
|
* SLOTPRSD ($AA6A-6B) and ADRPRSD ($AA72-73)
|
|
* respectively.)
|
|
* - a file name has been parsed and placed in the
|
|
* primary file name buffer (PRIMFNBF, $AA75).
|
|
|
|
|
|
(A38E)
|
|
CMDBRUN JSR CMDBLOAD ;Load the binary file.
|
|
|
|
(A35D)
|
|
CMDBLOAD .
|
|
.
|
|
(See dis'mbly of BLOAD command given below.)
|
|
.
|
|
.
|
|
(RTS)
|
|
|
|
(A391) JSR INITIOHK ;Point the I/O hooks at DOS.
|
|
;NOTE: This instruction is the source of an
|
|
;exotic bug that has made many an assembly
|
|
;language programmer fluent in profanity.
|
|
;(See discussion below.)
|
|
|
|
* Initialize the I/O hooks to that DOS intercepts
|
|
* all input & output. For instance, if a routine
|
|
* accesses "COUT JMP (CSW)", then execution will
|
|
* actually flow to DOS's output 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 the 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 the 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 the 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, so go exit.
|
|
|
|
* Reset the 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)
|
|
|
|
(A394) JMP (ADRPRSD) ;Begin execution of binary file.
|
|
------------ ;After the binary program is BRUN, execution
|
|
;returns to AFTRCMD ($A17D) located in the
|
|
;command parsing and processing routines.
|
|
|
|
*--------------------------- N O T E ----------------------------*
|
|
* The "JSR INITIOHK" instruction (at $A391) resets the I/O *
|
|
* hooks to point to DOS's own I/O handlers (INPTINCP, $9E81 and *
|
|
* OPUTINCP, $9EDB). Therefore, any input or ouput performed by *
|
|
* your BRUNed program is scrutinized by DOS. Each time INPTINCP *
|
|
* or OPUTINCP are entered, the stack pointer is saved in *
|
|
* STKSAVED ($AA75). However STKSAVED was previously set in the *
|
|
* command parsing and processing routines before the BRUN command*
|
|
* handler was entered. Because the BRUN command resets the stack*
|
|
* pointer incorrectly, the computer goes into an infinite loop *
|
|
* AFTER your BRUNed program is executed. If MON is NOT in *
|
|
* effect, execution keeps on branching back into your program. *
|
|
* Your program is re-entered at the first byte after the last *
|
|
* instruction that called the routine that contained the *
|
|
* "JMP (KSW)" or "JMP (CSW)" instruction. For example, after *
|
|
* the following program is BRUNed, the erroneous setting of the *
|
|
* stack pointer causes execution to branch back to MAKEBRK *
|
|
* ($30E). (This makes sense if you keep in mind that COUT *
|
|
* contains a "JMP (CSW)" instruction.) The computer does not *
|
|
* hang in an infinite loop because the program uses self- *
|
|
* modifying code to institute a BRK: *
|
|
* *
|
|
* 0300- A9 8D LDA #$8D *
|
|
* 0302- 20 ED FD JSR COUT *
|
|
* 0305- 20 09 03 JSR SUBRTN *
|
|
* *
|
|
* 0309- A9 C1 SUBRTN LDA #"A" *
|
|
* 030B- 20 ED FD JSR COUT *
|
|
* 030E- A9 00 MAKEBRK LDA #0 *
|
|
* 0310- 8D 0E 03 STA MAKEBRK *
|
|
* 0313- 60 RTS *
|
|
* *
|
|
* 0308- 60 RTS *
|
|
* *
|
|
* Even if your BRUNed program does not perform any input or *
|
|
* output, the computer can still hang if MON C is in effect. *
|
|
* This occurs because STKSAVED gets reset when the command- *
|
|
* terminating carriage return is printed after the BRUN command *
|
|
* is executed. The computer ends up in a endless loop running *
|
|
* between $9FAA and $9FC4. (See formatted disasembly titled *
|
|
* "DOSCMDPARSING&PROCESSING".) *
|
|
* The easiest way to avoid these problems is to avoid using *
|
|
* the BRUN command. Another solution is to save the contents of *
|
|
* STKSAVED ($AA75) and turn off MON C (LDA #0 STA $AA5E) right *
|
|
* after entering your binary program. Just before exiting your *
|
|
* program, restore STKAVED with its original value. A third and *
|
|
* even better solution is to disconnect DOS altogether. *
|
|
* A "JSR UNCONDOS" ($9EE0) instruction will prevent DOS from *
|
|
* intercepting your calls to KSW or CSW. (Other peripherals will*
|
|
* not be affected.) You can then exit your program with a *
|
|
* "JMP $3EA" instruction which will reconnect DOS. However, if *
|
|
* you are the type of programmer that abhors using direct calls *
|
|
* to DOS, use the monitor ROM routines to select the I/O ports *
|
|
* as needed. (See the INPORT ($FE8B) and OUPORT ($FE95) routines*
|
|
* listed in the formatted disassembly titled "CMDS PR IN MOM & *
|
|
* NOMON".) Assembly language programmers who perform DOS cmds *
|
|
* by indirectly addressing the file manager should be familar *
|
|
* with this technique. *
|
|
*----------------------------------------------------------------*
|
|
|
|
|
|
|
|
|
|
******************************************************************
|
|
* *
|
|
* BLOAD Command Handler *
|
|
* *
|
|
*----------------------------------------------------------------*
|
|
* *
|
|
* The BLOAD command handler (CMDBLOAD, $A35D) loads a *
|
|
* binary file into memory. A file name must be issued with the *
|
|
* command. Address, volume, drive and slot parameters are *
|
|
* optional. *
|
|
* *
|
|
* Execution pattern: *
|
|
* The BLOAD command is slightly confusing because it uses *
|
|
* functionally repetitive code. The first instruction calls *
|
|
* HNDLCMD ($A2A8) to close (if necessary) and the open the file. *
|
|
* Next, ADR4BLOD ($A36C) calls OPNCKTYP (A3D5) to do the same *
|
|
* thing. Therefore, by simply changing the "JSR HNDLCMD" *
|
|
* instruction at $A35D to "JMP ADR4BLOD", a reduction in loading *
|
|
* time can be realized. *
|
|
* Once the file is opened for the second time, the load *
|
|
* address is read off the disk and placed into the two-byte *
|
|
* buffer known as LENADRBF ($AA60). If an A(ddress)-parameter *
|
|
* (ADRPRSD, $AA72) was issued with the BLOAD command, the *
|
|
* address read off the disk is ignored. Otherwise, the disk- *
|
|
* based address is transferred from LENADRBF to the parsed table *
|
|
* at ADRPRSD. The load length is then read off the disk and *
|
|
* stored in LENADRBF. Finally, the contents of ADRPRSD and *
|
|
* LENADRBF are copied into the FM parameter list and the rest of *
|
|
* the file is read. CMDBLOAD is then exited via the close *
|
|
* command. (The start address and length of the last bload are *
|
|
* left in ADRPRSD and LENADRBF respectivley.) *
|
|
* During the BLOAD process, the file manager treats a *
|
|
* binary file as a collection of one-byte long records *
|
|
* (RECLENFM=1). However, during a BSAVE, the opposite structure *
|
|
* is assumed. The file is considered to consist of a single *
|
|
* record which has a record length equal to the byte length of *
|
|
* the file (i.e., LENPRSD = RECLENFM = val of L-parameter READ *
|
|
* FROM THE DISK). *
|
|
* *
|
|
******************************************************************
|
|
|
|
|
|
* On entry - CUMLOPTN ($AA65) has been updated
|
|
* to reflect parsed option words.
|
|
* - the validity of the options & their
|
|
* numeric values have been checked.
|
|
* (Only volume, drive, slot & address
|
|
* parameters are allowed with the BLOAD
|
|
* command. Their parsed values are stored
|
|
* in VOLPRSD ($AA66-67), DRVPRSD ($AA68-69),
|
|
* SLOTPRSD ($AA6A-6B) and ADRPRSD ($AA72-73)
|
|
* respectively.)
|
|
* - a file name has been parsed and placed in the
|
|
* primary file name buffer (PRIMFNBF, $AA75).
|
|
|
|
|
|
(A35D)
|
|
CMDBLOAD JSR HNDLCMD ;Call the FM command handler to open the file.
|
|
|
|
* 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 CLOSE command.)
|
|
.
|
|
.
|
|
- Note that execution flows thru CMDCLOSE twice if the
|
|
file is already open.
|
|
- The first time thru, the matching DOS filename buffer is
|
|
located & then CLOSEONE is used to close the file.
|
|
- Execution then jumps back to the start of CMDCLOSE.
|
|
- On this second pass, a matching filename is not found
|
|
because the DOS filename buffer was released on the
|
|
first pass. Therefore, A5L/H is left pointing at the
|
|
highest numbered (lowest in memory) FREE DOS buffer
|
|
when CMCLOSE is exited via EVENTXIT and CLOSERTS.
|
|
- If the file is not already open on the first entry to
|
|
CMDCLOSE, only one pass is made. This single pass
|
|
resembles the second pass mentioned above.
|
|
.
|
|
.
|
|
- 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. 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 CPYPRIM ;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
|
|
(AB1F) 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, starts a new file by:
|
|
(1) creates new file description entry
|
|
- copies name to 1rst available spc
|
|
in direc sec (if can't find spc, then
|
|
issues disk full error message).
|
|
- allocates secs for file.
|
|
- writes updated VTOC to disk.
|
|
- puts link to first T/S list, file size, etc
|
|
in directory entry space.
|
|
- writes directory sector buffer to disk.
|
|
(2) creates new T/S list & writes it to disk.
|
|
- 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 listed in a T/S list.
|
|
;(Not applicable to the open function.)
|
|
(A6B4) JMP OTHRERR ;No. See dis'mbly of errors.
|
|
------------
|
|
|
|
(A6C3)
|
|
FMDRVRTN RTS
|
|
|
|
(A360) LDA #%01111111 ;Strip lock bit from file type found.
|
|
AND FILTYPFM ;Type found (via OPEN function).
|
|
CMP #4 ;Was a BINARY file found?
|
|
BEQ ADR4BLOD ;Yes.
|
|
(A369) JMP TYPMISM ;No - go issue file-type-mismatch message.
|
|
------------ ;(See dis'mbly of errors.)
|
|
|
|
* REDUNDANT CODE! Close (if necessary)
|
|
* and open the file AGAIN.
|
|
(A36C)
|
|
ADR4BLOD LDA #4 ;Code for BINARY file.
|
|
(A36E) JSR OPNCKTYP ;Close & reopen file.
|
|
|
|
(A3D5)
|
|
OPNCKTYP STA FILTYPFM ;Put code for binary file in FM parm list
|
|
PHA ;and also save it on stk.
|
|
(A3D9) JSR HNDLCMD ;Use the command handler to open the file.
|
|
|
|
(A2A8) .
|
|
HNDLCMD .
|
|
.
|
|
(See dis'mbly given above.)
|
|
.
|
|
.
|
|
(RTS)
|
|
|
|
(A3DC) PLA ;Pull file type code wanted from stack.
|
|
(A3DD) JMP CHKFTYPE ;Go check if file just opened is correct type.
|
|
------------
|
|
|
|
* Check if file type wanted = file type found.
|
|
(A7C4)
|
|
CHKFTYPE EOR FILTYPFM ;Type found (via OPEN function).
|
|
(A7C7) BEQ CKTYPRTN ;Branch if type wanted = type found.
|
|
|
|
* File types didn't match.
|
|
* Check if correct type but locked.
|
|
(A7C9) AND #%01111111 ;Maybe matched - disregard locked bit.
|
|
(A7CB) BEQ CKTYPRTN ;Branch if matched.
|
|
|
|
* Type wanted < > type found.
|
|
* So go close file & then issue a
|
|
* type mismatch error message.
|
|
(A7CD) JSR CMDCLOSE ;Named file is wrong type, so go close it.
|
|
|
|
(A2EA)
|
|
CMDCLOSE .
|
|
.
|
|
(See dis'mbly of close command.)
|
|
.
|
|
.
|
|
(RTS)
|
|
|
|
(A7D0) JMP TYPMISM ;Exit with type-mismatch error message.
|
|
------------ ;(See dis'mbly of errors.)
|
|
|
|
(A7D3)
|
|
CKTYPRTN RTS
|
|
============
|
|
|
|
(A371) JSR RDADRLEN ;Read the bload address from the disk into LEN2RDWR.
|
|
|
|
* Common code used to read the load/bload
|
|
* address or file length from the disk.
|
|
* As indicated by the comments below,
|
|
* the BLOAD ADDRESS is read in at this point
|
|
* in time.
|
|
(A47A)
|
|
RDADRLEN LDA ADLENADR ;Get addr of the two-byte input buffer
|
|
STA CURIOBUF ;(LENADRBF, $AA60) from the relocatable
|
|
LDA ADLENADR+1 ;constants tbl & designate it as the
|
|
STA CURIOBUF+1 ;I/O buf in the FM parm list.
|
|
LDA #0 ;Put length to read (2 bytes) in FM parm list.
|
|
STA LEN2RDWR+1
|
|
LDA #2
|
|
STA LEN2RDWR
|
|
LDA #3 ;Put READ opcode in FM parm list.
|
|
STA OPCODEFM
|
|
LDA #2 ;Indicate want to read a range of bytes.
|
|
(A49A) JSR FMDRIVER ;Go read in the bload address.
|
|
|
|
|
|
* Use the file manager driver
|
|
* to do the READ FUNCTION.
|
|
(A6A8)
|
|
FMDRIVER JSR FILEMGR ;Call the file manager to do the function.
|
|
|
|
* File manager proper.
|
|
(AB06)
|
|
FILEMGR TSX ;Save stk ptr so can later rtn
|
|
(AB07) STX STKSAV ;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 adr of FM work
|
|
* buff from 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 code
|
|
(AE6F) STY RTNCODFM ;in FM parm list to
|
|
;signal no errors
|
|
(AE72) ;as default cond.
|
|
STORFMWK LDA (A4L),Y ;Copy FM work buf
|
|
STA FMWKAREA,Y ;2 FM wrk 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 .
|
|
.
|
|
(Uses read function and read-a-range
|
|
subfunction (READRNG, $AC96) to READ
|
|
THE 2-BYTE BLOAD ADDRESS FROM DISK.)
|
|
On entry - LEN2RDWR=2, RELFIRST=0, RECNMBWA=0,
|
|
- RECNMBFM=0, BYTOFFWA=0, FILPTSEC=0,
|
|
- FILPTBYT=0, CURIOBUF=addr of LENADRBF,
|
|
- RELPREV=$FF
|
|
.
|
|
.
|
|
RWTS is used to read 1rst sec into data sector buffer
|
|
(in DOS buffer chain). The Bload address is then copied
|
|
from the data sector buffer into the 2-byte LENADRBF buffer.
|
|
When a binary file is being read:
|
|
- RECLENFM is considered to = 1.
|
|
- RECNMBFM is incremented sequentially.
|
|
- reading is complete when LEN2RDWR decrements to 0.
|
|
.
|
|
.
|
|
On exit - LEN2RDWR=0, RELFIRST=0, RECNMBWA=2,
|
|
- RECNMBFM=2, BYTOFFWA=0, FILPTSEC=0,
|
|
- FILPTBYT=2, CURIOBUF=addr of LENADRBF+2,
|
|
- RELPREV=0
|
|
.
|
|
.
|
|
(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: (c) = 0
|
|
* if a byte from a data sector was just read. It
|
|
* makes no difference if the data byte was $00 or not.)
|
|
(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 - file ends at a full data sec and so
|
|
;we encountered a zeroed-out T/S link or
|
|
;zeroed-out data pair (trk/sec values)
|
|
;listed in a T/S list.
|
|
(A6B4) JMP OTHRERR ;No. Only take if got an error other than
|
|
;out-of-data err. (See dis'mbly of errs.)
|
|
TOAPPTCH JMP APNDPTCH ;(See dis'mbly of errors.)
|
|
(A6B7)
|
|
(A6BA) NOP
|
|
BK2FMDRV JSR CKIFAPND ; <----- NOTE: APNDPTCH returns here.
|
|
(A6BB)
|
|
|
|
* Check status of append flag.
|
|
(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 1-data-byte buffer in FM parm list.
|
|
STX ONEIOBUF ;(Also referred to as low byte of CURIOBUF.)
|
|
FMDRVRTN RTS
|
|
(A6C3)
|
|
|
|
(A49D) LDA LENADRBF+1 ;Get hi byte of adr just read from disk.
|
|
(A4A0) STA LEN2RDWR+1 ;Put val just read in FM parm list in case
|
|
;just read length (so know how many bytes to
|
|
;read when read main body of file).
|
|
(A4A3) TAY ;Save hi byte in (y).
|
|
LDA LENADRBF ;Do likewise with low byte.
|
|
STA LEN2RDWR
|
|
(A4A9) RTS
|
|
|
|
(A374) TAX ;(x)=low byte of bload addr read from disk.
|
|
LDA CUMLOPTN ;Chk to see if a bload addr (ie. A-parm)
|
|
AND #%00000001 ;was issued with the BLOAD command.
|
|
(A37A) BNE LEN4BLOD ;YES - SO IGNORE ADDRESS READ FROM DISK & USE
|
|
; THE ACTUAL PARSED A-PARAMETER INSTEAD.
|
|
(A37C) STX ADRPRSD ;Store addr read from disk in parsed table.
|
|
(A37F) STY ADPRSD+1 ;(This way can ALWAYS use val in table for
|
|
(A382) ;the bload address.)
|
|
LEN4BLOD JSR RDADRLEN ;Read the bload length off disk.
|
|
|
|
* Common code used to read the load/bload
|
|
* address or file length from the disk.
|
|
* As indicated by the comments below,
|
|
* the BLOAD LENGTH is read in at this point
|
|
* in time.
|
|
(A47A)
|
|
RDADRLEN LDA ADLENADR ;Get addr of the two-byte input buffer
|
|
STA CURIOBUF ;(LENADRBF, $AA60) from the relocatable
|
|
LDA ADLENADR+1 ;constants tbl & designate it as the
|
|
STA CURIOBUF+1 ;I/O buf in the FM parm list.
|
|
LDA #0 ;Put length to read (2 bytes) in FM parm list.
|
|
STA LEN2RDWR+1
|
|
LDA #2
|
|
STA LEN2RDWR
|
|
LDA #3 ;Put READ opcode in FM parm list.
|
|
STA OPCODEFM
|
|
LDA #2 ;Indicate want to read a range of bytes.
|
|
(A49A) JSR FMDRIVER ;Go read in the file length.
|
|
|
|
|
|
* Use the file manager driver
|
|
* to do the READ FUNCTION.
|
|
(A6A8)
|
|
FMDRIVER JSR FILEMGR ;Call the file manager to do the function.
|
|
|
|
* File manager proper.
|
|
(AB06)
|
|
FILEMGR TSX ;Save stk ptr so can later rtn
|
|
(AB07) STX STKSAV ;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 ;Point A4L/H at
|
|
;FM work buf.
|
|
|
|
* Get adr of FM work
|
|
* buff from 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 2 signal no
|
|
;errors as 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 .
|
|
.
|
|
(Uses read function and read-a-range
|
|
subfunction (READRNG, $AC96) to READ
|
|
THE 2-BYTE FILE LENGTH FROM DISK.)
|
|
On entry - LEN2RDWR=2, RELFIRST=0, RECNMBWA=0,
|
|
- RECNMBFM=0, BYTOFFWA=0, FILPTSEC=0,
|
|
- FILPTBYT=0, CURIOBUF=addr of LENADRBF,
|
|
- RELPREV=0
|
|
.
|
|
.
|
|
RWTS is not called because the appropriate data sec is
|
|
in memory from reading address bytes. Therefore, the
|
|
bload length is copied from the data sector buffer to
|
|
the two-byte LENADRBF buffer.
|
|
When a binary file is being read:
|
|
- RECLENFM is considered to = 1.
|
|
- RECNMBFM is incremented sequentially.
|
|
- reading is complete when LEN2RDWR decrements to 0.
|
|
.
|
|
.
|
|
On exit - LEN2RDWR=0, RELFIRST=0, RECNMBWA=4,
|
|
- RECNMBFM=4, BYTOFFWA=0, FILPTSEC=0,
|
|
- FILPTBYT=4, CURIOBUF=addr of LENADRBF+2,
|
|
- RELPREV=0
|
|
.
|
|
.
|
|
(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: (c) = 0
|
|
* if a byte from a DATA sector was just read. It
|
|
* makes no difference if the data byte was $00 or not.)
|
|
(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 - file ends at a full data sec and so
|
|
;we encountered a zeroed-out T/S link or
|
|
;zeroed-out data pair (trk/sec values)
|
|
;listed in a T/S list.
|
|
(A6B4) JMP OTHRERR ;No. Only take if got an error other than
|
|
;out-of-data err. (See dis'mbly of errs.)
|
|
TOAPPTCH JMP APNDPTCH ;(See dis'mbly of errors.)
|
|
(A6B7)
|
|
(A6BA) NOP
|
|
BK2FMDRV JSR CKIFAPND ; <----- NOTE: APNDPTCH returns here.
|
|
(A6BB)
|
|
|
|
* Check status of append flag.
|
|
(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 1-data-byte buffer in FM parm list.
|
|
STX ONEIOBUF ;(Also referred to as low byte of CURIOBUF.)
|
|
FMDRVRTN RTS
|
|
(A6C3)
|
|
|
|
(A49D) LDA LENADRBF+1 ;Get hi byte of length just read from disk.
|
|
(A4A0) STA LEN2RDWR+1 ;Put length val just read from disk in FM parm list
|
|
;so know how many bytes to read when read main
|
|
;body of file).
|
|
(A4A3) TAY ;Save hi byte in (y).
|
|
LDA LENADRBF ;Do likewise with low byte.
|
|
STA LEN2RDWR
|
|
(A4A9) RTS
|
|
|
|
(A385) LDX ADRPRSD ;Set (x)/(y) = either original parsed A-parm
|
|
LDY ADRPRSD+1 ;or bload address read from disk.
|
|
(A38B) JMP LODINTFP ;Go read in rest of file.
|
|
------------
|
|
|
|
* Finish setting up FM parameter list
|
|
* so can read in rest of file.
|
|
(A471)
|
|
LODINTFP STX CURIOBUF ;Designate load address as I/O buffer
|
|
STY CURIOBUF+1 ;in the FM parameter list.
|
|
(A477) JMP CLOSEFM
|
|
-------------
|
|
|
|
* USE THE FILE MANAGER TO READ IN THE REST OF
|
|
* THE FILE & THEN EXIT VIA THE CLOSE COMMAND.
|
|
(A40A)
|
|
CLOSEFM JSR FMDRIVER ;Call the file manager to read in rest of file.
|
|
|
|
* Use the file manager driver
|
|
* to do the READ FUNCTION.
|
|
(A6A8)
|
|
FMDRIVER JSR FILEMGR ;Call the file manager to do the function.
|
|
|
|
* File manager proper.
|
|
(AB06)
|
|
FILEMGR TSX ;Save stk ptr so can later rtn
|
|
STX STKSAV ;to caller of FM.
|
|
(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 adr of FM work
|
|
* buff from FM parm
|
|
* list & put it in the
|
|
* A4L/H pointer.
|
|
(AF08)
|
|
SELWKBUF LDX #0 ;ALWAYS.
|
|
(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 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.
|
|
.
|
|
.
|
|
(AC58) .
|
|
FNREAD .
|
|
.
|
|
(Uses read function and read-a-range subfunction
|
|
(READRNG, $AC96) TO READ IN REST OF FILE FROM DISK.)
|
|
On entry - file was recently opened so appropriate
|
|
T/S list in memory.
|
|
- because the last call to the read-a-range
|
|
subfunction only used the first 2 bytes
|
|
from the first data sector, the appropriate
|
|
data sector is already in the data sector buffer.
|
|
- LEN2RDWR=2, RELFIRST=0, RECNMBWA=0,
|
|
- RECNMBFM=0, BYTOFFWA=0, FILPTSEC=0,
|
|
- FILPTBYT=0, CURIOBUF=addr of LENADRBF,
|
|
- RELPREV=0
|
|
.
|
|
.
|
|
RWTS is not called because the appropriate data sec is in memory
|
|
from reading the address bytes. Therefore, the bload length
|
|
is copied from the data sector buffer to the two-byte
|
|
LENADRBF buffer.
|
|
When a binary file is being read:
|
|
- RECLENFM is considered to = 1.
|
|
- RECNMBFM is incremented sequentially.
|
|
- reading is complete when LRN2RDWR decrements to 0.
|
|
.
|
|
.
|
|
On exit - LEN2RDWR=0, RELFIRST=0, RECNMBWA=4,
|
|
- RECNMBFM=4, BYTOFFWA=0, FILPTSEC=0,
|
|
- FILPTBYT=4, CURIOBUF=addr of LENADRBF+2,
|
|
- RELPREV=0
|
|
.
|
|
.
|
|
(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: (c) = 0
|
|
* if a byte from a data sector was just read. It
|
|
* makes no difference if the data byte was $00 or not.)
|
|
(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 - file ends at a full data sec and so
|
|
;we encountered a zeroed-out T/S link or
|
|
;zeroed-out data pair (trk/sec values)
|
|
;listed in a T/S list.
|
|
(A6B4) JMP OTHRERR ;No. Only take if got an error other than
|
|
;out-of-data err. (See dis'mbly of errs.)
|
|
TOAPPTCH JMP APNDPTCH ;(See dis'mbly of errors.)
|
|
(A6B7)
|
|
(A6BA) NOP
|
|
BK2FMDRV JSR CKIFAPND ; <----- NOTE: APNDPTCH returns here.
|
|
(A6BB)
|
|
|
|
* Check status of append flag.
|
|
(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 buffer in FM parm list.
|
|
STX ONEIOBUF ;(Also referred to as low byte of CURIOBUF.)
|
|
FMDRVRTN RTS
|
|
(A6C3)
|
|
|
|
(A40D) JMP CMDCLOSE ;Go close the file.
|
|
------------
|
|
|
|
* Because the file is already open, execution flows through
|
|
* the close cmd twice. The first time thru, the matching
|
|
* DOS filename buffer is located & then CLOSEONE is used to
|
|
* close the file via the open FUNCTION. The 2nd time through,
|
|
* a matching filename buffer is not found because the DOS
|
|
* buffer was released on the first pass. Therefore, A5L/H is
|
|
* left pointing at the highest numbered (lowest in memory)
|
|
* FREE DOS buffer when the close command is exited via EVENTXIT
|
|
* and CLOSERTS.
|
|
|
|
(A2EA)
|
|
CMDCLOSE .
|
|
.
|
|
(See dis'mbly of CLOSE command.)
|
|
Note that the close FUNCTION updates
|
|
the data sector, T/S list sector &
|
|
the VTOC. It also fixes up links in
|
|
the directory sector and updates the
|
|
file size if needed.
|
|
.
|
|
.
|
|
(RTS) ;Return to the caller of the BLOAD command.
|
|
============ ;(If NOT called by the BRUN command,
|
|
;execution normally returns to AFTRCMD
|
|
;($A17D) located in the command parsing and
|
|
;processing routines.)
|