; --------------------------------------------------------------------- ;
; auxmem.asm			Acit				92Apr21 ;
;		asm support for ems/xms/virtual memory			;
; ---------------------------------------------------------------------	;

; --------------------------------------------------------------------- ;
; these routines support msgtab.c. they implement the low-level link to ;
; xms/ems/virtual memory that would be goofy to do in c. written for	;
; borland's tasm 2.0.                                                   ;
;									;
; BiB/92Apr21								;
; ----------------------------------------------------------------------;

; --------------------------------------------------------------------- ;
;				contents				;
;									;
; setUpAuxMem() 	inits memory for our use			;
; _addToEMS()		adds another chunk to our ems pool		;
; _addToVirt()		adds another chunk to our virtual pool		;
; _addToXMS()		adds another chunk to our xms pool		;
; disposeAuxMem()	releases any allocated memory			;
; HeapToXMS()		transfers memory from Heap to XMS		;
; HeapToEMS()		transfers memory from Heap to EMS		;
; HeapToVirt()		transfers memory from Heap to Virtual		;
; EMStoHeap()		transfers memory from EMS to Heap		;
; VirttoHeap()		transfers memory from Virtual to Heap		;
; XMStoHeap()		transfers memory from XMS to Heap		;
; --------------------------------------------------------------------- ;

ideal
model large, c

ifdef AUXMEM

public setUpAuxMem, _addToXMS, _addToEMS, _addToVirt, disposeAuxMem, XMStoHeap
public EMStoHeap, VirttoHeap, HeapToXMS, HeapToEMS, HeapToVirt

public usexms, xmshand, xmssize, emsframe, emshand, emssize, vrthand
public vrtpags, xmserr, emserr
dataseg

SIZE_K		equ	4		; Size of our pages in K
SIZE_B		equ	4096		; Size of our pages in bytes
PER_EMS_PAGE	equ	4		; Number of our pages that fit in one
					; EMS page (16K) Don't be fooled:
					; Some bit-shifting goes on, and
					; code needs to be changed to change
					; this.

xmsaddr dd      0
usexms	db	0
xmshand dw	0
xmssize dw	0	; in Kbytes
xmserr	dw	0

xmsxfr	dd	SIZE_B	; for xms func 0bh
srchand dw	0
srcofs	dd	0
dsthand dw	0
dstofs	dd	0


emmname db	'EMMXXXX0'
emsframe dw	0
emshand dw	0
emssize dw	0	; in our pages (SIZE_K)
emserr	dw	0

vrthand dw	0
vrtpags dw	0

codeseg
; inits memory for our use
proc setUpAuxMem uses si di, vmofs:word, vmseg:word
	; verify existance of xms memory
	mov ax, 4300h
	int 2fh
	cmp al, 80h
	jne no_xms

	mov ax, 4310h
	int 2fh
	mov [word ptr xmsaddr], bx
	mov [word ptr xmsaddr+2], es
	mov [usexms], 1

no_xms: ; now, verify existance of ems memory
	mov ax, 3567h
	int 21h
	mov di, 10
	mov si, offset emmname
	mov cx, 8
	cld
	repz cmpsb
	jne no_ems

	mov ah, 40h	; test ems status
	int 67h
	or ah, ah
	jne no_ems

	mov ah, 46h
	int 67h
	or ah, ah
	jne no_ems
	cmp al, 40h
	jb no_ems	; need ems 4.0+

	mov ah, 41h
	int 67h
	or ah, ah
	jnz no_ems
	mov [emsframe], bx

no_ems: ; now, create virtual memory
	push ds
	mov dx, [vmofs]
	mov ax, [vmseg]
	mov ds, ax
	mov ah, 3ch
	xor cx, cx
	int 21h
	pop ds
	jc no_vrt

	mov [vrthand], ax

no_vrt: ; bad file name or something
	ret
endp

proc _addToXMS
	mov bl, 0
	cmp [usexms], 0
	je noAddXMS

	cmp [xmshand], 0
	jne reallocxms

	; allocate new handle
	mov ah, 9
	mov dx, SIZE_K
	call [xmsaddr]
	or ax, ax
	je noAddXMS
	mov [xmshand], dx
	mov [xmssize], SIZE_K
	mov ax, 1
	ret

reallocxms:
	mov ah, 0fh
	mov bx, [xmssize]
	add bx, SIZE_K
	mov dx, [xmshand]
	call [xmsaddr]
	or ax, ax
	je noAddXMS
	add [xmssize], SIZE_K
	mov ax, [xmssize]
	mov cl, 2
	shr ax, cl
	ret

noAddXMS:
	mov bh, 0
	mov [xmserr], bx
	xor ax, ax
	ret
endp

proc _addToEMS
	cmp [emsframe], 0
	je noAddEMS

	cmp [emshand], 0
	jne reallocems

	; allocate new handle
	mov ah, 43h
	mov bx, 1
	int 67h
	or ah, ah
	jne noAddEMS
	mov [emshand], dx
	mov [emssize], 1
	mov ax, 1
	ret

reallocems:
	mov bx, [emssize]	; Number of our pages now
	inc bx			; Number of our pages soon

	mov ax, bx		; Save copy

	shr bx, 1
	shr bx, 1		; Divide by four

	and ax, 11b		; And add one more if partial...
	jz noPartialPage

	inc bx

noPartialPage:
	mov ah, 51h
	mov dx, [emshand]
	int 67h
	or ah, ah
	jne noAddEMS
	inc [emssize]
	mov ax, [emssize]
	ret

noAddEMS:
	mov al, ah
	mov ah, 0
	mov [emserr], ax
	xor ax, ax
	ret
endp

proc _addToVirt
	cmp [vrthand], 0
	je noAddVrt

	mov ax, [vrtpags]
	mov dx, SIZE_B
	mul dx
	mov cx, dx
	mov dx, ax
	mov bx, [vrthand]
	mov ax, 4200h
	int 21h
	jc noAddVrt

	mov ah, 40h	; it doesn't really matter where we write from.
	mov cx, SIZE_B	; actually, we may not need to write at all; i
	xor dx, dx	; forgot what happens if you seek beyond the end
	int 21h 	; of a file, and don't feel like checking it out.

	jc noAddVrt

	inc [vrtpags]
	mov ax, [vrtpags]
	ret

noAddVrt:
	xor ax, ax
	ret
endp

proc disposeAuxMem, vmofs:word, vmseg:word
	cmp [xmshand], 0
	je dsp_ems

	mov ah, 0ah
	mov dx, [xmshand]
	call [xmsaddr]
	mov [xmshand], 0
	mov [xmssize], 0
	mov [usexms], 0

dsp_ems:cmp [emshand], 0
	je dsp_vrt

	mov ah, 45h
	mov dx, [emshand]
	int 67h
	mov [emshand], 0
	mov [emssize], 0
	mov [emsframe], 0

dsp_vrt:mov bx, [vrthand]
	or bx, bx
	jz endDAM
	mov ah, 3eh
	int 21h 		; close the file

	push ds
	mov dx, [vmofs]
	mov ax, [vmseg]
	mov ds, ax
	mov ah, 41h
	int 21h 		; and delete it
	pop ds
	mov [vrthand], 0

endDAM: ret
endp

proc XMStoHeap uses si, tofs:word, tseg:word, fblk:word
	mov [dsthand], 0
	mov ax, [xmshand]
	mov [srchand], ax
	mov ax, [tofs]
	mov [word ptr dstofs], ax
	mov ax, [tseg]
	mov [word ptr dstofs+2], ax
	mov ax, [fblk]
	dec ax
	mov bx, SIZE_B
	mul bx
	mov [word ptr srcofs], ax
	mov [word ptr srcofs+2], dx
	mov si, offset xmsxfr
	mov ah, 0bh
	call [xmsaddr]

	mov bh, 0
	mov [xmserr], bx
	ret	; xms result is good for us, too
endp

proc EMStoHeap uses si di, tofs:word, tseg:word, fblk:word
	mov dx, [emshand]
	mov ax, 4400h
	mov bx, [fblk]
	dec bx
	mov cx, bx
	shr bx, 1
	shr bx, 1
	int 67h
	or ah, ah
	jne no_eth

	; Offset into EMS page...
	mov ax, cx
	and ax, 11b
	mov cx, SIZE_B
	mul cx
	mov si, ax

	push ds
	mov ax, [emsframe]
	mov bx, [tseg]
	mov di, [tofs]
	mov ds, ax
	mov es, bx

	mov cx, SIZE_B / 2
	cld
	rep movsw
	pop ds
	mov ax, 1
	ret

no_eth:	mov al, ah
	mov ah, 0
	mov [emserr], ax
	xor ax, ax
	ret
endp

proc VirttoHeap, tofs:word, tseg:word, fblk:word
	mov bx, [vrthand]
	or bx, bx
	je no_vth

	mov ax, [fblk]
	dec ax
	mov dx, SIZE_B
	mul dx
	mov cx, dx
	mov dx, ax
	mov ax, 4200h
	int 21h 	; seek the block
	jc no_vth

	push ds
	mov dx, [tofs]
	mov ax, [tseg]
	mov ds, ax
	mov cx, SIZE_B
	mov ah, 3fh
	int 21h 	; simple file read
	pop ds
	jc no_vth

	cmp ax, SIZE_B
	jne no_vth

	mov ax, 1
	ret

no_vth: xor ax, ax
	ret
endp

proc HeapToEMS uses si di, tblk:word, fofs:word, fseg:word
	mov dx, [emshand]
	mov ax, 4400h
	mov bx, [tblk]
	dec bx
	mov cx, bx
	shr bx, 1
	shr bx, 1
	int 67h
	or ah, ah
	jne no_hte

	; Offset into EMS page...
	mov ax, cx
	and ax, 11b
	mov cx, SIZE_B
	mul cx
	mov di, ax

	push ds
	mov ax, [emsframe]
	mov bx, [fseg]
	mov si, [fofs]
	mov ds, bx
	mov es, ax

	mov cx, SIZE_B / 2
	cld
	rep movsw
	pop ds
	xor ax, ax
	ret

no_hte:	mov al, ah
	mov ah, 0
	mov [emserr], ax
	ret
endp

proc HeapToXMS uses si, tblk:word, fofs:word, fseg:word
	mov [srchand], 0
	mov ax, [xmshand]
	mov [dsthand], ax
	mov ax, [fofs]
	mov [word ptr srcofs], ax
	mov ax, [fseg]
	mov [word ptr srcofs+2], ax
	mov ax, [tblk]
	dec ax
	mov bx, SIZE_B
	mul bx
	mov [word ptr dstofs], ax
	mov [word ptr dstofs+2], dx
	mov si, offset xmsxfr
	mov ah, 0bh
	call [xmsaddr]

	mov bh, 0
	mov [xmserr], bx
	ret	; xms result is good for us, too
endp

proc HeapToVirt, tblk:word, fofs:word, fseg:word
	mov bx, [vrthand]
	or bx, bx
	je no_htv

	mov ax, [tblk]
	dec ax
	mov dx, SIZE_B
	mul dx
	mov cx, dx
	mov dx, ax
	mov ax, 4200h
	int 21h
	jc no_htv	; seek the block

	push ds
	mov dx, [fofs]
	mov ax, [fseg]
	mov ds, ax
	mov cx, SIZE_B
	mov ah, 40h	
	int 21h 	; simple file write
	pop ds
	jc no_htv

	cmp ax, SIZE_B
	jne no_htv

	mov ax, 1
	ret

no_htv: xor ax, ax
	ret
endp

endif
end
