Basics

Working on the assumption that you are in protected mode and not using the BIOS to do screen writes, you will have to do screen writes direct to "video" memory yourself.

This is quite easy to do, the text screen video memory for colour monitors resides at 0xB8000, and for monochrome monitors it is at address 0xB0000.

Text mode memory takes two bytes for every "character" on the screen. One is the ASCII code byte and the other the attribute byte. so HeLlo is stored as

0x000b8000: 'H', colourforH
0x000b8002: 'e', colourfore
0x000b8004: 'L', colourforL
0x000b8006: 'l', colourforl
0x000b0008: 'o', colourforo

The attribute byte carries the foreground colour in its lowest 4 bits and the background color in its highest 3 bits. The bit #7 's interpretation depends on how you (or the BIOS) configured the hardware (see VgaResources for additionnal info).

For instance, using 0x00 as attribute means black-on-black (you'll see nothing). 0x07 is lightgrey-on-black (dos default), 0x1F is white-on-blue (Win9x's blue-screen-of-death), 0x2a is for green-monochrome nostalgics :P

For colour video cards, you have 16kb of text video memory to use, and since 80x25 mode (80x25x2==4000 bytes per screen) does not use all 16kb, you have what is known as 'pages' and in 80x25 screen mode you have 8 display pages to use.

When you print to any other page than 0, it will not appear on screen until that page is enabled or "copied" into the page 0 memory space.

Writing strings

If you have a pointer to video memory and want to write a string, here is how you might do it;

        /* note this example will always write to the top
           line of the screen */
        void write_string(int colour, char *string)
        {
                char *video=(char*)0xB8000;
                while(*string!=0)
                {
                        *video=*string;
                        string++;
                        video++;
                        *video=colour;
                        video++;
                }
        }

Okay for strings, but how do i print numbers ?

just like in any environment: convert the number into a string, then print the string. E.g. since 1234 = 4 + 10*3 + 100*2 + 1000*1, if you recursively divide "1234" by ten and use the result of the division, you get all the digits:

1234 = 123*10 + 4
123 = 12*10 + 3
12 = 1*10 + 2
1 = 1

digits to be displayed are '1','2','3','4' ... if you know the numerical value of number%10, you simply have to add this to the character '0' to have the correct character (e.g. '0'+4 == '4')

(see more on the forum)

How do i print formatted messages (a la printf) ?

If you're working with C, you may want to print any number of arguments and you may have looked at the stdarg.h file from other Operating Systems (e.g. linux 0.1 and Thix 0.3.x). These macro definitions may be a bit weird to understand as they're basically C voodoo using pointers and casts and sizeof. Beware before porting them to 16 bits system, though.

va_start() points to the first variable argument. va_arg() advances the pointer, then evaluates to the previous argument (comma operator). va_end() doesn't do anything.

E.g. to implement va_start(), you extract the address of the last 'known' argument and advance (yes, it's a + since you're rewinding the stack) to the next stack item. The voodoo comes to the fact that things are automatically aligned on 32bits boundary on the stack, even if just 1 byte. Under gcc, the __builtin_next_arg() function may help you. Versions 3.x even seem to have __builtin_va_start(), __builtin_va_end() and __builtin_va_arg() so no black magic is required at all.

va_arg() usually require a bit more black magic since you have two things to do:

You can get stdarg.h, _printf.h and doprintf.c from geezer/osd. It seems a spider ate Geezers website, here's a mirror from archive.org.

Uh ? I get nothing displayed at all ...

Keep in mind that this way of writing to video memory will only work if the screen has been correctly set up for 80x25 video mode (which is mode 03). You can do this either by initializing every VGA register manually or by calling the Set Video Mode service of the BIOS Int10h while you're still in real mode (in your bootsector, for instance). Most BIOSes does that initialization for you, but some other (mainly on laptops) do not. Check out Ralf Browns Interrupt List for details. Note also that some modes that are reported as "both text&graphic" by mode lists are actually graphic modes with BIOS functions that plot fonts when you call char/message output through Int10h (which means you'll end up with plain graphic mode once in ProtectedMode)

More hints for non-working implementations on Help! I cannot print to screen !?


Categories: HowTo, HardWareVga