DJGPP VGA access

Ok, I'm gonna have to assume you already know about accessing the VGA in real mode.

Setting the mode

So first, you need to set your mode, like so:
#include <dpmi.h>
__dpmi_regs regs;

memset(&regs, 0, sizeof regs); = 0x13; /* 0x13 is the mode number */
__dpmi_int(0x10, &regs);
Ok, you've got the mode. Now, how do we write to the frame buffer?

Writing to the frame buffer

You have 3 options:
  1. dosmemput(). Example: dosmemput(framebuffer, 64000, 0xa0000) would put the entirety of framebuffer onto the screen. The least fast. Also look at _dosmemputw and _dosmemputl, which write words and longwords, respectively. Notice the use of 0xa0000 instead of 0xa000 due to this function referring to physical memory locations.

  2. far pointers. Basically, these are macros that compile to one or two assembly MOV, but use FS to override memory protection. Example:
    #include <sys/farptr.h>
    #include <go32.h> /* for _dos_ds */
    _farpokeb(_dos_ds, 0xa0000, 1)

    sets the pixel in the upper left hand corner of the screen to 1. It compiles to:

      movl $0xa0000, %eax
      movw $_dos_ds, %fs
      movb $1, fs:(%eax)

    as long as you have at least -O1 turned on. (That's kind of a mangled AT&T+TASM syntax.) You can do a _farsetsel(_dos_ds) once before your sequence of peeks and pokes, and it'll leave FS set, and you can then use the _farns* functions like so:

    #include <sys/farptr.h>
    #include <go32.h> /* for _dos_ds */
    _farnspokeb(0xa0000, 1);
    _farnspokeb(0xa0001, 2);

    which will avoid loading FS every iteration.

  3. But those still ain't fast enough? That's when to break out the near pointers. Basically, you can address the DOS area with your default DS, it's just that it's protected from you. But you can change that with __djgpp_nearptr_enable(). What's the catch? It turns off ALL memory protection on the DOS memory area (first 640k)! Use at your own risk.

    #include <sys/nearptr.h>
    char *screen;
    if (__djgpp_nearptr_enable() == 0) return ERROR; /* could happen */
    /* You must recalculate the screen pointer every time you enter this mode
    because __djgpp_conventional_base can change when you malloc/new and other
    misc stuff. */
    screen = 0xa0000 + __djgpp_conventional_base;
    screen[0] = 1;
    screen[1] = 1;
    /* etc. */

    Each of those screen moves is one instruction, of course. And screen is a honest-to-god [19] pointer, that you can memcpy to and from, or whatever. (Hint: If the length of a memcpy is fixed, and -O1 and up is turned on, memcpy becomes an inline rep movsl (rep movsd in TASM notation).)

    Extra Note: __djgpp_nearptr_enable() is SLOW. Call it at most once per frame, and preferably just once at startup. While you're still debugging, though, you might want to turn it off and on per memory access.


Cheesey putpixel via dosmemput():
#include <sys/movedata.h>

void putpixel(int x, int y, int c) {
  _dosmemputb(&c, 1, 0xa0000 + x + y * 320);
Cheesey putpixel via far pointers:
#include <sys/farptr.h>
#include <go32.h> /* for _dos_ds */

void putpixel(int x, int y, int c) {
  _farpokeb(_dos_ds, 0xa0000 + x + y * 320, c)
Cheesey putpixel via near pointers:
#include <sys/nearptr.h>

void init_putpixel(void) {

void putpixel(int x, int y, int c) {
  char *screen = 0xa0000 + __djgpp_conventional_base;

  *(screen + x + y * 320) = c;

The palette

Never fear, you've still got outs, they're just named outportb/outportw now.

Example code:

#include <pc.h>

char my_palette[768]; /* 256 rgb triplets */

void get_palette(char *pal) {
  int i;
  /* get the palette */
  outportb(0x3c7, 0); /* want to read */
  for (i = 0; i < 768; i++)
    pal[i] = inportb(0x3c9);

void set_palette(char *pal) {
  int i;
  /* set palette */
  outportb(0x3c8, 0); /* want to write */
  for (i = 0; i < 768; i++)
    outportb(0x3c9, pal[i]);
You'll also want to see the main DJGPP + Games page, of course. Written by