home *** CD-ROM | disk | FTP | other *** search
- page ,132
- title User I/O Assembly Language Interface Functions
-
- .286P
-
- ; 16-Jan-91 cck
- ; Modified to set/restore PSP for proper handling of dynamic memory.
- ; 29-Nov-89 cck
- ; Kludge to overcome idiosyncracies of MSDOS 4.01
- ; 30-Sep-89 cck
- ; Modified to release all memory blocks belonging to PSP
- ;************************************************************************
- ;* *
- ;* User I/O Assembly Code Interface: Defines *
- ;* *
- ;************************************************************************
- ;
- ; *** WARNING *** WARNING *** WARNING ***
- ; This program will ONLY work with DOS 3.0 and above
- ; *** WARNING *** WARNING *** WARNING ***
- ;
- ; Communication Structure:
- ; Call:
- ; AH = register set to use:
- ; 0 = execute a NeuralWorks command
- ; 1 = return from User I/O request
- ; AL = request code (AH=0)
- ;
- ; Return:
- ; AL = return code
- ; 0 = all is well
- ; 1 = refresh display
- ; -1 = error / eof (AH = 0)
- ;
- ; also placed in Data_transfer_ptr->RPC_area.request
- ; refer to uio_if_d.c
-
- OpSize MACRO
- ; db 66h
- ENDM
-
-
- AdSize MACRO
- db 67h
- ENDM
-
- ;************************************************************************
- ;* *
- ;* Public Routine Declarations *
- ;* *
- ;************************************************************************
-
- public FindMem
- public _FindMem
- public _LeaveTSR
-
- public _InitIO ; initialize i/o interface
- public InitIO
- public _XUIF
-
-
- ;************************************************************************
- ;* *
- ;* Public Data Declarations *
- ;* *
- ;************************************************************************
-
- DGROUP group _DATA
- assume ds:DGROUP
- _DATA segment word public 'DATA'
-
- public __okbigbuf ; for DataLight "C"
- public _IOStr,_IOData,_IOReqC,_IORtnC,_UserIOP
- public _IOCount,_IOLayer
- public _IOUIFC ; user interface code
- public _IOPSP,_IOPara ; program size
- public _ProgSize
- public _PProgName ; program name pointer
- public _ProgEnd ; pointer to end of program
-
- public IOStr,IOData,IOReqC,IORtnC,UserIOP
- public IOCount,IOLayer
- public IOUIFC ; user interface code
- public IOPSP,IOPara ; program size
- public ProgSize
- public PProgName ; program name pointer
- public ProgEnd ; pointer to end of program
-
- __okbigbuf dw 0 ; special for DataLight "C"
- IOStr label word
- _IOStr dd 0 ; i/o string pointer
- IOData label word
- _IOData dd 0 ; i/o data pointer
- IOCount label word
- _IOCount dw 0 ; i/o # of data items
- IOLayer label word
- _IOLayer dw 0 ; i/o layer number of request
- IOReqC label word
- _IOReqC dw 0 ; i/o request code
- IORtnC label word
- _IORtnC dw 0 ; i/o return code
- IOUIFC label word
- _IOUIFC dw 0 ; i/o user interface code
- ProgSize label word
- _ProgSize dw 0 ; program size in paragraphs
- UserIOP label dword
- _UserIOP dd 0 ; user i/o routine pointer
- IOPara label word
- _IOPara dw 0 ; program size in paragraphs
- IOPSP label word
- _IOPSP dw 0 ; program segment prefix (segment)
-
- ProgEnd label dword ; pointer to end of program
- _ProgEnd dd 0
- PProgName label dword
- _PProgName dd 0 ; pointer to program name
- ProgHandle dw 0 ; program file handle
- DosHdr label word
- dw 0 ; n/c: 4D5A
- dw 0 ; n/c: bytes in last page
- ExeBlocks dw 0 ; # of 512 byte blocks in image
- dw 0 ; n/c: # of relocation entries
- dw 0 ; n/c: size of header in paragraphs
- ExeMinAlc dw 0 ; minimum # of paragraphs to allocate
- ExeMaxAlc dw 0 ; maximum # of paragraphs to allocate
- DosHEnd dw 0 ; End of Dos Header
- DosHLen equ DosHEnd-DosHdr ; size of header to read
- _DATA ends
-
- ;************************************************************************
- ;* *
- ;* User I/O Assembly Code Interface *
- ;* *
- ;************************************************************************
-
- USERUTL_PROG segment word 'CODE'
- assume cs:USERUTL_PROG
-
- ; *** Host Save Area ***
- ;
- ; NOTE: though it is usually considered poor programming practice,
- ; we are saving register data in the code segment because that is
- ; the only thing we are always sure of.
- ;
- ; The save area is broken into two parts. The "main" part is used
- ; to save register data when the program was initialized and thus
- ; to invoke the user's i/o routine.
- ;
- ; The "slave" part is used to save context information for
- ; handling User I/O requests for information from NeuralWorks.
- ; This allows NWORKS to do a return to the requesting function.
- ;
- PSP dw 0 ; program segment prefix
- CALLPSP dw 0 ; calling program PSP
- ParaLen dw 0 ; length to save in paragraphs
-
- SMS dw 12 DUP (0) ; slave save area
-
- SAS dw 12 DUP (0) ; slave alternate save area
-
- MyReqC dw 0 ; my request code
-
- _OldVec dw 0,0 ; old vector
- MySvcRtne dd 0 ; "my" service routine
- StrPtr dd _IOStr ; point to the string pointer
- DataPtr dd _IOData ; point to the data pointer
- DataSeg dw seg DGROUP ; point to data segment
- Inited db 0 ; see if we are initialized
- MyVecNum db 0 ; interrupt used for communication
- MyVec dd InterruptH ; new interrupt handling vector
-
- MyBlock dw 0,0,0,0,0,0 ; my "blocks" to free regardless
- MYBLOCKSIZE equ 10 ; size of "blocks"
-
- ;************************************************************************
- ;* *
- ;* Initiate The Interface with NWORKS *
- ;* *
- ;************************************************************************
-
- VecNum equ word ptr ss:4[bp]
- SvcRtne equ dword ptr ss:6[bp]
-
- InitIO proc far
- jmp far ptr _InitIO
- InitIO endp
-
- _InitIO proc far
- mov SMS+0, ax ; save main's registers
- mov SMS+2, bx
- mov SMS+4, cx
- mov SMS+6, dx
- mov SMS+8, si
- mov SMS+10, di
- mov SMS+12, bp
- mov SMS+14, es
- mov SMS+16, ds
- mov SMS+18, ss
- mov SMS+20, sp
- mov bp, sp
-
- les si, SvcRtne ; get address of service routine
- mov word ptr MySvcRtne+0, si ; save this for posterity
- mov word ptr MySvcRtne+2, es
-
- mov ax, VecNum ; get interrupt vector number
- mov MyVecNum, al
-
- LSvcOK:
- mov ds, DataSeg ; make sure we have right data segment
-
- mov bx, _IOPSP ; see if PSP was properly specified
- or bx, bx
- jne PSPOk
- mov ax, 05100h ; get PSP
- int 21h
- PSPOk: mov PSP, bx ; save PSP for posterity
- mov ds, DataSeg ; make sure we have right data segment
- mov _IOPSP, bx
-
- ; The program end has been specified, figure out whether the stack or
- ; the heap are at the end and use that.
-
- mov ax, word ptr _ProgEnd+0 ; cvt to paragraph
- add ax, 17 ; length 2 + round up
- mov cx, 4 ; position right
- shr ax, cl
- and ax, 0fffh ; clean it up
- add ax, word ptr _ProgEnd+2 ; add in base seg
- mov bx, ax ; save it (bx)
-
- push ss ; push stack seg
- mov ax, sp ; get SP
- add ax, 127 ; round up
- shr ax, cl ; cvt to paragraph
- and ax, 0fffh ; clean it up
- pop cx ; ss->cx
- add ax, cx ; ax = end para for stk
- cmp ax, bx
- jae UseAX
- mov ax, bx
- UseAX: sub ax, _IOPSP ; subtract off base
- inc ax ; de-zero bias it
-
- mov ParaLen, ax ; save it for later
- mov _ProgSize, ax ; and make it global
-
- ; With the preliminaries done, attach to the interface vector.
- ; Save the existing vector first so that we can restore it later.
-
- SetVector:
-
- ; Find which memory belongs to this TSR for DOS4.01
-
- push ds
- call far ptr FindMem
- pop ds
-
- ; Flag that we are initialized successfully, and do a terminate and
- ; stay resident.
- ;
- ; NOTE: Unfortunately, terminate and stay resident CLOSES all open
- ; file handles. Thus, it is necessary to open these file handles AFTER
- ; the main routine is DONE.
-
- mov Inited, -1 ; we are initialized
-
- mov al, MyVecNum ; save the old user_vect server
- mov ah, 35h
- int 21h
- mov _OldVec+2, es
- mov _OldVec+0, bx
-
- lds dx, MyVec ; install the new user_vect server
- mov al, MyVecNum
- mov ah, 25h
- int 21h
-
- mov ah, 31h ; terminate and stay resident
- mov dx, ParaLen ; leave everything resident
- int 21h
-
- InitErr: ; initialization error, die
- mov ax, 4cffh ; terminate w/-1 code
- int 21h
-
- _InitIO endp
-
-
- ;************************************************************************
- ;* *
- ;* Free all memory related to this program *
- ;* *
- ;************************************************************************
- ; NOTE: the following defines are used to manipulate system memory block
- ; headers. This is basically very dangerous, but necessary. Do not
- ; change or alter these or the code which frees memory unless you really
- ; understand what we are doing and know how all of these undocumented
- ; system calls and memory configurations work.
- ;
- MFLAG equ byte ptr ES:0[BX]
- MOWNER equ word ptr ES:1[BX]
- MSIZE equ word ptr ES:3[BX]
-
- ;************************************************************************
- ;* *
- ;* Find Memory which belongs to this TSR *
- ;* *
- ;************************************************************************
- ;
- ; NOTE: DOS4.01 changes the owner of the block to the calling program
- ; when certain system calls are made. As a result, it is necesary to get
- ; a list of TSR blocks prior to allowing the user to do their thing.
-
- _FindMem proc far
- jmp FindMem
- _FindMem endp
-
- FindMem proc far
-
- ; --- Find which memory blocks belong to me and record them ---
-
- mov ax,5200h ; get pointer to DOS tables
- int 21h ; es:bx -> dos table, pick up -2
- sub bx, 2 ; bx[-2]
- mov ax, es:0[bx] ; get paragraph number
- xor bx,bx ; no offset
- mov es, ax ; point to head of first memory block
- ; ex:bx points to first memory control block
-
- ; --- Search for & Release all Memory owned by this PSP ---
-
- mov si, 0 ; index into my array
- mov dx, PSP ; owner we are looking for
- or dx, dx ; see if bad PSP
- je FindDone ; PSP was never properly set.
- FindLoop:
- mov ax, MOWNER ; paragraph owner
- cmp ax, dx
- jne FindNxtBlk ; not ours, try next one
-
- mov ax, es ; point to memory block
- inc ax
- mov MyBlock[si], ax ; save it
- add si, 2 ; next location
- cmp si, MYBLOCKSIZE ; done?
- jae FindDone ; yes, all spaces used
-
- FindNxtBlk:
- mov al, MFLAG ;pick up flag
- cmp al, 04dh ;see if end if chain?
- jne FindDone ;yes, go home
-
- ;figure out next memory block by adding size +1
- mov ax, es ;current segment
- add ax, MSIZE ;add size of memory block
- inc ax ;plus one for header
- mov es, ax ; es:bx -> next memory block
- jmp FindLoop ; keep looking
-
- FindDone:
- ret
- FindMem endp
-
-
- ;************************************************************************
- ;* *
- ;* Free Memory which belongs to this TSR *
- ;* *
- ;************************************************************************
-
- public FreeMem
- public _FreeMem
-
- _FreeMem proc far
- jmp FreeMem
- _FreeMem endp
-
- FreeMem proc far
-
- ; --- Free memory which is Mine ---
-
- mov si, 0 ; index into table
- MyFree: mov ax, MyBlock[si] ; next block to free
- or ax, ax
- je MyFreeDone
-
- push si
- mov es, ax
- mov ax, 4900h ; deallocate program memory (es = para number)
- int 21h
- pop si
- add si, 2
- cmp si, MYBLOCKSIZE
- jb MyFree
- MyFreeDone:
-
- ; --- Get pointer to the first of the Memory Control Blocks ---
-
- ReFree:
- mov ax,5200h ; get pointer to DOS tables
- int 21h ; es:bx -> dos table, pick up -2
- sub bx, 2 ; bx[-2]
- mov ax, es:0[bx] ; get paragraph number
- xor bx,bx ; no offset
- mov es, ax ; point to head of first memory block
- ; ex:bx points to first memory control block
-
- ; --- Search for & Release all Memory owned by this PSP ---
-
- mov dx, PSP ; owner we are looking for
- FreeLoop:
- mov ax, MOWNER ; paragraph owner
- cmp ax, dx
- jne NxtBlk ; not ours, try next one
-
- push es ; save ES for next time through
- mov ax, es ; point to memory block
- inc ax
- mov es, ax
-
- mov ax, 4900h ; deallocate program memory (es = para number)
- int 21h
- pop es ; restore last pointer
- jmp short ReFree ; just to be safe!!
-
- NxtBlk:
- mov al, MFLAG ;pick up flag
- cmp al, 04dh ;see if end if chain?
- jne FreeDone ;yes, go home
-
- ;figure out next memory block by adding size +1
- mov ax, es ;current segment
- add ax, MSIZE ;add size of memory block
- inc ax ;plus one for header
- mov es, ax ; es:bx -> next memory block
- jmp FreeLoop ; keep looking
-
- FreeDone:
- ret
- FreeMem endp
-
- ; Exit routine
- ;
-
- _LeaveTSR proc far
- mov ds, _OldVec+2 ; load old handler
- mov dx, _OldVec+0
- mov al, MyVecNum ; load interrupt number
- mov ah, 25h
- int 21h
- call far ptr FreeMem
- ret
- _LeaveTSR endp
-
-
- HS dw 26 DUP (0) ; host save area
- HSAdr dw offset HS
- dw seg HS
-
- InterruptH proc far ; interrupt from host
- cli
- OpSize
- mov HS+0, ax
- OpSize
- mov HS+4, bx
- OpSize
- mov HS+8, cx
- OpSize
- mov HS+12, dx
- OpSize
- mov HS+16, si
- OpSize
- mov HS+20, di
- OpSize
- mov HS+24, bp
- OpSize
- mov HS+28, sp
-
- mov HS+32, ss
- mov HS+36, ds
- mov HS+40, es
- sti ; turn interrupts back on for DOS
-
- push ax ; save "calling code"
- ; ---- get calling PSP & save it ---
- mov ax, 05100h ; undocumented get psp
- int 21h
- mov CALLPSP, bx ; save calling PSP
- ; ---- set our PSP as current one ---
- mov bx, PSP
- mov ax, 05000h ; undocumented set psp
- int 21h
-
- pop ax ; restore "calling" code
- or ah, ah ; see if response to User I/O request
- je HostInt ; no, host command
-
- ; restore calling registers
- mov ax, SAS+18 ; set up return stack
- mov bp, SAS+20
- cli
- mov ss, ax
- mov sp, bp
- sti
- mov ax, SAS+0
- mov bx, SAS+2
- mov cx, SAS+4
- mov dx, SAS+6
- mov si, SAS+8
- mov di, SAS+10
- mov bp, SAS+12
- mov es, SAS+14
- mov ds, SAS+16
- ret ; return to caller
-
- HostInt: ; call the user service routine
- cli ; turn interrupts off jc
- mov ax, SMS+0 ; restore old context
- mov bx, SMS+2
- mov cx, SMS+4
- mov dx, SMS+6
- mov si, SMS+8
- mov di, SMS+10
- mov bp, SMS+12
- mov es, SMS+14
- mov ds, SMS+16
- mov ss, SMS+18
- mov sp, SMS+20
-
- push HSAdr+2
- push HSAdr+0
- sti ; turn interrupts back on
- call MySvcRtne
-
- HostReturn: ; return to NWORKS
- mov bx, CALLPSP ; --- restore calling PSP ---
- mov ax, 05000h ; undocumented set psp
- int 21h
-
- cli ; turn interrupts off
- OpSize
- mov ax, HS+0
- OpSize
- mov bx, HS+4
- OpSize
- mov cx, HS+8
- OpSize
- mov dx, HS+12
- OpSize
- mov si, HS+16
- OpSize
- mov di, HS+20
- OpSize
- mov bp, HS+24
- OpSize
- mov sp, HS+28
-
- mov ss, HS+32
- mov ds, HS+36
- mov es, HS+40
- iret
- InterruptH endp
-
- ;************************************************************************
- ;* *
- ;* XUIF - perform user i/o interface *
- ;* *
- ;************************************************************************
-
- _XUIF proc far
- push ds
- mov ds, DataSeg
- mov ah, byte ptr _IOUIFC ; get request code
- pop ds
- COM_IF:
-
- cmp Inited, 0 ; see if we are ready
- jne SIO_OK ; yes
- ret ; no, return immediately
- SIO_OK:
- mov SAS+0, ax ; save main's registers
- mov SAS+2, bx
- mov SAS+4, cx
- mov SAS+6, dx
- mov SAS+8, si
- mov SAS+10, di
- mov SAS+12, bp
- mov SAS+14, es
- mov SAS+16, ds
- mov SAS+18, ss
- mov SAS+20, sp
-
- mov ds, DataSeg ; get data segment base
-
- xor ax,ax ; clear h.o. byte
- mov al, byte ptr _IORtnC ; user return code
- mov HS+0, ax ; save host return code
-
- jmp HostReturn
- _XUIF endp
-
- USERUTL_PROG ends
-
- end
-