; ;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 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 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 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 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 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. ;