Metropoli BBS
VIEWER: frmi_ex2.asm MODE: TEXT (CP437)
; 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
[ RETURN TO DIRECTORY ]