home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-10-13 | 47.9 KB | 1,092 lines |
- EMSLIB
- Version-independent C Interface to LIM EMS Functions
- for LIM EMS versions 3.0 and higher
- EMSLIB version 2.21
- by James W. Birdsall
- 10/13/91
-
-
- 0. CONTENTS
- -----------
-
- 0. CONTENTS
- I. INTRODUCTION
- I.1 WHAT IS SUPPORTED
- I.2 COPYRIGHT AND LICENSE
- II. COMPILING AND LINKING WITH THE LIBRARIES
- II.1 WITH C
- II.2 WITH C++
- II.3 EMSTEST, THE EXAMPLE PROGRAM
- III. PROGRAMMING WITH EMSLIB
- III.1 INITIALIZING THE LIBRARY
- III.2 ORDINARY USE
- III.3 FRAME CACHING
- III.4 SAVE/RESTORE
- III.5 OTHER TIPS
- IV. LIBRARY REFERENCE
- IV.1 GLOBAL VARIABLES
- IV.2 FUNCTIONS
- V. ERROR CODES
- V.1 INTERNAL ERRORS
- V.2 EMS DRIVER ERRORS
- VI. THE END
- VI.1 ACKNOWLEDGEMENTS
-
-
- I. INTRODUCTION
- ---------------
-
- EMSLIB provides a high-level interface to LIM EMS control functions
- for common operations such as allocating, mapping, and freeing EMS, and
- copying data to and from EMS. The interface has been made independent of
- the version of the EMS driver as far as possible, so that parameters and
- returned data are always in the same format, but the EMS call most
- appropriate to the EMS version implemented by the driver is used.
-
- EMSLIB is written in assembly language for speed and assembled with
- Borland's Turbo Assembler (TASM) 2.5. The source code is not compatible
- with the Microsoft Assembler (MASM).
-
- I.1 WHAT IS SUPPORTED
- ---------------------
-
- EMSLIB expressly supports the Lotus-Intel-Microsoft (LIM) Expanded
- Memory Specification (EMS) versions 3.0, 3.2, and 4.0. Versions above
- 4.0 are supported as 4.0. Versions below 3.0 are not supported.
- Save/restore is not supported under version 3.0, and assigning names to
- EMS handles is only supported under version 4.0. These exceptions to
- version-independence are due to limitations of the unsupported versions;
- the necessary services are not available from the driver.
-
- EMSLIB supports tiny, small, medium, compact, large, and huge memory
- models. The small model library supports both tiny and small models, so
- no library is provided specifically for tiny model.
-
- EMSLIB supports any version of Turbo C, Turbo C++, or Borland C++, in
- both C and C++ modes, and Microsoft C 6.00 and 6.00A. EMSLIB has been
- tested with Borland C++ 2.0 and Microsoft C 6.00A in all of the
- supported memory models. EMSLIB should work with earlier versions of
- Microsoft C and any other C compiler that 1) uses compatible parameter
- passing and return methods and 2) can use standard-format libraries.
-
- I.2 COPYRIGHT AND LICENSE
- -------------------------
-
- EMSLIB is not in the public domain. All the files are copyright 1991
- by James W. Birdsall, all rights reserved. Permission is granted to do
- the following:
-
- You may freely redistribute this archive, so long as it contains
- all the files listed in the file MANIFEST, intact and
- unmodified.
-
- You may use the libraries in programs for your own use. You may
- not distribute programs linked with these libraries.
-
- Payment of the $5 shareware registration fee ($50 for commercial use)
- grants the following license, in addition to the permissions listed
- above:
-
- You may request the source to EMSLIB. You may modify the source
- as necessary for use in your programs. However, you may not
- redistribute either the original or modified source.
-
- You may distribute programs linked with either the original
- libraries or libraries generated from source you have modified,
- without royalty.
-
- For the purposes of this license, commercial use is defined as use by an
- incorporated entity in a software product that is regarded as the
- product of the corporation, no matter how the software product is
- distributed, but only if 100 or more copies of the product are expected
- to be made.
-
- The contents of the distribution archive, and all other related
- files, information, and services are provided as-is. While every effort
- has been made to ensure that the files, information, and services are
- accurate and correct, the author cannot be held liable for damages
- arising out of the use of or inability to use this product.
-
- Information on contacting the author is provided at the end of this
- file.
-
-
- II. COMPILING AND LINKING WITH THE LIBRARIES
- --------------------------------------------
-
- This section describes how to use the EMSLIB libraries with your
- programs.
-
- EMSLIB is provided as Borland/Microsoft standard library files.
- Libraries are provided for small, medium, compact, large, and huge memory
- models (tiny model uses the small model library). The model for which a
- library is intended is indicated by the last letter of the filename
- proper, which is the same as the first letter for the model. For
- example, EMSLIBL.LIB is the large model library.
-
- II.1 WITH C
- -----------
-
- To use EMSLIB in C programs, you must #include the file EMSLIB.H in
- every source file that calls EMSLIB functions, accesses EMSLIB global
- variables, or uses #defined constants provided by EMSLIB.
-
- The procedures for linking EMSLIB with the rest of your program vary
- according to the compiler and method you are using. In general, you must
- include the appropriate library (the library corresponding to the memory
- model in which you have compiled the rest of your program) in the link.
-
- If you are compiling in the Integrated Development Environment of
- Turbo/Borland C[++], you should include the name of the appropriate
- library in the project file for your program. For example, if you are
- working in the compact memory model, you should include EMSLIBC.LIB in
- your project file.
-
- If you are using a command-line compiler (bcc, tcc, or cl) to compile
- and link, simply place the full name of the appropriate EMSLIB library
- on the command line. For example, "bcc -mc foo.c emslibc.lib" will
- compile the file "foo.c" and link it with emslibc.lib.
-
- If you are linking manually (using TLINK or LINK), place the name of
- the appropriate library in with the other libraries. For example,
- tlink c0c.obj foo.obj, foo.exe, foo.map, cc.lib emslibc.lib
- or
- link foo.obj, foo.exe, foo.map, emslibc.lib ;
- will link the object "foo.obj" with the appropriate startup object and
- standard library (LINK automatically includes the startup object and
- standard library, so it is not necessary to explicitly include them) and
- the compact model EMSLIB library.
-
- II.2 C++
- --------
-
- To use EMSLIB in C++ programs, you must #include the file EMSLIB.HPP
- in every file that calls EMSLIB functions, accesses EMSLIB global
- variables, or uses #defined constants provided by EMSLIB. Be careful to
- include EMSLIB.HPP instead of EMSLIB.H. If you include the wrong one,
- you will probably see "undefined symbol" errors when linking.
-
- Otherwise, the procedures for using EMSLIB with C++ programs are the
- same as for using it with C programs.
-
- II.3 EMSTEST, THE EXAMPLE PROGRAM
- ---------------------------------
-
- A large and complete example program and tester, EMSTEST, has been
- included in this distribution. It can be compiled in any of the
- supported memory models (although tiny model requires some contortions
- to do so), with either Borland or Microsoft compilers.
-
- The test program has three source files: EMSTEST.C, EMSTEST2.C, and
- EMSTEST3.C, and a header file EMSTEST.H. When compiling in tiny model
- with Borland compilers, an additional source file, STACK.ASM, is needed.
- STACK.OBJ, which is STACK.ASM pre-assembled, has been included for those
- who do not have assemblers.
-
- Example makefiles have been included for Borland and Microsoft
- compilers, EXMAKETC and EXMAKEMS respectively. Complete instructions for
- making the example program and using the example makefiles are included
- at the beginning of each makefile. More information about the program is
- also included at the beginning of EMSTEST.C.
-
- EMSTEST requires at least eight pages of available expanded memory
- and at least 210,000 bytes of available conventional memory to run.
-
-
- III. PROGRAMMING WITH EMSLIB
- ----------------------------
-
- This section describes how to make EMSLIB calls in your program, and
- details various tricks and tips which you may find useful.
-
- III.1 INITIALIZATION
- --------------------
-
- The library initialization function EMMlibinit() _must_ be called
- before any other EMSLIB calls are made. All other EMSLIB functions are
- guaranteed to fail if called before EMMlibinit(). EMMlibinit()
- determines whether an EMS driver is present and sets up various internal
- and global variables necessary to the functioning of EMSLIB.
-
- III.2 ORDINARY USE
- ------------------
-
- EMSLIB provides several sets of functions. First, there is a set of
- functions which are intended to be orthogonal with the standard C
- functions malloc() and free(), and the Turbo C[++] function coreleft().
- These functions are EMMalloc(), EMMfree(), and EMMcoreleft().
-
- Second, there is a group of functions for copying data to and from
- expanded memory. These functions allow you to treat allocated blocks of
- expanded memory pages as linear memory, hiding the details of page
- mapping. These functions are EMMcopyto(), EMMcopyfrom(), EMMicopyto(),
- EMMicopyfrom(), _EMMicopyto(), and _EMMicopyfrom().
-
- Third, there is a group of low-level functions which allow more
- direct control of EMS functions. These functions are EMMallocpages(),
- EMMgetframeaddr(), EMMgetnumframe(), EMMgetsinfraddr(), and
- EMMmappage(). With these functions it is possible to duplicate the
- copying functions or access expanded memory in other ways. Calls to
- these functions can be mixed with calls to copying functions without
- trouble.
-
- Fourth, there is a group of miscellaneous functions: EMMgetname(),
- EMMsetname(), EMMgetversion(), EMMsave(), and EMMrestore().
-
- Finally, there is a group of functions which affect only the
- operation of EMSLIB itself: _EMMenc(), _EMMdisc(), _EMMinval(),
- EMMlibinit(), and EMMsrinit(). For details on all the functions listed
- above, see section IV.2.
-
- To use expanded memory, first it is necessary to allocate some. This
- can be done with either EMMalloc(), which takes a size in bytes, or
- EMMallocpages(), which allocates EMS pages directly. Both return a
- handle which will be used to reference the allocated memory.
-
- To access the expanded memory, you can either use the copying
- functions, or access it directly. The copying functions are pretty
- self-explanatory. Accessing expanded memory directly is more
- complicated. First, it is necessary to determine the addresses of the
- EMS page frames. EMS page frames 0 through 3 are available under all EMS
- versions and are intended for general use. While EMS version 4.0
- provides additional page frames, they are intended for use by
- multitaskers such as Quarterdeck DesqView and Microsoft Windows. These
- additional page frames may appear anywhere, even in the middle of your
- program. Use them only with great caution. To obtain the addresses of
- all page frames, use EMMgetframeaddr(). To obtain the address of a
- single page frame, use EMMgetsinfraddr(). The addresses returned by both
- these functions are segment addresses and must be converted to far
- pointers before actually being used.
-
- Having decided which page frame you wish to use, and determined where
- that page frame is located, it is then necessary to map an EMS logical
- page into that page frame. This is accomplished with EMMmappage(). Once
- this is done, you can then access any byte in that logical page (which
- is 16384 bytes long) using the far pointer created earlier.
-
- The miscellaneous functions listed above allow you to determine the
- EMS version supported by the driver (EMMgetversion()), to associate a
- string name with an EMS handle and retrieve the name associated with an
- EMS handle (EMMsetname()/EMMgetname()), and save and restore EMS page
- mappings (EMMsave()/EMMrestore()). More information on the last is
- available in section III.4.
-
- The internal functions _EMMenc(), _EMMdisc(), and _EMMinval() are
- discussed in section III.3 below. EMMlibinit() has already been
- discussed, in section III.1, and EMMsrinit() is discussed in section
- III.4 below.
-
- Many functions return a status directly. For those functions, a
- return value of 0 indicates success and a return value of EMMOOPS
- indicates failure. The global variable _EMMerror contains an error code
- which gives further information on why the function failed, or has value
- 0 if the function succeeded. Many functions return some other value
- instead of a status code (0 or EMMOOPS). In these cases, the value of
- _EMMerror should be checked upon return. The recommended method of
- error-checking is indicated for each function in section IV.2 below.
-
- III.3 FRAME CACHING
- -------------------
-
- EMSLIB uses a technique called "frame caching" to speed up the
- copying functions. It keeps track of the handle and page number of the
- logical page currently mapped into page frame 2. When starting a copy,
- EMSLIB calculates the handle and logical page needed, and if that page
- is already mapped into page frame 2, does not perform a mapping call.
- This technique can greatly increase the copying speed, especially if
- many separate copies to the same page are being performed.
-
- Frame caching is on by default. To check the current setting, inspect
- the global variable _EMMframecache. If it is nonzero, frame caching is
- on; if it is 0, frame caching is off. The state of frame caching is
- changed via the functions _EMMenc() (enable caching) and _EMMdisc()
- (disable caching).
-
- Frame caching has one unfortunate weakness. It assumes that all EMS
- mapping activity will be performed via EMSLIB, so that an accurate
- record of the contents of frame 2 can be kept. If you are using another
- third-party library that also uses EMS, then obviously there is mapping
- activity that is not performed via EMSLIB, and frame caching will cause
- the copying functions to malfunction.
-
- This is why _EMMenc() and _EMMdisc() were created. If you have this
- problem, you have a number of options:
-
- 1) You can disable frame caching globally. Just call _EMMdisc()
- somewhere between the EMMlibinit() call and the first call to
- an EMSLIB copying function. If you mostly do large copies,
- especially copies which cross page boundaries, then there
- will be almost no performance loss. If you do lots of
- separate copies to the same page, performance may drop by up
- to 50% or more. In that case, you should probably pick
- another option.
-
- 2) You can disable frame caching around calls to the other
- library. If the calls to the other library occur in clusters,
- you can call _EMMdisc() before the cluster and _EMMenc()
- after. Alternatively, if the calls to EMSLIB form more
- convenient clusters, you can call _EMMenc() before and
- _EMMdisc() after. Note that _EMMdisc() sets a flag which
- invalidates the current cache contents, so that when caching
- is re-enabled EMSLIB does not become confused.
-
- 3) If calls to the other library are sparse, you can simply
- invalidate the cache each time you make a call to the other
- library, using the macro _EMMinval(). It does not matter
- whether you call _EMMinval() before or after the call to the
- other library, as long as the cache is invalidated before the
- next EMSLIB copying call is made.
-
- III.4 SAVE/RESTORE
- ------------------
-
- Worse interactions with other libraries can occur. If the other
- library assumes that the EMS mapping will not change between calls to
- it, then almost any EMSLIB activity at all will interfere with the other
- library. This is why save/restore capability was added to EMSLIB. Note
- that save/restore only works with EMS version 3.2 and up. While EMS
- version 3.0 claimed to have save/restore capability, it is so radically
- different from that in versions 3.2 and up that it cannot be
- consolidated under the same interface.
-
- The EMS specification (for versions 3.2 and up) includes calls to
- save the current EMS mapping to a buffer in memory, and restore a
- mapping from such a buffer. EMSLIB's save/restore function are an
- interface to these calls. Before any save/restore calls can be made,
- EMMsrinit() must be called to initialize save/restore. It takes a single
- parameter, which is a pointer to a function used to allocate save
- buffers. Malloc() may be passed in any memory model, but any other
- function with the same prototype may be used. Note that the passed
- function will never be called to allocate more that 255 bytes in one
- call.
-
- Having initialized save/restore, you can call EMMsave() to save a
- mapping and EMMrestore() to restore one. The pointer returned by
- EMMsave() is the value returned by an internal call to the function
- which was passed to EMMsrinit(), and may be freed when necessary with
- whatever function would ordinarily be called; for example, if malloc()
- was passed to EMMsrinit(), then pointers returned by EMMsave() may be
- passed to free(). Note that EMMrestore() does not free save buffers. You
- must free them yourself.
-
- To avoid interference with libraries that assume that the EMS mapping
- will not change, simply call EMMsave() after calls to that library, and
- call EMMrestore() with the pointer returned by the last EMMsave() before
- the next call to that library. Note that EMMrestore() invalidates the
- frame cache. In fact, if you have to use save/restore in this way, it
- would probably be best to disable frame caching globally, perhaps
- enabling it around loops which perform lots of copies if you really need
- the performance boost.
-
- Save/restore can also be used to quickly alternate between several
- complex mappings. Having established a mapping, save it with EMMsave().
- Then, when you need it again, a call to EMMrestore() will restore it
- quickly and easily.
-
- III.5 OTHER TIPS
- ----------------
-
- Expanded memory is not deallocated automatically when a program
- exits. If the program does not deallocate expanded memory it has
- allocated, that expanded memory is stuck, not available to any other
- program until the machine is rebooted. Under normal circumstances, it is
- easy enough to free expanded memory when it is no longer needed.
- However, an emergency exit due to the user hitting control-break or due
- to a hardware error (e.g. the famous "Abort, Retry, Fail?") can cause
- expanded memory to become stuck unless your program takes special
- measures to intercept these errors and perform cleanup before exiting.
- There are a number of ways to do this and they vary from compiler to
- compiler. Look for functions named things like ctrlbrk(), harderr() and
- signal().
-
- If you are copying array elements, _EMMicopyto()/_EMMicopyfrom() or
- EMMicopyto()/EMMicopyfrom() may be more efficient. These functions allow
- copying of elements of fixed size which are separated by gaps also of
- fixed size. For example, if you have an array of integers and wish to
- copy all the even-indexed elements (a[0], a[2], a[4], etc.), these
- functions are far faster than calling a standard copying function
- (EMMcopyto() or EMMcopyfrom()) from within a loop. While the performance
- improvement varies from machine to machine, the smallest speed increase
- that I have seen is seven times, ranging up to over twenty times on a
- fast machine with frame caching off.
-
-
- IV. LIBRARY REFERENCE
- ---------------------
-
- IV.1 GLOBAL VARIABLES
- ---------------------
-
- _EMMerror
- ---------
-
- unsigned char const _EMMerror;
-
- _EMMerror contains the error code from the last EMSLIB call. If the
- call succeeded, _EMMerror will be 0. If the call failed because the EMS
- driver returned an error, _EMMerror contains the error code returned by
- the EMS driver. If the call failed because EMSLIB detected an error
- internally, _EMMerror contains an intenal error code. A list of error
- code values, their meanings, and #defined constants for them is in
- section V.
-
- _EMMframecache
- --------------
-
- unsigned char const _EMMframecache;
-
- _EMMframecache is a flag which indicates whether frame caching is
- enabled or not. A nonzero value indicates that frame caching is enabled,
- and 0 indicates that frame caching is disabled. See section IV.3 for a
- discussion of frame caching.
-
- _EMMversion
- -----------
-
- unsigned char const _EMMversion;
-
- _EMMversion contains the EMS version implemented by the EMS driver in
- packed BCD format. For example, if the EMS version is 4.0, the value of
- _EMMversion will be 0x40. If _EMMversion is 0x32, the EMS version is
- 3.2. This value is the same as that returned by EMMgetversion().
-
- emslib_vers_vers, emslib_vers_date, emslib_vers_time
- ----------------------------------------------------
-
- char const emslib_vers_vers[];
- char const emslib_vers_date[];
- char const emslib_vers_time[];
-
- These are null-terminated strings containing information about the
- name and version of the library, the date of assembly, and the time of
- assembly, respectively.
-
- IV.2 FUNCTIONS
- --------------
-
- _EMMdisc() - disable frame caching
- ----------
-
- void _EMMdisc(void);
- void _EMMenc(void);
- void _EMMinval(void);
-
- _EMMdisc() disables frame caching, invalidates the current cache
- contents, and sets _EMMframecache to zero. _EMMerror should be checked
- after calling this function. It is not an error to call this function
- when frame caching is already disabled.
-
- _EMMenc() enables frame caching, invalidates the current cache
- contents, and sets _EMMframecache to a nonzero value. _EMMerror should
- be checked after calling this function. It is not an error to call this
- function when frame caching is already enabled; however, the current
- cache contents will still be invalidated.
-
- _EMMinval() is a macro that invalidates the current cache contents if
- frame caching is enabled, or has no effect if frame caching is disabled.
- The frame caching status is not changed. _EMMerror should be checked
- afterwards.
-
- For more information on frame caching, see section III.3.
-
- _EMMenc() - enable frame caching
- ---------
-
- void _EMMenc(void);
-
- See _EMMdisc();
-
- _EMMicopyfrom() - copy data by intervals from EMS
- ---------------
-
- int _EMMicopyfrom(unsigned long nelem, int elsize,
- unsigned int srcskip, int handle, unsigned long foffset,
- unsigned char far *dest, unsigned int destskip);
- int _EMMicopyto(unsigned long nelem, int elsize,
- unsigned int srcskip, unsigned char far *source,
- int handle, unsigned long foffset, unsigned int destskip);
-
- _EMMicopyfrom() allows painless copying of array elements from
- expanded memory to conventional memory. EMS mapping, calculation of
- addresses, skipping of unwanted elements, etc., are all handled by the
- function. Elements spread across more than 64K, or totalling more than
- 64K in length, can be copied without special treatment.
- Nelem elements are copied, each of which is elsize bytes long. The
- elements are copied from the EMS pages owned by handle, starting at byte
- offset foffset and with srcskip bytes between elements, to conventional
- memory starting at dest with destskip bytes between elements. Dest must
- be a far pointer; a near pointer can be converted to a far pointer with
- a cast when the function is called. Byte offsets in EMS are as for
- EMMcopyfrom().
- If nelem or elsize is zero, the function returns immediately without
- error. Elsize must be in the range 0 through 16384, or the function will
- return error EMM_ELTOOBIG. Byteskip must be in the range 0 through 32768,
- or the function will return EMM_SKTOOBIG.
- This function returns 0 on success or EMMOOPS on error. The specific
- error may be determined from _EMMerror.
-
- _EMMicopyto() allows painless copying of array elements from
- conventional memory to expanded memory. EMS mapping, calculation of
- addresses, skipping of unwanted elements, etc., is handled by the
- function. Elements spread across more than 64K, or totalling more than
- 64K in length, can be copied without special treatment.
- Nelem elements are copied, each of which is elsize bytes long. The
- elements are copied from conventional memory starting at source with
- srcskip bytes between elements, to the EMS pages owned by handle, starting
- at byte offset foffset and with destskip bytes between elements. Source
- must be a far pointer; a near pointer can be converted to a far pointer
- with a cast when the function is called. Byte offsets in EMS are as for
- EMMcopyto().
- If nelem or elsize is zero, the function returns immediately without
- error. Elsize must be in the range 0 through 16384, or the function will
- return error EMM_ELTOOBIG. Byteskip must be in the range 0 through
- 32768, or the function will return EMM_SKTOOBIG.
- This function returns 0 on success or EMMOOPS on error. The specific
- error may be determined from _EMMerror.
-
- _EMMicopyto() - copy data by intervals to EMS
- -------------
-
- int _EMMicopyto(unsigned long nelem, int elsize,
- unsigned int srcskip, unsigned char far *source,
- int handle, unsigned long foffset, unsigned int destskip);
-
-
- See _EMMicopyfrom().
-
- _EMMinval() - invalidate frame cache contents
- -----------
-
- void _EMMinval(void);
-
- See _EMMdisc().
-
- EMMalloc() - allocate EMS
- ----------
-
- int EMMalloc(unsigned long bytes);
- int EMMallocpages(int pages);
-
- EMMalloc() allocates EMS memory. It takes the given number of bytes
- and allocates the smallest number of pages which contain that many
- bytes. It returns the EMS handle assigned by the EMS driver. _EMMerror
- should be checked after calling this function.
- Note that EMS cannot be allocated in units smaller than a page (16384
- bytes). Requesting one byte will allocate a whole page; 16385 bytes will
- allocate two pages. Requesting zero bytes allocates one page.
-
- EMMallocpages() allocates EMS memory by pages directly. It returns
- the EMS handle assigned by the EMS driver. _EMMerror should be checked
- after calling this function. It is possible to allocate 0 pages with
- this function, but only under EMS version 4.0; under earlier versions,
- allocating 0 pages is an error.
-
- EMMallocpages() - allocate EMS by pages
- ---------------
-
- int EMMallocpages(int pages);
-
- See EMMalloc().
-
- EMMcopyfrom() - copy data from EMS
- -------------
-
- int EMMcopyfrom(unsigned long copylen,
- int handle, unsigned long foffset,
- unsigned char far *dest);
- int EMMcopyto(unsigned long copylen,
- unsigned char far *source,
- int handle, unsigned long foffset);
-
- EMMcopyfrom() allows painless copying of blocks of data from expanded
- memory to conventional memory. All mapping, calculation of addresses,
- etc., is handled by the function. Copies longer than 64K are possible
- without special treatment.
- Copylen bytes of data are copied, from the EMS pages owned by handle,
- starting at byte offset foffset, to the conventional memory area pointed
- to by dest. Dest must be a far pointer; a near pointer can be converted
- to a far pointer with a cast when the function is called. To convert an
- expanded memory offset (such as foffset) to a page and offset within
- that page, divide the offset by the size of a page (16384 bytes). The
- quotient is the page number and the remainder is the offset within that
- page. Offsets 0 through 16383 are in page 0; offsets 16384 through 32767
- are in page 1, etc. This feature allows you to treat expanded memory
- blocks as linear memory rather than a collection of pages.
- This function returns 0 on success or EMMOOPS on error. The specific
- error may be determined from _EMMerror. If copylen is 0, the function
- returns immediately without error.
-
- EMMcopyto() is the mirror image of EMMcopyfrom(). It allows painless
- copying of blocks of data from conventional memory to expanded memory.
- All mapping, calculation of addresses, etc., is handled by the function.
- Copies longer than 64K are possible without special treatment.
- Copylen bytes of data are copied, from the conventional memory area
- pointed to by source, to the EMS pages owned by handle, starting at
- byte offset foffset. Expanded memory offsets are as in EMMcopyfrom().
- This function returns 0 on success or EMMOOPS on error. The specific
- error may be determined from _EMMerror. If copylen is 0, the function
- returns immediately without error.
-
- See also EMMicopyto() and EMMicopyfrom().
-
- EMMcopyto() - copy data to EMS
- -----------
-
- int EMMcopyto(unsigned long copylen,
- unsigned char far *source,
- int handle, unsigned long foffset);
-
- See EMMcopyfrom().
-
- EMMcoreleft() - get amount of free EMS
- -------------
-
- unsigned long EMMcoreleft(void);
-
- This function returns the amount of EMS memory available, in bytes.
- To determine the number of EMS pages available, divide the returned
- value by 16384. _EMMerror should be checked after calling this function.
-
- EMMfree() - deallocate EMS
- ---------
-
- int EMMfree(int handle);
-
- This function accepts an EMS handle (as returned by EMMalloc() or
- EMMallocpages(), or otherwise obtained from the EMS driver) and releases
- it and any EMS pages allocated to it. This function returns 0 on success
- or EMMOOPS on error. The specific error may be determined from
- _EMMerror.
-
- EMMgetframeaddr() - get EMS page frame segment addresses
- -----------------
-
- int EMMgetframeaddr(frameinfo *buffer);
- int EMMgetnumframe(void);
- unsigned int EMMgetsinfraddr(int frame);
-
- EMMgetframeaddr() returns the segment addresses of all the EMS page
- frames. Buffer is a pointer to an array of frameinfo structures; this
- array is assumed to be large enough to contain information about all the
- frames. The number of frameinfo structures needed can be determined with
- the EMMgetnumframe() function described below.
- Each frameinfo structure contains the number and the segment address
- of a frame. Check EMSLIB.H or EMSLIB.HPP for the exact format of the
- frameinfo structure. The information is returned in whatever order the
- EMS driver provides it, which is typically sorted by address rather than
- frame number. Do NOT just assume that the first element in the array
- contains information for frame 0! The segment addresses returned must be
- converted to far pointers (using MK_FP() or your compiler's equivalent)
- before they can be used to access memory.
- This function returns 0 on success or EMMOOPS on error. The specific
- error may be determined from _EMMerror.
-
- EMMgetnumframe() returns the number of EMS page frames present in the
- system. For EMS versions below 4.0, this will always be 4. For EMS
- version 4.0, it will be at least 4. _EMMerror should be checked after
- calling this function.
-
- EMMgetsinfraddr() returns the segment address of a particular EMS
- page frame. This address must be converted to a far pointer (using
- MK_FP() or your compiler's eqivalent) before it can be used to access
- memory. _EMMerror should be checked after calling this function.
-
- EMMgetname() - obtain string name associated with an EMS handle
- ------------
-
- int EMMgetname(int handle, char *name);
- int EMMsetname(int handle, char *name);
-
- EMMgetname() returns (as a null-terminated string) the name, if any,
- assigned to an EMS handle. Real names are only implemented in EMS
- version 4.0. Under earlier versions, this function fills the name buffer
- with nulls ('\0'), which is also the return under version 4.0 when no
- name has been associated with the given handle. The buffer pointed to by
- name must be at least nine characters long (since an EMS name may be up
- to eight characters long and there must be room for the terminating
- null). This function returns 0 on success or EMMOOPS on error. The
- specific error may be determined from _EMMerror.
-
- EMMsetname() allows the association of a name up to eight characters
- long with an EMS handle. It only works for EMS version 4.0; under
- earlier versions, it returns the error EMM_BADVERS. Version independency
- has been abandoned in this case because the main purpose of associating
- a name with an EMS handle is to allow several different programs to
- recognize shared data. While EMSLIB could implement a naming function
- within itself, the names would not be visible outside the program
- assigning the name, defeating the purpose of doing it in the first
- place.
- This function returns 0 on success or EMMOOPS on error. The specific
- error may be determined from _EMMerror.
-
- EMMgetnumframe() - obtain number of EMS page frames
- ----------------
-
- int EMMgetnumframe(void);
-
- See EMMgetframeaddr().
-
- EMMgetsinfraddr() - get segment address of one EMS page frame
- -----------------
-
- unsigned int EMMgetsinfraddr(int frame);
-
- See EMMgetframeaddr().
-
- EMMgetversion() - obtain EMS version implemented by EMS driver
- ---------------
-
- int EMMgetversion(void);
-
- This function returns the EMS version implemented by the EMS driver.
- The version number is in packed BCD format as in the global variable
- _EMMversion, and is in fact the same value. _EMMerror should be checked
- after calling this function.
-
- EMMicopyfrom() - copy data by intervals from EMS
- --------------
-
- int EMMicopyfrom(unsigned long nelem, int elsize, unsigned int byteskip,
- int handle, unsigned long foffset,
- unsigned char far *dest);
- int EMMicopyto(unsigned long nelem, int elsize, unsigned int byteskip,
- unsigned char far *source,
- int handle, unsigned long foffset);
-
- EMMicopyfrom() is a macro which calls _EMMicopyfrom(). It allows
- painless copying of array elements from expanded memory to conventional
- memory. EMS mapping, calculation of addresses, skipping of unwanted
- elements, etc., are all handled by the function. Elements spread across
- more than 64K, or totalling more than 64K in length, can be copied without
- special treatment.
- Nelem elements are copied, each of which is elsize bytes long, with
- byteskip bytes between elements at both source and destination. The
- elements are copied from the EMS pages owned by handle, starting at byte
- offset foffset, to conventional memory starting at dest. Dest must be a
- far pointer; a near pointer can be converted to a far pointer with a cast
- when the function is called. Byte offsets in EMS are as for EMMcopyfrom().
- If nelem or elsize is zero, the function returns immediately without
- error. Elsize must be in the range 0 through 16384, or the function will
- return error EMM_ELTOOBIG. Byteskip must be in the range 0 through
- 32768, or the function will return EMM_SKTOOBIG.
- This function returns 0 on success or EMMOOPS on error. The specific
- error may be determined from _EMMerror.
-
- EMMicopyto() is a macro which calls _EMMicopyto(). It allows painless
- copying of array elements from conventional memory to expanded memory. EMS
- mapping, calculation of addresses, skipping of unwanted elements, etc., is
- handled by the function. Elements spread across more than 64K, or totalling
- more than 64K in length, can be copied without special treatment.
- Nelem elements are copied, each of which is elsize bytes long, with
- byteskip bytes between elements at both source and destination. The elements
- are copied from conventional memory starting at source, to the EMS pages
- owned by handle, starting at byte offset foffset. Source must be a far
- pointer; a near pointer can be converted to a far pointer with a cast when
- the function is called. Byte offsets in EMS are as for EMMcopyto().
- If nelem or elsize is zero, the function returns immediately without
- error. Elsize must be in the range 0 through 16384, or the function will
- return error EMM_ELTOOBIG. Byteskip must be in the range 0 through
- 32768, or the function will return EMM_SKTOOBIG.
- This function returns 0 on success or EMMOOPS on error. The specific
- error may be determined from _EMMerror.
-
- EMMicopyto() - copy data by intervals to EMS
- ------------
-
- int EMMicopyto(unsigned long nelem, int elsize, unsigned int byteskip,
- unsigned char far *source,
- int handle, unsigned long foffset);
-
-
- See EMMicopyfrom().
-
- EMMlibinit() - initialize EMSLIB
- ------------
-
- int EMMlibinit(void);
-
- EMMlibinit() initializes EMSLIB. Any other EMSLIB function will
- return the error EMM_NOINIT if called before EMMlibinit() has been
- called. This function returns 0 on success, EMMOOPS on error, or NOEMM
- if no EMS driver is detected. The specific error may be determined from
- _EMMerror. Note that EMSLIB will not initialize if the EMS driver claims
- that fewer than four EMS page frames exist, since that is a violation of
- the EMS specification and the driver may have other anomalies that
- EMSLIB does not know how to handle.
- Detection of the EMS driver relies on DOS services, so this library
- cannot be used in a device driver as it stands. If you need this library
- for a device driver or other program that cannot access DOS services,
- you can buy the source (it's cheap) and easily modify EMMlibinit() to
- use another method of detection. There are no other calls to DOS
- services in EMSLIB. The method used was chosen for its reliability;
- there is another method, suitable for use in device drivers, which is
- not as reliable and typically is useful _only_ for device drivers.
-
- EMMmappage() - map an EMS logical page into an EMS page frame
- ------------
-
- int EMMmappage(int frameno, int handle, int logpage);
-
- This function maps a logical page into an EMS page frame so that it
- can be accessed. The logical page logpage belonging to handle is mapped
- into page frame number frameno. This function returns 0 on success or
- EMMOOPS on error. The specific error may be determined from _EMMerror.
-
- EMMrestore() - restore an EMS mapping from a save buffer
- ------------
-
- int EMMrestore(void *saveblock);
- void *EMMsave(void);
- int EMMsrinit(void *(*mallocfunc)(size_t));
-
- EMMrestore() restores an EMS mapping that has earlier been saved in a
- save buffer with a call to EMMsave(). The contents of the frame cache
- are invalidated, since the format of the contents of the save buffer
- varies from one EMS driver to the next and it is thus not possible to
- determine what will be mapped into the cached frame when the restore is
- done. EMMrestore() does not deallocate the save buffer.
- This function returns 0 on success or EMMOOPS on error. The specific
- error may be determined from _EMMerror. It is an error if this function
- is called before EMMsrinit() has been called.
-
- EMMsave() allocates a save buffer (see EMMsrinit(), below) and saves
- the current EMS mapping into it. The current EMS mapping is not changed,
- nor are the contents of the frame cache invalidated. This function
- returns the pointer returned by the allocation function (see below).
- _EMMerror should be checked after calling this function. It is an
- error if this function is called before EMMsrinit() has been called.
-
- EMMsrinit() initializes the save/restore capability of EMSLIB. It
- takes a pointer to a memory-allocation function which is used by
- EMMsave() to allocate save buffers. Malloc() is compatible in all memory
- models, but any function which works the same way (returns a void
- pointer of the size normal for the memory model (near or far), takes a
- single parameter of type size_t which is the number of bytes to
- allocate, and returns NULL (0) if the memory cannot be allocated) can
- also be used. Note that the function will never have to allocate more
- than 255 bytes in one call
- EMMsrinit() will fail to initialize and return EMM_BADVERS if the EMS
- version is 3.0. Since it did not initialize, EMMsave() and EMMrestore()
- will not work either.
- _EMMerror should be checked after calling this function.
-
- For more information on frame caching and suggestions on using
- save/restore, see sections III.3 and III.4 respectively.
-
- EMMsave() - save an EMS mapping into a save buffer
- ---------
-
- void *EMMsave(void);
-
- See EMMrestore().
-
- EMMsetname() - associate string name with an EMS handle
- ------------
-
- int EMMsetname(int handle, char *name);
-
- See EMMgetname().
-
- EMMsrinit() - initialize save/restore
- -----------
-
- int EMMsrinit(void *(*mallocfunc)(size_t));
-
- See EMMrestore().
-
-
- V. ERROR CODES
- --------------
-
- This section is a list of the error codes to which the global variable
- _EMMerror may be set, and the values and meanings thereof.
-
- V.1 INTERNAL ERRORS
- -------------------
-
- Internal codes indicate an error detected by EMSLIB itself.
-
- NAME VALUE MEANING
- ---- ----- -------
- EMM_BADVERS 0x40 Bad EMS version, earlier than 3.0.
-
- EMM_BADOFFSET 0x41 Offset plus copy length runs off last
- EMS page owned by handle.
-
- EMM_NOFRAME 0x42 Could not find segment address of frame
- used for copying functions.
-
- EMM_NOINIT 0x43 EMMlibinit() has not been called yet.
-
- EMM_FEWFRAMES 0x44 The EMS driver claims that there are fewer
- than four page frames.
-
- EMM_NOSR 0x45 EMMsrinit() must be called before
- EMMsave() or EMMrestore() can be called.
-
- EMM_MEMNULL 0x46 The save/restore memory allocation
- function (the one passed to EMMsrinit())
- returned NULL.
-
- EMM_ELTOOBIG 0x47 The element size passed to EMMicopyto()
- or EMMicopyfrom() is too big.
-
- EMM_SKTOOBIG 0x48 The skip size passed to EMMicopyto()
- or EMMicopyfrom() is too big.
-
- V.2 EMS DRIVER ERRORS
- ---------------------
-
- These codes are defined in the EMS specification and are returned by
- the EMS driver. They are saved in _EMMerror by EMSLIB without alteration.
-
- NAME VALUE MEANING
- ---- ----- -------
- EMM_SOFTERROR 0x80 Internal error exists in EMS driver (can
- indicate corrupted memory image of driver)
-
- EMM_HARDERROR 0x81 Malfunction in expanded memory hardware
-
- EMM_BUSY 0x82 EMS driver is busy
-
- EMM_BADHANDLE 0x83 Invalid EMS handle
-
- EMM_UNIMP 0x84 Function not defined
-
- EMM_NOFREEHAN 0x85 No free EMS handles
-
- EMM_CONTEXTERR 0x86 Error in save or restore of mapping context
-
- EMM_WAYTOOBIG 0x87 Tried to allocate more pages than physically
- exist in system; no pages allocated
-
- EMM_TOOBIG 0x88 Tried to allocate more pages than currently
- available; no pages allocated
-
- EMM_TOOSMALL 0x89 Cannot allocate 0 pages
-
- EMM_BADLOGPAGE 0x8A Requested logical page is outside range of
- pages owned by handle
-
- EMM_BADFRAMENO 0x8B Illegal frame number in mapping request
-
- EMM_HSTATESAVFULL 0x8C Page-mapping hardware-state save area full
-
- EMM_MSTATESAVFULL 0x8D Mapping-context save failed; save area
- already contains context associated with
- specified handle
-
- EMM_MSTATERESTERR 0x8E Mapping-context restore failed; save area
- does not contain context for specified
- handle
-
- EMM_UNIMPSUB 0x8F Subfunction parameter not defined
-
- EMM_BADATTRIB 0x90 Attribute type not defined
-
- EMM_NOFEATURE 0x91 Feature not supported
-
- EMM_SRCOVERWRITE 0x92 Source and destination memory regions have
- same handle and overlap; requested move
- was performed, but part of the source region
- was overwritten
-
- EMM_BADLENGTH 0x93 Copy length longer than actual length
-
- EMM_CONEMSOVERLAP 0x94 Conventional memory region and expanded
- memory region overlap
-
- EMM_OFFPAGE 0x95 Specified offset outside logical page
-
- EMM_TOOLONG 0x96 Copy length exceeds one megabyte
-
- EMM_EMSEMSOVERLAP 0x97 Source and destination memory regions have
- same handle and overlap; exchange cannot be
- performed
-
- EMM_LOST 0x98 Memory source and destination types
- undefined
-
- EMM_UNUSED 0x99 This error code is currently unused
-
- EMM_BADALTREG 0x9A Alternate map or DMA register sets are
- supported, but specified alternate register
- set is not supported
-
- EMM_NOFREEALTREG 0x9B Alternate map or DMA register sets are
- supported, but all alternate register sets
- are currently allocated
-
- EMM_NOALTREG 0x9C Alternate map or DMA register sets are not
- supported, specified alternate register
- set is not 0
-
- EMM_BADALTREG2 0x9D Alternate map or DMA register sets are
- supported, but the alternate register set
- specified is not defined or not allocated
-
- EMM_NODEDDMA 0x9E Dedicated DMA channels are not supported
-
- EMM_BADDEDDMA 0x9F Dedicated DMA channels are supported, but
- specified DMA channel is not supported
-
- EMM_UNKNAME 0xA0 Handle for specified name not found
-
- EMM_NAMETAKEN 0xA1 Handle with same name already exists
-
- EMM_ADDRWRAP 0xA2 Memory address wraps; sum of source or
- destination region base address and length
- exceeds one megabyte
-
- EMM_BADPTR 0xA3 Invalid pointer passed to function, or
- contents of source array corrupted
-
- EMM_FORBIDDENFUNC 0xA4 Access to function denied by operating
- system
-
- VI. THE END
- -----------
-
- Technical support via email is available from the following addresses:
-
- INTERNET:
- First choice (the following are alternate addresses for the same place):
- support@picarefy.com [coming soon -- try it, anyway]
- picarefy!support@amc.com
- picarefy!support@netcom.com
- picarefy!support@halcyon.com
- amc-gw!picarefy!support@coco.ms.washington.edu
- halcyon!picarefy!support@sumax.seattleu.edu
- uunet!uw-coco!amc-gw!picarefy!support
-
- Second choice:
- jwbirdsa@amc.com
-
- COMPUSERVE:
- 71261,1731
-
- AMERICA ON-LINE:
- GreenTiger
-
- GENIE:
- J.BIRDSALL2
-
- Registrations should be sent to:
-
- James W. Birdsall
- 11112 NE 124 LN #D204
- Kirkland, WA 98034
-
- If you have an email address on any of the networks listed above,
- please include it when registering, especially if you are requesting
- source code. It is much easier to send the source code by email. Also,
- please specify what sort of archive (ZIP, ZOO, ARC, LZH, ARJ, UNIX shar)
- you can handle most easily.
-
- VI.1 ACKNOWLEDGEMENTS
- ---------------------
-
- Thanks to Bob Parsons of Parsons Technology Inc. for some good suggestions
- on the documentation and for providing the original C++ header file.
-
-