Files
RomWBW/Source/BPBIOS/NZFCP13/nzfcp13.z80
2020-02-14 17:22:56 -08:00

1424 lines
33 KiB
Z80 Assembly
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
; Program: NZFCP
; Date: October 9, 1989
; Author: Carson Wilson <crw>
; Version: 1.3
; Changes: Updated & improved JetLDR signon.
; Changed four JR's to JP's.
; Date: August 21, 1988
; Author: Carson Wilson
; Version: 1.2
; Derived from:
; Date: April 1988
; Name changed and code modified for NZ-COM.
; Derived from:
; PROGRAM: Z34FCP
; AUTHOR: Jay Sage
; VERSION: 1.0
; DATE: May 25, 1987
; DERIVATION: FCP10 by Jay Sage (ZSIG)
; ZCPR34 is copyright 1987 by Jay P. Sage. All rights reserved. End-user
; distribution and duplication permitted for non-commercial purposes only.
; Any commercial use of ZCPR34, defined as any situation where the duplicator
; recieves revenue by duplicating or distributing ZCPR34 by itself or in
; conjunction with any hardware or software product, is expressly prohibited
; unless authorized in writing by Jay P. Sage.
;=============================================================================
;
; R E V I S I O N H I S T O R Y
;
;=============================================================================
;
; 21 Aug 88 Added JetLDR signon description.
; IF IN now prints ' (Y/N)? ', and accepts only Y or y or
; N or n.
; Added macro code to show FCP length following assembly.
;
; Carson Wilson.
;
; 6 April 88 Handles latest Type 4 IF.COM
; 1.2 Changed command tail loader to accept :IF. Joe Wright
;
; 12/31/87 Modified for use with Z34CMN.LIB for NZ-COM. Joe Wright.
; 1.1
;
; 05/25/87 Created ZCPR33 version from the code I released through ZSIG.
; 1.0 This code differs only in the more efficient way in which it
; determines if it was invoked with a directory prefix that
; signals that the transient IF.COM should be used to process
; the IF command. This permits the user to force the use of a
; more powerful option processor in the transient IF.COM than in
; the resident code. Option bytes were added after the end of
; the resident option dispatch table so that SHOW can report
; configuration options to the user.
;
; FCP10 notes
;
; The transient processor can now be loaded at an address other
; than 100h so as not to interfere with code loaded in the TPA.
; Then the GO command can normally be used even after IF.COM is
; used to process the flow test. If the LOADCHK equate
; is true then the FCP will verify that the transient
; processor has been loaded to the page in memory for which
; it was assembled. If loaded to the wrong page, it will
; be reloaded to the correct one.
;
; The test for the form ARG1=ARG2 was tightened up so as not to
; be confused by an equal sign in some later part of the command
; tail (e.g., "IF REG 1 = 2"). Now only the first token
; (contiguous string of characters) is checked. This extra code
; is under the control of the XEQOPT equate. The only option
; that is still a problem is the COMIF form '~='. Since the '='
; is in the first token, this 'not equal' condition cannot be
; distinguished from an equality test against the character '~'.
; The solution is to turn off equality testing in the resident FCP
; or to use the alternative COMIF options 'NE' or '~EQ' for this
; test.
;
; Added optional commands AND and OR. These work like IF except
; that they affect the current IF level rather than going one
; level deeper.
;
; Added optional command ZIF to zero out all IF states no matter
; whether current state is true or false (XIF only works if state
; is true.
;
; Added new optional command IFQ (if-query) and enhanced the
; IFSTAT code that is invoked when the NOISE equate is true.
; In both cases, the entire tree of IF states is now shown,
; starting with the current level. For example, IFQ might result
; in the display "IF FTT" (we are at third IF level and it is
; false; the second and first IF levels are true). If the
; current IF level is 0, then the display is "IF None".
;
; Added two new resident options: AMBIGUOUS (AM) returns true if
; the file specification in the second token has a '?' (or '*')
; in it; COMPRESSED (CO) returns true if the file specificaton in
; the second token has a 'Z' or a 'Q' in the second character of
; the file type.
;
; Howard Goldstein contributed significantly to the development
; of this code. Bridger Mitchell also offered helpful
; suggestions.
;
; Jay Sage
;
; Notes from earlier SYSFCP revisions
;
; 09/12/85 Fixed bug in my code used when IF.COM is found in a specified
; drive/user area. The values of CDISK and CUSER were not being
; set, and as a result the user was not returned to the correct
; directory. The EXIST and EMPTY tests did not work correctly
; unless a DIR: or DU: was given explicitly with each file name.
; Jay Sage
; 08/29/85 Reorganized code so that COMIF code handles only those
; options not in the table of local IF functions. Also changed
; code to allow searching for IF.COM in a specified directory
; instead of using the ROOT of the path. Also renamed macros
; to make code ZAS compatible.
; Jay Sage
; 07/21/85 Corrected reversed sensing of program error flag in the
; IF ERROR test.
; Jay Sage
; 01/02/85 Revised to correct a bug in the IF EMPTY test. First, the
; current record byte was not being set to zero before trying
; to read from the file. Secondly, the test for error was not
; testing for FF but for 00. My BDOS does not return 0 for
; success. It seems to return 00, 01, 02, or 03. This made the
; file appear to be empty.
; Jay Sage
;=============================================================================
;
; M A C R O S A N D E Q U A T E S
;
;=============================================================================
name ('FCP')
; External macro references
maclib Z34CMN.LIB ; Source of system addresses
maclib NZFCP.LIB ; Source of configuration options
maclib Z34MAC.LIB ; Z34 macros
; Equates section
version equ 13
lf equ 0ah
cr equ 0dh
bell equ 07h
base equ 0
wboot equ base+0000h ; CP/M warm boot address
udflag equ base+0004h ; User num in high nybble, disk in low
bdos equ base+0005h ; BDOS function call entry point
tfcb equ base+005ch ; Default FCB buffer
fcb1 equ tfcb ; 1st and 2nd FCBs
fcb2 equ tfcb+16
tbuff equ base+0080h ; Default disk I/O buffer
tpa equ base+0100h ; Base of TPA
;=============================================================================
;
; J e t L D R S I G N - O N
;
;=============================================================================
; This prints an extended ID message upon loading with JetLDR.
; These are NOT the command names.
COM /_ID_/
db 'Copyright 1989 ZSA',cr,lf
db 'Commands:',cr,lf
db ' IF ELSE FI XIF '
if andopt
db 'AND '
endif
if oropt
db 'OR '
endif
if ifqopt
db 'IFQ '
endif
if zifopt
db 'ZIF '
endif
db cr,lf,'Options'
if ifoneg
db ' (use "',negchar,'" to negate)'
endif
if noise
db '; (noise)'
endif
db ':',cr,lf
if ifotrue
db ' T F '
endif
if ifambig
db 'AMbig '
endif
if ifcompr
db 'COmpr '
endif
if ifoempty
db 'EMpty '
endif
if ifoeq
db 'x=y '
endif
if ifoerror
db 'ERror '
endif
if ifoexist
db 'EXist '
endif
if ifoinput
db 'INput '
endif
if ifonull
db 'NUll '
endif
if iforeg
db 'REgs '
endif
if ifotcap
db 'TCap '
endif
if ifowheel
db 'WHeel '
endif
if comif
db cr,lf,' Use '
if pathroot
db 'root:'
endif
db 'IF.COM'
endif
db 0 ; End of JetLDR sign-on message
CSEG
;=============================================================================
; Start of code
start:
db 'Z3FCP' ; Flag for Package Loader
;=============================================================================
;
; C O M M A N D T A B L E
;
;=============================================================================
; The command name table is structured as follows:
;
; The first byte is the number of characters in each command name.
; Next come records consisting of command names followed by entry
; point addresses for the code to process the command. Finally,
; there is a null to indicate the end of the dispatch table.
db cmdsize ; Size of text entries
ctab: ctable ; Macro defined in NZFCP.LIB
db 0
;=============================================================================
;
; I F C O N D I T I O N O P T I O N S
;
;=============================================================================
condtab:
if ifotrue
db 'T ' ; TRUE
dw ifctrue
db 'F ' ; FALSE
dw ifcfalse
endif ; ifotrue
if ifambig ; Ambiguous file spec
db 'AM'
dw ifcambig
endif ; ifambig
if ifcompr ; Squeezed or crunched
db 'CO'
dw ifccompr
endif ; ifcompr
if ifoempty
db 'EM' ; File empty
dw ifcempty
endif ; ifoempty
if ifoerror
db 'ER' ; Error message
dw ifcerror
endif ; ifoerror
if ifoexist
db 'EX' ; File exists
dw ifcex
endif ; ifoexist
if ifoinput
db 'IN' ; User input
dw ifcinput
endif ; ifoinput
if ifonull
db 'NU'
dw ifcnull
endif ; ifonull
if ifotcap ; Z3 TCAP available
db 'TC'
dw ifctcap
endif ; ifotcap
if ifowheel ; Wheel Byte
db 'WH'
dw ifcwheel
endif ; ifowheel
db 0
; Option bytes: these option bytes can be used to convey information to
; programs such as SHOW. The first one is used to reduce the chance of
; misinterpreting data from an earlier version of the FCP that does not
; have the option bytes. The next byte tells if COMIF has been activated
; and if the root of the path will be used as the directory in which to look
; for IF.COM. If PATHROOT is not selected (or if the path is empty), then
; the specified drive/user will be used. The overflow bit in case the user
; number is greater than 15 is kept in bit 2 of the second option byte. The
; combined user/drive value is kept in the third option byte.
highuser defl ifusr gt 15
opt0: db 34h ; ZCPR34 version ID
opt1: optflag highuser,pathroot,comif
opt2: db ( ifusr and 0fh ) shl 4 + ( ifdrv - 'A' ) ; user/drive flag
;=============================================================================
;
; C O M M A N D P R O C E S S I N G C O D E
;
;=============================================================================
; Command: ZIF
;
; This command zeros out the IF system no matter what the current
; level IF state is.
if zifopt
ifzero:
if noise
call nl ; Print new line
endif ; noise
jr ifexit1
endif ; zifopt
;-----------------------------------------------------------------------------
; Command: XIF
;
; If current IF state is true, XIF terminates all IFs, restoring a basic
; TRUE state.
ifexit:
if noise
call nl ; Print new line
endif ; noise
call iftest ; See if current IF is running and FALSE
if noise
jr z,ifstat ; Abort with status message if so
else ; not noise
ret z ; Or just return if false
endif ; noise
ifexit1:
ld hl,z3msg+1 ; Pt to IF flag
ld (hl),0 ; Zero IF flag
jr ifendmsg ; Print message
;-----------------------------------------------------------------------------
; Command: FI
;
; FI decrements to the previous IF level. It does this by shifting the
; current-if-bit in the first 'if' message in the Z3MSG buffer right one
; position.
ifend:
if noise
call nl ; Print new line
endif ; noise
; ld hl,z3msg+1 ; Point to IF flag
; ld a,(hl) ; Get it
; or a ; No IF active?
call msgbf1
dec hl ; Save a byte over the three lines above
jr z,ifnderr
ifendmsg:
if noise
call print
dc 'To ' ; Prefix to status display
endif ; noise
srl (hl) ; Adjust active bit
if noise
jr nz,ifstat ; Print status if IF still active
endif ; noise
ifnderr:
if noise
call print ; Print message
dc 'No '
jp prif
else ; not noise
ret
endif ; noise
;-----------------------------------------------------------------------------
; Command: ELSE
;
; ELSE complements the Active Bit for the Current IF provided the
; previous IF state was true. If the previous state was false, the
; command is flushed.
;
; This is accomplished according to the following algorithm. If the
; current IF is 0 (no IF) or 1 (one IF), then take the previous state
; to be true and perform the toggle. Otherwise, test the previous
; IF level condition and toggle only if it is true.
ifelse:
if noise and (not ifqopt)
call nl ; Print new line
endif ; noise and (not ifqopt)
call msgbf1 ; Get current if
ld b,a ; Save in B
srl a ; Back up if pointer bit to previous IF level
jr z,iftog ; If no previous IF level, go to toggle code
and (hl) ; Determine state of previous IF level
if noise
if ifqopt
jr z,ifstat0 ; Print status on new line
else
jr z,ifstat ; If false, just print status
endif ; Ifqopt
else ; not noise
ret z ; Or simply return
endif ; noise
iftog:
ld a,(hl) ; Get if-status message byte
xor b ; Flip current state
ld (hl),a ; Put result back in message byte
; ..and fall thru to print status
if not noise
ret
endif
;-----------------------------------------------------------------------------
; Indicate if current IF is True or False
ifstat0:
call nl
ifstat:
call prif ; Print 'IF '
call msgbf1 ; Get current if byte and set flags
ld b,a ; Get it into B
jr nz,ifstat1 ; Nz means if active
call print
dc 'None'
ret
ifstat1:
ld a,(hl) ; Get if-status message byte
and b ; Mask in currently active IF level status
ld c,'F' ; Load with false indicator
jr z,ifstat2 ; If current IF is false, jump
ld c,'T' ; Else, load with true indicator
ifstat2:
ld a,c
call conout
srl b ; Drop one IF level
jr nz,ifstat1 ; Loop through all IF states
ret
;-------------------------
; Output CRLF
nl: call print
dc cr,lf
ret
;-----------------------------------------------------------------------------
; Command: OR
; This command performs a logical or operation by updating the
; if state without going to a new level. If there are active
; IFs and the current state is true, we do nothing. Else we back
; up one level and fall through to normal IF processing.
if oropt
orstart:
call msgbf1 ; Get if active byte
jr z,backup ; Treat like if if no IFs active
and (hl) ; Check current state
jr z,backup ; Current STATE false so go proecess
if noise
jr ifstat0 ; Else return and show status
else
ret ; Or just return
endif ; Noise
endif ; Oropt
;-----------------------------------------------------------------------------
; Command: AND
; This command performs a logical and operation by updating the
; if state without going to a new level. If there are active
; IFs and the current state is false, we do nothing. Else we back
; up one level and fall through to normal IF processing.
if andopt
andstart:
call iftest ; Test for IF running and false
if noise
jr z,ifstat0 ; Condition met, show status & return
else
ret z ; Condition met, return
endif ; Noise
endif ; Andopt
; Common stuff for and and or
if andopt or oropt
backup:
dec hl ; Pt to flag byte
srl (hl) ; Drop back one level
;
; Poke "IF" into external fcb for transient
;
if comif
pokefcb:
ld de,extfcb+1 ; Pt to external fcb
ld hl,ifcmd ; Pointer to IF command in table
ld bc,cmdsize ; Length
ldir ; Move it in
endif ; comif
; Fall through to IF PROCESSING
endif ;Andopt or oropt
;-----------------------------------------------------------------------------
; FCP Command: IF
;
; If current IF state is false, then advance to next level and set it
; to false also. If current IF state is true, then test condition and
; set the next level accordingly.
ifstart:
if not ifqopt
ld a,(extfcb) ; NZ if explicit
ld hl,tbuff
or (hl)
jp z,ifstat0 ; Report IF status
endif ; not ifqopt
ifstrt:
if noise
call nl ; Print new line
endif ; noise
call iftest ; See if current IF is running and FALSE
jP z,ifcf ; Yes, do the right thing
; Test for presence of colon in command. If colon present, then go directly
; to COMIF processing.
if comif
ld a,(extfcb) ; Check drive byte of external FCB
or a ; If it is zero, no colon was present
jp nz,runcomif ; If colon, go to comif processing
; Else fall through to resident processing
endif ; comif
;-----------------------------------------------------------------------------
;
; R E S I D E N T C O M M A N D P R O C E S S I N G
;
;-----------------------------------------------------------------------------
resident:
; Test for Equality if Equal Sign in Token
if ifoeq
ld hl,tbuff+1
if xeqopt ; Extended equal testing
skipsp: ; Skip over any space to first token
ld a,(hl)
or a ; Check for end of tail
jr z,ifck0 ; If so , go on
cp ' '+1 ; Test for space or control character
jr nc,tsteq ; If not, we are at first token
inc hl ; Otherwise advance to next character
jr skipsp ; ..and continue testing
endif ; xeqopt
tsteq:
ld a,(hl) ; Get character from command tail
inc hl ; Point to next one
or a ; EOL?
jr z,ifck0 ; Continue if so
if xeqopt
cp ' '+1 ; End of token?
jr c,ifck0 ; If so, go on
endif ; xeqopt
cp '=' ; Found '=' ?
jr nz,tsteq ; If not, continue scan
ld hl,fcb1+1 ; Else, get ready to compare FCBs
ld de,fcb2+1
ld b,11 ; 11 bytes
eqtest:
ld a,(de) ; Compare
cp (hl)
jr nz,ifcf
inc hl ; Pt to next
inc de
djnz eqtest
jr ifct
endif ; ifoeq
ifck0:
ld de,fcb1+1 ; Point to first character in FCB1
if ifoneg
ld a,(de) ; Get it
ld (negflag),a ; Set negate flag
cp negchar ; Is it a negate?
jr nz,ifck1 ; If not, go on
inc de ; Else point to character after negchar
ifck1:
endif ; ifoneg
if iforeg ; REGISTERS
call regtest ; Test for register value
jr nz,runreg
endif ; iforeg
call condtest ; Test of condition match
jr nz,runcond ; If found, process condition
if comif
jp runcomif ; If function not found in table, use transient
else
call print ; Beep to indicate error
dc bell
if noise
jp ifstat ; No condition, display current condition
else ; no noise
ret
endif ; noise
endif ; comif
;-----------------------------------------------------------------------------
;
; Process register - register value is in A
;
;-----------------------------------------------------------------------------
if iforeg
runreg:
push af ; Save value
call getnum ; Extract value in FCB2 as a number
pop af ; Get value
cp b ; Compare against extracted value
jr jrtrue ; True if match; false if not
endif ; iforeg
;-----------------------------------------------------------------------------
;
; Process conditional test - address of conditional routine is in HL
;
;-----------------------------------------------------------------------------
runcond:
jp (hl) ; "call" routine pted to by HL
;=============================================================================
;
; R E S I D E N T C O N D I T I O N O P T I O N S
;
;=============================================================================
; Condition: AMBIGUOUS
if ifambig
ifcambig:
ld hl,fcb2+1 ; Scan FCB2 for a '?' character
ld bc,11 ; Characters to scan
ld a,'?' ; Reference character
cpir
jr jrtrue ; True if '?' found; false if not
endif ; ifambig
;-----------------------------------------------------------------------------
; Condition: COMPRESSED
if ifcompr
ifccompr:
ld a,(fcb2+10) ; Get middle character of file type
cp 'Z' ; Crunched
jr z,ifctrue
cp 'Q' ; Squeezed
jr jrtrue
endif ; ifcompr
;-----------------------------------------------------------------------------
; Condition: TRUE
; IFCTRUE enables an active IF
; Condition: FALSE
; IFCFALSE enables an inactive IF
if ifoempty or ifoerror or ifoexist or ifowheel
jrfalse:
jr z,ifcfalse
endif ; Ifoempty or ifoerror or ifoexist or ifowheel
ifctrue:
if ifoneg
call negtest ; Test for negate
jr z,ifcf
endif ; ifoneg
ifct:
ld b,0ffh ; Active
jp ifset
if iforeg or ifambig or ifcompr or ifoinput or ifonull
jrtrue:
jr z,ifctrue
endif ; Iforeg or ifambig or ifcompr or ifoinput or ifonull
ifcfalse:
if ifoneg
call negtest ; Test for negate
jr z,ifct
endif ; ifoneg
ifcf:
ld b,0 ; Inactive
jp ifset
;-----------------------------------------------------------------------------
; Condition: EMPTY filename.typ
if ifoempty
ifcempty:
call tlog ; Log into FCB2's DU
ld de,fcb2 ; Pt to fcb2
ld c,15 ; Open file
push de ; Save fcb ptr
call bdos
pop de
inc a ; Not found?
jr z,ifctrue
ld c,20 ; Try to read a record
xor a ; <JPS> set cr value to zero
ld (fcb2+32),a ; <JPS> to attempt to read first record
call bdos
or a ; 0=OK
jr jrfalse ; true if no read
endif ; ifoempty
;-----------------------------------------------------------------------------
; Condition: ERROR
if ifoerror
ifcerror:
ld a,(z3msg+6) ; Get error byte
or a ; 0=FALSE (no error registered)
jr jrfalse
endif ; ifoerror
;-----------------------------------------------------------------------------
; Condition: EXIST filename.typ
if ifoexist
ifcex:
call tlog ; Log into DU
ld de,fcb2 ; Pt to fcb
ld c,17 ; Search for first
call bdos
inc a ; Set zero if error
jr jrfalse
endif ; Ifoexist
;-----------------------------------------------------------------------------
; Condition: INPUT (from user)
; Modified to say " (Y/N)? ", and accept ONLY Y or y or N or n
; Carson Wilson 3/1/88
if ifoinput
ifcinput:
call print
dc ' (Y/N)? '
ifcinp1:
ld hl,z3msg+7 ; Pt to ZEX message byte
ld (hl),10b ; Suspend ZEX input
push hl ; Save ptr to ZEX message byte
ifcinp2:
ld e,0ffh
ld c,6 ; Direct input from console
call bdos
or a ; Any input yet?
jr z,ifcinp2 ; Nope, try again
pop hl ; Get ptr to ZEX message byte
ld (hl),0 ; Return ZEX to normal processing
and 5fh ; Mask and capitalize user input
cp 'Y'
jr nz,testN ; No, check if 'N'
call conout ; Display 'Y'
jr ifctrue ; Process as true
testN:
cp 'N'
jr nz,notN ; Not 'N' or 'n'
call conout ; Display 'N'
jr ifcfalse ; Process as false
notN:
ld a,bell ; Protest!
call conout
jr ifcinp1 ; Force either Y or y or N or n
endif ; ifoinput
;-----------------------------------------------------------------------------
; Condition: NULL (2nd file name)
if ifonull
ifcnull:
ld a,(fcb2+1) ; Get first char of 2nd file name
cp ' ' ; Space = null
jr jrtrue
endif ; ifonull
;-----------------------------------------------------------------------------
; Condition: TCAP
if ifotcap
ifctcap:
ld a,(z3env+80h) ; Get first char of Z3 TCAP Entry
cp ' '+1 ; Space or less = none
jP c,ifcfalse
jP ifctrue
endif ; ifotcap
;-----------------------------------------------------------------------------
; Condition: WHEEL
if ifowheel
ifcwheel:
ld hl,(z3env+29h) ; Get address of wheel byte
ld a,(hl) ; Get byte
or a ; Test for true
jP jrfalse ; False if 0
endif ; ifowheel
;=============================================================================
;
; S U P P O R T R O U T I N E S
;
;=============================================================================
; Convert chars in FCB2 into a number in B
if iforeg
getnum:
ld b,0 ; Set number
ld hl,fcb2+1 ; Pt to first char
getn1:
ld a,(hl) ; Get char
inc hl ; Pt to next
sub '0' ; Convert to binary
ret c ; Done if error
cp 10 ; Range?
ret nc ; Done if out of range
ld c,a ; Value in C
ld a,b ; A=old value
add a,a ; *2
add a,a ; *4
add a,b ; *5
add a,a ; *10
add a,c ; Add in new digit value
ld b,a ; Result in B
jr getn1 ; Continue processing
endif ; iforeg
;-----------------------------------------------------------------------------
; Log into DU in FCB2
if ifoexist or ifoempty
tlog:
ld a,(fcb2) ; Get disk
or a ; Current?
jr nz,tlog1
ld c,25 ; Get disk
call bdos
inc a ; Increment for following decrement
tlog1:
dec a ; A=0
ld e,a ; Disk in E
ld c,14
call bdos
ld a,(fcb2+13) ; Pt to user
ld e,a
ld c,32 ; Set user
jp bdos
endif ; ifoexist or ifoempty
;-----------------------------------------------------------------------------
; Test of Negate Flag = negchar
if ifoneg
negtest:
negflag equ $+1 ; Pointer for in-the-code modification
ld a,0 ; 2nd byte is filled in
cp negchar ; Test for No
ret
endif ; ifoneg
;-----------------------------------------------------------------------------
; Test FCB1 against a single digit (0-9)
; Return with register value in A and NZ if so
if iforeg
regtest:
ld a,(de) ; Get digit
sub '0'
jr c,zret ; Z flag for no digit
cp 10 ; Range?
jr nc,zret ; Z flag for no digit
ld hl,z3msg+30h ; Pt to registers
add a,l ; Pt to register
ld l,a
ld a,h ; Add in H
adc 0
ld h,a
xor a ; Set NZ
dec a
ld a,(hl) ; Get register value
ret
zret:
xor a ; Set Z
ret
endif ; iforeg
;-----------------------------------------------------------------------------
; Test to see if a current IF is running and if it is FALSE
; If so, return with Zero Flag Set (Z)
; If not, return with Zero Flag Clear (NZ)
; Affect only HL and PSW
iftest:
call msgbf1 ; Test for active IF
jr z,ifok ; No active IF
and (hl) ; Check active flag
ret z ; Return Z since IF running and FALSE
ifok:
or 255 ; Return NZ for OK
ret
msgbf1:
ld hl,z3msg+1 ; Get IF active flag
ld a,(hl)
inc hl ; Pt to If status byte
or a ; Set z if no IF active
ret
;-----------------------------------------------------------------------------
; Test FCB1 against condition table (must have 2-char entries)
; Return with routine address in HL if match and NZ flag
condtest:
ld hl,condtab ; Pt to table
condt1:
ld a,(hl) ; End of table?
or a
ret z
ld a,(de) ; Get char
cp (hl) ; Comppare entries
inc hl ; Pt to next
inc de
jr nz,condt2
ld a,(de) ; Get 2nd char
cp (hl) ; Compare
jr nz,condt2
inc hl ; Pt to address
ld a,(hl) ; Get address in HL
inc hl
ld h,(hl)
ld l,a ; HL = address
jr ifok ; Set NZ for OK
condt2:
inc hl ; Pt to next entry
inc hl ; Skip over addr
inc hl
dec de ; Pt to 1st char of condition
jr condt1
;-----------------------------------------------------------------------------
; Turn on next IF level
; B register is 0 if level is inactive, 0FFH if level is active
ifset:
; ld hl,z3msg+1 ; Get IF flag
; ld a,(hl)
; or a ; If no if at all, start 1st one
call msgbf1
dec hl
jr z,ifset1
ifset0:
add a,a ; Advance to next level
jr c,iferr ; Check for overflow (8 IFs max)
ld (hl),a ; Set IF byte
jr ifset2
ifset1:
inc a ; A=1
ld (hl),a ; Set 1st IF
ifset2:
ld d,a ; Get IF byte
and b ; Set interested bit
ld b,a
inc hl ; Pt to active flag
ld a,d ; Complement IF byte
cpl
and (hl) ; Mask in only uninterested bits
or b ; Mask in interested bit
ld (hl),a ; Save result
if noise
jp ifstat ; Print status and exit
else
ret ; Or just exit
endif ; noise
iferr:
call print ; Beep to indicate overflow
dc bell
ret
;=============================================================================
;
; T R A N S I E N T I F P R O C E S S I N G
;
;=============================================================================
if comif
runcomif:
; First we have to find IF.COM
ld bc,100h*(ifdrv-'A')+ifusr ; Values to use if null path
if pathroot
ld hl,(expath) ; Point to symbolic path (indirect)
fndroot:
ld a,(hl) ; Check for end of path
or a
jr z,froot2 ; If end, branch
; Process Next Path Element
cp curint ; Current disk/user symbol?
jr nz,froot0 ; If not, branch
ld a,(curdr) ; Get current disk
inc a ; Compensate for following decrement
froot0:
dec a ; Shift to range 0..15
ld b,a ; Set disk
inc hl ; Point to user in path
ld a,(hl) ; Get user
cp curint ; Current drive/user symbol?
jr nz,froot1 ; If not, branch
ld a,(curusr) ; Get current user
froot1:
ld c,a ; Set user
inc hl ; Point to next element in symbolic path
jr fndroot
; Done with Search - BC Contains ROOT DU (or specified DU if path is empty)
endif ; pathroot
froot2:
call logbc ; Log into IF.COM's directory
; Try to Open File IF.COM
ld de,extfcb ; Point to command FCB
xor a
ld (de),a ; Force current drive
ld c,15 ; Open file
call bdos
inc a
jr nz,ifload ; Branch if file found
; IF.COM not found - process as IF F
ifnotfnd:
call iferr ; Ring bell
call reset ; Return home
jp ifcf
; Load File IF.COM
ifload:
call defdma ; First record to tbuff
call readcmd ; Read 1st record from IF.COM
jr nz,ifnotfnd ; If eof, treat as if file not found
ld (extfcb+32),a ; Start from scratch (record 0)
ld a,(tbuff+8)
cp 3
jr c,ifnotfnd ; Only Types 3 and 4 are acceptable
call loadif ; Load IF.COM and set IFADR appropriately
;
; Build the command tail at tbuff
;
ld de,tbuff ; Point DE to tbuff
push de ; Save it for later
ld hl,(z3msg+4) ; Points into MCL buffer
;
; Advance HL to first 'space' after IF or .IF or :IF
;
advsp: inc hl
ld a,(hl)
cp ' '+1 ; Carry if space or null
jr nc,advsp
ld c,0 ; Clear a counter
putt: inc de ; Advance tbuff pointer
ld a,(hl) ; From MCL
ld (de),a ; To tbuff
inc hl ; Advance MCL pointer
or a ; Check for null
jr z,putx ; End of command line
cp ';' ; Command separator
jr z,putx ; End of command
inc c ; Count it up
jr putt ; Next..
putx: xor a ; Get a null
ld (de),a ; Terminate the line in tbuff
pop hl ; Beginning of tbuff
ld (hl),c ; Character count
;
; Pick up the execution address for Type 3 or 4
;
ld hl,(ifadr) ; Load address
ld a,(hl) ; First byte at load address
cp 0c7h ; Test for RST 0
jr nz,runif ; Nope, execute it
ld (hl),0c3h ; Plug in a JP
;
; Arrive here to execute IF.COM
;
runif: ld hl,z3env ; Pass environment in HL
db 0c3h ; JP instruction
ifadr: dw 0 ; Load/Execution address of IF.COM
;
; Load IF.COM
;
loadif:
ld hl,(tbuff+11) ; Type 3 load address
jr z,loada ; Load as Type 3
;
; Assume Type 4 (or higher)
;
ld hl,extfcb+32 ; Point to CR of extfcb
ld (hl),2 ; Set up for record 2
push hl ; Save the pointer
call readcmd ; Get it into tbuff
pop hl
jp nz,ifnotfnd ; Too short
ld (hl),a ; Record 0 again
ld hl,(tbuff+11) ; Size word
push hl ; Save it
call readcmd ; Read record 0 again
pop bc ; Size
ld de,(ccp) ; CCP start
ld hl,z3env
dec a ; Phony fullget flag
call tbuff+9 ; Call Type 4 loader
push hl ; Save load address
call readcmd ; Read record 1 to tbuff (point to record 2)
pop hl ; Load address
;
loada: ld (ifadr),hl ; Save it
;
; Load IF.COM to (HL) until end of file, reset DMA and DU and return
;
load: push hl ; Save loading address
call setdma ; According to HL
call readcmd ; Read a record from file
pop hl ; Get current loading address back
jr nz,reset ; End of file
ld de,128 ; Advance it by one record
add hl,de
jr load ; Back to read some more
; Reset DMA and Current DU
reset: call defdma
ld bc,(curusr) ; Return home
; Log Into DU in BC
logbc: ld e,b ; Set disk
push bc
ld c,14 ; Select disk
call bdos
pop bc
ld e,c ; Set user
ld c,32 ; Select user
jp bdos
; Set default DMA address
defdma: ld hl,tbuff
; Set DMA to address according to HL
setdma: push hl ; Save it
ex de,hl ; To DE
ld c,26 ; Set DMA command
call bdos ; Do it
pop hl ; DMA address
ret
; Read a record from file in EXTFCB
readcmd:
ld de,extfcb
ld c,20
call bdos
or a ; Set NZ if error (end of file)
ret
endif ; comif
;=============================================================================
;
; U T I L I T Y S U B R O U T I N E S
;
;=============================================================================
; Print "IF "
prif:
call print
dc 'IF '
ret
;-----------------------------------------------------------------------------
; Print String (terminated in 0 or MSB Set) at Return Address
print:
ex (sp),hl ; Get address
call print1
ex (sp),hl ; Put address
ret
; Print String (terminated by MSB Set) pted to by HL
print1:
ld a,(hl) ; Done?
inc hl ; Pt to next
call conout ; Print char
or a ; Set msb flag (m)
ret m ; Msb terminator
jr print1
;-----------------------------------------------------------------------------
; Console Output Routine
conout:
push hl ; Save regs
push de
push bc
push af
and 7fh ; Clear msb
ld e,a ; Char in E
ld c,2 ; Output
call bdos
pop af ; Get regs
pop bc
pop de
pop hl
ret
;=============================================================================
;
; Display current length in records
;
prtval macro m1,v1,m2,v2,m3
.radix 10
.printx m1 v1 m2 v2 m3
endm
length equ $ - start
recs equ length / 128
bytes equ length mod 128
.printx
prtval <FCP is now>,%recs,<records and>,%bytes,<bytes long.>
.printx
end
; End of NZFCP.Z80