LOCALS

.MODEL	SMALL


.DATA

sEMMXXXX0		DB	'EMMXXXX0'


.DATA?

PUBLIC	szMainMemSize
PUBLIC	szFreeMainMemSize
PUBLIC	szExtMemSize
PUBLIC	szFreeExtMemSize
PUBLIC	szExpMemSize
PUBLIC	szFreeExpMemSize

fpXMSControl		DD	?		;адрес управляющей программы
						;драйвера XMS

szMainMemSize		DB	6 DUP(?)	;строка с размером основной
						;памяти
szFreeMainMemSize	DB	6 DUP(?)	;строка с размером свободной
						;основной памяти
szExtMemSize		DB	11 DUP(?)	;строка с размером памяти XMS
szFreeExtMemSize	DB	11 DUP(?)	;строка с размером свободной
						;памяти XMS
szExpMemSize		DB	11 DUP(?)	;строка с размером памяти EMS
szFreeExpMemSize	DB	11 DUP(?)	;строка с размером свободной
						;памяти EMS


.CODE

PUBLIC	GetMemoryInfo
PUBLIC	FreeMainMemSize

EXTRN	ReadCMOSReg:PROC
EXTRN	WordToStr:PROC
EXTRN	DWordToStr:PROC

;*******************************************************************************
;GetMemoryInfo	определяет основную информацию о памяти
;*******************************************************************************
;Использует:	WordToStr, DWordToStr, GetMainMemSize, FreeMainMemSize,
;		GetExtMemSize, XMS_Installed, fpXMSControl, EMS_Detect
;		int 67h
;
;Вызов:		нет
;
;Возврат:	нет
;
;Изменяемые
;  регистры:	EAX,BX,ECX,EDX,Flags
;*******************************************************************************
GetMemoryInfo	PROC

		push	es		;сохраняем регистры в стеке
		push	si
		push	di

		push	ds
		pop	es		;ES = сегмент данных

;-------------------------------------------------------------------------------
;Основная память
;-------------------------------------------------------------------------------

;Размер основной памяти

		call	GetMainMemSize	;AX = размер основной оперативной памяти
					;в килобайтах

		mov	di,OFFSET szMainMemSize	;ES:DI -> szMainMemSize
		call	WordToStr

;Размер свободной основной памяти

		call	FreeMainMemSize	;AX = размер свободной основной
					;оперативной памяти в параграфах
		mov	cl,6
		shr	ax,cl
		adc	ax,0		;AX = размер свободной основной памяти
					;в килобайтах

		mov	di,OFFSET szFreeMainMemSize	;ES:DI -> szFreeMainMemSize
		call	WordToStr

;-------------------------------------------------------------------------------
;Память XMS
;-------------------------------------------------------------------------------

;Размер всей памяти XMS

		call	GetExtMemSize	;DX:AX = размер памяти XMS в килобайтах

		mov	di,OFFSET szExtMemSize	;ES:DI -> szExtMemSize
		call	DWordToStr

;Размер свободной памяти XMS

		mov	di,OFFSET szFreeExtMemSize	;ES:DI -> szFreeExtMemSize

		call	XMS_Installed	;AX=0 - драйвер HIMEM.SYS не установлен
					;AX=1 - драйвер HIMEM.SYS установлен
		or	ax,ax
		jz	@@XMS_AXToStr

		mov	ah,88h		;AH = расширенная функция определения
					;размера свободной памяти XMS (> 64Мб)
		call	[fpXMSControl]	;BL = код ошибки (BL=0 - успешно)
					;EDX = общий размер свободной
					;памяти XMS в килобайтах
		cmp	bl,80h		;функция осуществлена?
		je	@@XMS_Up64Mb

.386
		mov	ax,dx
		shr	edx,16		;DX:AX = общий размер свободной
					;памяти XMS в килобайтах
.8086
		call	DWordToStr
		jmp	@@XMS_End

@@XMS_Up64Mb:	mov	ah,8		;AH = функция определения размера
					;свободной памяти XMS
		call	[fpXMSControl]	;DX = общий размер свободной
					;памяти XMS в килобайтах
		mov	ax,dx

@@XMS_AXToStr:	call	WordToStr

@@XMS_End:

;-------------------------------------------------------------------------------
;Память EMS
;-------------------------------------------------------------------------------

;Размер всей памяти EMS

		call	EMS_Detect	;AX=0 - драйвер EMS не установлен
					;AX=1 - драйвер EMS установлен
		xor	dx,dx
		xor	bx,bx

		or	ax,ax
		jz	@@11

		mov	ax,4200h	;AX = функция получения размера доступной
					;памяти EMS
		int	67h		;DX = общее количество 16-килобайтных
					;страниц EMS в системе
					;BX = число доступных в настоящее время
					;страниц EMS

@@11:		push	bx		;сохраняем в стеке размер доступной
					;памяти EMS

		mov	ax,16
		mul	dx		;DX:AX = размер памяти EMS в килобайтах

		mov	di,OFFSET szExpMemSize	;ES:DI -> szExpMemSize
		call	DWordToStr

;Размер доступной памяти EMS

		pop	ax
		mov	cx,16
		mul	cx		;DX:AX = размер доступной памяти EMS
					;в килобайтах

		mov	di,OFFSET szFreeExpMemSize	;ES:DI -> szFreeExpMemSize
		call	DWordToStr

		pop	di		;восстанавливаем регистры
		pop	si
		pop	es

		ret

GetMemoryInfo	ENDP

;*******************************************************************************
;GetMainMemSize	возвращает размер основной оперативной памяти в килобайтах
;*******************************************************************************
;Использует:	ReadCMOSReg
;
;Вызов:		нет
;
;Возврат:	AX = размер основной оперативной памяти в килобайтах
;
;Изменяемые
;  регистры:	AX
;*******************************************************************************
GetMainMemSize	PROC

		mov	ax,1516h	;AL=16h	(номер регистра RT/CMOS)
					;AH=15h	(номер регистра RT/CMOS)
		call	ReadCMOSReg	;считываем старший байт
		xchg	al,ah
		call	ReadCMOSReg	;AX = размер основной оперативной памяти
					;в килобайтах

		ret

GetMainMemSize	ENDP

;*******************************************************************************
;FreeMainMemSize возвращает размер свободной основной памяти в параграфах
;*******************************************************************************
;Использует:	int 21h
;
;Вызов:		нет
;
;Возврат:	AX = размер свободной основной памяти в параграфах
;
;Изменяемые
;  регистры:	AX,BX,Flags
;*******************************************************************************
FreeMainMemSize	PROC

		push	ds

		mov	ah,62h		;AH = номер функции получения адреса PSP
		int	21h		;BX = сегмент PSP

		mov	ds,bx		;DS = сегмент PSP
		mov	ax,ds:[02h]	;AX = сегментный адрес последнего
					;параграфа памяти, выделенной программе
		sub	ax,bx		;AX = размер свободной основной памяти

		pop	ds

		ret

FreeMainMemSize	ENDP

;*******************************************************************************
;GetExtMemSize	возвращает размер расширенной оперативной памяти в килобайтах
;*******************************************************************************
;Использует:	ReadCMOSReg
;		int 15h
;
;Вызов:		нет
;
;Возврат:	DX:AX = размер расширенной оперативной памяти в килобайтах
;
;Изменяемые
;  регистры:	AX,BX,CX,DX,Flags
;*******************************************************************************
GetExtMemSize	PROC

		mov	ax,0E801h	;AX=0E801h (получить размер памяти)
		int	15h		;CF = флаг успешного/неудачного завершения
					;AX = размер расширенной памяти
					;от 1Мб до 16Мб в килобайтах
					;BX = размер расширенной памяти
					;свыше 64Мб в 64-килобайтных блоках
					;CX = размер сконфигурированной памяти
					;от 1Мб до 16Мб в килобайтах
					;DX = размер сконфигурированной памяти
					;свыше 64Мб в 64-килобайтных блоках
		jc	@@Below64Mb

		mov	ax,cx
		mov	bx,dx
		mov	cl,6
		shl	bx,cl
		mov	cl,0Ah
		shr	dx,cl
		add	ax,bx
		adc	dx,0		;DX:AX = размер расширенной оперативной
					;памяти в килобайтах

		ret

@@Below64Mb:	mov	ax,1718h	;AL=18h	(номер регистра RT/CMOS)
					;AH=17h (номер регистра RT/CMOS)
		call	ReadCMOSReg	;считываем старший байт
		xchg	al,ah
		call	ReadCMOSReg
		xor	dx,dx		;DX:AX = размер расширенной оперативной
					;памяти в килобайтах

		ret

GetExtMemSize	ENDP

;*******************************************************************************
;XMS_Installed	проверяет наличие драйвера HIMEM.SYS и в случае его присутствия
;		запоминает адрес управляющей функции
;*******************************************************************************
;Использует:	int 2Fh
;
;Вызов:		нет
;
;Возврат:	AX=0 - драйвер HIMEM.SYS не установлен
;		AX=1 - драйвер HIMEM.SYS установлен
;
;Изменяемые
;  регистры:	AX,BX,Flags
;*******************************************************************************
XMS_Installed	PROC

		push	es

		mov	ax,4300h
		int	2Fh		;AL=80h - драйвер HIMEM.SYS установлен
					;AL<>80h - драйвер HIMEM.SYS не установлен

		cmp	al,80h
		mov	ax,0		;AX=0
		jne	@@Exit

		mov	ax,4310h
		int	2Fh		;ES:BX -> адрес управляющей программы

		mov	WORD PTR [fpXMSControl],bx
		mov	WORD PTR [fpXMSControl+2],es

		mov	ax,1		;AX=1

@@Exit:		pop	es

		ret

XMS_Installed	ENDP

;*******************************************************************************
;EMS_Detect	проверяет наличие драйвера EMS
;*******************************************************************************
;Использует:	нет
;
;Вызов:		нет
;
;Возврат:	AX=0 - драйвер EMS не установлен
;		AX=1 - драйвер EMS установлен
;
;Изменяемые
;  регистры:	AX,CX,Flags
;*******************************************************************************
EMS_Detect	PROC

		push	es		;сохраняем регистры
		push	si		;в стеке
		push	di

		xor	ax,ax
		mov	es,ax		;ES = нулевой сегмент

		mov	ax,es:[4*67h+2]
		mov	es,ax		;ES = сегмент обработчика прерывания
					;int 67h
		mov	di,10		;ES:DI -> строка "EMMXXXX0", если
					;драйвер EMS установлен

		mov	si,OFFSET sEMMXXXX0	;DS:SI -> sEMMXXXX0

		xor	ax,ax		;AX=0

		mov	cx,8
		cld
		repe	cmpsb		;проверяем наличие строки "EMMXXXX0"
					;в ОП
		jne	@@Exit

		inc	ax		;AX=1

@@Exit:		pop	di		;восстанавливаем регистры
		pop	si
		pop	es

		ret

EMS_Detect	ENDP


END
