home *** CD-ROM | disk | FTP | other *** search
- page 55,132
- title "PERUSEX = XMS interface for PERUSE"
-
- ; ---------------------------------------------------------------------
- ;
- ; PERUSEX - XMS interface for PERUSE
- ; First Published in PC Magazine April 12, 1994
- ;
- ; ---------------------------------------------------------------------
-
- ; ---------------------------------------------------------------------
- ; $lgb$
- ; 1.0 02/09/94 RVF Final beta complete. Can release if
- ; + no other errors found.
- ; $lge$
- ; ---------------------------------------------------------------------
- ; $nokeywords$
-
-
- ; -----------------------------------------------------------------------
- ;
- ; Buffer Memory Interface Routines
- ;
- ; -----------------------------------------------------------------------
-
- ; The folowing routines serve as the interface to the buffer memory.
- ;
- ; All (or in this case, both) modules have the same inteface that
- ; allows use of the buffer storage without the utilitie's specific
- ; knowledge of what memory is in use.
- ;
- ; Each module has a standard header that consists of the following:
- ;
- ; 2 byte length of module
- ; 1 byte module identifier (E = EMX, X = XMS)
- ; Note: Must be upper case
- ; JMP instrution to main entry point
- ;
- ; Nothing is guaranteed beyond the header.
- ;
- ; The module must be completely self contained, lying completely within
- ; it's own segment. Any references within the segment must be relative
- ; to that segment since PERUSE moves the module, in its entirety, to
- ; another segment aligned address where it is actually executed.
- ;
-
- ; -----------------------------------------------------------------------
- ;
- ; Here are the specific calling sequences:
- ;
- ; -----------------------------------------------------------------------
-
-
- ; General Return
- ; --------------
- ; If any error occurs, the function sets the carry flag.
- ;
- ; carry flag = error
-
-
- ; Initialize Scroll Memory
- ; ------------------------
- ; This call checks that the requested type of memory exists in
- ; sufficient quantity to complete the call. If so, it allocates the
- ; the memory and stores any information needed to access the memory.
- ;
- ; ax = 00h
- ; cx = number of 1k records needed
-
-
- ; Read scroll record
- ; ------------------
- ; This function reads a record from the scroll buffer. If there are
- ; n used records in the scroll buffer, the application may request
- ; record numbers 0 to n-1. The contents of the record are placed in
- ; the buffer located at es:dx.
- ;
- ; The most recent record is considered record 0 and the oldest is n-1.
- ;
- ; ax = 01h
- ; bx = record number; where: 0=oldest record, n-1=most recent
- ; es:di -> buffer
-
-
- ; Write scroll record
- ; -------------------
- ; This function writes a new record to the scroll buffer. If the
- ; scroll buffer has already filled, the oldest record is overwritten.
- ;
- ; ax = 02h
- ; ds:bx -> buffer to write
-
-
- ; Get number of used records
- ; --------------------------
- ; This function returns the number of records used in the scroll buffer.
- ;
- ; ax = 03h
- ;
- ; returns:
- ; ax = number of records used
-
-
- ; Release scroll buffer
- ; ---------------------
- ; This function is called to release the scroll buffer before removing
- ; the TSR from memory. If this function is not called, the scroll
- ; buffer will not be released until the system is rebooted.
- ;
- ; ax = 04h
-
- ; Save record pointer
- ; -------------------
- ; This function saves the current record information maintained by the
- ; interface routine. Any future records written to the buffer can then
- ; be "unsaved" by calling function 6.
- ;
- ; ah = 05h
-
- ; Restore pointers
- ; ----------------
- ; This function restores the record pointers saved with function 5.
- ; Furthermore, it clears any records written after the save.
- ;
- ; ax = 06h
-
- ; ----------------------------------------------------------------------
-
- IFNDEF Borland ; Assemble in MASM only
- MaxFunction equ 6 ; Maximum function number
- RecSize equ 1024 ; record size
- ENDIF
-
-
- ; ----------------------------------------------------------------------
- ;
- ; Xms Interface Routine
- ;
- ; ----------------------------------------------------------------------
-
- XmsInt segment para public 'code' ; Xms interface
- assume cs:XmsInt, ds:XmsInt ; called via far call
-
- XmsStart:
- XmsLen dw XmsEnd ; length of module
- db 'X' ; module identifier
-
- jmp short Xms ; jump to dispatcher
-
- XmsAdr dd 0 ; call address for XMS driver
- XmsDS dw 0 ; entry DS register
-
- ;
- ; XMS move structure
- ;
-
- XmsMvStr struc ; XMS move structure
- XmsMvLen dd 0 ; length to move
- XmsMvShnd dw 0 ; source handle
- XmsMvSoff dd 0 ; source offset
- XmsMvDhnd dw 0 ; destination handl
- XmsMvDoff dd 0 ; destination offset
- XmsMvStr ends ; ..end of structure
-
- XmsBlock XmsMvStr <> ; instance of XMS move structure
-
- ;
- ; Equates to access XMS move structure
- ;
-
- XmsBLen equ word ptr XmsBlock.XmsMvLen ; Length Field
-
- XmsBShnd equ XmsBlock.XmsMvShnd ; Source handle
- XmsBSoffL equ word ptr XmsBlock.XmsMvSoff ; Source offset low
- XmsBSoffH equ word ptr XmsBlock.XmsMvSoff+2; Source offset high
-
- XmsBDhnd equ XmsBlock.XmsMvDhnd ; Dest handle
- XmsBDoffL equ word ptr XmsBlock.XmsMvDoff ; Dest offset low
- XmsBDoffH equ word ptr XmsBlock.XmsMvDoff+2; Dest offset high
-
-
- XmsRecs dw 0 ; records allocated
- XmsUsed dw 0 ; records used
- XmsOld dw 0 ; Oldest Record
-
- XmsSUsed dw 0 ; saved records used
- XmsSOld dw 0 ; saved oldest record
- XmsWrites dw 0 ; writes since save
-
- XmsHndl dw 0 ; Xms handle
-
- XmsTbl label byte ; function dispatch table
- dw Xms0 ; Initialize
- dw Xms1 ; Read Record
- dw Xms2 ; Write Record
- dw Xms3 ; Get number of records
- dw Xms4 ; Free Xms memory
- dw Xms5 ; Save 4k
- dw Xms6 ; Restore 4k
-
- ; ---------------------
- ; Interface Entry Point
- ; ---------------------
-
- Xms proc Far ; dispatch the call
- push si ; save registers
- push ds
- push es
-
- mov cs:XmsDS, ds ; save entry DS register
-
- push cs ; save our segment
- pop ds ; ds -> this segment
-
- cmp ax, 07h ; q. out of range?
- jnb XmsRtnErr ; a. yes .. error
-
- shl ax, 1 ; ax = ax * 2 (table index)
- mov si, ax ; si = table index
- jmp word ptr XmsTbl[si] ; go to the routine
-
-
- ; --------------
- ; Error return..
- ; --------------
-
- XmsRtnErr: stc ; set the carry bit
-
- pop es ; restore
- pop ds ; ..saved
- pop si ; .. ..registers
-
- ret ; return with error
-
-
- ; -----------
- ; Return OK..
- ; -----------
-
- XmsRtnOk: clc ; reset carry bit
-
- pop es ; restore
- pop ds ; ..saved
- pop si ; .. ..registers
-
- ret ; return OK
-
-
- ; --------------------------------------------------
- ; Initialization; cx = number of records to allocate
- ; --------------------------------------------------
-
- Xms0 label byte
-
- push bx ; save registers
- push dx
- push di
- push si
-
- mov XmsRecs, cx ; save records requested
-
- mov ax, 4300h ; ax = XMS Installed request
- int 2fh ; ..ask if XMS installed
-
- cmp al, 80h ; q. XMS installed?
- jne Xms0Err ; a. no .. return with error
-
- ;
- ; Get the XMS call address
- ;
-
- mov ax, 4310h ; ax = get XMS call address
- int 2fh ; es:bx -> call address
-
- mov word ptr XmsAdr, bx ; save the offset
- mov word ptr XmsAdr+2, es ; ..and the segment
-
- ;
- ; XMS found .. Allocate the buffer (if possible)
- ;
-
- mov dx, XmsRecs ; dx = number of records req'd
- mov ah, 09h ; ah = allocate page
- call [XmsAdr] ; ..request memory
-
- cmp ax, 1 ; q. allocate ok?
- jne Xms0Err ; a. no .. return with error
-
- mov XmsHndl, dx ; save the handle
-
- ;
- ; Return with no error ..
- ;
-
- pop si ; restore registers
- pop di
- pop dx
- pop bx
- jmp XmsRtnOk ; ..return no error
-
- ;
- ; Return with an error ..
- ;
-
- Xms0Err: pop si ; restore registers
- pop di
- pop dx
- pop bx
- jmp XmsRtnErr ; ..return w/error
-
-
- ; ------------------------------------------------
- ; Read record; bx = record number; es:di -> buffer
- ; ------------------------------------------------
-
- Xms1 label byte
-
- cmp bx, XmsUsed ; q. valid record number?
- jae XmsRtnErr ; a. no .. exit now
-
- push cx ; save registers
- push dx
- push di
-
- add bx, XmsOld ; add in oldest record number
-
- cmp bx, XmsUsed ; q. beyond end of buffer?
- jb Xms1$10 ; a. no .. use this number
-
- sub bx, XmsUsed ; bx = record number
-
- Xms1$10: mov XmsBDhnd, 0 ; set the handle
-
- mov XmsBDoffL, di ; set the target address
- mov XmsBDoffH, es ; set the target segment
-
- mov di, XmsHndl ; di = our XMS handle
- mov XmsBShnd, di ; ..put in move structure
-
- mov ax, bx ; ax = record number
- mov cx, 1024 ; cx = multiplier (record length)
- mov XmsBLen, cx ; ..save as move length
- mul cx ; dx:ax = offset of record
-
- mov XmsBSoffL, ax ; save lsw of offset
- mov XmsBSoffH, dx ; save msw of offset
-
- mov ah, 0bh ; ah = move block
- mov si, offset XmsBlock ; ds:si -> XMS block
-
- call [XmsAdr] ; ask XMS to move the memory
-
- cmp ax, 1 ; q. move successful?
- jne Xms1Err ; a. no .. exit with error
-
- ;
- ; Return with no error ..
- ;
-
- pop di ; restore registers
- pop dx
- pop cx
- jmp XmsRtnOk ; return without error
-
- ;
- ; Return with an error ..
- ;
-
- Xms1Err: pop di ; restore registers
- pop dx
- pop cx
- jmp XmsRtnErr ; return with error
-
-
- ; ------------------------------------
- ; Write record; ds:bx -> record buffer
- ; ------------------------------------
-
- Xms2 label byte
-
- push bx ; save registers
- push dx
-
- mov XmsBShnd, 0 ; zero the source handle
- mov XmsBSoffL, bx ; ..save offset of record
- mov bx, XmsDS ; bs = record's segment
- mov XmsBSoffH, bx ; ..save record's segment
-
- mov bx, XmsUsed ; bx = records used
-
- cmp bx, XmsRecs ; q. all records used?
- jnb Xms2$10 ; a. yes .. use old to calc
-
- inc XmsUsed ; Add to used records
- jmp short Xms2$20 ; ..continue
-
- Xms2$10: mov bx, XmsOld ; bx = next record to write
-
- lea ax, 1[bx] ; ax = bx + 1 (next old record)
-
- cmp ax, XmsRecs ; q. hit the top of buffer?
- jb Xms2$15 ; a. no .. continue
-
- xor ax, ax ; else .. ax = first rec in Xms
-
- Xms2$15: mov XmsOld, ax ; XmsOld = oldest record number
-
- ;
- ; When we get here, bx contains the record number
- ;
-
- Xms2$20: mov ax, bx ; ax = record number
- mov bx, 1024 ; bx = multiplier (record length)
- mov XmsBLen, bx ; ..save as move length
- mul bx ; dx:ax = offset of record
-
- mov XmsBDoffL, ax ; save lsw of offset
- mov XmsBDoffH, dx ; save msw of offset
-
- mov ax, XmsHndl ; ax = memory handle
- mov XmsBDhnd, ax ; ..save the handle
-
- mov ah, 0bh ; ah = move block
- mov si, offset XmsBlock ; ds:si -> XMS block
-
- call [XmsAdr] ; ask XMS to move the memory
- inc cs:XmsWrites ; ..increment write count
-
- cmp ax, 1 ; q. move successful?
- jne Xms2Err ; a. no .. exit with error
-
- ;
- ; Return with no error ..
- ;
-
- pop dx
- pop bx
- jmp XmsRtnOk ; return without error
-
- ;
- ; Return with an error ..
- ;
-
- Xms2Err: pop dx ; restore registers
- pop bx
- jmp XmsRtnErr ; return with error
-
- ; --------------------------
- ; Get number of used records
- ; --------------------------
-
- Xms3 label byte
-
- mov ax, XmsUsed ; ax = records used
- jmp XmsRtnOk ; ..return ok
-
-
- ; ---------------------
- ; Release scroll buffer
- ; ---------------------
-
- Xms4 label byte
-
- push dx ; save registers
-
- mov ah, 0ah ; ah = deallocate Xms memory
- mov dx, XmsHndl ; dx = our Xms handle
- call [XmsAdr] ; ..Hey, Xms, deallocate it!
-
- pop dx
- jmp XmsRtnOk ; return no error
-
-
- ; --------------------
- ; Save record pointers
- ; --------------------
-
- Xms5 label byte
-
- push cs:XmsUsed ; save records used
- pop cs:XmsSUsed ; ..in save field
-
- push cs:XmsOld ; save oldest record
- pop cs:XmsSOld ; ..in save field
-
- mov cs:XmsWrites, 0 ; zero write counter
-
- jmp XmsRtnOk ; ..return without error
-
- ; -----------------------
- ; Restore record pointers
- ; -----------------------
-
- Xms6 label byte
-
- push cs:XmsSUsed ; reload used field
- pop cs:XmsUsed ; ..from save field
-
- push cs:XmsSOld ; reload oldest record
- pop cs:XmsOld ; ..from save field
-
- mov ax, cs:XmsWrites ; return number of writes
- jmp XmsRtnOk ; ..return without error
-
- align 16 ; boundary for next driver
- XmsEnd label byte
-
- Xms endp
- XmsInt ends
-
- IFNDEF Borland ; Assemble in MASM only
-
- ENDSTMT macro ; macro only needed with MASM
- end XmsStart ; end the assembly
- endm
-
- ENDIF
-
- ENDSTMT ; varies with Tasm and Asm
-