Newsgroups: comp.os.msdos.programmer
Subject: How to access memory above 640K
Followup-To: comp.os.msdos.programmer
Distribution: world
References: none

Last-modified: 18 Apr 1993

Part of the following material originally appeared in the FAQ list for
comp.os.msdos.programmer.  However, subsequent email revealed that the
answer is not really settled.  Since the FAQ list should contain
"canonical best answers", I have created this separate article.  One of
my rainy-day projects is to investigate this area myself.  Until then,
I'm simply appending the emails and posted articles that seem relevant.

If you want your comments to be appended to this file, please be sure to
email me at brown@ncoast.org.  I try to follow the newsgroup, but I may
miss posted articles because c.o.m.p gets heavy traffic.

The following appeared in the December 1992 FAQ list.  It is by Jamshid
Afshar (jamshid@emx.utexas.edu) and incorporates comments from Duncan
Murdoch (dmurdoch@mast.queensu.ca).

    1. Use XMS or EMS memory.  XMS is preferable in most cases, but
    some machines won't provide it.  There are some libraries available
    at Simtel to access XMS or EMS.  The disadvantage is that you
    don't allocate the memory as you would with malloc() (or `new' in
    C++).  I believe it also requires that you lock this memory when in
    use.  This means your code is not easily ported to other (and
    future) operating systems and that your code is more convoluted than
    it would be under a "real" os.  The advantage is that the library
    works with compilers since Turbo C 2.0 (I think) and that your
    program will easily run on even 286s.

    2.  Program under MS Windows.  MS Windows functions as a 16-bit DOS
    Extender (see #3).  Borland/Turbo C++ 3.x includes EasyWin [and
    Microsoft C/C++ 7.0 has QuickWin --ed.] which is a library that
    automatically lets you compile your current code using C/C++
    standard input or <conio.h> into a MS Windows program so your code
    can immediately allocate many MBs of memory (Windows enhanced mode
    even does virtual memory).  The disadvantage is that like any 16-bit
    Extender a single malloc() is restricted to 64K (unless you want to
    mess with huge pointers in Windows).  Also, EasyWin's screen output
    is significantly slower than a DOS character-mode program's and you
    must of course run the program from Windows.

    3.  Use a 16-bit or 32-bit DOS Extender.  This is definitely the
    best solution from the programmer's standpoint.  You just allocate
    as much memory as you need using malloc() or 'new'.  A 16-bit
    Extender still has 16-bit ints and restricts arrays to 64K, but a
    32-bit Extender has 32-bits ints (which makes porting a lot of UNIX
    code easier) so there are no 64K limits.  A 32-bit Extender requires
    a 32-bit compiler and the program will not run on 286s.  Some
    Extenders also do virtual memory.  Using an Extender doesn't require
    source code changes and unlike option #1 your code is portable and
    not obsolete in a few months.  Your options for this solution are:

    - Buy PharLap's 16-bit Extender that works with BC++ 3.0+ and MSC
      (just requires a relink).  Note, the BC++ 3.1 upgrade came with
      PharLap "lite".  Pharlap's 32-bit Extender works with 32-bit
      compilers like [?]

    - Get the GNU (free,copylefted) gcc 2.x compiler which DJ Delorie
      ported from UNIX and which uses his 32-bit Extender.  It supports
      C and C++, but the Extender is VCPI which means neither the
      compiler nor programs it produces will run in a DOS session under
      Windows.  FTP to barnacle.erc.clarkson.edu and get
      pub/msdos/djgpp/readme.  [See update in message of 9 April.--ed.]

    - Get a 32-bit compiler or one that comes with a DOS Extender.
      Zortech comes with 16-bit and a 32-bit Extenders (no debugger for
      32-bit programs, but Flashtek sells one).  Watcom also makes a C
      [and C++?] 32-bit compiler.  [If anyone else has products or plans
      to announce, please let me know.]

    - Buy Borland Pascal 7.0.  It includes a 16 bit royalty-free DOS
      extender using the same interface as MS Windows.  It functions
      under a DPMI server like Windows or QDPMI from Quarterdeck, and
      also provides its own server which you can distribute with your
      programs.

    4.  This option doesn't really count since it's not a solution in
    DOS, but you could switch to a full 32-bit operating system like
    OS/2 2.0 or UNIX (or NT when it comes out).  I believe Win32 will
    allow you to write 32-bit Windows programs.  [can someone fill me in
    on what exactly Win32 is?]


Date: Mon, 21 Dec 92 08:36:50 -0500
From: malak@grebyn.com (Michael Malak)
Message-Id: <9212211336.AA02279@daily.grebyn.com>

    You should also mention the Intel 386/386 C Code Builder Kit.  It is
    a 32-bit C compiler, linker, and 32-bit DOS extender.  It is the
    _only_ 32-bit DOS extender that allows you to link in 32-bit MASM
    6.0 modules, thus obviating the need to buy Phar Lap's assembler and
    be stuck with its archaic MASM 4.x syntax.  All for a list price of
    $595.


Date: Thu, 24 Dec 92 13:45:40 EST
From: dmurdoch@mast.QueensU.CA (Duncan Murdoch)
Message-Id: <9212241845.AA23280@mast.mast.QueensU.CA>

    I don't know anything about the Intel package, but certainly
    wouldn't object to putting the information in.  I'd delete the claim
    that it's the only package to link MASM code; that may be true, but
    isn't likely to last for long.


Date: Wed, 27 Jan 1993 23:25:12 GMT
From: gah@trc.mew.mei.co.jp (Gary A. Hildebrand)
Subject: Re: Accessing mem above 1 meg???
Message-ID: <GAH.93Jan28082512@trcrik.trc.mew.mei.co.jp>

>>>>> ">" == Ernest Ong <ernie@tartarus.uwa.edu.au> writes:
>> Does anyone know how to access memory above 1 meg on a 386 machine???
>> without switching to protected mode
>> ie in real mode & using linear addressing (bypassing MMU).

Although you can use 386-style 32-bit effective addresses in real mode (by
specifying the appropriate instruction prefix of 0x67), they are still
limited to a maximum value of (64KB - 1).  This is because the segment
limit cached into each and every segment register is (64KB - 1) when in
real mode.  It would be impossible to change these limits without switching
to protected mode and reloading the segment register, and would have
unpredictable results back in real mode.  If you do exceed a segment limit
in real mode, it will generate an exception, which will hang most machines
because the real-mode BIOS usually cannot distinguish an exception specific
to a 286 or higher processor from a hardware/software interrupt, and
doesn't know how to recover.  So basically, you *can't* do the above!

But there is a tricky way to get a little less than 64KB of additional
memory in real mode, which is the basis for the HMA (High Memory Area)
specification.  It is possible, even with 16-bit offset and segment values
in real mode, to create an address greater than 1MB.  Consider the far
address 0xFFFF:0xFFFF.  The corresponding linear address would be 0x10FFEF,
clearly above 1MB.  The 386, like the 286, will not wrap this address
around to 0xFFEF the way the 8086/88/186 does, given the larger address
bus.  And this address doesn't violate segment limits set for real mode.

There are a few gotchas with using the HMA.  For one, most PC-compatible
systems by default deliberately disable address lines A20 (and above?) to
protect 8086 software (sometimes including the BIOS itself) which *expect*
wraparound to occur past 1MB.  Before using the HMA, you must enable A20,
and the method varies from system to system.  True AT-compatibles, PS/2's,
HP Vectras, and AT&T 6300's all use different methods, some of them truly
bizarre, in order to really protect this line from casually being changed.
On an AT-compatible, the A20 gate is enabled using the 8042 keyboard
controller, of all things!

Another has to do with normalization of far pointers.  To normalize means
to set up the segment and offset so that there are no overlapping set bits
between them, and is handy for "uniqueifying" an address.  The problem with
this is that it breaks the HMA, since you can't go above 1MB with a
normalized address!  So be wary of DOS functions which might want to
normalize your pointer first.

Good luck!


From: usenet.INS.CWRU.Edu!logicraft.com!lacroix (Scott LaCroix)
Message-Id: <9302091954.AA04224@logicraft.com>

    The Zortech compiler I have (I'm not sure of the version, it's at
    home) does C and C++, comes with a 16 and 32 bit extander, and a 32
    bit debugger.  (Although, I can't vouch for the debugger, my install
    disk was a little flaky and as a result the debugger doen't work
    quite right...)  Also, I beleive the Watcom compiler DOES do C++.

    As a side note, both the Watcom and the Zortech compilers have
    Windows libraries available and their debuggers will run under
    Windows.

    My money (by FAR) is on the Watcom set.  It costs more, but the
    functionality is phenomenal!  I wrote a 32 bit, TCPIP, Windows 3.1
    app with the 16-32 bit conversion tools provided standard with it,
    and I don't think I could do the same with Zortech.  (Just as a
    note, I used FTP Software's TCPIP package...)


From: usenet.INS.CWRU.Edu!pharlap.com!jim (James E. Phillips)
Date: Mon, 15 Mar 93 13:43:03 EST
Message-Id: <9303151843.AA04998@pharlap.pharlap.com>

    [ed. note:  Phillips works for Phar Lap, which is the "our" in the
    text below]

    Just trying to correct a couple of things that were either incorrect
    or misleading (I got misled) in the recent posting to the newsgroup.
    Feel free to spread the word along, along with my e-mail address.

    Most 16-bit extenders, the Phar Lap 286|DOS-Extender among them,
    allow you to allocate arrays larger than 64K by using the "huge"
    keyword, and special malloc() functions like halloc() (MSC) or
    farmalloc() (Borland).  This is the same thing that people do under
    MS-DOS to create arrays larger than 64K.

    Our 286|DOS-Extender "officially" works with Borland 2.0, 3.0 and
    3.1, Microsoft C 5.1, 6.0, 6.0a and 7.0, and Microsoft Fortran 5.0
    and 5.1.

    Some applications may require source code changes, but the
    modifications are in many cases relatively minor.

    The 386|DOS-Extender works with a number of 32-bit compilers like
    Metaware High C/C++, Watcom C/386 and Microsoft's NT compiler.

    Our 386|DOS-Extender will accept 32-bit modules from MASM 6.0, and
    has for the last three versions.  Our own 386|ASM is still MASM 4.x
    compatible, however.

    I should also point out that our extenders will run fine under
    MS-DOS, Windows or OS/2 2.0 (and we have our fingers crossed for Win
    NT...).


Date: Fri, 9 Apr 93 10:04:55 EDT
From: DJ Delorie <usenet.INS.CWRU.Edu!ctron.com!dj>
Message-Id: <9304091404.AA26988@delorie.ctron>

    Please change the reference for djgpp from barnacle.erc.clarkson.edu
    to omnigate.clarkson.edu (it moved).


Date: Sun, 19 Apr
From: Stan Brown <brown@ncoast.org>

You may want to browse through the Simtel directories.  Files such as
the following look promising, though I haven't explored them myself:

pd1:<msdos.turbo-c>xmsif142.zip  XMS interface for Borland/MS C[++]
