home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
cpm
/
22rsx
/
22rsx-20.ark
/
22INSTA.ASM
next >
Wrap
Assembly Source File
|
1984-10-13
|
12KB
|
456 lines
;
;Program name: 22INSTA.ASM v2.0
;Author : James Whorton
;Date written: 10/13/84
;(Derived from 22RSX.ASM v1.0 09/23/84)
;
;This is the first segment of the driver module for installing Resident
;System Extensions to BDOS in a CP/M 2.2 environment. The idea for this
;came from the CP/M 3.0 RSX facility.
;When a suitable object module is attached to this driver and the
;result is assembled and loaded, it will, on execution, install
;the BDOS extension into the system. On all subsequent calls to
;BDOS, this and any other extension present will intercept and
;anaylyze it first, passing it along to the next function or doing
;other processing as desired.
;If one or more 22RSX modules are already present, the current one
;will be patched in underneath the last extension, and the appro-
;piate pointers will be adjusted.
;>> Note: the 22RSX manager MUST be installed first. If it is not resident
;when this driver is run, an error will occurr and the driver will abort.
;
; vers. 2.0 (10/13/84):This module is taken from 22RSX 1.0. An RSX manager
; is first installed by running 22RSX, then the
; module .COM file is run, installing the RSX desired.
; For assembly instructions, see .DOC.
; (Note: the PARM code herein has been left in place
; to facilitate future improvments I have on the draw-
; ing board. If you want details, contact me. JHW)
;
;
;BDOS equates
;
bdos: equ 5
cout: equ 2
callrsx:equ 59 ;RSX function call
rtwrm: equ 1 ;RSX Return WMLOC function #
;
;other equates
;
lxid: equ 11h ;define byte of LIX D,nnnn to fake loader
cr: equ 13
lf: equ 10
tab: equ 9
bell: equ 7
esc: equ 27
;
; ***
;
;Program starts here
;
org 0100h
;
jmp hitit ;pass the following
;
;this line is an assembler trap to warn the user if he doesn't have the
;RSX module terminated properly...
;
call ilprt ;** ERROR -- CHECK RSX MODULE FOR LINK '22INSTB' AT END.
;
hitit: lxi h,0 ;save old stack pointer
dad sp
shld oldstk
lxi sp,stack ;set stack for local ops.
;
;Print signon message
;
lxi h,signon
call ilprt
;
lxi h,begobj ;setup table for loader
shld parm ;first param.
lxi h,endobj
shld parm+2 ;second param
lxi h,pend
shld parm+4 ;third param.
;
mvi a,0 ;set flag for return
mvi c,callrsx ;get WMLOC from manager
lxi d,rtwrm
call bdos ;do it
cpi 0FFh ;manager there?
jz dupchk ;yes, proceed
lxi h,nogo$msg ;manager wasn't there, so abort
call ilprt
jmp wrap ;byebye...
;
;check to see if RSX module has already been loaded;;;
;
dupchk: push d ;save returned addr.
lhld bdos+1
shld point ;starting pointer
;
chk1: lhld point ;get pointer
lxi d,16 ;offset to name
dad d
push h ;save for a sec...
lxi h,begobj ;point to local name
lxi d,16
dad d
pop d ;get param back
mvi b,8 ;check 8 bytes
call compar ;a match?
jnz chk2 ;no, go ahead
lxi h,dup$msg ;tell user and abort
call ilprt
jmp wrap ;exit
;check for manager
chk2: lhld point ;get current pointer
lxi d,16 ;offset to name
dad d
xchg ;put in <de>
lxi h,manchk ;manager name block
mvi b,8
call compar ;match?
jz load ;yes, module wasn't installed, go ahead
;set up for next loop
lhld point
lxi d,10
dad d
lxi d,point
mvi b,2
call move
jmp chk1 ;cycle again
;
;The following loader section, which loads the object code
;into high memory, then adjusts any addresses contained
;therein, is a modified version of that found in BYE3-23.
;Many thanks to all concerned.
;
load: pop d ;get addr. back
xchg ;put WMLOC in <hl> to store
shld wmloc ;store it for later
lhld bdos+1 ;get current jump addr.
shld parm+6 ;save it for later (prevd)
lhld bdos+1 ;get pointer again
lxi d,-32 ;subtract 32 bytes to be safe
dad d ;destination for this module
;
;HL now contains the destination address of the object module
;
push h ;save
lhld parm+4 ;set up the source pointer
dcx h
xchg
push d
lxi b,pend-begobj ;set up byte counter
lhld parm
xchg
lhld parm+4
call sbc ;subtract de from hl
push h ;save it
;
;Now pop them back off the stack
;
pop b
pop d
pop h
block: ldax d ;get object module byte
mov m,a ;move it
mov a,b ;get byte count
ora c ;finished block transfer?
jz update ;yes, check on the opcode values
dcx d ;no, set source pointer
dcx h ;set destination pointer
dcx b ;set byte counter
jmp block ;continue transfer
;
update: xchg ;move the source address into HL
call neghl ;prepare value for subtraction
dad d ;form the proper offset
shld offset ;save the offset
xchg ;set up the offset register
lhld parm+2 ;get the ending addr of the RSX code. (endobj)
dad d ;form the new ending addr (new location)
shld endrng ;save the ending addr of the RSX code.
lhld parm ;get the start addr of the object module (begobj)
dad d ;form new beginning addr (new location)
;
;The following code determines whether or not an address is within the
;object module and sets it to the new address if it is - otherwise it will
;not disturb the code...
;
dcx h ;set up source pointer for the modi-
;..fication routine entry
modify: inx h ;point to the next (hopefully) instr.
db lxid ;get the address of the end of object module
;
endrng: dw 0
mov a,e
sub l
mov a,d
sbb h ;have we finished moving this block?
jc patch ;yes, we can patch now
;
;Here is where we test for 3-byte opcodes
;
mvi b,inst3e-inst3 ;get th number of elements in the table
lxi d,inst3 ;set up the 3-byte opcodes table pointer
;
thrbyt: ldax d ;get opcode byte from table
cmp m ;is this byte a 3-byte opcode?
jz change ;change the 2nd and 3rd bytes if needed
inx d ;no, advance table pointer
dcr b ;end of 3-byte table?
jnz thrbyt ;no, keep looking
;
;Skip all the 2-byte opcodes - this keeps the transfer program from
;trying to figure out what the second byte is.
;
mvi b,inst2e-inst2 ;get the number of elements in the table
lxi d,inst2 ;set up the 2-byte opcodes table pointer
;
twobyt: ldax d ;get opcode byte from table
cmp m ;is this byte a 2-byte opcode?
jz skip ;yes, skip it and continue
dcr b ;no, end of 2-byte table?
inx d ;advance table pointer
jnz twobyt ;no, keep looking
jmp modify ;yes, it's a one-byte opcode, keep going
;
skip: inx h ;advance object code pointer
jmp modify ;continue search
;
change: push h ;save pointer
lhld parm+2 ;set up end of range pointer (endobj)
push h ;stack it up
lhld parm ;set up beginning of range pointer (begobj)
push h ;stack it up...
pop b ;now pop them off in order
pop d
pop h
;
;See if the address is above the range
;
inx h ;advance pointer to the LSB of the addr
mov a,e
sub m
inx h ;advance pointer to the MSB of the addr
mov a,d
sbb m
jc modify
;
;See if the address is below the range
;
dcx h ;set back pointer to the LSB of the addr
mov a,m
sub c
inx h ;advance pointer to the MSB of the addr
mov a,m
sbb b
jc modify
;
;Update the value of this address by adding the offset to it
;
dcx h ;set back pointer to the LSB of the addr
db lxid ;load DE with the offset value
;
offset: dw 0
mov a,m ;get base address
add e ;change LSB to new address
mov m,a ;update memory
inx h ;advance pointer to the MSB of the addr
mov a,m ;get the MSB of the base addr
adc d ;change LSB to new address
mov m,a ;update memory
jmp modify ;take care of the next instruction
;
;Small routine to negate the contents of HL
;
neghl: mov a,h
cma
mov h,a ;get the complement of the MSB
mov a,l
cma
mov l,a ;get th complement of the LSB
inx h ;make 'HL' totally negative
ret
;
patch: lhld parm ;calc. dest (begobj)
xchg ;put it in <de>
lhld offset
dad d
shld dest ;save it
;
lhld bdos+1 ;get pointer to current module (or manager)
lxi d,12 ;offset to PREV field
dad d
xchg ;put it in <de>
lxi h,dest ;point to new module addr.
mvi b,2
call move ;patch it in
;
lhld dest ;get module address
shld bdos+1
lhld wmloc ;update warm boot routine so that
xchg ;it won't reset our vector to
lxi h,dest ;something wierd
mvi b,2
call move
;
;Patch this RSX in front of the previous one.
;
patch1: lhld parm ;patch NEXT field with address of
;previously installed RSX
lxi d,10 ;offset to NEXT field
dad d
xchg
lhld offset
dad d
xchg
lxi h,parm+6 ;(prevd)
mvi b,2
call move
;
;patches done, let user know what has been added
;
patch2: lxi h,mod1$msg ;print module name
call ilprt
lhld parm ;point to RSX name (NAME)
lxi d,16 ;offset 16 bytes
dad d
xchg
lhld offset
dad d
mvi b,8
loop: mov e,m
push h
push b
mvi c,cout
call bdos
pop b
pop h
inx h
dcr b ;finished?
jnz loop ;no, do it again
;
lxi h,mod2$msg ;print load addr.
call ilprt
lhld bdos+1
call outhl
lxi h,mod3$msg
call ilprt
;
wrap: lhld oldstk ;get back old stack pointer
sphl ;put it in <sp>
ret ;back to CP/M...
;
;The following table defines the 3-byte load instructions used in the
;8080 instruction set.
;
inst3: db 01h
db 11h
db 21h
db 22h
db 2Ah
db 31h
db 32h
db 3Ah
db 0C2h
db 0C3h
db 0C4h
db 0CAh
db 0CCh
db 0CDh
db 0D2h
db 0D4h
db 0DAh
db 0DCh
db 0E2h
db 0E4h
db 0EAh
db 0ECh
db 0F2h
db 0F4h
db 0FAh
db 0FCh
;
inst3e: equ $ ;end of 3-byte opcodes
;
;The following table is the listing of the 2-byte opcodes used in the
;8080 instruction code set.
;
inst2: db 06h
db 0Eh
db 16h
db 1Eh
db 26h
db 2Eh
db 36h
db 3Eh
db 0C6h
db 0CEh
db 0D3h
db 0D6h
db 0DBh
db 0DEh
db 0E6h
db 0EEh
db 0F6h
db 0FEh
;
inst2e: equ $ ;end of 2-byte opcodes
;
;>> Driver storage area <<
;
ds 20h
stack: dw 0 ;top of stack
oldstk: dw 0 ;old stack pointer
;
;the following 7 or so addresses are stored here for the RSX manager
;to access. it accesses them through a pointer to the first address stored,
;so that parm=begobjp, parm+2=endobjp, parm+4=pendp, etc...
;
parm: ds 2 ;beginning of code
ds 2 ;end of code
ds 2 ;end of module
ds 2 ;storage for previous RSX dest.
dest: ds 2 ;destination of module
point: ds 2 ;work pointer
signon: db cr,lf,'22INSTAL v2.0 10/13/84'
db cr,lf,'Copyright (C) 1984 by James H. Whorton'
db cr,lf,'RSX Generation Module for CP/M 2.x'
db cr,lf,0
mod1$msg:db cr,lf,lf,'Installing extension...'
db cr,lf,lf,'RSX module name: ',0
mod2$msg:db cr,lf,'Installed at: ',0
mod3$msg:db cr,lf,lf,'Installation complete.',0
nogo$msg:db cr,lf,lf,'** 22RSX Manager not installed **'
db cr,lf,'** To install, run 22RSX.COM',bell,cr,lf,0
dup$msg:db cr,lf,'++ RSX module already installed!',cr,lf,0
manchk: db '22RSX '
wmloc: dw 0
;
;===============================================================
;
; ** RSX modules to be used with this sytem should conform
; ** to the DRI format, with one(1) exception.
; ** The END must be replaced with LINK 'INSTB'.
; ** Other than that, any RSX's written for CP/M 3.0 that
; ** deal with functions found in CP/M 2.x should work
; ** properly.
;
; The following module gets moved to memory
; just underneath the CCP or the previous
; RSX by the loader routine.
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
begobj: equ $ ;marks start of object module
;
link '22MODULE' ;this is the renamed module file
;to be linked into the driver.
;
$ ;marks start of object module
;
link '22MODULE' ;this is the