home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
mbug
/
mbug167.arc
/
ZMP-BEE.LBR
/
RSXMAST.MZC
/
RSXMAST.MAC
Wrap
Text File
|
1979-12-31
|
25KB
|
714 lines
title rsxmast outline rsx for cpm2.2 (85/11/13)
;
; Copyright (c) 1985 by C.B Falconer (203) 281-1438
; 680 Hartford Tpk, Hamden, Ct 06517. All rights reserved.
;
; This program may be copied/used/modified etc, but it may NOT
; be sold without express written permission from C.B. Falconer
;
; This system was assembled with SLR's SLRMAC. M80 can also be
; used, but care must be taken with macro parameter names.
;
rsxver equ 12 ; Version number to be filled in. <10 debug
;
; ==================== I M P O R T A N T =======================
; AN ACTUAL SYSTEM IS CONSTRUCTED WITH INCLUDE FILES. THE FILES
; REQUIRED ARE:
; RSXCUST.INC, RSXINIT.INC, BYERSX.INC and RSXMAIN.INC
; in addition to this file and BDOS.DEF
; If your assembler cannot handle include files, then you must
; make the insertions manually with your editor.
; ==============================================================
;
false equ 0
true equ not false
no equ false ; synonyms for convenience
yes equ true
;
; The system implements a generalized CPM 2.2 RSX system. The
; RSX is installed by running the system, and removed by running
; it again. The program uses 8080 opcodes only in the RSX
; section, although the included files required may contain
; Z80 code. This should ease porting to 8080 only systems.
;
; NOTE: This source file requires SLRs SLRMAC or M80 for assembly,
; and RELOCCP.SYS for run-time load and relocation.
;
; Revisions: (in LIFO order)
; 1.2 85/11/13. FINDOS/CHKSYS are now application init callable
; procs. BDOSLGH, BDOSARG, CCPLGH are now equates, to allow
; for non-CPM systems. Increased min. stack to 48 bytes.
; Added boothk. Some name changes for M80 compatibility.
; Modified the CCP re-entry mechanism for ZCPR compatibility.
; 1.1 85/11/09. Allowances for range of RSX's. Drivers may now
; be installed after a non-driver RSX has been mounted. These
; changes allow implementation of a BYE replacement system.
; Separate RSXCUST.INC file.
; 1.0 85/09/23. Initial release.
; 0.3 85/01/27. First working disk drive.
; 0.2 85/01/24. Provisions for BDOS driver installation,
; checks etc.
; 0.1 85/01/05. Inactive causes reversion to original BDOS call in
; case this was a substitute for it. debug allows testing.
; Keep track of current DMA address.
; 0.0 Original version, by C.B. Falconer (85/Jan/04).
;
; This system is the outline of a generalized RSX system, with
; initialization and termination code. It is expected to
; respond to BDOS calls with the value @RSX (normally larger
; than any usual CPM call value), and receive an argument of
; some form in the (de) register. Two special values of (de)
; are reserved (0 and -1). In usual operation the (de) value
; is normally a pointer, which cannot take on either of these
; special values. For character output RSXs (e.g. list output
; replacement) this prevents sending a nul or a rubout with all
; bits set. Remember this is a full word parameter.
;
; 0 implies a residence inquiry, and should return a zero
; value if the system is not resident, (as will CPM 2.2 for any
; invalid calls), and non-zero if resident and activated. This
; allows the initialization code to detect that the system is
; already mounted, and avoid multiple loading. Similarly
; application programs can check that the RSX is available. A
; zero value returned in (a) signifies the RSX is not available.
;
; The second special value is 0ffffh (i.e. -1), which
; signals the system to become inactive, so that the next
; warm boot will remove it entirely.
;
; A third special argument is 0001h. This is optional, and is
; used to return a data address. For DSKDRIVE in particular
; this is used to return a pointer to the memory resident
; drive configuration table (whose structure thus should not
; be altered in order to maintain compatibility with auxiliary
; software). (DSKDRIVE actually returns this pointer for all
; DE arguments other than 0 or -1, but this should not be
; counted on.)
;
; This file implements an example RSX, and indicates where the
; code should be installed, and the calling conventions for other
; RSXs. See the label "chkparms" to allow initialization
; parameters, and the label "rsx" to install the actual code.
; Note especially than any code located ahead of the label
; "@keep" is available only during initialization. However
; the initialization section can call routines in the retained
; portion. The "bthook" connector allows re-initialization on
; each "warm boot" or disk reset. "boothk" is different, and is
; called on each warm boot, but not at disk reset.
;
; The system, when combined with "RELOCCP", loads itself just
; below the CCP, and keeps the CCP resident. (See RELOCCP.OVR,
; which is an assembly time option for RELOCCP, for a method
; of minimizing memory wastage for multiple RSX's). If RSX.COM
; is executed while resident, it attempts to remove itself and
; reclaim memory. If other systems have been loaded below RSX
; it will not be able to reclaim memory until those systems
; (probably further RSX's) have been removed. The customizable
; routine "killhk" allows manipulation of a resident RSX.
;
; To create a custom RSX modify the files RSXINIT, RSXMAIN, RSXCUST
; and possibly BYERSX.xxx, rename them with the extensions ".INC"
; and .DEF as required, and re-assemble RSXMAST. Give the resultant
; relocatable file the appropriate name, and create the MYRSX.COM
; with RELOCCP (See RELOCCP documentation). When executed you now
; have available a new BDOS function, which executes whatever you put
; in. IF YOUR BDOS/CCP is non-standard see BDOS.DEF file.
;
; Acknowledgement: Some of the mechanisms used in this system
; have been taken from various public domain systems, especially
; those by Gary Novasielski and Bruce Ratoff.
;
; This system was created to ease installation of two operations:
; a generalized foreign disc driver, and a "CHAIN" mechanism
; whereby programs can load and execute arbitrary commands. The
; pre-existing KEYS program can probably be converted to execute
; under this system, as can UNSPOOL40 (enhancement of Br. Ratoffs
; UNSPOL30).
;
; While some code economies could easily be made for any particular
; application, I feel that using one standard environment is much
; more important. Thus the provisions for bios driver modification
; have been installed, with the complete check/restore system. The
; disadvantage remains that custom code must be included in this
; source and assembled, rather than standing by itself.
;
; Definitions of BDOS functions.
include BDOS.DEF
;
; Put any customization equates here
include RSXCUST.DEF
;
; Macro Definitions
;
; Force location counter zero modulo val
; with respect to "wrto" by filling with "fill" bytes
align macro val,wrto,fill
local here
here equ $ - wrto
if (here+val)/val*val-here-val
if nul fill
ds (here+val)/val*val-here
else ; ; SLRMAC specific coding.
ds (here+val)/val*val-here,fill
endif
endif
endm
;
; ************************************************************
; * This is my standard page relocatable system. See RELOCCP *
; ************************************************************
;
.z80
cseg ; system requires org 0 and org 100h modules
; You may replace this with two "orgs" in two
; different assemblies to get the overall system
; for RELOCCP to prepare and relocate at run-time.
;
; This defines the first location of the relocated image.
; The portion from here to "@keep" is not retained after
; initialization. The data here is used for relocation
@base: jp intro ; Following is std relocation data
@size: dw segsiz ; size of segment to relocate
@memsz: db pages ; total memory use in pages
;
; Patch/alter this value to non-zero if the RSX may only be
; loaded in a virgin system. This should be done if the system
; installs bios modifications that the BDOS can see.
chkflg: db driver ; Set non-zero for virgin system only
;
; This code gets everything started
intro: ld hl,(bdos+1) ; First so other calls work
ld (gobdos+1),hl ; Save the BDOS entry point
ld de,signon
call tstr
call findos
jp nz,badsys ; Invalid system configuration
; " "
; Set up the connector to return to CCP on boots
ld de,-ccplgh-7+3 ; Form pointer to CCP re-entry
add hl,de
ld (ccpret+1),hl ; and save for future use
; " "
; Do application specific parameter checking
call chkparms ; Do any parameter checking needed
jp c,exeunt ; ..with help message on carry=fault
; " "
; Check for initial load, or re-entry
ld de,0
ld a,@rsx ;
call dos ; enquire whether loaded
or a ; If loaded, then
jp nz,intro1 ; bring it down
call rsxset ; else initialize.
; " "
; Now do the user customizable initialization
call init ; Customized portion
jp bootrq ; ..bootrq, which sets connectors
;
; already loaded, bring it down
intro1: call killhk ; for systems that modify running RSX
ld de,-1
ld a,@rsx
call dos ; tell it to come down on next boot
jp boot ; which should kill it
;
; Setup the system. First, check environment to see if
; BIOS vectors are accessible and reasonable.
; a,f,c,d,e,h,l
rsxset: ld hl,(boot+1)
ld (boot0+1),hl ; Save the BOOT vector
if nodrive
inc hl
ld e,(hl) ; save warm boot connector
inc hl
ld d,(hl)
ex de,hl
ld (bsave),hl
ld hl,bootrq ; and reconnect to our system
ex de,hl
ld (hl),d
dec hl
ld (hl),e
ret
else ; drivers to be available
ld a,(boot) ; Location BOOT should
cp 0c3h ; have a JMP instruction
jp nz,vecterr
ld hl,(boot+1) ; Location one points to
ex de,hl ; the table of bios jumps
ld hl,(bdos+1) ; This should point to BDOS
ld a,(chkflg)
ld (kill+1),a ; Save for use at exit time. Unclean
or a ; but want it user patchable (1 place)
if multidrv
call findos
else ; NOT multidrv
call nz,chksys ; Hook, prevent loading invalid system
endif
ex de,hl ; bios pointer to hl
ld c,nvects ; preserve z flag in here
ld de,biosv
push de ; by default init our vector
jp nz,vecterr ; after push, to correct stack
ld de,bsave ; which we move into
ex de,hl ; the code.
; " "
; Now copy the original vectors into our tables, while verifying
; that they are reasonable (i.e. start with CALL or JMP). The
; CALLs allow for warmboots that call a ROM routine, with the
; stack identifying the actual system location.
rsxset1:ld a,nvects-n22vec
cp c
jp nc,rsxset2 ; stop checking after 2.2 types
ld a,(de)
xor (hl) ; another JMP?
and 0f1h ; allow Call or Jmp
jp nz,vecterr
rsxset2:ld a,(de)
ld (hl),a ; bsave[n,0]
inc de
inc hl
ex (sp),hl
inc hl
ld a,(de)
ld (hl),a ; biosv[n,1]
inc hl
ex (sp),hl
ld (hl),a ; bsave[n,1]
inc de
inc hl
ld a,(de)
ld (hl),a ; bsave[n,2]
ex (sp),hl
ld (hl),a ; biosv[n,2]
inc hl ; biosv[n+1,0]
ex (sp),hl
inc hl ; biosv[n+1,0]
inc de
dec c ; n := n+1;
jp nz,rsxset1
pop hl ; purge 2nd transfer address
; This was satisfactory, now if "driver" is TRUE, patch the
; BIOS drivers to point to the new copy (only the std CPM 2.2
; entries) so that new entries can be made locally. The final
; exit mechanism will restore everything.
ld a,(chkflg)
or a
ret z ; no bios patches needed
; " "
; Patch the original bios drivers, which have been checked
; for validity and a reasonable location, to point to the
; new bios table. Only called when "driver" is TRUE. DO NOT
; PATCH the original warm/cold boot entries.
bpatch: ld hl,(boot+1)
inc hl
inc hl
ld de,biosv
ld c,n22vec-1 ; count of 2.2 bios entries only
bpat1: inc hl
inc de
inc de
inc de
inc hl
ld (hl),e
inc hl
ld (hl),d
dec c
jp nz,bpat1 ; more
ret
;
; Check system is in usable state. (de) holds the bios pointer,
; and (hl) holds the bdos pointer. If the values are not
; reasonable, return non-zero flag. If successful returns hl
; a pointer to location 7 on the BDOS entry page (CPM 2.2).
; Modifications here can allow installation of multiple
; drivers. This is safer as it stands.
; a,f,h,l
chksys: call findos ; worked before, must work now
ld a,e
cp 3
ret nz ; boot pointer should end in 3
ld a,d
sub h
sub bdoslgh ; Z flag if correct page,
ret ; else non-virgin BIOS pointer
;
vecterr:
pop de ; remove the extra pointer
endif ; NOT nodrive
; " "
; Exit with invalid system message
badsys: ld de,vcterrmsg
; " "
; exit with message de^
exeunt: call tstr
jp boot ; try re-booting.
;
vcterrmsg:
db cr,lf,'Invalid system$'
;
; Find the actual location of BDOS by following the trail from
; the pointer in hl. Return z flag and hl = pointer to location
; 7 of the base BDOS page if found, else nz flag.
; For this to function connectors must be of the form used in
; intercept below. Scan for label "intercept:"
; Note that ENTRY IS IN THE MIDDLE, not the next instruction
; a,f,h,l
fndos1: cp 03eh ; (mvi a). Check for intercept
ret nz ; not a connector, not found
inc hl ; ignore operand for MVI A,--
inc hl
ld a,(hl)
cp 0b9h ; (cmp c)
ret nz ; not a connector
inc hl
ld a,(hl)
and 0e7h ; may be an intercept
cp 0c2h ; jz, jnz, jc, jnc are acceptable
ret nz ; not a connector
inc hl
fndos2: ld a,(hl)
fndos3: inc hl ; load the JMP operand
ld h,(hl)
ld l,a ; and continue up the chain
; " "
; Main entry point here
findos: ld a,(hl) ; find the actual BDOS. *** ENTRY <<<
cp 0c3h ; (jmp). Code for CPM 2.2 only
jp nz,fndos1 ; Not the real thing
fndos4: inc hl
ld a,(hl)
cp bdosarg mod 256 ; known value in CPM 2.2
jp nz,fndos3 ; not end, continue up the chain
inc hl
ld a,(hl)
add a,bdosarg / 256 ; allow for non-CPM systems
cp h ; at end JMP is on same page (CPM2.2)
dec hl ; point back to start of arg
jp nz,fndos2 ; else continue up the chain
ret ; (z) FOUND it.
;
; =============================================================
; **** Custom portion of initialization code here ****
; =============================================================
;
; The following code is used on initialization and then discarded.
; See "RSXINIT.xxx" for details. It may call on all routines in
; the system.
include RSXINIT.INC
;
; ------------------ End custom initialization area ----------------
;
align 256,@base,0 ; ensure page aligned
;
; *******************************************************
; * The code from here up is retained in memory after *
; * initialization. It may be used by the initializer *
; * This code MUST start on a page boundary. *
; *******************************************************
@keep:
;
; During operation, this location will point to intercept and will
; be jumped to by BDOS calls from location 5. This organization
; depends on the fact that BDOS calls the bios directly (ignoring
; the pointer at location 1), except when needing a warm boot
; (e.g. after a disk error), when it uses the pointer at 1.
;
; This must be at the lowest location in the protected code segment.
bdosv: jp intercept ; the bdos link
;
; This will normally contain no code, but can be used to create a
; system compatible with the existing BYE programs.
include BYERSX.INC
;
if nodrive
bsave: dw $-$ ; save original warm boot connector
else ; NOT nodrive
; This area replaces the bios jump table, allowing intercepts.
; Any intercepts (usually console commands) are set up by the
; initializing code, which is discarded after execution. See
; comments on "nvects" above. Normally these bios vectors will be
; accessed only by executing programs, and not by the BDOS unit.
; To insert drivers in the bios it is necessary to save the original
; bios pointers (for restoration when the RSX is removed) and
; install jumps to this revised table in the original table. Note
; that the original table may contain a CALL for the warmboot vector,
; so that ROM based code can tell the CPM system size when called.
biosv: rept nvects ; ; biosv is the new warmboot connector
jp $-$
endm
;
; This table has two purposes - it allows connection to the original
; bios vectors destinations, and it saves all the values for
; restoration upon RSX exit. Thus the custom initialization section
; can patch the real bios table to install new disk drivers, etc.
; Note that this can only work when this is the FIRST rsx installed.
; Further ones can only intercept user bios calls and BDOS calls.
; Provided that the bios table in effect on entry to this system
; does not hold any data areas, the restoration on RSX removal will
; be harmless.
bsave: rept nvects ; ; bsave is the old warmboot connector
jp $-$
endm
;
; An example showing how to refer to the "old" entries needed.
; Index 0 here is warmboot, not cold. Similarly for "new" entries
;@home equ bsave+(7*3)
;@seldk equ bsave+(8*3)
;@setrk equ bsave+(9*3)
;@setsec equ bsave+(10*3)
;@setdma equ bsave+(11*3)
;@read equ bsave+(12*3)
;@write equ bsave+(13*3)
;@sectran equ bsave+(15*3)
endif ; NOT nodrive
;
; This routine intercepts all BDOS calls.
; Note that the initial code sequence allows applications to
; find the actual BDOS, if necessary. See SD88F6 for one use.
intercept:
ld a,0ffh
cp c
jp c,gobdos ; Never taken, but SD trackable
ld a,@sys ; Get function
cp c
jp z,sysreq ; a reboot request
ld a,@dma
cp c
jp z,dodma
ld a,@log
cp c
jp z,drvreset ; reset this drive also
ld a,@rsx ; defined for this system
cp c
jp z,inrange
ld a,@rsxx ; check for a special extra
cp c ; intercept (e.g. setuser for
jp z,inrange ; BYE replacement)
ld a,@rsxy ; check for another special extra
cp c ; intercept (e.g. chain for
jp z,inrange ; BYE replacement)
ld a,@rsxlo-1
cp c
jp nc,gobdos ; not in range
ld a,@rsxhi
cp c
jp c,gobdos ; not for us
; DO NOT optimize the above sequence. It is intended to be
; trackable by utilities to list the RSX's active. The series
; stops when the instruction is not "ld a,bytevalue". The
; initial "ld a,0ffh" will not be counted by tracking utilities
; and the checks on @SYS and @DMA are always expected. This
; organization allows a range of BDOS calls to be intercepted.
; " "
inrange:
ld hl,0 ; intercepting, switch stacks
add hl,sp ; because application may not
ld sp,lclstk ; allow sufficient room
push hl ; save entry stack pointer
call doit ; This is an extension call
ex de,hl ; save return value
pop hl ; restore entry stack
ld sp,hl
ex de,hl ; return its result
ld a,l ; copy result to (a)
ld b,h ; so (ba)=(hl), like BDOS
ret ; to the caller.
;
; Reset this drive also when application wants a drive reset
; Added to RSX system for disk drive application.
; This is also called on any warm-boots
drvreset:
push bc
call bthook ; user customizable.
pop bc
jp gobdos
;
; Keep track of the current DMA address on general principles
dodma: ex de,hl
ld (dmadr),hl ; BDOS' view, not BIOS
ex de,hl
; " "
; Connects to the "real" BDOS routine
gobdos: jp $-$ ; Patched on entry
;
; The RSX (resident system extension). Argument is de as usual,
; and the extension specified is (c). Return value is put in hl.
; The stack is already set to the local stack, with the old
; stack pointer under the return from doit.
; a,f,b,c,d,e,h,l (allowed)
doit: ld hl,(active) ; set "enquiry" return value in (l)
ld a,l
or a
jp z,gobdos ; inactive, use bdos call
ld a,c
cp @rsx
jp nz,rsx ; not the master call, ignore parm
ld h,0
ld a,e ; check for "loaded enquiry"
or d
ret z ; signal active on enquiry
ld a,e
and d
inc a
jp nz,rsx ; not "pulldown" request.
; " "
; Inactivate the RSX. Next boot will try to recover the memory.
kill: ld a,$-$ ; patched with "chkflg" at init
or a
call nz,unpch ; Remove any bios alterations
xor a
ld (active),a ; mark inactive
ld l,a ; return 0, pulldown accepted
ld h,a ; and we are now inactive.
ret
;
unpch: if nodrive
ret
else ; NOT nodrive
; Remove any bios patches made on initialization, in case this is a
; driver being inactivated, and further RSX's are loaded beyond it.
; Thus a "kill" request will be logically executed, even though the
; memory is not reclaimed. However bios alterations via the pointer
; at 1 cannot be removed until a warm boot occurs (that pointer may
; be pointing to an RSX installed later). Thus the table at biosv
; must be updated to point to the original bios entries
ld de,bsave+3
ld hl,(boot0+1)
inc hl
inc hl
inc hl ; start at the constat entry
push hl
ld hl,biosv+3
ld c,n22vec-1 ; dont alter the warm boot entries
unpch1: ld b,l ; offset, depends on page alignment
inc de ; past opcode
inc hl ; Ignore the opcode (dont change)
ld (hl),b ; biosv[n,1] --> oldbios[n,0]
inc hl
ex (sp),hl
ld b,h ; oldbios page
inc hl
ld a,(de) ; lsb
ld (hl),a ; oldbios[n,1]
inc de ; ^msb
inc hl
ld a,(de) ; msb
ld (hl),a ; oldbios[n,2]
inc hl ; oldbios[n+1,0]
ex (sp),hl
ld (hl),b ; biosv[n,2] --> oldbios[n,0]
inc hl ; biosv[n+1,0]
inc de ; next opcode
dec c ; n := n+1
jp nz,unpch1
pop hl
ret
endif ; NOT nodrive
;
; Note that the following "boot" entries will never be reached if a
; further RSX has been installed, since that RSX will intercept the
; boot and do a direct return to the CCP (unless it is inactive, and
; removes itself, when a whole chain of RSX removals can be started)
;
; The application process has requested a warm-boot by invoking BDOS
; function 0. If the system is inactive remove it, otherwise return
; to the CCP via the stored (on initialization) CCP return value.
sysreq: jp bootrq ; This allows separation if needed
;
; The application process has requested a reboot by jumping to
; location 0. If we are no longer active, we will honor the request
; by executing the address found in the BOOT vector at entry.
; Otherwise return to CCP without rebooting.
bootrq: ld sp,lclstk ; set up a valid stack
ld a,(active)
or a
jp z,done ; Not active, all done. Remove self
call boothk ; For applications to detect reboot
ld c,@log
call drvreset ; Reset drives, like any other reboot
ld de,actmsg ; does. Calls bthook routine
call tstr
ld de,altid ; added message portion for
call tstr ; DSKDRIVE use
; " "
; Reset the system pointers to use this system.
ld hl,bdosv
ld (bdos+1),hl
if not nodrive ; else leave connectors alone
ld hl,bootrq
ld (biosv+1),hl
ld hl,biosv
ld (boot+1),hl
endif ; NOT nodrive
ld hl,tbuff
ld (dmadr),hl ; Will be set by CCP
ld a,(drvusr)
ld c,a ; drive/user under which to re-enter
ccpret: jp $-$ ; Patched on startup
;
; Done with the system
done: ld de,donemsg ; Message and jump to old boot addr.
call tstr ; as originally read from memory wd 1
if nodrive ; Then we have to reset the wboot
ld hl,(bsave)
ex de,hl
ld hl,(boot0+1) ; The original destination
inc hl
ld (hl),e
inc hl
ld (hl),d ; restore it all
endif
boot0: jp $-$ ; Reboot. Patched on initialization
; This value points to old bios table
; and the old reboot resets connectors
;
; ================================================================
; Utility routine area
; ================================================================
;
; Put string (de) to console, '$' terminated
; a,f
tstr: ld a,@msg
; " "
; dos call (a) without disturbing registers. Does not use the RSX
; a,f
dos: push bc
push de
push hl
ld c,a
call gobdos
pop hl
pop de
pop bc
ret
;
; ==================================================================
; **** To keep as much as possible constant, put real RSX here ****
; ==================================================================
;
; The following allows for machine dependant code for i/o drivers
; the file may consist of comments only if not needed.
include RSXIO.INC
;
; The following is the actual application code. It may only call on
; the following routines: TSTR, DOS, GOBDOS. (See above)
include RSXMAIN.INC
;
; This organization allows RSXMAIN to assign storage contiguous
; to the local stack, but not past it.
ds stksz ; Local stack of at least STKSZ/2 words
; plus any remainder on page
ds 2 ; allow for dmadr below, forced to page end
; align to next page boundary
align 256,bdosv
;
lclstk equ $-2 ; Reserve space for following
dmadr equ lclstk ; Keeps track of current value known to DOS.
; Note that this may not be that known to BIOS
;*************************************************
; End of segment to be relocated.
pages equ ($-@base)/256 ; So loader knows memory needs.
;
end