'===========================================================================
' Subject: EMS FUNCTIONS                      Date: 06-18-97 (15:03)       
'  Author: Chris Butler                       Code: QB, PDS                
'  Origin: FidoNet QUIK_BAS Echo            Packet: MEMORY.ABC
'===========================================================================
'> How can you, using XMS, EMS, or any other memory system, get more
'> space for arrays, strings, integers, ect?

'I've got some code I converted from a C program...

'The trouble with QB is you don't have to ability to PEEK/POKE blocks at a
'time,or the ability to create a pointer to a block of memory (like C)... So
'you have to use indiviual PEEK and POKE statements.

'But anyway, here it is:

' .-----------------------------------------.
' | EMS Functions in QuickBasic             |
' |                                         |
' | Author of original C functions unknown. |
' |                                         |
' | Converted by Chris Butler.              |
' |                                         |
' | Be sure to load QB with the /L switch.  |
' `-----------------------------------------'
'
' $INCLUDE: 'qb.bi'

DECLARE FUNCTION AllocateEMSPages! (PagesNeeded%, EMMHandle%)
DECLARE FUNCTION DeallocateEMSPages! (Handle%)
DECLARE FUNCTION EMMInstalled! ()
DECLARE FUNCTION EnoughEMSAvail! (PagesNeeded%)
DECLARE FUNCTION GetPageFrameAddress! (Segment&)
DECLARE FUNCTION MapEMSPages! (EMMHandle%, PhysicalPage%, LogicalPage%)

CONST EMMInt = &H67, GetPageFrame = &H4100, GetUnallocPageCount = &H4200
CONST AllocatePages = &H4300, MapPages = &H4400, DeallocatePages = &H4500

CONST False = 0, True = NOT False

IF NOT EMMInstalled THEN
 PRINT "EMM not installed!"
 SYSTEM
END IF

IF NOT EnoughEMSAvail(1) THEN
 PRINT "Not enough EMM available!"
 SYSTEM
END IF

IF NOT AllocateEMSPages(1, Handle%) THEN
 PRINT "Unable to allocate EMS Pages!"
 SYSTEM
END IF

IF NOT MapEMSPages(Handle%, 0, 0) THEN
 PRINT "Unable to map EMS Pages!"
 IF NOT DeallocateEMSPages(Handle%) THEN
  PRINT "Unable to deallocate EMS Pages!"
 END IF

 SYSTEM
END IF

IF NOT GetPageFrameAddress(Segment&) THEN
 PRINT "Unable to get the Page Frame address!"
 IF NOT DeallocateEMSPages(Handle%) THEN
  PRINT "Unable to deallocate EMS Pages!"
 END IF

 SYSTEM
END IF

' .--------------.
' | Write to EMS |
' `--------------'
'
' This is a bit slow, as you have to use POKE (and PEEK to read).
'

DEF SEG = Segment&

FOR index = 0 TO &H3FFF
 POKE index, index
NEXT

IF NOT DeallocateEMSPages(Handle%) THEN
 PRINT "Unable to deallocate EMS Pages!"
END IF

SYSTEM

FUNCTION AllocateEMSPages (PagesNeeded%, EMMHandle%)
 DIM InRegs AS RegType, OutRegs AS RegType

 InRegs.AX = AllocatePages
 InRegs.BX = PagesNeeded%
 CALL INTERRUPT(EMMInt, InRegs, OutRegs)
 IF (OutRegs.AX \ 256) = 0 THEN EMMHandle% = OutRegs.DX
 AllocateEMSPages = ((OutRegs.AX \ 256) = 0)
END FUNCTION

FUNCTION DeallocateEMSPages (Handle%)
 DIM InRegs AS RegType, OutRegs AS RegType

 InRegs.AX = DeallocatePages
 InRegs.DX = Handle%
 CALL INTERRUPT(EMMInt, InRegs, OutRegs)

 DeallocateEMSPages = ((OutRegs.AX \ 256) = 0)
END FUNCTION

FUNCTION EMMInstalled
 DIM InRegsX AS RegTypeX, OutRegsX AS RegTypeX

 InRegsX.AX = &H3567     ' Get vector for INT 67h

 CALL InterruptX(&H21, InRegsX, OutRegsX)

 DEF SEG = OutRegsX.es

 Test$ = CHR$(PEEK(&HA)) + CHR$(PEEK(&HB)) + CHR$(PEEK(&HC))

 EMMInstalled = (Test$ = "EMM")
END FUNCTION

FUNCTION EnoughEMSAvail (PagesNeeded%)
 DIM InRegs AS RegType, OutRegs AS RegType

 InRegs.AX = GetUnallocPageCount
 CALL INTERRUPT(EMMInt, InRegs, OutRegs)

 EnoughEMSAvail = (((OutRegs.AX \ 256) = 0) AND (OutRegs.BX >= PagesNeeded))
END FUNCTION

FUNCTION GetPageFrameAddress (Segment&)
 DIM InRegs AS RegType, OutRegs AS RegType

 InRegs.AX = GetPageFrame
 CALL INTERRUPT(EMMInt, InRegs, OutRegs)

 IF (OutRegs.AX \ 256) = 0 THEN
  Segment& = OutRegs.BX
 END IF

 GetPageFrameAddress = ((OutRegs.AX \ 256) = 0)
END FUNCTION

FUNCTION MapEMSPages (EMMHandle%, PhysicalPage%, LogicalPage%)
 DIM InRegs AS RegType, OutRegs AS RegType

 InRegs.AX = MapPages + (PhysicalPage% MOD 256)
 InRegs.BX = LogicalPage%
 InRegs.DX = EMMHandle%
 CALL INTERRUPT(EMMInt, InRegs, OutRegs)

 MapEMSPages = ((OutRegs.AX \ 256) = 0)
END FUNCTION

'=== End ems.bas ===

'As you can probably tell, this program doesn't actually do much, but it shows
'you how to use EMS...
