This file contains a useful method to access real mode memory space using
Borland's PowerPack (DPMI32) 32-bit extender without undue hardship <g>.

First: this (unfortunately) isn't my grand idea; my thanks to Dave Mandala
for posting this elegant approach in the BCPPDOS forum, DPMI section.

How it works: the intel 32-bit processors (80386, 80486, Pentium, and
(supposedly) the P6) use a segmented architecture when running DPMI32. The
application uses a "small" memory model, and one standard code selector,
and one standard data selector. That is, all of your code is accessed with
a single code selector, using a 32-bit offset. And the same for data - 
you've got a standard data selector, and 32-bit offsets to each item.

Unfortunately, DPMI32 doesn't start the data selector at 00000000h linear
address - it starts it up above the 1MB mark. So under normal circumstances
you cannot use near pointers (ie the default ds selector) to access real
mode memory.

What Dave Mandala pointed out, and I've implemented here, is that you can
use offset wrap-around (or 32-bit truncation) to let near pointers access
real mode address space.

As I mentioned, the base linear address for the ds selector is up around the
1MB mark - lets call it BLA. That is, if you call DPMI function 0006h with
BX set to the DS selector, it will return the 32-bit value BLA. In C code,
its kinda like:

  unsigned int BLA = <base linear address for the DS selector>;

Note that in DPMI32, unsigned int is a 32-bit value.

The limit (max allowed reference into a selector before the CPU will cause
an exception 0D - ie a General Protection Fault) for the DS selector is
basically set to <Max memory accessible = 0xFFFFFFFFUL> - BLA; that is,
using the ds selector, you can address memory location [0] (BLA), memory
address [1] (BLA+1), ... [xxxx] (Max Mem - BLA).

Another way to view this limit is: let LIM = the limit for the DS register;
then BLA + LIM = 0xFFFFFFFFUL. Again, in C:

  unsigned int LIM = MAX_UINT - BLA;

Now consider what would happen if we increased LIM to LIM+1. What will 
happen when we try to access memory [LIM+1] with the DS selector?

Under the current crop of intel 32-bit processors, this is valid; the only
requirement for an offset is that it be within the limit for the selector.
And what the processor does to calculate the true linear memory address to
access is: adds the address (LIM+1) to the base (BLA). But this works out
to:

  memAddr = BLA + (LIM+1)
          = BLA + ((MAX_UINT-BLA)+1)
          = BLA+MAX_UINT-BLA+1
          = MAX_UINT+1

Inside the processor, it is just adding into a 32-bit register (and is ignoring
any overflow); so MAX_UINT+1 = 0! That is, we've just set it up so that we can
access the 1st byte of real mode address space!

So if we extend the limit for the ds selector to its maximum 
(0xFFFFFFFFUL = MAX_UINT) we can use offsets big enough that the CPU will wrap
them (ie truncate to 32-bits when we add it to the BLA) into the real mode
address space.

The next question is: so what new offset do we want to use for a given real mode
linear address (such as 0xB8000, which is the real mode address B800:0000 - the
start of the color text video memory)? If we think of all the offsets as just
being unsigned ints, the answer is obvious from the work above:

  Let unsigned int rmAddr = the real mode linear memory we want to access.
  BLA = base linear address for the DS selector.
  memAddr = the offset we have to use to access rmAddr.
  
As I explained, the CPU comes up with a linear memory address by adding the BLA
to the memAddr to get the rmAddr (and will truncate to 32-bits if necessary):

  rmAddr = BLA + memAddr, or:
  memAddr = rmAddr - BLA

Note that rmAddr is lower than BLA (BLA is up around 1MB, but rmAddr is down in real
mode address space, like B8000); so if we were using signed values, we'd end up with
a negative result. But that's what we want - a large (unsigned) value that will wrap
around (truncate) when we add BLA to it.

I've included a source file (FAST32.C), and an associated header (FAST32.H) to
automate this. Also included is a demo file TEST.C which shows how to use these
functions - it writes to the color video memory directly using the ds selector.

These files are provided as-is to the public domain. I'm not responsible for how
you use, or mis-use <g>, them and I don't offer support for their use. However,
I'm a TeamB member in the BCPPDOS forum, so if you post questions in the DPMI
section there, I'll see what I can do to answer them.

  -Pat-
