www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1998/06/17/16:00:40

From: brunobg AT geocities DOT com (Bruno Barberi Gnecco)
Newsgroups: comp.os.msdos.djgpp
Subject: Re: far pointers using djgpp
Date: Wed, 17 Jun 1998 19:55:08 GMT
Organization: UNINET (Unisys Brasil Internet Access Service)
Lines: 224
Message-ID: <35881d34.2869157@news.unisys.com.br>
References: <Pine DOT SOL DOT 3 DOT 95 DOT 980617000723 DOT 17603A-100000 AT tiger DOT vut DOT edu DOT au>
NNTP-Posting-Host: saopm06p18.unisys.com.br
To: djgpp AT delorie DOT com
DJ-Gateway: from newsgroup comp.os.msdos.djgpp

On Tue, 16 Jun 1998 14:12:23 GMT, Butler Owen scm2211 <s9708172 AT tiger DOT vut DOT edu DOT au>
wrote:

>I would like to create a pointer to my VGA cards memory.  I know this
>starts at 0xA000,0000 
>in another compiler I would use:
>char far *screen= (char far *) MK_FP(0xa000,0);
>problems arise:
>1. djgpp does not support the "far" keyword
>2. the implementation of "dos.h" that comes with djgpp does not contain
>MK_FP()
>if I try this:
>char * screen = (char *) 0xa0000000;
>it compiles fine, then crashes at the point I try and set anything through
>this pointer.
>Any suggestions?

You need to use the _far* functions... Here is a little tutorial I wrote. It's
basic, but once you understand far pointers in DJGPP it's easy to go deeper. Hope
it helps, any questions, please email me.

-----------cut----------
                           Far pointers and DJGPP

Comments, suggestions, questions or anything? Please contact the author,
Bruno Barberi Gnecco, via email: brunobg AT geocities DOT com.

Introduction

One of the most frequent questions in comp.os.msdos.dgjpp is how to work
with far pointers in DJGPP, so I'll try to make a brief explanation.

Some compilers have a keyword far. When one declares a far pointer, like:

char far *ptr;

it means: create a pointer to a memory address. Far pointers let you access
RAM memory using DOS memory address type (SEGMENT:OFFSET). But, as DJGPP
uses DPMI and protected mode, you can't directly access memory like in
others compilers.

There's a way to do it, however; in fact, many of them. You can read about
in FAQ section 18, specially in question 4. We'll discuss just one of them:
using _far*.

Basic memory operations

DJGPP has a library, sys/farptr.h to deal with direct memory operations.
The functions of the library can be divided basically in two: peek and
poke. Peek functions are used to get information from memory, while poke
functions move information to memory.

Any color video adapter has its video RAM at B800:0000. Monochrome adapter
has it at B000:0000. As monochrome adapters are really hard to find
nowadays, I'll use B800 as the beginning of video RAM. You, can however,
write a function to know which adapter is in the system: interrupt 16,
function 15 returns the current video mode; if the mode is 7, it's a
monochrome adaptor. We'll be using the default videomode, 3, which is 80x25
and 16 colors.

You should know that video memory requires two bytes for each character:
one is the character to be displayed, the second is the attribute. So, it
takes 160 bytes for each line, and 4000 bytes to display a whole screen.

It's important also to know how addresses will be used in the _far*
functions: you should use the formula

address = segment*16+offset

Let's start with an example: we want to print 'Godzilla', beggining at 0,0
(the top-left of the screen). Let's write:

#include <go32.h>
#include <sys/farptr.h>
#include <string.h>
#define NORMAL 7

int main() {
        int i, limit;
        char *st = "Godzilla";
    limit = strlen(st);
    for ( i = 0; i < limit; i++ ) {
        _farpokeb(_dos_ds, 0xB800*16+2*i, *st++ );
        _farpokeb(_dos_ds, 0xB800*16+2*i+1, NORMAL );
        }
        return 0;
}

Let's see this code. First, we must include sys/farptr.h, which contains
the _far* functions, and go32.h, which contains _dos_ds (which is just a
shortcut to _go32_info_block.selector_for_linear_memory. We'll talk about
his later. In main(), we create two ints, a string, set the value of limit
to the length of the string. Next, we open a for, which will count, one by
one, from zero to limit. Now, the interesting part.

_farpokeb is the function which copies a byte to a specific position in
memory. Its sintax is: (unsigned short selector, unsigned long offset,
unsigned char val). The selector we will use is _dos_ds, which let's use
DOS memory and use the formula above for calculating the offset, which is
the second parameter. Last, but not least, the third parameter is what you
want to print. In the example, we print each one of the characters. And the
second _farpokeb? Remember, you have to set the attribute of the character:
it's the next position in memory.

The colorful world of video memory

Now you know the basics of direct video memory manipulation. Let's continue
using the attributes. Here's a table of them:

                    Bit  Binary value  What does it do?

                    0    1             blue foreground

                    1    2             green foreground

                    2    4             red foreground

                    3    8             low intensity

                    4    16            blue background

                    5    32            green background

                    6    64            red background

                    7    128           blinking

Combining it, you can display 16 colors (low intensity creates a 'light'
color). The value passed to _farpokeb is usually in hexadecimal or decimal.
Example: we want a green letter in a purple background. Summing up, it's:
5A, or 90. We can use then:

_farpokeb(_dos_ds, 0xB800*16+2*i, *st++ );
_farpokeb(_dos_ds, 0xB800*16+2*i+1, 0x5A );

EXERCISE: create a program that displays the number of attribute in
decimal, and set each number's attribute to the number's value.

More about addresses: row, column, and _farsetsel

You don't need to type _dos_ds every time you use _farpoke* or _farpeek*.
If you write:

_farsetsel(_dos_ds);

you can use _farns*. Example:

_farsetsel(_dos_ds);
for ( i = 0; i < limit; i++ ) {
   _farnspokeb( 0xB800*16+2*i, *st++ );
   _farnspokeb( 0xB800*16+2*i+1, NORMAL );
}

Using _farsetsel(_dos_ds); is also faster than set it every time you use
_far*.

Now, supposing you want to write 'B' at position 50,18 (51th column, 19th
row). How to do? Well, if a line has 80 characters, and each character is 2
bytes long in video memory, each line is 80*2=160 characters long. So, we
can use:

_farnspokeb( 0xB800*16+160*18+2*50, character );

or, generally:

offset = 0xB800*16+160*line+2*column

Peeking the memory

Now that we now how to get an specific position in memory given a pair
(x,y), we have an use for _farpeek* functions. They are used almost the
same way their brothers:

  char ch = _farpeekb( _dos_ds, 0xB800*16+2*x+160*y );

The differences are: as peek gets from memory, the return value should be
put in a variable; and there's no third parameter.

Peek functions are used to save the screen (or some area of it). Let's do
an example: we want to print "This is a phrase" with reverse attribute (or
white background) at (26,10), wait for a key, and then restore whatever was
in that position.

#include <go32.h>
#include <sys/farptr.h>
#include <string.h>

void pause(void) {
     while( !bioskey(1) ) { }
}

int main() {
        int i, length;
        char *st = "This is a phrase";
        char buffer[(2 * strlen(st))];
    length = strlen(st);
    _farsetsel(_dos_ds);
    for ( i = 0; i < length; i++ ) {
        buffer[2*i] = _farnspeekb( 0xB800*16+160*Y+2*(X+i) );
        buffer[2*i+1] = _farnspeekb( 0xB800*16+160*Y+2*(X+i)+1 );
        _farnspokeb( 0xB800*16+160*Y+2*(X+i), *st++ );
        _farnspokeb( 0xB800*16+160*Y+2*(X+i)+1, 0x70 );
    }
    pause();
    for ( i = 0; i < (2*length); i++ ) {
        _farnspokeb( 0xB800*16+160*Y+2*(X)+i, buffer[i] );
    }
    return 0;
}

Text by Bruno Barberi Gnecco < brunobg AT geocities DOT com>
---------------cut--------------
Note that it's the same if you want to use VGA memory. For example:
for ( i = 0; i < 320*200; i++ ) {
        _farnspokeb( 0xA000*16+i, buffer[i] );
}

Or something like it... 

"There's never enough time to do all the nothing you want" Bill Watterson 
"Is ALL that we see or seem / But a dream within a dream?" - Edgar A. Poe
Bruno Barberi Gnecco <brunobg AT geocities DOT com> ICQ #1383173 - PGP 5.0i user
-=My other OS is Linux=- 3DS4, Max, Rhino, Photoshop and everything about 
computer graphics? It sure is on Graphx Page!!! http://graphx.home.ml.org

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019