Program: flat100.zip Title: Version: Description: SVGA VESA API linear framebuffer, a very brief intro As you probably know from writing SVGA code in real mode, the graphics card uses a technic called bank switching to map areas of the video memory into a 64k segment. This is necessary, as the amount of video memory required for SVGA modes exceedes the 64k limit. But that's not the only way to access the video memory. As the number of 32-bit protected mode software increased, new functions were added to the VESA API. These include direct access to the *en Keywords: Source-code: Author: by Tobias Romann adress Platforms: Copying-policy: Copyright by Tobias Romann --------------------------------------- SVGA VESA API linear framebuffer, a very brief intro As you probably know from writing SVGA code in real mode, the graphics card uses a technic called bank switching to map areas of the video memory into a 64k segment. This is necessary, as the amount of video memory required for SVGA modes exceedes the 64k limit. But that's not the only way to access the video memory. As the number of 32-bit protected mode software increased, new functions were added to the VESA API. These include direct access to the *entire* video memory, mapped somewhere into your computer's memory. That's called the linear framebuffer (because it uses linear access without bank switching). That's an extremely fast way for 32-bit software to enhance video performance, but it couldn't be used in real mode. But with flat real mode we may use it too. The gain of speed is more than significant. Below are three excerps from Ralf Brown's interrupt, release 47. These are the functions used in the example program. Hope you got it... INT 10 - VESA SuperVGA BIOS (VBE) - GET SuperVGA INFORMATION AX = 4F00h ES:DI -> buffer for SuperVGA information (see #0063) Return: AL = 4Fh if function supported AH = status 00h successful ES:DI buffer filled 01h failed VBE v2.0 02h function not supported by current hardware configuration 03h function invalid in current video mode Desc: determine whether VESA BIOS extensions are present and the capabilities supported by the display adapter SeeAlso:AX=4E00h,AX=4F01h,AX=7F00h,AX=A00Ch Index: installation check;VESA SuperVGA Format of SuperVGA information: Offset Size Description (Table 0063) 00h 4 BYTEs (ret) signature ("VESA") (call) VESA 2.0 request signature ("VBE2"), required to receive version 2.0 info 04h WORD VESA version number (one-digit minor version) 06h DWORD pointer to OEM name "761295520" for ATI 0Ah DWORD capabilities flags (see #0064) 0Eh DWORD pointer to list of supported VESA and OEM video modes (list of words terminated with FFFFh) 12h WORD total amount of video memory in 64K blocks VBE v1.x 14h 236 BYTEs reserved VBE v2.0 14h WORD OEM software version 16h DWORD pointer to vendor name 1Ah DWORD pointer to product name 1Eh DWORD pointer to product revision string 22h 222 BYTEs reserved 100h 256 BYTEs OEM scratchpad Notes: the list of supported video modes is stored in the reserved portion of the SuperVGA information record by some implementations, and it may thus be necessary to either copy the mode list or use a different buffer for all subsequent VESA calls the 1.1 VESA document specifies 242 reserved bytes at the end, so the buffer should be 262 bytes to ensure that it is not overrun; for v2.0, the buffer should be 512 bytes the S3 specific video modes will most likely follow the FFFFH terminator at the end of the standard modes. A search must then be made to find them, FFFFH will also terminate this second list Bitfields for VESA capabilities: Bit(s) Description (Table 0064) 0 DAC can be switched into 8-bit mode 1 non-VGA controller 2 programmed DAC with blank bit 3-31 reserved INT 10 - VESA SuperVGA BIOS - GET SuperVGA MODE INFORMATION AX = 4F01h CX = SuperVGA video mode ES:DI -> 256-byte buffer for mode information (see #0065) Return: AL = 4Fh if function supported AH = status 00h successful ES:DI buffer filled 01h failed Desc: determine the attributes of the specified video mode SeeAlso: AX=4F00h,AX=4F02h Format of VESA SuperVGA mode information: Offset Size Description (Table 0065) 00h WORD mode attributes (see #0066) 02h BYTE window attributes, window A (see #0067) 03h BYTE window attributes, window B (see #0067) 04h WORD window granularity in KB 06h WORD window size in KB 08h WORD start segment of window A 0Ah WORD start segment of window B 0Ch DWORD -> FAR window positioning function (equivalent to AX=4F05h) 10h WORD bytes per scan line remainder is optional for VESA modes in v1.0/1.1, needed for OEM modes 12h WORD width in pixels (graphics) or characters (text) 14h WORD height in pixels (graphics) or characters (text) 16h BYTE width of character cell in pixels 17h BYTE height of character cell in pixels 18h BYTE number of memory planes 19h BYTE number of bits per pixel 1Ah BYTE number of banks 1Bh BYTE memory model type (see #0068) 1Ch BYTE size of bank in KB 1Dh BYTE number of image pages 1Eh BYTE reserved (0) VBE v1.2+ 1Fh BYTE red mask size 20h BYTE red field position 21h BYTE green mask size 22h BYTE green field size 23h BYTE blue mask size 24h BYTE blue field size 25h BYTE reserved mask size 26h BYTE reserved mask position 27h BYTE direct color mode info bit 0: color ramp is programmable bit 1: bytes in reserved field may be used by application VBE v2.0 28h DWORD physical address of linear video buffer 2Ch DWORD pointer to start of offscreen memory 30h WORD KB of offscreen memory 32h 206 BYTEs reserved (0) Bitfields for VESA SuperVGA mode attributes: Bit(s) Description (Table 0066) 0 mode supported 1 optional information available 2 BIOS output supported 3 set if color, clear if monochrome 4 set if graphics mode, clear if text mode VBE v2.0 5 mode is not VGA-compatible 6 bank-switched mode not supported 7 linear framebuffer mode supported Bitfields for VESA SuperVGA window attributes: Bit(s) Description (Table 0067) 0 exists 1 readable 2 writable 3-7 reserved (Table 0068) Values for VESA SuperVGA memory model type: 00h text 01h CGA graphics 02h HGC graphics 03h 16-color (EGA) graphics 04h packed pixel graphics 05h "sequ 256" (non-chain 4) graphics 06h direct color (HiColor, 24-bit color) 07h YUV (luminance-chrominance, also called YIQ) 08h-0Fh reserved for VESA 10h-FFh OEM memory models INT 10 - VESA SuperVGA BIOS - SET SuperVGA VIDEO MODE AX = 4F02h BX = mode (see #0069,#0070) bit 15 set means don't clear video memory bit 14 set means enable linear framebuffer mode (VBE v2.0+) Return: AL = 4Fh if function supported AH = status 00h successful 01h failed SeeAlso: AX=4E03h,AX=4F01h,AX=4F03h (Table 0069) Values for VESA video mode: 00h-FFh OEM video modes (see #0009 at AH=00h) 100h 640x400x256 101h 640x480x256 102h 800x600x16 103h 800x600x256 104h 1024x768x16 105h 1024x768x256 106h 1280x1024x16 107h 1280x1024x256 108h 80x60 text 109h 132x25 text 10Ah 132x43 text 10Bh 132x50 text 10Ch 132x60 text VBE v1.2 10Dh 320x200x32K 10Eh 320x200x64K 10Fh 320x200x16M 110h 640x480x32K 111h 640x480x64K 112h 640x480x16M 113h 800x600x32K 114h 800x600x64K 115h 800x600x16M 116h 1024x768x32K 117h 1024x768x64K 118h 1024x768x16M 119h 1280x1024x32K 11Ah 1280x1024x64K 11Bh 1280x1024x16M VBE 2.0 81FFh special full-memory access mode Note: the special mode 81FFh preserves the contents of the video memory and gives access to all of the memory; VESA recommends that the special mode be a packed-pixel mode SeeAlso: #0009,#0070 Index: video modes;VESA (Table 0070) Values for S3 OEM video mode: 201h 640x480x256 202h 800x600x16 203h 800x600x256 204h 1024x768x16 205h 1024x768x256 206h 1280x960x16 207h 1152x864x256 (Diamond Stealth 64) 208h 1280x1024x16 20Ah 1152x864x64K (Diamond Stealth 64) 211h 640x480x64K (Diamond Stealth 24) 212h 640x480x16M (Diamond Stealth 24) 301h 640x480x32K Note: these modes are only available on video cards using S3's VESA driver SeeAlso: #0069 Index: video modes;S3 Example programs There are several small example programs demonstrating the basic concepts of the library. ex1.c - setup flat real mode and use the information provided by the library ex2.c - use the library in no extended memory mode to access the video memory ex3.c - copy a file using low level 32-bit file functions, ex4.txt ex4.h ex4.c - access the video memory in SVGA modes using the VESA 2.00+ linear framebuffer; draws a nice plasma :-) They are written in a memory model independant manner and should work with any ANSI compiler. Flat real mode for C/C++ is a small library designed to allow C/C++ programmers of 16-bit real mode DOS programs to use the entire memory without special memory managers in a fast and efficient way. It uses a technique called flat real mode, available on 386+, to enable linear 32-bit memory access. Installation is simple: unzip the file into into a directory of your choice (e.g. c:/src/flat/). Precompiled objects, full source code (NASM), documentation and example programs are included. The library is free software under the GNU GPL and may be used, modified and distributed under it's terms, see flat.doc or src/flat.asm for details. It comes with ABSOLUTELY NO WARRANTY. Tobias Romann FLAT REAL MODE FOR C/C++ 1.00 Copyright by Tobias Romann Table of contents first release introduction copyleft requirements (system and knowledge) usage 4.0 - compiling the library 4.1 - setting up / shutting down flat real mode 4.2 - system variables 4.3 - accessing memory 4.4 - constants and macros 4.5 functions 4.5.1 - memory management (alloc32.c) 4.5.2 - 32-bit file access (file32.c) 4.6 - writing your own flat real mode code 4.7 - example programs contacting the author credits questions & answers first release This is the first (official) release of my flat real mode for C/C++ library. I wrote it in the beginning of 1999 for two main reasons: keep using my old 16-bit code and get access to extended memory without any slow drivers. When I started writing my programs with DJGPP, there was no more need to finish or even publish this library. But when I had looked at some shareware 16-bit DOS extenders, I decided to finish it and make it freely available to the public. The technique used is old and messy. If (for some obscure reason) you still use a 16-bit compiler, this might be a solution for your memory problems. It could also be of some (low) value for beginners with assembly language. (Really beginners!) Using this library within "normal" software (i.e. tools, ...) is probably not a good idea, as it requires a system configuration, which varies from those most users have. But it could be quite a speed and size improvement for demos and games. introduction There are several ways to access extended memory within 16-bit real mode programs: XMS or EMS, the BIOS or (did you guess it?) this tiny library. The idea is simple: switch to protected mode, adjust the segment limits to 4GB, return to real mode, and - they stay 4GB(1). This bug/feature of CPUs as of the 80386 allows full access to all available memory, in real mode, using 32-bit registers as indexes. But as you either know or probably guess there are also some problems: (a) it doesn't work with EMMs or other v86 mode memory managers. I had a quick look at gemmis.txt from ftp://x2ftp.oulu.fi/. If that stuff really worked, it would be a solution. But as I already said, I don't really need it anymore. (b) it also does not, and never will work under multitasking OS'. I heard it could work using VCPI, but if you want a DOS extended environment, get DJGPP (http://www.delorie.com/djgpp/). Footnotes: 1: This is due to the shadow registers, which are loaded with the appropriate descriptors every time a segment register is being modified in protected mode. They keep their values between the mode switches, and (normally (exception: loadall)) cannot be modified in real mode. copyleft Flat real mode for C/C++ Copyright (C) 1999 Tobias Romann This library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Of course, the GPL also applies to this document and the example programs. It is in the file "copying", in the root directory of the library. There are several shareware 16-bit DOS extenders out there. If you intend to write proprietary software use one them. This is a free library to be used in free software. requirements (system and knowledge) The library code is split into two seperate parts: (a) the basic functions, written in compiler independant asm, and (b) higher level ones, which have to be recompiled with your C compiler. The asm code has been written for the Netwide Assembler, because it's free and has a much clearer design than commercial assemblers (and doesn't use GAS' stupid syntax). The C code should work with every 16-bit compiler supporting basic ANSI file i/o and memory management functions (i.e. FILE stuff and malloc/free). There are no special knowledge requirements to use this library. If you know how memory is organized under DOS, what extended memory and flat real mode are, there should be no problems. This library is ment for C beginners who want a cheap ($0.00e1) and civilized way to use extended memory in their programs. (Whether this actually *is* civilized could be discussed ;-) usage This chapter explains how to use flat real mode in your own programs. 4.0 - compiling the library This package includes precompiled object files of the asm file in the obj directory. You may link them with your programs as they are, create a lib(1) from them - whatever you want. I didn't include objects for the C files, because (a) they have to be recompiled on every compiler other than the one I would have used and (b) I don't know a good free 16-bit C compiler. You may either compile them yourself (they are in the src/c directory), or #include them, if your program is small enough. Footnotes: 1: I would have done so, if I had a free librarian (or wasn't too lazy to write one ;-). 4.1 - setting up / shutting down flat real mode First, every file intended to use flat real mode should #include "flat.h". It declares all variables to be used by you and prototypes all functions. The function to set up flat real mode is called init_flat. It checks the CPU type, whether a v86 manager is running, switches to flat real mode and tries to allocate extended memory using an XMM (e.g. himem.sys) or the bios (raw mode (int 0x15)). The default behaviour lets init_flat allocate *all* available extended memory for you to use it. You way change the maximum size of memory used by setting unsigned em_max to a value that fits you need (in kb) prior to calling init_flat. The value returned is an error code with one of the following meanings: no error, flat real mode running an 80386 or better CPU wasn't detected CPU is in v86 mode (e.g. a multitasker is active) memory, said to be available by the XMM, couldn't be allocated memory couldn't be locked, this error requires exit_flat to be called Errors 3 and 4 can be disabled by setting em_max to zero, which deactivates extended memory usage. Alternatively, you may consider not loading an XMM at all. This also get's you rid of memory allocation problems, as none is used. All available memory is considered free. As important as setting up flat real mode, is the shutdown function, exit_flat. Since extended memory has been allocated (if you didn't set em_max=0), it has to be freed before program exit. As it is save to call exit_flat, even if init_flat failed, you may call atexit (exit_flat) in your program to ensure memory is freed. ( While debugging your program you may wish to lower em_max, as every time you abort the program, memory is not freed. Otherwise, you would have to reboot your system, or free it manually. 4.2 - system variables There are several variables, set by init_flat informing you about the state of the computer your program is running on. int cpu_type 8086/8088, 80286, 80386, 80486 or better const int mem_mode if in raw mode, otherwise an XMM is used long em_avail - extended memory available for you to use unsigned em_max - you already know; defaults to 0xffff (64MB) flatptr em_base, em_top - base and top adress of the allocated extended memory; see chapter 4.3 for a description of flat pointers unsigned fbuf_size void far *fbuf_ptr - please read chapter 4.5.2 for this See 4.5.1 for a description of the heap32 variables. 4.3 - accessing memory Memory access is done using flat pointers. These are simply longs, containing absolute adresses. As you should know, the 80x86 uses a segmented memory adressing scheme in real mode. That is, a pair of a segment and an offset, forming an absolute adress in the 1mb adress space. 32-bit protected mode and flat real mode instead, use a linear way to adress memory. Since flat real mode acutally *is* (a little hacked) real mode, memory is still segmented; but with a segment limit of 4GB (for ds, es, fs and gs). Absolute adresses can be easily calculated from a seg:off pair, by computing 16 * seg + off, this is done by the macros MK_FPTR(seg,off), which creates a flat pointer from a given segmented adress and PTR2FPTR(ptr), which converts an ordinary (i.e. segmented) pointer into a flat one. Since flat pointers are no real pointers through the eyes of a 16-bit compiler, memory can't be adressed using the '*' operator. Instead, a couple of functions(1) will do the job. I'll show it to you with a couple of comparisons. Assume sp = segmented pointer (void*), fp = flat pointer, ch char value, in = an int value, li long value and size_t. Accessing single values: segmented pointer flat pointer *(char*)sp peekb32 (fp) *(int*)sp peekw32 (fp) *(long*)sp peekd32 (fp) *(char*)sp = ch pokeb32 (fp, ch) *(int*)sp = in pokew32 (fp, in) *(long*)sp = li poked32 (fp, li) Accessing memory groups: segmented pointer flat pointer scan for a specific byte memchr (sp, ch, s) memchr32 (fp, ch, li) compare two memory regions memcmp (sp1, sp2, s) memcmp32 (fp1, fp2, li) copy one memory area to another memcpy (sp2, sp1, s) memcpy32 (fp2, fp1, li) fill a memory area with a (byte) value memset (sp, ch, s) memset32 (fp, ch, li) These work like the corresponding stdlib functions, except they use flat pointers and allow to work on regions >64k (up to 4G, of course) Footnotes: 1: They are implemented as real far call functions. If your compiler supports inline assembly or direct byte inserting you should consider #defining them as macros, to *really* enhance performance. 4.4 - constants and macros flat.h #defines several constants you may wish to use. #defined constants: FLATC_VERSION - major version number FLATC_SUB_VERSION - minor version number FLATC_VERSION_STR - What do you think? HEAP32_USED_BIT - flag indicating a used memory block pointer macros: MK_FP (segment, offset) - create a far pointer to segment:offset FP_SEG (pointer) - return a (far or near) pointer's segment FP_OFF (pointer) - or the offset MK_FPTR (segment, offset) - create a *flat* pointer to segment:offset PTR2FPTR (pointer) - convert a (far or near) pointer into a flat one 4.5 functions Some parts of the library are written in ANSI(1) C. They are designed to enhance a few 16-bit stdlib functions, to make them work with 32-bit data. Since stdlib calling conventions and long maths are handled differently by nearly every compiler, you have to compile them yourself (they are in the src/c directory). Footnotes: 1: It's not true ANSI, as they both #include "flat.h", which uses the common far keyword and file32.c also declares a pointer of that type. This shouldn't be a problem, as every DOS compiler I know either supports far, or uses it anyway (which means you may delete or #define it in that case). 4.5.1 - memory management (alloc32.c) Yes, this library provides dynamic extended memory allocation! It works nearly the same way as the stdlib functions malloc and free (realloc isn't implemented, but could be easily done (simply don't need it)). As this library is not intended to store small data (a few hundred bytes) within extended memory (although it is possible), the allocation system is oriented to a few *big* blocks. The system works using a dynamically sized heap table within conventional memory. As I said above, the number and sizeof allocated blocks should be kept within useful dimensions. That's why I use a dynamic array for the data. If you need a system for lot of small data, rewrite the allocation system using recursive data structures and another system for the heap nodes. Each time you allocate an extended memory block, a new item is inserted into a heap table. If it's full, the system automagically tries to *double* it's size. Every entry takes 4 bytes. The first time memory is allocated, a table for a maximum of 64 entries is being created. If you don't want to waste memory, I suggest not to allocate more than 255 memory blocks (which should really be enough). Now the functions: flatptr malloc32 (long size) void free32 (flatptr p) As you may guess, they work like the stdlib ones. Call malloc32 with the size (in bytes) of extended memory you want to allocate, and it returns either a flat pointer to the block or 0L, on error. If malloc32 fails, and you wish to get a more detailed error description, have a look at heap32_errno. It can contain one of the following enums: * HEAP32_ZERO, no error * HEAP32_NOCONV, not enough *conventional* memory available. This indicates a failure while trying to create the heap table. * HEAP32_EXT, not enough extended memory available * HEAP32_NOTFOUND, set by free32 if you tried to free a block not in the heap list If you often call malloc32 and free32, the heap becomes fragmented with sequences of small free/free/... pairs. If malloc32 cannot find a free block, even though enough memory should be available, it calls a function named heap32_sort. It joins sequences of free blocks into one big. You may consider calling it yourself from time to time if your misusing the library for small data storage. The memory left on the heap can be examined by reading long heap32_avail. As I told above, this doesn't have to mean that a block of this size actually *can* be allocated. Now follows a detailed description of the heap table. You may skip this, if you simply want to use the functions. After the first call of malloc32, heap32 points to an array of structures containing the actual data. typedef struct { long size; }heap32_node; heap32_node *heap32; As you see, a heap node is simply a long. int heap32_items; Contains the number of currently allocated blocks; int heap32_max; The maximum number of blocks that can be allocated without resizing the heap table All memory starting from em_base with the size em_avail, is divided into blocks which are either free or used (i.e. have been allocated). The size members in the heap table contains the memory blocks size (bits 0-30) and a flag indicating whether they are used (bit31) or free (!bit31). The adress of the block can be calculated, as they are placed within the table in ascending order. Thus, the adress of a block is the adress plus the size of the predecesser (or em_base, if none). This system is quite efficient concerning memory usage (4 bytes per entry), but requires (in a worst case situation) scanning the entire table with every malloc32 or free32 call. There's another function called heap32_downsize, which allows you to *reduce* the heap table. This can be useful, if you've allocated several memory blocks before, which are now free, as malloc32 sometimes tries to increase the table's size, but free32 *never* decreases it. Call it with the new maximum number of entries you want. As usual, -1 indicates an error. 4.5.2 - 32-bit file access (file32.c) This library also offers a comfortable way to break with the OS' limits regarding file access, by allowing (pseudo) direct reading or writing of data of any size from/to FILEs. Of course the OS neither supports reading data >64k with a single call nor extended memory usage. Thus, the library simulates 32-bit access by holding a transfer buffer within conventional memory to provide an interface between you and the OS. This buffer has to be allocated by you(!), prior to using *any* 32-bit file functions. It's a far pointer called fbuf_ptr, the buffer's size has to be in fbuf_size (default 32k). It is important that in near data models (i.e. small and medium) the buffer resides within the program's data segment. Otherwise, the functions will (probably) crash. e.g.: fbuf_ptr = (void far*) malloc (fbuf_size); if (!fbuf_ptr) { ... } ... You may wish to lower (or even increase) the value of fbuf_size if you're rare of conventional memory (or have plenty of it). The functions work on stdio FILE streams. Their prototypes are quite similiar to those of fread and fwrite, with the exception of using one size parameter instead of a elements and sizeof (element) pair. long fread32 (flatptr p, long n, FILE *stream); Read n bytes from stream to p. Returns the number of bytes read, or -1 on error. errno is set if needed. long fwrite32 (flatptr p, long n, FILE *stream); Write n bytes from p to stream. Returns the number of bytes written, or -1 on error. 4.7 - writing your own flat real mode code This sub chapter explains the basic differences between segmented and flat real mode, through the eyes of an asm programmer. segment limits: The segment limit for the registers ds, es, fs and gs is set to 4GB by init_flat while in protected mode. This effectively disables *any* limit (at least for the next years ;-). Adressing is simply done using 32-bit indexes instead of the 16-bit ones you are familiar with. e.g.: ;16-bit mov ax, [bx] ;32-bit mov ax, [ebx] ;or eax, ecx, ... Any 32-bit data register can be used as an index (not only ebx). If you want to access flat pointers in asm code, you should load a segment register with 0, to access absolute adresses instead of relatives to ds. In some situations you may want to hard code 32-bit adressing, using a 0x67 prefix. e.g.: xor ax, ax mov es, ax mov al, [es:esi] ;accesses absolute esi mov al, [esi] ;or esi relative to beginning of ds db 0x67 ;writes to es:edi instead of es:di stosb 4.8 - example programs The above is quite abstract. If you want to see the library in action, have a look at the programs in the directory "examples". Of course, they aren't really useful in any way, but they're quite well commented and show everything much better than the above reference does. You should create a library with all the files in the obj directory in it and link the example programs with it. The C files are automagically #included if they are needed, so you don't need to bother compiling them. Also consider recompiling the asm files with debug information (-g switch), so that you can debug the library code. contacting the author questions about the library, bug reports or even improvements. I really like to receive mail. credits Thanks to the following people: * Simon Tatham and Julian Hall for the Netwide Assembler; visit the NASM page at http://www.cryogen.com/Nasm * NiX and Butterfly from MASSiVE; they wrote a library with the same purpose for assembly language programmers and this inspired me to write something like that for C/C+ Ralf Brown for the Interrupt List; get it at ftp://simtel.net/pub/msdos/info/inter??[a-d].zip * Randall Hyde and others for the UCR Standard Library for Assembly Language Programmers (ripped the get_cpu stuff from it) * the Free Software Foundation and any contributers to it (http://www.fsf.org/, http://www.gnu.org/) * Phil Inch (ripped the plasma code in ex4 from one of his pd sources) questions & answers (Calling this an FAQ wouln't make much sense ;-) Q: My program terminates due to an error. I try to restart it, but it complains about missing extended memory, what's up? A: Your program didn't call exit_flat on termination. Thus, all memory allocated thru an XMM has not been freed. You should either: (a) free the memory by hand (Get Ralf Browns interrupt list!) (b) reboot your computer (c) set em_max to a lower value, if your program works with less memory (d) don't load an XMM at all. Thus, no memory allocation exists and your program always has access to all extended memory Q: I can't get any flat real mode program running, what shall I do? A: Run your computer under plain DOS (not a DOS box or DOSemu) without any extended memory managers like EMM386, QEMM, ... loaded. Preferable not even an XMM. Then, everything should work. You have got a 386 or better, don't you ;-? Q: Your 32-bit file access stuff crashes my computer! What's wrong? A: Did you allocate memory for a transfer buffer? fread32 and fwrite32 will write to the memory pointed to by fbuf_ptr, which is NULL! Randomly writing within the interrupt vector table will definitely *not* help your computer behave normally. It would be a waste of time to check for fbuf_ptr to be valid, within every read or write operation. You have to do this! Q: cpu_type doesn't contain really up-to-date information about my CPU? A: No, init_flat simply detects the presence of a 386 or lower, which is required. Q: Can I use my old 16-bit real mode code with this library? A: Yeah, that's another reason why I originally wrote this stuff. If your code doesn't do something really stupid/tricky (i.e. rely on the wrap around) you shouldn't encounter any problems with your old code. Q: I use a different 16-bit DOS compiler, it refuses to accept flat.h. Help! A: The easiest way is probably to make a few #defines before including flat.h. e.g.: #define far /* you will have to set a memory model yourself, /* or pass far-pointers by-hand Q: Is there anything I should *not* do with this library? A: There are a few things, either this library or flat real mode are not good for. This primary includes writing TSRs or spawning child processes. It will work, but you will probably have to add some code to the asm kernel to get better control over allocated memory (e.g. the library doesn't follow the convention to let int 0x15 fn 0x88 return a reduced memory size). ---------------------------------------------------------------- /pc/prg/notxt/flat100.zip/examples/ex4.txt SVGA VESA API linear framebuffer, a very brief intro **************************************************** As you probably know from writing SVGA code in real mode, the graphics card uses a technic called bank switching to map areas of the video memory into a 64k segment. This is necessary, as the amount of video memory required for SVGA modes exceedes the 64k limit. But that's not the only way to access the video memory. As the number of 32-bit protected mode software increased, new functions were added to the VESA API. These include direct access to the *entire* video memory, mapped somewhere into your computer's memory. That's called the linear framebuffer (because it uses linear access without bank switching). That's an extremely fast way for 32-bit software to enhance video performance, but it couldn't be used in real mode. But with flat real mode we may use it too. The gain of speed is more than significant. Below are three excerps from Ralf Brown's interrupt, release 47. These are the functions used in the example program. Hope you got it... INT 10 - VESA SuperVGA BIOS (VBE) - GET SuperVGA INFORMATION AX = 4F00h ES:DI -> buffer for SuperVGA information (see #0063) Return: AL = 4Fh if function supported AH = status 00h successful ES:DI buffer filled 01h failed ---VBE v2.0--- 02h function not supported by current hardware configuration 03h function invalid in current video mode Desc: determine whether VESA BIOS extensions are present and the capabilities supported by the display adapter SeeAlso:AX=4E00h,AX=4F01h,AX=7F00h,AX=A00Ch Index: installation check;VESA SuperVGA Format of SuperVGA information: Offset Size Description (Table 0063) 00h 4 BYTEs (ret) signature ("VESA") (call) VESA 2.0 request signature ("VBE2"), required to receive version 2.0 info 04h WORD VESA version number (one-digit minor version) 06h DWORD pointer to OEM name "761295520" for ATI 0Ah DWORD capabilities flags (see #0064) 0Eh DWORD pointer to list of supported VESA and OEM video modes (list of words terminated with FFFFh) 12h WORD total amount of video memory in 64K blocks ---VBE v1.x --- 14h 236 BYTEs reserved ---VBE v2.0 --- 14h WORD OEM software version 16h DWORD pointer to vendor name 1Ah DWORD pointer to product name 1Eh DWORD pointer to product revision string 22h 222 BYTEs reserved 100h 256 BYTEs OEM scratchpad Notes: the list of supported video modes is stored in the reserved portion of the SuperVGA information record by some implementations, and it may thus be necessary to either copy the mode list or use a different buffer for all subsequent VESA calls the 1.1 VESA document specifies 242 reserved bytes at the end, so the buffer should be 262 bytes to ensure that it is not overrun; for v2.0, the buffer should be 512 bytes the S3 specific video modes will most likely follow the FFFFH terminator at the end of the standard modes. A search must then be made to find them, FFFFH will also terminate this second list Bitfields for VESA capabilities: Bit(s) Description (Table 0064) 0 DAC can be switched into 8-bit mode 1 non-VGA controller 2 programmed DAC with blank bit 3-31 reserved INT 10 - VESA SuperVGA BIOS - GET SuperVGA MODE INFORMATION AX = 4F01h CX = SuperVGA video mode ES:DI -> 256-byte buffer for mode information (see #0065) Return: AL = 4Fh if function supported AH = status 00h successful ES:DI buffer filled 01h failed Desc: determine the attributes of the specified video mode SeeAlso: AX=4F00h,AX=4F02h Format of VESA SuperVGA mode information: Offset Size Description (Table 0065) 00h WORD mode attributes (see #0066) 02h BYTE window attributes, window A (see #0067) 03h BYTE window attributes, window B (see #0067) 04h WORD window granularity in KB 06h WORD window size in KB 08h WORD start segment of window A 0Ah WORD start segment of window B 0Ch DWORD -> FAR window positioning function (equivalent to AX=4F05h) 10h WORD bytes per scan line remainder is optional for VESA modes in v1.0/1.1, needed for OEM modes 12h WORD width in pixels (graphics) or characters (text) 14h WORD height in pixels (graphics) or characters (text) 16h BYTE width of character cell in pixels 17h BYTE height of character cell in pixels 18h BYTE number of memory planes 19h BYTE number of bits per pixel 1Ah BYTE number of banks 1Bh BYTE memory model type (see #0068) 1Ch BYTE size of bank in KB 1Dh BYTE number of image pages 1Eh BYTE reserved (0) ---VBE v1.2+--- 1Fh BYTE red mask size 20h BYTE red field position 21h BYTE green mask size 22h BYTE green field size 23h BYTE blue mask size 24h BYTE blue field size 25h BYTE reserved mask size 26h BYTE reserved mask position 27h BYTE direct color mode info bit 0: color ramp is programmable bit 1: bytes in reserved field may be used by application ---VBE v2.0 --- 28h DWORD physical address of linear video buffer 2Ch DWORD pointer to start of offscreen memory 30h WORD KB of offscreen memory 32h 206 BYTEs reserved (0) Bitfields for VESA SuperVGA mode attributes: Bit(s) Description (Table 0066) 0 mode supported 1 optional information available 2 BIOS output supported 3 set if color, clear if monochrome 4 set if graphics mode, clear if text mode ---VBE v2.0 --- 5 mode is not VGA-compatible 6 bank-switched mode not supported 7 linear framebuffer mode supported Bitfields for VESA SuperVGA window attributes: Bit(s) Description (Table 0067) 0 exists 1 readable 2 writable 3-7 reserved (Table 0068) Values for VESA SuperVGA memory model type: 00h text 01h CGA graphics 02h HGC graphics 03h 16-color (EGA) graphics 04h packed pixel graphics 05h "sequ 256" (non-chain 4) graphics 06h direct color (HiColor, 24-bit color) 07h YUV (luminance-chrominance, also called YIQ) 08h-0Fh reserved for VESA 10h-FFh OEM memory models INT 10 - VESA SuperVGA BIOS - SET SuperVGA VIDEO MODE AX = 4F02h BX = mode (see #0069,#0070) bit 15 set means don't clear video memory bit 14 set means enable linear framebuffer mode (VBE v2.0+) Return: AL = 4Fh if function supported AH = status 00h successful 01h failed SeeAlso: AX=4E03h,AX=4F01h,AX=4F03h (Table 0069) Values for VESA video mode: 00h-FFh OEM video modes (see #0009 at AH=00h) 100h 640x400x256 101h 640x480x256 102h 800x600x16 103h 800x600x256 104h 1024x768x16 105h 1024x768x256 106h 1280x1024x16 107h 1280x1024x256 108h 80x60 text 109h 132x25 text 10Ah 132x43 text 10Bh 132x50 text 10Ch 132x60 text ---VBE v1.2--- 10Dh 320x200x32K 10Eh 320x200x64K 10Fh 320x200x16M 110h 640x480x32K 111h 640x480x64K 112h 640x480x16M 113h 800x600x32K 114h 800x600x64K 115h 800x600x16M 116h 1024x768x32K 117h 1024x768x64K 118h 1024x768x16M 119h 1280x1024x32K 11Ah 1280x1024x64K 11Bh 1280x1024x16M ---VBE 2.0--- 81FFh special full-memory access mode Note: the special mode 81FFh preserves the contents of the video memory and gives access to all of the memory; VESA recommends that the special mode be a packed-pixel mode SeeAlso: #0009,#0070 Index: video modes;VESA (Table 0070) Values for S3 OEM video mode: 201h 640x480x256 202h 800x600x16 203h 800x600x256 204h 1024x768x16 205h 1024x768x256 206h 1280x960x16 207h 1152x864x256 (Diamond Stealth 64) 208h 1280x1024x16 20Ah 1152x864x64K (Diamond Stealth 64) 211h 640x480x64K (Diamond Stealth 24) 212h 640x480x16M (Diamond Stealth 24) 301h 640x480x32K Note: these modes are only available on video cards using S3's VESA driver SeeAlso: #0069 Index: video modes;S3 /pc/prg/notxt/flat100.zip/examples/examples.txt Example programs **************** There are several small example programs demonstrating the basic concepts of the library. ex1.c - setup flat real mode and use the information provided by the library ex2.c - use the library in no extended memory mode to access the video memory ex3.c - copy a file using low level 32-bit file functions, ex4.txt ex4.h ex4.c - access the video memory in SVGA modes using the VESA 2.00+ linear framebuffer; draws a nice plasma :-) They are written in a memory model independant manner and should work with any ANSI compiler. /pc/prg/notxt/flat100.zip/readme.txt Flat real mode for C/C++ is a small library designed to allow C/C++ programmers of 16-bit real mode DOS programs to use the entire memory without special memory managers in a fast and efficient way. It uses a technique called flat real mode, available on 386+, to enable linear 32-bit memory access. Installation is simple: unzip the file into into a directory of your choice (e.g. c:/src/flat/). Precompiled objects, full source code (NASM), documentation and example programs are included. The library is free software under the GNU GPL and may be used, modified and distributed under it's terms, see flat.doc or src/flat.asm for details. It comes with ABSOLUTELY NO WARRANTY. Tobias Romann /pc/prg/notxt/flat100.zip/flat.doc FLAT REAL MODE FOR C/C++ 1.00 Copyright by Tobias Romann Table of contents 0 - first release 1 - introduction 2 - copyleft 3 - requirements (system and knowledge) 4 - usage 4.0 - compiling the library 4.1 - setting up / shutting down flat real mode 4.2 - system variables 4.3 - accessing memory 4.4 - constants and macros 4.5 - C functions 4.5.1 - memory management (alloc32.c) 4.5.2 - 32-bit file access (file32.c) 4.6 - writing your own flat real mode code 4.7 - example programs 5 - contacting the author 6 - credits 7 - questions & answers 0 - first release This is the first (official) release of my flat real mode for C/C++ library. I wrote it in the beginning of 1999 for two main reasons: keep using my old 16-bit code and get access to extended memory without any slow drivers. When I started writing my programs with DJGPP, there was no more need to finish or even publish this library. But when I had looked at some shareware 16-bit DOS extenders, I decided to finish it and make it freely available to the public. The technique used is old and messy. If (for some obscure reason) you still use a 16-bit compiler, this might be a solution for your memory problems. It could also be of some (low) value for beginners with assembly language. (Really beginners!) Using this library within "normal" software (i.e. tools, ...) is probably not a good idea, as it requires a system configuration, which varies from those most users have. But it could be quite a speed and size improvement for demos and games. 1 - introduction There are several ways to access extended memory within 16-bit real mode programs: XMS or EMS, the BIOS or (did you guess it?) this tiny library. The idea is simple: switch to protected mode, adjust the segment limits to 4GB, return to real mode, and - they stay 4GB(1). This bug/feature of CPUs as of the 80386 allows full access to all available memory, in real mode, using 32-bit registers as indexes. But as you either know or probably guess there are also some problems: (a) it doesn't work with EMMs or other v86 mode memory managers. I had a quick look at gemmis.txt from ftp://x2ftp.oulu.fi/. If that stuff really worked, it would be a solution. But as I already said, I don't really need it anymore. (b) it also does not, and never will work under multitasking OS'. I heard it could work using VCPI, but if you want a DOS extended environment, get DJGPP (http://www.delorie.com/djgpp/). Footnotes: 1: This is due to the shadow registers, which are loaded with the appropriate descriptors every time a segment register is being modified in protected mode. They keep their values between the mode switches, and (normally (exception: loadall)) cannot be modified in real mode. 2 - copyleft Flat real mode for C/C++ Copyright (C) 1999 Tobias Romann This library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Of course, the GPL also applies to this document and the example programs. It is in the file "copying", in the root directory of the library. There are several shareware 16-bit DOS extenders out there. If you intend to write proprietary software use one them. This is a free library to be used in free software. 3 - requirements (system and knowledge) The library code is split into two seperate parts: (a) the basic functions, written in compiler independant asm, and (b) higher level ones, which have to be recompiled with your C compiler. The asm code has been written for the Netwide Assembler, because it's free and has a much clearer design than commercial assemblers (and doesn't use GAS' stupid syntax). The C code should work with every 16-bit compiler supporting basic ANSI file i/o and memory management functions (i.e. FILE stuff and malloc/free). There are no special knowledge requirements to use this library. If you know how memory is organized under DOS, what extended memory and flat real mode are, there should be no problems. This library is ment for C beginners who want a cheap ($0.00e1) and civilized way to use extended memory in their programs. (Whether this actually *is* civilized could be discussed ;-) 4 - usage This chapter explains how to use flat real mode in your own programs. 4.0 - compiling the library This package includes precompiled object files of the asm file in the obj directory. You may link them with your programs as they are, create a lib(1) from them - whatever you want. I didn't include objects for the C files, because (a) they have to be recompiled on every compiler other than the one I would have used and (b) I don't know a good free 16-bit C compiler. You may either compile them yourself (they are in the src/c directory), or #include them, if your program is small enough. Footnotes: 1: I would have done so, if I had a free librarian (or wasn't too lazy to write one ;-). 4.1 - setting up / shutting down flat real mode First, every file intended to use flat real mode should #include "flat.h". It declares all variables to be used by you and prototypes all functions. The function to set up flat real mode is called init_flat. It checks the CPU type, whether a v86 manager is running, switches to flat real mode and tries to allocate extended memory using an XMM (e.g. himem.sys) or the bios (raw mode (int 0x15)). The default behaviour lets init_flat allocate *all* available extended memory for you to use it. You way change the maximum size of memory used by setting unsigned em_max to a value that fits you need (in kb) prior to calling init_flat. The value returned is an error code with one of the following meanings: 0 - no error, flat real mode running 1 - an 80386 or better CPU wasn't detected 2 - CPU is in v86 mode (e.g. a multitasker is active) 3 - memory, said to be available by the XMM, couldn't be allocated 4 - memory couldn't be locked, this error requires exit_flat to be called Errors 3 and 4 can be disabled by setting em_max to zero, which deactivates extended memory usage. Alternatively, you may consider not loading an XMM at all. This also get's you rid of memory allocation problems, as none is used. All available memory is considered free. As important as setting up flat real mode, is the shutdown function, exit_flat. Since extended memory has been allocated (if you didn't set em_max=0), it has to be freed before program exit. As it is save to call exit_flat, even if init_flat failed, you may call atexit (exit_flat) in your program to ensure memory is freed. ( While debugging your program you may wish to lower em_max, as every time you abort the program, memory is not freed. Otherwise, you would have to reboot your system, or free it manually. 4.2 - system variables There are several variables, set by init_flat informing you about the state of the computer your program is running on. int cpu_type - 0 = 8086/8088, 1 = 80286, 2 = 80386, 3 = 80486 or better const int mem_mode - 0 if in raw mode, otherwise an XMM is used long em_avail - extended memory available for you to use unsigned em_max - you already know; defaults to 0xffff (64MB) flatptr em_base, em_top - base and top adress of the allocated extended memory; see chapter 4.3 for a description of flat pointers unsigned fbuf_size void far *fbuf_ptr - please read chapter 4.5.2 for this See 4.5.1 for a description of the heap32 variables. 4.3 - accessing memory Memory access is done using flat pointers. These are simply longs, containing absolute adresses. As you should know, the 80x86 uses a segmented memory adressing scheme in real mode. That is, a pair of a segment and an offset, forming an absolute adress in the 1mb adress space. 32-bit protected mode and flat real mode instead, use a linear way to adress memory. Since flat real mode acutally *is* (a little hacked) real mode, memory is still segmented; but with a segment limit of 4GB (for ds, es, fs and gs). Absolute adresses can be easily calculated from a seg:off pair, by computing 16 * seg + off, this is done by the macros MK_FPTR(seg,off), which creates a flat pointer from a given segmented adress and PTR2FPTR(ptr), which converts an ordinary (i.e. segmented) pointer into a flat one. Since flat pointers are no real pointers through the eyes of a 16-bit compiler, memory can't be adressed using the '*' operator. Instead, a couple of functions(1) will do the job. I'll show it to you with a couple of comparisons. Assume sp = segmented pointer (void*), fp = flat pointer, ch = a char value, in = an int value, li = a long value and s = a size_t. Accessing single values: segmented pointer flat pointer *(char*)sp peekb32 (fp) *(int*)sp peekw32 (fp) *(long*)sp peekd32 (fp) *(char*)sp = ch pokeb32 (fp, ch) *(int*)sp = in pokew32 (fp, in) *(long*)sp = li poked32 (fp, li) Accessing memory groups: segmented pointer flat pointer scan for a specific byte memchr (sp, ch, s) memchr32 (fp, ch, li) compare two memory regions memcmp (sp1, sp2, s) memcmp32 (fp1, fp2, li) copy one memory area to another memcpy (sp2, sp1, s) memcpy32 (fp2, fp1, li) fill a memory area with a (byte) value memset (sp, ch, s) memset32 (fp, ch, li) These work like the corresponding stdlib functions, except they use flat pointers and allow to work on regions >64k (up to 4G, of course) Footnotes: 1: They are implemented as real far call functions. If your compiler supports inline assembly or direct byte inserting you should consider #defining them as macros, to *really* enhance performance. 4.4 - constants and macros flat.h #defines several constants you may wish to use. #defined constants: FLATC_VERSION - major version number FLATC_SUB_VERSION - minor version number FLATC_VERSION_STR - What do you think? HEAP32_USED_BIT - flag indicating a used memory block pointer macros: MK_FP (segment, offset) - create a far pointer to segment:offset FP_SEG (pointer) - return a (far or near) pointer's segment FP_OFF (pointer) - or the offset MK_FPTR (segment, offset) - create a *flat* pointer to segment:offset PTR2FPTR (pointer) - convert a (far or near) pointer into a flat one 4.5 - C functions Some parts of the library are written in ANSI(1) C. They are designed to enhance a few 16-bit stdlib functions, to make them work with 32-bit data. Since stdlib calling conventions and long maths are handled differently by nearly every compiler, you have to compile them yourself (they are in the src/c directory). Footnotes: 1: It's not true ANSI, as they both #include "flat.h", which uses the common far keyword and file32.c also declares a pointer of that type. This shouldn't be a problem, as every DOS compiler I know either supports far, or uses it anyway (which means you may delete or #define it in that case). 4.5.1 - memory management (alloc32.c) Yes, this library provides dynamic extended memory allocation! It works nearly the same way as the stdlib functions malloc and free (realloc isn't implemented, but could be easily done (simply don't need it)). As this library is not intended to store small data (a few hundred bytes) within extended memory (although it is possible), the allocation system is oriented to a few *big* blocks. The system works using a dynamically sized heap table within conventional memory. As I said above, the number and sizeof allocated blocks should be kept within useful dimensions. That's why I use a dynamic array for the data. If you need a system for lot of small data, rewrite the allocation system using recursive data structures and another system for the heap nodes. Each time you allocate an extended memory block, a new item is inserted into a heap table. If it's full, the system automagically tries to *double* it's size. Every entry takes 4 bytes. The first time memory is allocated, a table for a maximum of 64 entries is being created. If you don't want to waste memory, I suggest not to allocate more than 255 memory blocks (which should really be enough). Now the functions: flatptr malloc32 (long size) void free32 (flatptr p) As you may guess, they work like the stdlib ones. Call malloc32 with the size (in bytes) of extended memory you want to allocate, and it returns either a flat pointer to the block or 0L, on error. If malloc32 fails, and you wish to get a more detailed error description, have a look at heap32_errno. It can contain one of the following enums: * HEAP32_ZERO, no error * HEAP32_NOCONV, not enough *conventional* memory available. This indicates a failure while trying to create the heap table. * HEAP32_EXT, not enough extended memory available * HEAP32_NOTFOUND, set by free32 if you tried to free a block not in the heap list If you often call malloc32 and free32, the heap becomes fragmented with sequences of small free/free/... pairs. If malloc32 cannot find a free block, even though enough memory should be available, it calls a function named heap32_sort. It joins sequences of free blocks into one big. You may consider calling it yourself from time to time if your misusing the library for small data storage. The memory left on the heap can be examined by reading long heap32_avail. As I told above, this doesn't have to mean that a block of this size actually *can* be allocated. Now follows a detailed description of the heap table. You may skip this, if you simply want to use the functions. After the first call of malloc32, heap32 points to an array of structures containing the actual data. typedef struct { long size; }heap32_node; heap32_node *heap32; As you see, a heap node is simply a long. int heap32_items; Contains the number of currently allocated blocks; int heap32_max; The maximum number of blocks that can be allocated without resizing the heap table All memory starting from em_base with the size em_avail, is divided into blocks which are either free or used (i.e. have been allocated). The size members in the heap table contains the memory blocks size (bits 0-30) and a flag indicating whether they are used (bit31) or free (!bit31). The adress of the block can be calculated, as they are placed within the table in ascending order. Thus, the adress of a block is the adress plus the size of the predecesser (or em_base, if none). This system is quite efficient concerning memory usage (4 bytes per entry), but requires (in a worst case situation) scanning the entire table with every malloc32 or free32 call. There's another function called heap32_downsize, which allows you to *reduce* the heap table. This can be useful, if you've allocated several memory blocks before, which are now free, as malloc32 sometimes tries to increase the table's size, but free32 *never* decreases it. Call it with the new maximum number of entries you want. As usual, -1 indicates an error. 4.5.2 - 32-bit file access (file32.c) This library also offers a comfortable way to break with the OS' limits regarding file access, by allowing (pseudo) direct reading or writing of data of any size from/to FILEs. Of course the OS neither supports reading data >64k with a single call nor extended memory usage. Thus, the library simulates 32-bit access by holding a transfer buffer within conventional memory to provide an interface between you and the OS. This buffer has to be allocated by you(!), prior to using *any* 32-bit file functions. It's a far pointer called fbuf_ptr, the buffer's size has to be in fbuf_size (default 32k). It is important that in near data models (i.e. small and medium) the buffer resides within the program's data segment. Otherwise, the functions will (probably) crash. e.g.: fbuf_ptr = (void far*) malloc (fbuf_size); if (!fbuf_ptr) { ... } ... You may wish to lower (or even increase) the value of fbuf_size if you're rare of conventional memory (or have plenty of it). The functions work on stdio FILE streams. Their prototypes are quite similiar to those of fread and fwrite, with the exception of using one size parameter instead of a elements and sizeof (element) pair. long fread32 (flatptr p, long n, FILE *stream); Read n bytes from stream to p. Returns the number of bytes read, or -1 on error. errno is set if needed. long fwrite32 (flatptr p, long n, FILE *stream); Write n bytes from p to stream. Returns the number of bytes written, or -1 on error. 4.7 - writing your own flat real mode code This sub chapter explains the basic differences between segmented and flat real mode, through the eyes of an asm programmer. segment limits: The segment limit for the registers ds, es, fs and gs is set to 4GB by init_flat while in protected mode. This effectively disables *any* limit (at least for the next years ;-). Adressing is simply done using 32-bit indexes instead of the 16-bit ones you are familiar with. e.g.: ;16-bit mov ax, [bx] ;32-bit mov ax, [ebx] ;or eax, ecx, ... Any 32-bit data register can be used as an index (not only ebx). If you want to access flat pointers in asm code, you should load a segment register with 0, to access absolute adresses instead of relatives to ds. In some situations you may want to hard code 32-bit adressing, using a 0x67 prefix. e.g.: xor ax, ax mov es, ax mov al, [es:esi] ;accesses absolute esi mov al, [esi] ;or esi relative to beginning of ds db 0x67 ;writes to es:edi instead of es:di stosb 4.8 - example programs The above is quite abstract. If you want to see the library in action, have a look at the programs in the directory "examples". Of course, they aren't really useful in any way, but they're quite well commented and show everything much better than the above reference does. You should create a library with all the files in the obj directory in it and link the example programs with it. The C files are automagically #included if they are needed, so you don't need to bother compiling them. Also consider recompiling the asm files with debug information (-g switch), so that you can debug the library code. 5 - contacting the author My email adress is t.rossmann@gmx.at. You may of course mail me questions about the library, bug reports or even improvements. I really like to receive mail. 6 - credits Thanks to the following people: * Simon Tatham and Julian Hall for the Netwide Assembler; visit the NASM page at http://www.cryogen.com/Nasm * NiX and Butterfly from MASSiVE; they wrote a library with the same purpose for assembly language programmers and this inspired me to write something like that for C/C++ * Ralf Brown for the Interrupt List; get it at ftp://simtel.net/pub/msdos/info/inter??[a-d].zip * Randall Hyde and others for the UCR Standard Library for Assembly Language Programmers (ripped the get_cpu stuff from it) * the Free Software Foundation and any contributers to it (http://www.fsf.org/, http://www.gnu.org/) * Phil Inch (ripped the plasma code in ex4 from one of his pd sources) 7 - questions & answers (Calling this an FAQ wouln't make much sense ;-) Q: My program terminates due to an error. I try to restart it, but it complains about missing extended memory, what's up? A: Your program didn't call exit_flat on termination. Thus, all memory allocated thru an XMM has not been freed. You should either: (a) free the memory by hand (Get Ralf Browns interrupt list!) (b) reboot your computer (c) set em_max to a lower value, if your program works with less memory (d) don't load an XMM at all. Thus, no memory allocation exists and your program always has access to all extended memory Q: I can't get any flat real mode program running, what shall I do? A: Run your computer under plain DOS (not a DOS box or DOSemu) without any extended memory managers like EMM386, QEMM, ... loaded. Preferable not even an XMM. Then, everything should work. You have got a 386 or better, don't you ;-? Q: Your 32-bit file access stuff crashes my computer! What's wrong? A: Did you allocate memory for a transfer buffer? fread32 and fwrite32 will write to the memory pointed to by fbuf_ptr, which is NULL! Randomly writing within the interrupt vector table will definitely *not* help your computer behave normally. It would be a waste of time to check for fbuf_ptr to be valid, within every read or write operation. You have to do this! Q: cpu_type doesn't contain really up-to-date information about my CPU? A: No, init_flat simply detects the presence of a 386 or lower, which is required. Q: Can I use my old 16-bit real mode code with this library? A: Yeah, that's another reason why I originally wrote this stuff. If your code doesn't do something really stupid/tricky (i.e. rely on the wrap around) you shouldn't encounter any problems with your old code. Q: I use a different 16-bit DOS compiler, it refuses to accept flat.h. Help! A: The easiest way is probably to make a few #defines before including flat.h. e.g.: #define far /* you will have to set a memory model yourself, */ /* or pass far-pointers by-hand */ Q: Is there anything I should *not* do with this library? A: There are a few things, either this library or flat real mode are not good for. This primary includes writing TSRs or spawning child processes. It will work, but you will probably have to add some code to the asm kernel to get better control over allocated memory (e.g. the library doesn't follow the convention to let int 0x15 fn 0x88 return a reduced memory size).