1 ' Using EMS in QuickBASIC: Part 1 of 3
\r
4 ' By Jon Petrosky (Plasma)
\r
7 ' [Remember to start QB with the /L switch to enable interrupts]
\r
13 DIM SHARED Regs AS RegTypeX
\r
14 DIM SHARED EMS.Error 'Holds the error code of the last operation
\r
16 DECLARE FUNCTION EMS.ErrorMsg$ ()
\r
17 DECLARE FUNCTION EMS.Init ()
\r
18 DECLARE FUNCTION EMS.Version$ ()
\r
19 DECLARE FUNCTION EMS.PageFrame ()
\r
20 DECLARE FUNCTION EMS.FreeHandles ()
\r
21 DECLARE FUNCTION EMS.FreePages ()
\r
22 DECLARE FUNCTION EMS.TotalPages ()
\r
23 DECLARE FUNCTION EMS.AllocPages (NumPages)
\r
24 DECLARE SUB EMS.DeallocPages (Handle)
\r
25 DECLARE SUB EMS.MapPage (Physical, Logical, Handle)
\r
26 DECLARE SUB EMS.MapXPages (PhysicalStart, LogicalStart, NumPages, Handle)
\r
27 DECLARE SUB EMS.CopyMem (Length&, SrcHandle, SrcSegment, SrcOffset, DstHandle, DstSegment, DstOffset)
\r
28 DECLARE SUB EMS.ExchMem (Length&, SrcHandle, SrcSegment, SrcOffset, DstHandle, DstSegment, DstOffset)
\r
32 IF NOT EMS.Init THEN
\r
33 PRINT "No EMM detected."
\r
38 PRINT SPACE$(22); "Using EMS in QuickBasic: Part 1 of 3"; SPACE$(22)
\r
40 PRINT STRING$(31, 196); " EMS Information "; STRING$(32, 196)
\r
42 PRINT "EMM Version: "; EMS.Version$
\r
44 IF EMS.Version$ < "4.0" THEN
\r
46 PRINT "EMM 4.0 or later must be present to use some of the EMS functions."
\r
50 PRINT "Page frame at: "; HEX$(EMS.PageFrame); "h"
\r
51 PRINT "Free handles:"; EMS.FreeHandles
\r
53 IF EMS.FreeHandles = 0 THEN
\r
55 PRINT "You need at least one free handle to run this demo."
\r
59 PRINT "Total EMS:"; EMS.TotalPages; "pages /"; EMS.TotalPages * 16&; "KB /"; EMS.TotalPages \ 64; "MB"
\r
60 PRINT "Free EMS:"; EMS.FreePages; "pages /"; EMS.FreePages * 16&; "KB /"; EMS.FreePages \ 64; "MB"
\r
62 IF EMS.FreePages < 64 THEN
\r
64 PRINT "You need at least 64 pages (1 MB) free EMS to run this demo."
\r
70 PRINT STRING$(31, 196); " Allocation Test "; STRING$(32, 196)
\r
72 PRINT "Allocating 64 pages (1 MB) of EMS...";
\r
74 Handle = EMS.AllocPages(64)
\r
83 PRINT "Pages allocated to handle"; Handle
\r
86 PRINT STRING$(30, 196); " Page Map/Copy Test "; STRING$(30, 196)
\r
88 PRINT "Mapping logical page 0 to physical page 0...";
\r
90 EMS.MapPage 0, 0, Handle
\r
99 PRINT "Mapping logical pages 0-3 to physical pages 0-3...";
\r
101 EMS.MapXPages 0, 0, 4, Handle
\r
104 PRINT EMS.ErrorMsg$
\r
110 PRINT "Copying logical pages 0-31 to logical pages 32-63...";
\r
112 EMS.CopyMem 512288, Handle, 0, 0, Handle, 32, 0
\r
115 PRINT EMS.ErrorMsg$
\r
121 PRINT "Exchanging logical pages 0-31 with logical pages 32-63...";
\r
123 EMS.ExchMem 512288, Handle, 0, 0, Handle, 32, 0
\r
126 PRINT EMS.ErrorMsg$
\r
134 PRINT STRING$(22, 196); " 10-Second Speed Test (Please Wait) "; STRING$(22, 196)
\r
139 DO UNTIL StartTime! + 5 <= TIMER
\r
140 EMS.MapXPages 0, 0, 4, Handle
\r
141 Mapped& = Mapped& + 4
\r
146 DO UNTIL StartTime! + 5 <= TIMER
\r
147 EMS.CopyMem 512288, Handle, 0, 0, Handle, 32, 0
\r
148 Copied& = Copied& + 1
\r
151 PRINT "Pages Mapped/Sec:"; Mapped& \ 5
\r
152 PRINT "Bytes copied/Sec:"; (Copied& * 512288) \ 5
\r
155 PRINT STRING$(30, 196); " Deallocation Test "; STRING$(31, 196)
\r
157 PRINT "Deallocating 64 pages...";
\r
159 EMS.DeallocPages (Handle)
\r
162 PRINT EMS.ErrorMsg$
\r
168 KeyPress$ = INPUT$(1)
\r
172 FUNCTION EMS.AllocPages (NumPages)
\r
174 'Allocates the number of pages in [NumPages] and
\r
175 'returns the EMS handle the memory is allocated to.
\r
177 Regs.ax = &H4300 'Allocate [NumPages] pages of EMS
\r
179 InterruptX &H67, Regs, Regs
\r
180 EMS.Error = (Regs.ax AND &HFF00&) \ &H100 'Store the status code
\r
182 EMS.AllocPages = Regs.dx 'Return the handle
\r
186 SUB EMS.CopyMem (Length&, SrcHandle, SrcSegment, SrcOffset, DstHandle, DstSegment, DstOffset)
\r
188 'Copies memory from EMS or base memory to EMS or base memory, where:
\r
190 'Length& = Length of memory to copy in bytes
\r
191 'SrcHandle = EMS handle of source memory (use 0 if source is base memory)
\r
192 'SrcSegment = Segment of source memory (or page number if source is EMS)
\r
193 'SrcOffset = Offset of source memory
\r
194 'DstHandle = EMS handle of destination memory (use 0 if destination is base memory)
\r
195 'DstSegment = Segment of destination memory (or page number if destination is EMS)
\r
196 'DstOffset = Offset of destination memory
\r
198 'Determine the source and destination memory types by checking the handles
\r
199 IF SrcHandle = 0 THEN SrcType$ = CHR$(0) ELSE SrcType$ = CHR$(1)
\r
200 IF DstHandle = 0 THEN DstType$ = CHR$(0) ELSE DstType$ = CHR$(1)
\r
202 'Create a buffer containing the copy information
\r
203 CopyInfo$ = MKL$(Length&) + SrcType$ + MKI$(SrcHandle) + MKI$(SrcOffset) + MKI$(SrcSegment) + DstType$ + MKI$(DstHandle) + MKI$(DstOffset) + MKI$(DstSegment)
\r
205 Regs.ax = &H5700 'Copy the memory region
\r
206 Regs.ds = VARSEG(CopyInfo$) 'described in the buffer
\r
207 Regs.si = SADD(CopyInfo$)
\r
208 InterruptX &H67, Regs, Regs
\r
209 EMS.Error = (Regs.ax AND &HFF00&) \ &H100 'Store the status code
\r
213 SUB EMS.DeallocPages (Handle)
\r
215 'Deallocates the EMS pages allocated the EMS handle [Handle].
\r
216 'You MUST remember to call the sub before your program ends
\r
217 'if you allocate any memory!
\r
219 Regs.ax = &H4500 'Release the pages allocated to [Handle]
\r
221 InterruptX &H67, Regs, Regs
\r
222 EMS.Error = (Regs.ax AND &HFF00&) \ &H100 'Store the status code
\r
226 FUNCTION EMS.ErrorMsg$
\r
228 'Returns a text string describing the error code in EMS.Error.
\r
230 SELECT CASE EMS.Error
\r
231 CASE &H0: Msg$ = "successful"
\r
232 CASE &H80: Msg$ = "internal error"
\r
233 CASE &H81: Msg$ = "hardware malfunction"
\r
234 CASE &H82: Msg$ = "busy -- retry later"
\r
235 CASE &H83: Msg$ = "invalid handle"
\r
236 CASE &H84: Msg$ = "undefined function requested by application"
\r
237 CASE &H85: Msg$ = "no more handles available"
\r
238 CASE &H86: Msg$ = "error in save or restore of mapping context"
\r
239 CASE &H87: Msg$ = "insufficient memory pages in system"
\r
240 CASE &H88: Msg$ = "insufficient memory pages available"
\r
241 CASE &H89: Msg$ = "zero pages requested"
\r
242 CASE &H8A: Msg$ = "invalid logical page number encountered"
\r
243 CASE &H8B: Msg$ = "invalid physical page number encountered"
\r
244 CASE &H8C: Msg$ = "page-mapping hardware state save area is full"
\r
245 CASE &H8D: Msg$ = "save of mapping context failed"
\r
246 CASE &H8E: Msg$ = "restore of mapping context failed"
\r
247 CASE &H8F: Msg$ = "undefined subfunction"
\r
248 CASE &H90: Msg$ = "undefined attribute type"
\r
249 CASE &H91: Msg$ = "feature not supported"
\r
250 CASE &H92: Msg$ = "successful, but a portion of the source region has been overwritten"
\r
251 CASE &H93: Msg$ = "length of source or destination region exceeds length of region allocated to either source or destination handle"
\r
252 CASE &H94: Msg$ = "conventional and expanded memory regions overlap"
\r
253 CASE &H95: Msg$ = "offset within logical page exceeds size of logical page"
\r
254 CASE &H96: Msg$ = "region length exceeds 1 MB"
\r
255 CASE &H97: Msg$ = "source and destination EMS regions have same handle and overlap"
\r
256 CASE &H98: Msg$ = "memory source or destination type undefined"
\r
257 CASE &H9A: Msg$ = "specified alternate map register or DMA register set not supported"
\r
258 CASE &H9B: Msg$ = "all alternate map register or DMA register sets currently allocated"
\r
259 CASE &H9C: Msg$ = "alternate map register or DMA register sets not supported"
\r
260 CASE &H9D: Msg$ = "undefined or unallocated alternate map register or DMA register set"
\r
261 CASE &H9E: Msg$ = "dedicated DMA channels not supported"
\r
262 CASE &H9F: Msg$ = "specified dedicated DMA channel not supported"
\r
263 CASE &HA0: Msg$ = "no such handle name"
\r
264 CASE &HA1: Msg$ = "a handle found had no name, or duplicate handle name"
\r
265 CASE &HA2: Msg$ = "attempted to wrap around 1M conventional address space"
\r
266 CASE &HA3: Msg$ = "source array corrupted"
\r
267 CASE &HA4: Msg$ = "operating system denied access"
\r
268 CASE ELSE: Msg$ = HEX$(EMS.Error) '"undefined error"
\r
271 EMS.ErrorMsg$ = Msg$
\r
275 SUB EMS.ExchMem (Length&, SrcHandle, SrcSegment, SrcOffset, DstHandle, DstSegment, DstOffset)
\r
277 'Exhanges memory from EMS or base memory to EMS or base memory, where:
\r
279 'Length& = Length of memory to exchange in bytes
\r
280 'SrcHandle = EMS handle of source memory (use 0 if source is base memory)
\r
281 'SrcSegment = Segment of source memory (or page number if source is EMS)
\r
282 'SrcOffset = Offset of source memory
\r
283 'DstHandle = EMS handle of destination memory (use 0 if destination is base memory)
\r
284 'DstSegment = Segment of destination memory (or page number if destination is EMS)
\r
285 'DstOffset = Offset of destination memory
\r
287 'Determine the source and destination memory types by checking the handles
\r
288 IF SrcHandle = 0 THEN SrcType$ = CHR$(0) ELSE SrcType$ = CHR$(1)
\r
289 IF DstHandle = 0 THEN DstType$ = CHR$(0) ELSE DstType$ = CHR$(1)
\r
291 'Create a buffer containing the copy information
\r
292 ExchInfo$ = MKL$(Length&) + SrcType$ + MKI$(SrcHandle) + MKI$(SrcOffset) + MKI$(SrcSegment) + DstType$ + MKI$(DstHandle) + MKI$(DstOffset) + MKI$(DstSegment)
\r
294 Regs.ax = &H5701 'Exchange the memory region
\r
295 Regs.ds = VARSEG(ExchInfo$) 'described in the buffer
\r
296 Regs.si = SADD(ExchInfo$)
\r
297 InterruptX &H67, Regs, Regs
\r
298 EMS.Error = (Regs.ax AND &HFF00&) \ &H100 'Store the status code
\r
302 FUNCTION EMS.FreeHandles
\r
304 'Returns the number of free (available) EMS handles.
\r
306 Regs.ax = &H4B00 'Get the # of handles in use
\r
307 InterruptX &H67, Regs, Regs
\r
308 UsedHandles = Regs.bx
\r
310 Regs.ax = &H5402 'Get the total # of handles
\r
311 InterruptX &H67, Regs, Regs
\r
312 EMS.Error = (Regs.ax AND &HFF00&) \ &H100 'Store the status code
\r
313 TotalHandles = Regs.bx
\r
315 EMS.FreeHandles = TotalHandles - UsedHandles 'Subtract to get the # of free handles
\r
319 FUNCTION EMS.FreePages
\r
321 'Returns the number of free (available) EMS pages
\r
322 '(Multiply by 16 to get the amount free EMS in KB.)
\r
324 Regs.ax = &H4200 'Get the # of free pages
\r
325 InterruptX &H67, Regs, Regs
\r
326 EMS.Error = (Regs.ax AND &HFF00&) \ &H100 'Store the status code
\r
327 EMS.FreePages = Regs.bx
\r
333 'Returns true (-1) if an EMM is installed
\r
334 'or false (0) if an EMM is not installed.
\r
336 Regs.ax = &H3567 'Get the interrupt vector for int 67h
\r
337 InterruptX &H21, Regs, Regs
\r
338 DEF SEG = Regs.es 'Point to the interrupt segment
\r
339 FOR x = 10 TO 17 'Store the 8 bytes at ES:0A in EMM$
\r
340 EMM$ = EMM$ + CHR$(PEEK(x))
\r
342 IF EMM$ <> "EMMXXXX0" THEN
\r
343 EMS.Init = 0 'EMM not installed
\r
345 EMS.Init = -1 'EMM installed
\r
350 SUB EMS.MapPage (Physical, Logical, Handle)
\r
352 'Maps the logical EMS page [Logical] (allocated to the handle [Handle])
\r
353 'to the physical page [Physical] in the EMS page frame.
\r
355 Regs.ax = &H4400 + Physical 'Map the logical page [Logical]
\r
356 Regs.bx = Logical 'to the physical page [Physical]
\r
358 InterruptX &H67, Regs, Regs
\r
359 EMS.Error = (Regs.ax AND &HFF00&) \ &H100 'Store the status code
\r
363 SUB EMS.MapXPages (PhysicalStart, LogicalStart, NumPages, Handle)
\r
365 'Maps up to 4 logical EMS pages to physical pages in the page frame, where:
\r
367 'PhysicalStart = Physical page first logical page is mapped to
\r
368 'LogicalStart = First logical page to map
\r
369 'NumPages = Number of pages to map (1 to 4)
\r
370 'Handle = EMS handle logical pages are allocated to
\r
372 'Create a buffer containing the page information
\r
373 FOR x = 0 TO NumPages - 1
\r
374 MapInfo$ = MapInfo$ + MKI$(LogicalStart + x) + MKI$(PhysicalStart + x)
\r
377 Regs.ax = &H5000 'Map the pages in the buffer
\r
378 Regs.cx = NumPages 'to the pageframe
\r
380 Regs.ds = VARSEG(MapInfo$)
\r
381 Regs.si = SADD(MapInfo$)
\r
382 InterruptX &H67, Regs, Regs
\r
383 EMS.Error = (Regs.ax AND &HFF00&) \ &H100 'Store the status code
\r
387 FUNCTION EMS.PageFrame
\r
389 'Returns the segment of the EMS page frame
\r
391 Regs.ax = &H4100 'Get the segment of the page frame
\r
392 InterruptX &H67, Regs, Regs
\r
393 EMS.Error = (Regs.ax AND &HFF00&) \ &H100 'Save the status code
\r
394 EMS.PageFrame = Regs.bx
\r
398 FUNCTION EMS.TotalPages
\r
400 'Returns the total number of EMS pages
\r
401 '(Multiply by 16 to get the total amount of EMS in KB.)
\r
403 Regs.ax = &H4200 'Get the # of total pages
\r
404 InterruptX &H67, Regs, Regs
\r
405 EMS.Error = (Regs.ax AND &HFF00&) \ &H100 'Store the status code
\r
406 EMS.TotalPages = Regs.dx
\r
410 FUNCTION EMS.Version$
\r
412 'Returns a string containing the EMM version.
\r
413 '(Must be "4.0" or greater to use our routines.)
\r
415 Regs.ax = &H4600 'Get the EMM version
\r
416 InterruptX &H67, Regs, Regs
\r
417 EMS.Error = (Regs.ax AND &HFF00&) \ &H100 'Save the status code
\r
419 Version = Regs.ax AND &HFF 'Split the version number into
\r
420 Major = (Version AND &HF0) \ &H10 'its major and minor counterparts
\r
421 Minor = Version AND &HF
\r
422 EMS.Version$ = LTRIM$(STR$(Major)) + "." + LTRIM$(STR$(Minor))
\r