Due to popular demand, a few hints how to manage 32 bit pmode with Delphi 2 and DOS. 1. How is the adress space organized? Hmm... where to start? Well, the new thing on a 386+ CPU is a thing called "paging". To understand paging you need to understand that there is a difference between LINEAR and PHYSICAL addresses. Physical addresses are those used by the CPU to address physical memory on your main board. If there was no paging, they would map identically to linear address space, right? Now, assume, there actually _is_ paging enabled. This would mean, that ANY address your program generates while reading/writing memory or executing code is a linear address that would not neccessarily be the equivalent of the "real", physical address. The CPU uses some sort of an address translation table (which is maintained by the OS or the DOS extender) to generate physical addresses. This, BTW, is how it is possible to run more than one DOS box at a time in Windows. Every DOS box has a linear address space starting at linear address 00000000. It's obvious that they cannot map to the same physical memory, isn't it? However, this is not a thing you have to worry about unless you decide to write an operating system or a DOS extender or such... Now we know how it's possible to have the full 4G address space for each application in flat memory model as it is used in WIN 95/NT. This is done by giving each application an unique set of those address translation tables. What about the segment registers, you may ask? Well, in WIN 95/NT they are loaded with descriptor values that have a linear base of 00000000 also. (this applies to CS:,DS:,SS: and ES:. FS: usually too, but there are things like TLS I do not want to go deeper into...) So every offset address (a pointer in Delphi 2 is NEAR and nothing else than an offset) is a linear address too. Things get different while running under a DOS extender. The base adresses of CS:, DS:... are identical though, but they are not 00000000. Even worse, the linear start address may change during program execution. This is, because the DPMI host is allowed to move the segment around in memory if you decide to resize it. Resizing the segment may (but need not) happen anytime a heap object is created/destroyed. The above section about paging may already have told you that there is no physical memory moved around. The OS merely modifies the address translation tables for the current process. You also don't have to take care of this fact unless you want to do direct memory read/write (VIDEO...), since the DOS extender is managing anything else for you in almost no time. 2. But what if I actually _want_ to do direct mem and stuff...? Well, first of all, I suggest, you grab the DPMI 0.9 spec from somewhere so a lot of questions will be self- answering. A good place is: ftp://x2ftp.oulu.fi/pub/msdos/programming/specs/dpmispec.arj Problem here is that I'm instantly thinking in terms of Assembler, not Pascal as a majority of you may do. So there are cases where I would say "no problem at all" and hacked in the ASM straight from mind. So, my explaination may appear a bit confusing to others. Anyway, keep in mind that there is almost no problem that cannot be solved with inline assembly! However, personally I use to create a descriptor that actually has a base of 00000000 and a limit of 4G so I can access all memory using offsets only. If you like to know how this is done, have a look into CRT.PAS. If you get no idea anyway, just move the "huge_selector" thing from "implementation" to "interface" and it will be public. (SECRET HINT: I've done this for you already, have a look at the source code... Psssttt, don't tell anybody... :) Now, as an example, instead of saying: mem[$A000:0000]:=color; just say: asm push gs mov gs,huge_selector mov edx,0a0000h mov al,color mov gs:[edx],al pop gs end; ------------------------------------------------------------------------------- IMPORTANT NOTE! ------------------------------------------------------------------------------- RECENTLY I WROTE IN THIS PLACE: >Here's the well known putpixel in mode $13: > >procedure putpixel (X,Y: Integer; Color: Byte); >begin > asm > mov eax,Y > mov edx,X > shl eax,6 > push gs > add edx,eax > mov gs,huge_selector > mov cl,Color > mov gs:[edx+eax*4+0a0000h],cl > pop gs > end; >end; THIS ONE IS VERY LIKELY TO CRASH!!! Take my apologies for not testing it first. The misbehaviour is because of a compiler bug not processsing immediate offsets correctly when the low word is set to zero. So the immediate 0a0000h is very likely to be ignored by the compiler. Use DejaNews to parse COMP.LANG.PASCAL.DELPHI.MISC for a discussion of this. The subject line was: "D2 sux! (inline asm bug... ) AAARRRGHHH!!!" (without the quotes) Furthermore, see the file PUTPIXEL.PAS for a version that actually works! It actually may (and, in most cases, will) work to load GS: with the selector once and use it all the time, so you save the cycles spent on saving/loading/restoring a segment register in PM. You can load even ES: and FS: with another selector, yeah, you even could change DS: if only the local stack is dereferenced, but you _will_ have to save/restore them since DS:, ES: and FS: are used during program execution while GS: usually isn't. LINEAR FRAME BUFFER (VESA) This one may be interesting for some of you since you couldn't do it in 16 bit pascal. I've not tried it yet since I have no VESA 2.0 card here (shame on me), but there's no reason why it shouldn't work: - Use DPMI "MAP PHYSICAL REGION" with base address and size of the LFB as you received it from VESA BIOS, a linear address will be returned. - Now you have the choice: use either the above huge_selector and the linear address as an offset or create a new descriptor to access the LFB. 3. Pointer casting In Delphi 2 a pointer isn't a Segment:Offset thing anymore, its merely a dword. So we can do all that neat pointer arithmetic stuff C programmers are doing. However, the compiler will complain if one tries something like: var i:integer; p:pointer; ... i:=p; i:=i+some_offset; p:=i; Well, but be are free to say: asm mov eax,p add eax,some_offset mov i,eax mov p,eax end Hope this helps a bit. Wuschel