; Program to test FRMI with Get_RAM and Free_RAM procedures
; Written by Erwann Corvellec
IDEAL
P386
DOSSEG
JUMPS
MODEL HUGE, PASCAL
INCLUDE "FRMI.INC"
INCLUDE "MYMACROS.MAC"
STACK 200h
═══════════════════════════════════════════════════════════════════════════════
DATASEG
MEM_TO_ALLOC EQU 250
MEM_TO_ALLOC_STR EQU "250"
MAX_MB EQU 50
MAX_MB_STR EQU "50"
TCR EQU 13, 10
@MKPS ERRMSG_Bad_CPU, <TCR, "A 386 CPU or greater is needed !", TCR>
@MKPS ERRMSG_V86, <TCR, "Your CPU is running in V86 MODE ! Please remove QEMM386, 386MAX, EMM386, etc.", TCR>
@MKPS ERRMSG_XMS_DRIVER_Error, <TCR, "Error while initializing XMS driver !", TCR>
@MKPS ERRMSG_Alloc_Error_Head, <TCR, TCR, "Error while allocating a new block:", TCR>
@MKPS ERRMSG_Alloc_Error, <"Not enough free memory...">
@MKPS ERRMSG_EMB_Error, <"No more EMB available...">
@MKPS ERRMSG_Lock_Error, <"Can't lock XMS...">
@MKPS ERRMSG_Alloc_Error_Tail <TCR, TCR, "Freeing allocated blocks now...", TCR>
@MKPS ERRMSG_Free_Error, <TCR, TCR, "Error(s) occured while freeing block(s) !", TCR>
@MKPS INFOMSG_Alloc_Blocks, <TCR, "Allocating ", MAX_MB_STR, " blocks of ", MEM_TO_ALLOC_STR, "KB...", TCR>
@MKPS INFOMSG_Free_Blocks, <TCR, TCR, "All blocks allocations are OK ! Freeing blocks now...", TCR>
@MKPS INFOMSG_Free_OK, <TCR, TCR, "Freeing is successful !", TCR>
LABEL Error_Free_RAM BYTE
DB FALSE
UDATASEG
LABEL Address_Table DWORD
DD MAX_MB DUP (?)
═══════════════════════════════════════════════════════════════════════════════
CODESEG
ASSUME CS:@code, DS:@data
PROC Disp_PS NEAR USES AX BX CX DX
ARG PS:NEAR PTR BYTE
Mov AH, 40h
Mov CH, 0
Mov BX, [PS]
Mov CL, [BX]
Inc BX
Mov DX, BX
Mov BX, 1
INT 21h
RET
ENDP
PROC Disp_Hex NEAR USES AX BX CX
ARG Digit:DWORD
Mov CX, 8
@@Disp_Loop:
Rol [Digit], 4
Mov AL, [BYTE Digit]
And AL, 0Fh
Cmp AL, 10
JB @@Dec_Number
Add AL, 'A'-'0'-10
@@Dec_Number:
Add AL, '0'
Mov BH, 0
Mov AH, 0Eh
INT 10h
LOOP @@Disp_Loop
RET
ENDP
───────────────────────────────────────────────────────────────────────────────
STARTUPCODE
; Release all memory except the amount currently being used
; End of stack is end of non-heap portion of program
Mov BX, SP
Shr BX, 4 ; Convert SP into paragraphs
Inc BX
Mov AX, SS ; Calculate size of program using PSP address in ES
Add BX, AX
Mov AX, ES
Sub BX, AX
Mov AH, 4Ah ; Resize memory block with PSP address in ES
INT 21h
CALL FRMI_START
JNC @@In_FRM
Cmp AH, CPU_80386
JAE @@CPU_Type_OK
CALL Disp_PS, OFFSET ERRMSG_Bad_CPU
@DOS_EXIT 1
@@CPU_Type_OK:
CALL Disp_PS, OFFSET ERRMSG_V86
@DOS_EXIT 1
───────────────────────────────────────────────────────────────────────────────
@@In_FRM:
CALL XMS_INIT
JNC @@XMS_Init_OK
CALL Disp_PS, OFFSET ERRMSG_XMS_DRIVER_Error
@DOS_EXIT 1
───────────────────────────────────────────────────────────────────────────────
@@XMS_Init_OK:
@SEG2LIN <EBX>, <SEG Address_Table>, <OFFSET Address_Table>
Xor EDI, EDI
Mov ES, DI
CALL Disp_PS, OFFSET INFOMSG_Alloc_Blocks
@@Alloc_Loop:
CALL GET_RAM, MEM_TO_ALLOC
JNC @@Enough_Free
CALL Disp_PS, OFFSET ERRMSG_Alloc_Error_Head
Cmp AX, NO_FREE_RAM
JNE @@Test_No_Free_EMB
CALL Disp_PS, OFFSET ERRMSG_Alloc_Error
JMP @@Alloc_Error_End
@@Test_No_Free_EMB:
Cmp AX, NO_FREE_EMB
JNE @@Cant_Lock_XMS
CALL Disp_PS, OFFSET ERRMSG_EMB_Error
JMP @@Alloc_Error_End
@@Cant_Lock_XMS:
CALL Disp_PS, OFFSET ERRMSG_Lock_Error
JMP @@Alloc_Error_End
@@Alloc_Error_End:
CALL Disp_PS, OFFSET ERRMSG_Alloc_Error_Tail
JMP @@MEM_Clean_Loop
───────────────────────────────────────────────────────────────────────────────
@@Enough_Free:
Mov [ES:EBX+EDI*4], EAX ; Great addressing, eh ?
Or DI, DI
JZ @@No_Sep
@DSEP ','
@@No_Sep:
CALL Disp_Hex, EAX
Inc DI ; Should be EDI but MAX_MB<=65535 !
Cmp DI, MAX_MB ; Inc+Cmp=4 bytes instead of 6 with EDI...
JB @@Alloc_Loop ; So, it's a very little bit faster...
; Maybe 1 or 2 cycles...
; But NOT really sure with a PENTIUM !
; I don't even know with a 486...
; But it surely is with the DECEASED 386 !
; So, do as you want to do !
CALL Disp_PS, OFFSET INFOMSG_Free_Blocks
───────────────────────────────────────────────────────────────────────────────
@@MEM_Clean_Loop:
Dec DI
JS @@Test_Clean
Mov EAX, [DWORD ES:EBX+EDI*4] ; I love CISC
CALL Disp_Hex, EAX
Or DI, DI
JZ @@No_Sep_2
@DSEP ','
@@No_Sep_2:
CALL FREE_RAM, EAX
JNC @@MEM_Clean_Loop
Mov [Error_Free_RAM], TRUE
JMP @@MEM_Clean_Loop
───────────────────────────────────────────────────────────────────────────────
@@Test_Clean:
Cmp [Error_Free_RAM], TRUE
JNE @@Exit
CALL Disp_PS, OFFSET ERRMSG_Free_Error
@DOS_EXIT 1
@@Exit:
CALL Disp_PS, OFFSET INFOMSG_Free_OK
Mov AX, 0B800h ; ES can be used as a standard segment reg
Mov ES, AX
Mov [DWORD ES:2*80], 0CF4BBF4Fh
@DOS_EXIT 0
END