home *** CD-ROM | disk | FTP | other *** search
- ;
- ;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