home *** CD-ROM | disk | FTP | other *** search
- page 55,132
- title "PERUSEE = EMS interface for PERUSE"
-
- ; ---------------------------------------------------------------------
- ;
- ; PERUSEE - EMS 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.
- ; 1.1 03/21/94 RVF Added proper mask when allocating
- ; + memory
- ; $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
-
- ; ----------------------------------------------------------------------
-
- MaxFunction = 6 ; Maximum function number
- RecSize = 1024 ; record size
-
-
- ; ----------------------------------------------------------------------
- ;
- ; EMS Interface Routine
- ;
- ; ----------------------------------------------------------------------
-
-
- EmsInt segment para public 'code' ; EMS interface
- assume cs:EmsInt ; called via far call
-
- EmsStart:
- EmsLen dw EmsEnd ; length of module
- db 'E' ; module identifier
-
- jmp short Ems ; jump to dispatcher
-
- Ems67v equ word ptr ds:[67h * 4] ; offset for int 67h (EMS)
-
- EmsSig db 'EMMXXXX0' ; EMS driver signature
-
- EmsRecs dw 0 ; records allocated
- EmsUsed dw 0 ; records used
- EmsOld dw 0 ; oldest record
-
- EmsSUsed dw 0 ; saved records used
- EmsSOld dw 0 ; saved oldest record
- EmsWrites dw 0 ; writes since save
-
- EmsHndl dw 0 ; EMS handle
-
- EmsFrame dw 0 ; segment of page frame
-
- EmsTbl label byte ; function dispatch table
- dw Ems0 ; Initialize
- dw Ems1 ; Read Record
- dw Ems2 ; Write Record
- dw Ems3 ; Get number of records
- dw Ems4 ; Free EMS memory
- dw Ems5 ; Save 4k
- dw Ems6 ; Restore 4k
-
- ; ---------------------
- ; Interface Entry Point
- ; ---------------------
-
- Ems proc Far ; dispatch the call
- push si ; save registers
- push ds
- push es
-
- cmp ax, MaxFunction ; q. out of range?
- ja EmsRtnErr ; a. yes .. error
-
- shl ax, 1 ; ax = ax * 2 (table index)
- mov si, ax ; si = table index
- jmp word ptr cs:EmsTbl[si] ; go to the routine
-
-
- ; --------------
- ; Error return..
- ; --------------
-
- EmsRtnErr: stc ; set the carry bit
-
- pop es ; restore
- pop ds ; ..saved
- pop si ; .. ..registers
-
- ret ; return with error
-
-
- ; -----------
- ; Return OK..
- ; -----------
-
- EmsRtnOk: clc ; reset carry bit
-
- pop es ; restore
- pop ds ; ..saved
- pop si ; .. ..registers
-
- ret ; return OK
-
-
- ; --------------------------------------------------
- ; Initialization; cx = number of records to allocate
- ; --------------------------------------------------
-
- Ems0 label byte
-
- push bx ; save registers
- push dx
- push di
- push si
-
- mov cs:EmsRecs, cx ; save records requested
-
- xor ax, ax ; clear ax
- mov ds, ax ; ds -> low memory
-
- mov ax, Ems67v+2 ; ax = int 67's segment
- mov ds, ax ; ds -> int 67's segment
- mov si, 0ah ; ds:si -> signature, if any
-
- push cs ; save our segment
- pop es ; es -> our segment
- lea di, cs:EmsSig ; si -> signature expected
-
- cld ; ensure incremental compare
- mov cx, 8 ; bytes to test
-
- repe cmpsb ; q. EMS found?
- jne Ems0Err ; a. no .. error
-
- ;
- ; Get the page frame segment
- ;
-
- mov ah, 41h ; ah = get page frame address
- int 67h ; get the page frame
-
- or ah, ah ; q. any problem?
- jne Ems0Err ; a. yes .. error
-
- mov cs:EmsFrame, bx ; save the segment
-
- ;
- ; EMS found .. Allocate the buffer (if possible)
- ;
-
- mov bx, cs:EmsRecs ; bx = number of records req'd
-
- add bx, 15 ; Round up ..
- and bx, 0fff0h ; ..to next 16
- mov cs:EmsRecs, bx ; save in records available
-
- mov cl, 4 ; cl = shift counter
- shr bx, cl ; bx = bx / 16
-
- mov ah, 43h ; ah = allocate memory
- int 67h ; ..ask EMS for the memory
-
- or ah, ah ; q. memory found?
- jne Ems0Err ; a. no .. error
-
- mov cs:EmsHndl, dx ; save the handle
-
- ;
- ; Return with no error ..
- ;
-
- pop si ; restore registers
- pop di
- pop dx
- pop bx
- jmp EmsRtnOk ; ..return no error
-
- ;
- ; Return with an error ..
- ;
-
- Ems0Err: pop si ; restore registers
- pop di
- pop dx
- pop bx
- jmp EmsRtnErr ; ..return w/error
-
-
- ; ------------------------------------------------
- ; Read record; bx = record number; es:di -> buffer
- ; ------------------------------------------------
-
- Ems1 label byte
-
- cmp bx, cs:EmsUsed ; q. valid record number?
- jae EmsRtnErr ; a. no .. exit now
-
- push cx ; save registers
- push dx
- push di
-
- mov ah, 47h ; ah = save page map
- mov dx, cs:EmsHndl ; dx = our handle
- int 67h ; save current map
-
- add bx, cs:EmsOld ; add in oldest record number
-
- cmp bx, cs:EmsUsed ; q. beyond end of buffer?
- jb Ems1$10 ; a. no .. use this number
-
- sub bx, cs:EmsUsed ; bx = record number
-
- Ems1$10: mov si, bx ; si = real record number
- mov cl, 4 ; cl = shift counter
- shr bx, cl ; bx = bx / 16 (EMS page number)
-
- and si, 0fh ; si = record in page
- mov cl, 10 ; cl = shift counter
- shl si, cl ; si = si * 1024 (offset in page)
-
- mov ax, 4400h ; ax = map into frame page 0
- int 67h ; ..get the page from EMS
-
- push ax ; save return code
-
- mov ds, cs:EmsFrame ; ds:si-> record in EMS
-
- cld ; assure incremental move
- mov cx, RecSize/2 ; ..512 words (or 1024 bytes)
- rep movsw ; ..move the record
-
- mov ah, 48h ; ah = restore page map
- int 67h ; ..ask EMS to do it
-
- pop ax ; restore return code
-
- or ah, ah ; q. any error in map page?
- jnz Ems1Err ; a. yes .. return with error
-
- ;
- ; Return with no error ..
- ;
-
- pop di ; restore registers
- pop dx
- pop cx
- jmp EmsRtnOk ; return without error
-
-
- ;
- ; Return with an error ..
- ;
-
- Ems1Err: pop di ; restore registers
- pop dx
- pop cx
- jmp EmsRtnErr ; return with error
-
-
- ; ------------------------------------
- ; Write record; ds:bx -> record buffer
- ; ------------------------------------
-
- Ems2 label byte
-
- push bx ; save registers
- push cx
- push dx
- push di
-
- mov si, bx ; ds:si -> record
-
- mov bx, cs:EmsUsed ; bx = records used
-
- cmp bx, cs:EmsRecs ; q. all records used?
- jnb Ems2$10 ; a. yes .. use old to calc
-
- inc cs:EmsUsed ; Add to used records
- jmp short Ems2$20 ; ..continue
-
- Ems2$10: mov bx, cs:EmsOld ; bx = next record to write
-
- lea ax, 1[bx] ; ax = bx + 1 (next old record)
-
- cmp ax, cs:EmsRecs ; q. hit the top of buffer?
- jb Ems2$15 ; a. no .. continue
-
- xor ax, ax ; else .. ax = first rec in EMS
-
- Ems2$15: mov cs:EmsOld, ax ; EmsOld = oldest record number
-
- ;
- ; When we get here, bx contains the record number
- ;
-
- Ems2$20: mov di, bx ; di = record number
- mov cl, 4 ; cl = shift counter
- shr bx, cl ; bx = bx / 16 (EMS page number)
-
- and di, 0fh ; di = record in page
- mov cl, 10 ; cl = shift counter
- shl di, cl ; di = di * 1024 (offset in page)
-
- mov ah, 47h ; ah = save page map
- mov dx, cs:EmsHndl ; dx = our handle
- int 67h ; save current map
-
- mov ax, 4400h ; ax = map into frame page 0
- int 67h ; ..get the page from EMS
-
- or ah, ah ; q. any error in map page?
- jnz Ems2Err ; a. yes .. return with error
-
- mov es, cs:EmsFrame ; es:di -> record in EMS
-
- cld ; assure incremental move
- mov cx, RecSize/2 ; ..512 words (or 1024 bytes)
- rep movsw ; ..move the record
-
- ;
- ; Return with no error ..
- ;
-
- mov ah, 48h ; ah = restore page map
- mov dx, cs:EmsHndl ; dx = our handle
- int 67h ; ..ask EMS to do it
-
- inc cs:EmsWrites ; ..increment write counter
-
- pop di ; restore registers
- pop dx
- pop cx
- pop bx
- jmp EmsRtnOk ; return without error
-
-
- ;
- ; Return with an error ..
- ;
-
- Ems2Err: mov ah, 48h ; ah = restore page map
- mov dx, cs:EmsHndl ; dx = our handle
- int 67h ; ..ask EMS to do it
-
- pop di ; restore registers
- pop dx
- pop cx
- pop bx
- jmp EmsRtnErr ; return with error
-
- ; --------------------------
- ; Get number of used records
- ; --------------------------
-
- Ems3 label byte
-
- mov ax, cs:EmsUsed ; ax = records used
- jmp EmsRtnOk ; ..return ok
-
-
- ; ---------------------
- ; Release scroll buffer
- ; ---------------------
-
- Ems4 label byte
-
- push dx ; save registers
-
- mov ah, 45h ; ah = deallocate EMS pages
- mov dx, cs:EmsHndl ; dx = our EMS handle
- int 67h ; ..Hey, EMS, deallocate it!
-
- pop dx
- jmp EmsRtnOk ; return no error
-
- Ems endp
-
-
- ; --------------------
- ; Save record pointers
- ; --------------------
-
- Ems5 label byte
-
- push cs:EmsUsed ; save records used
- pop cs:EmsSUsed ; ..in save field
-
- push cs:EmsOld ; save oldest record
- pop cs:EmsSOld ; ..in save field
-
- mov cs:EmsWrites, 0 ; zero write counter
-
- jmp EmsRtnOk ; ..return without error
-
- ; -----------------------
- ; Restore record pointers
- ; -----------------------
-
- Ems6 label byte
-
- push cs:EmsSUsed ; reload used field
- pop cs:EmsUsed ; ..from save field
-
- push cs:EmsSOld ; reload oldest record
- pop cs:EmsOld ; ..from save field
-
- mov ax, cs:EmsWrites ; return number of writes
- jmp EmsRtnOk ; ..return without error
-
- align 16 ; boundary for next driver
- EmsEnd label byte
-
- EmsInt ends
-
-
- IFNDEF Borland ; Assemble in MASM only
-
- ENDSTMT macro ; macro only needed with MASM
- end EmsStart ; end the assembly
- endm
-
- ENDIF
-
- ENDSTMT ; varies with Tasm and Asm