Hardware Ports

Atrevida Game Programming Tutorial #6
Copyright 1997, Kevin Matz, All Rights Reserved.

"Prerequisites":

  • Chapter 1: Introduction to Binary and Hexadecimal
  • Chapter 2: Binary Operations
  • Chapter 3: Binary Manipulations

       

What are hardware ports?

Hardware ports are the primary method of communication with external devices and the PC's support chips. (Reading and writing to specific memory locations, or memory-mapped I/O, is the other method; this method is applicable to very few devices, such as the video card. BIOS and DOS services that access hardware devices make use of either hardware ports or memory.)

We can read and write values to and from hardware ports. I like to think of ports as "portholes" or "doorways" through which information can be passed to or retrieved from "the outside world". The term "outside world" is actually quite commonly used, and it usually refers to everything outside of the processor (so the support chips inside the computer are often deemed part of the outside world). When we read from or write to a port, we are actually reading from or writing to memory locations that are not part of the main memory, but are a part of the device that we are programming.

There are 65536 possible hardware ports, although most of them are unused. They are always numbered using hexadecimal, so the range is 0 hex to FFFF hex.

Writing to hardware ports using C/C++

In Turbo/Borland C and C++, we can use the port input/output functions from either dos.h or conio.h.

If we "#include <dos.h>", then we can use the functions (or macros) outportb(), for writing a byte, and outport(), for writing a word.

If we "#include <conio.h>", we can use outp() for writing bytes and outpw() for writing words to hardware ports.

The prototypes for each are listed below:

int outportb (unsigned int port, int value);
unsigned int outport (unsigned int port, unsigned int value);
int outp (unsigned int port, int value);
unsigned int outportw (unsigned int port, unsigned int value);

Notice that outport() and outp() use int types in the places where I think that char types (bytes) would have been more appropriate.

So, as an example, say we wish to write the byte-sized value 85 hex to port number 9D4 hex. We could use either of the following statements:

outportb (0x9D4, 0x85);
outp (0x9D4, 0x85);

What happens if we write a word? Writing a word to a port results in writing a word to a particular device's memory, and that memory must use the little endian format for storing multiple-byte numbers. The least-significant (rightmost) byte of the word is stored in the first memory location, and the most-significant (leftmost) byte of the word is stored in the next memory location. The same effect can be achieved by writing the least-significant byte to a port number "x", and then writing the most-significant byte to the port "x + 1". So, the following code fragments for writing words to ports are equivalent:

outpw (0x9EB, 0x4D3C);

and

outp (0x9EB, 0x3C);
outp (0x9EC, 0x4D);             /* 0x9EB + 1 = 0x9EC */

(Of course, you could replace "outpw" with "outport" and "outp" with "outportb"; just be sure to include the correct header file.)

By writing values to ports, we can send commands or data to devices.

Reading from hardware ports in C/C++

Again, using Turbo/Borland C and C++, we have the choice of using the dos.h or the conio.h routines for accessing the hardware ports.

With dos.h, we can use the inportb() and inport() functions or macros; with conio.h, we can use the inp() and inpw() functions or macros. The syntaxes are listed below:

int inportb (unsigned int port);
unsigned int inport (unsigned int port);
int inp (unsigned int port);
unsigned int inpw (unsigned int port);

Suppose we wish to read a byte from port 76A hex, and store the result in a variable called value. We could use either of the following two statements:

value = inportb(0x76A);
value = inp(0x76A);

Reading a word from a port is similar to writing a word to a port. We must take into account the fact that little endian number storage is used. Reading a word from a port means that the word that is returned is constructed from two bytes: the least-significant byte will come from the first port address "x", and the most-significant byte will come from the next port address, "x + 1". So, the following two examples should be equivalent:

value = inpw(0x4000);

and

value = inp(0x4000) + (inp(0x4001) << 8);

An example of the usage of ports

For an interesting example of how ports can be used, we will construct a short program that accesses some of the VGA's registers. (If you do not have a VGA card (in this case, an EGA should work as well), this example will not work.) The example is fairly involved, but it demonstrates a fairly common situation that is encountered when programming devices through ports.

If you have done any programming in text mode (or drawing "ANSI art") using different colors and attributes, you are aware that each character can have one of sixteen foreground colors, one of eight background colors, and as well, that character's foreground can blink or remain solid. But by manipulating some of the VGA's registers by using ports, we can change this setup: we will be able to select from sixteen colors for the foreground (as usual), but we will be able to select from sixteen background colors instead of eight (but we give up blinking). We will gain access to the "high-intensity" colors, 8 dec through 15 dec, for use as background colors.

First, I'll give some brief background information for using colors in text mode. (Admittedly, this part is unrelated to ports.)

In Borland and Turbo C/C++, with conio.h, there are facilities for changing the foreground and background colors. The function textcolor() accepts an integer in the range 0..15 dec as a parameter, and sets the current color to that value. The function textbackground() accepts an integer in the range 0..7 dec as a paramter, and sets the current background color to that value. For example, to use a bright magenta (pink) foreground on a cyan background, we can use:

textcolor (13);                 /* 13 is the "code" for bright magenta */
textbackground (3);             /* 3 is the "code" for cyan */

Now, to use this tacky color combination, you use the cprintf() function, which works just like printf():

cprintf ("This text is bright magenta, with a cyan background.\n");

To use blinking, you can use a function called textattr(), which takes as its parameter an int in the range 0..255. Here is a bit diagram showing how to construct the color codes:

          7     6     5     4     3     2     1     0
       +-----+-----+-----+-----+-----+-----+-----+-----+
       |BLINK|  R  |  G  |  B  |  I  |  R  |  G  |  B  |
       +-----+-----+-----+-----+-----+-----+-----+-----+
             |<-- Background ->|<---- Foreground ----->|

       Bit 7:  1 = blinking on; 0 = blinking off
       Bit 6:  Background red component on/off
       Bit 5:  Background green component on/off
       Bit 4:  Background blue component on/off
       Bit 3:  High-intensity foreground on/off
       Bit 2:  Foreground red component on/off
       Bit 1:  Foreground green component on/off
       Bit 0:  Foreground blue component on/off

If we wanted blinking bright green text (blink bit + high intensity foreground + green foreground) on a purple background (green background + blue background), our attribute code would be 2^7 + 2^3 + 2^1 + 2^5 + 2^4, or 128 + 8 + 2 + 32 + 16 (decimal), which equals 186 dec. The faster method is to create the pattern 10111010 bin, which is BA hex:

textattr (0xBA);
cprintf ("This is bright green blinking text on a purple background.\n");

Note that when high-intensity backgrounds are enabled, bit 7, the "blinking on/off" bit, will instead be the "high-intensity background on/off" bit. This will allow 16 possible colors for the background.

Now we can return to our discussion of ports.

There is one bit in one of the VGA's registers which, if set, permits blinking, and if cleared, permits high-insensity backgrounds. The register that we need to modify is the "Attribute Controller Mode Control Register". Unfortunately, we cannot write directly to this register in one easy step.

On the VGA, and often with other devices, there are many registers available, but the VGA (or other device) only uses a few ports. The registers need to share the limited number of ports. To allow access to multiple registers, the following scheme is common: an "array" of registers exists that is accessible through an "address" or "index" port and read and/or write ports. You write a number to the index port, which tells the device which register you want to access. If there were, say, ten registers available, and you wanted to write a value to register number 8, you would usually write the number 8 to the index port. Then, you would write the value that you wish to put in register 8 to the write port. Or, if a read port was available, you could read a value from that read port, and you would get returned the current value of register number 8.

This is the way that you access most registers on the VGA. The VGA has several "families" of registers, such as the Sequencer Registers, the CRT Controller Registers, and so on. Each family of registers has an index port and a read and/or write port.

The Attribute Controller family of registers is slightly different, however. There is no real index port, just a write port and a separate read port. Here's how you use it: you first need to "reset" the circuitry controlling the write port. You do this by reading a byte from another VGA port, the "Input Status #1" register (you can throw away the returned byte). Then, you write a specially coded address byte (described shortly) to the write port to indicate which register you wish to access. In the Attribute Controller family, there are twenty registers available (0 hex through to 14 hex). Then, you can either write a value to the selected register through the write port, or you can read a value from that selected register from the read port.

The Input Status #1 register is located at port 3DA hex. The Attribute Controller family's write port is at port 3C0 hex, and its read port is at 3C1 hex.

Here is the format of the address byte for the Attribute Controller family of registers:

          7     6     5     4     3     2     1     0
       +-----+-----+-----+-----+-----+-----+-----+-----+
       | XXXXXXXXX | PAS |             ADR             |
       +-----+-----+-----+-----+-----+-----+-----+-----+

       Bits 6..7:  Unused
           Bit 5:  Palette Address Source bit.  (This should be left as
                   1; if it is 0, the screen goes blank, because the
                   VGA is not allowed to access the memory containing
                   palette information).
       Bits 0..4:  Address index (in the range 0 hex to 14 hex).

The Attribute Controller register we want to access, the Mode Control register, has the index 10 hex. If you're curious about the other nineteen registers in this family, I'd suggest taking a look at the books listed in the "references" section at the end of this article. Here is the format for the Mode Control register:

          7     6     5     4     3     2     1     0
       +-----+-----+-----+-----+-----+-----+-----+-----+
       | IPS | PCS | PPC | XXX | B/I | ELG | DT  | G/A |
       +-----+-----+-----+-----+-----+-----+-----+-----+

       Bit 3:  Blink/Intensity bit.  0 = permit high-intensity
                                         backgrounds
                                     1 = permit blinking (default)

You're probably curious about all of those other bits. I'd like to list them all, but that would take up too much space, and I'd probably be violating some copyrights. Again, if you're interested, check out the "references" section at the end of this article.

So, finally, here's our plan:

masterbation machine, same sex marriage, thong tgp, young kids incest stories, toon orgies, holly marie combs nude, kid fuck, free adult thumb gallery, christian dating websites, homemade bdsm toys, male butt, drizzle rain boots, free paris hilton nude, itv fantasy football, free midget sex thumbnail's, naked army men, teen feet, reality porn reveiws, female celebrity silicone doll, fucking the secretary, door peep holes, deep throat face fuck, cheerleader lesbian sex, chocolate dip creampie, throat, blonde sex clips, butt buffer, daddy's little slut, lesbian sex toy, sakura xxx, fiberglass shower repair do it yourself, used modular office furniture, dad fuck daughter, 1973 mg midget hood release cable, zoo empire screenshots, dildo fucking free, teen cheerleader topless, traditional swallow tattoo flash, chase the hottie brunette, cum covered foot, lesbo group sex, juicy big melons, toon bj, voyeur video free, mature moms with young boys, naked pics of celebreties, amateur swap, adult anime movies, gay xxx, atlanta oral surgery, free naked guys, gay twink facials, mom fucks son stories, free female domination movies, pelvic exam video, ebony girls pics, massaging shower heads, cfnm dvd loverboys, screaming orgasm videos, nylon covered plastiants, face fuck, gay sex cartoons, free asian pussy galleries, tanned strippers, free gay photos, mini-14 peep sight, free nude teen web cams, fun movie clips, stocking teen, sad and shaved, skinny black teen, pierced hood, zoo de quebec, onion butt, amateur facials teri, young twink porn, gothic teen thumbs, philippines maids sponsorship citizenship, good charlotte i just wanna live, dog nail covers, brutal facials, girly feminine tattoos, free deep throat video, adult children of alcoholics, cock, thick dick, gothic fetish clothing, mothers licking daughters pussy, retro game online, minority youth athletic sponsorship, stroy trans gaz, anal creampies, extreme, young horny schoolgirls, screaming orgasm, again does it sylvia, shaved ffm, cedar rapids swap meet, amatuer blowjob, blowjob in public, horny mature housewives, young teens in thongs, eat forced shit, lesbian rimjob, xxx gay outdoor, zoo beastiality, free big nipples, young teenage models, wife swap nude pictures, free gay porn galleries, pornstars nude, nudity publiublic anal sex, dog facial, tiny angel bbs, ebony bbw, black teen feet, panty creampie, ass teen, chubby teens free pictures, fuck her throat, stud horse sex, hot gangbang, xtreme machine tool, retro sports, girl pajama party, redhead teen, extreme tattoos, intruder family rape, toon schoolgirls, dirty white boys, incest art galleries, free adult web cam chats, beastiality penetration, fuck me mommy, watching mom and dad fucking, ffm fucking, pregnant lesbians, graduation cartoons, watching wife have sex, cheerleader, peep skirt, mindy vega hardcore, cartoon doll makers, death fetish, arabic sluts, xxx midget, getting lip pierced, live streaming video cams, underaged porn, hotel burgundy paris, lockdown party, bike youth baseball pants, new nude celeb videos, cheerleaders hot coed, skinny naked girl, sciatic nerve leg pain, trans holly, nail tek hydration therapy, xxx, swallow his cum, history of strep throat, bbw asian galleries, give a facial, midget whore, chubby dildo, boobs mafia, ass, hot chicks wallpaper, black pornstars, amateur pussy, asian tits, toon nude, hot tanned nude babes, extreme 3d, milf lesbians, ebony strapon, bondage spanking, extreme cfnm clips, hot blondes in panties, sexual fantasy stories, extreme porn, girls first masturbation, ashley macisaac bitch -release, amateur milf, spanking boy, used military history books, speculum page one, free female orgasm movies, real life rape stories, fucking sexy toons, birth defects vagina, midget on woman sex, babes sading there legs, closeup, huge clit picture, teen lesbo, naked drunk chicks, shemale comics, titty fuck, double dildo sex, brazil trannys, tits secretaries galleries, dirty old ladies, final fantasy 7 doujinshi, cat vagina, butt fucked, girls with legs sad, free nude pics of celebs, saggy tits, sylvia davies, gay anal, hot scat, female flashers in public, amature redhead, orgasm videos, incest board, beach celeb paparazzi, bsdm bondage domination furniture, moms masturbating, live nude cam

  1. Read in a byte from the Input Status #1 register (port 3DA hex).
  2. Construct an index or address byte. The register we want to access has the index 10 hex, and we want to turn on bit 5, which we can do by OR'ing the index number with 20 hex, like this: "index_byte = 0x10 | 0x20;"
  3. Output index_byte to the Attribute Controller family's write port (port 3C0 hex).
  4. Read in the value from the register we have selected by inputting a byte from the read port (port 3C1 hex). Store this value in a temporary variable such as x.
  5. Set (to permit blinking) or clear (to permit high-intensity background colors) the Blink/Intensity bit (bit 3) in x. To turn that bit on, we could use "x |= 0x80;". To turn that bit off, we could use "x &= 0xF7;".
  6. We want to write the value in x back to the Mode Control register, so to "reset" the write port's circuitry, read in a byte from the Input Status #1 register again (port 3DA hex).
  7. Output our index byte to the write port (3C0 hex) again.
  8. Write out the new value of x to the write port (3C0 hex).

Let's construct two functions in C using the above algorithm. EnableBlinking() will enable blinking, and EnableHighIntensityBackgrounds() will enable high-intensity backgrounds. While we're at it, let's write a short function to draw characters on the screen, using all of the different attribute codes from 0 to 255 dec. This will let us see the results of the change. In our main() function, we will draw the colored characters, wait for a keypress, switch to high-intensity background mode, wait for a keypress, and then return to blinking-enabled mode:

/* VGAREGS1.C: Quick VGA registers test program
   Copyright 1997, Kevin Matz, All Rights Reserved.

   This program displays some text-mode color patterns on the screen, and
   then switches between blinking and high-intensity modes.

   References used:
   - "Programmer's Guide to the EGA, VGA, and Super VGA Cards, Third
	 Edition", Copyright 1994, Richard F. Ferraro.  Addison-Wesley
	 Publishing Co., Inc., Reading, Massachusetts.  ISBN 0-201-62490-7.
   ------------------------------------------------------------------------*/

#include <stdio.h>
#include <conio.h>
#include <dos.h>

void DrawColorPatterns ();
void EnableBlinking ();
void EnableHighIntensityBackgrounds ();

main ()
{
    DrawColorPatterns ();

    printf ("This is the normal (blinking) state.\n");
    getch ();

    EnableHighIntensityBackgrounds ();
    printf ("This is the high-intensity background state.\n");
    getch ();

    EnableBlinking ();
    printf ("This is the blinking state again.\n");
    getch ();

    return 0;
}

void DrawColorPatterns ()
{
    int x, y, attribute;

    /* Draw the asterisk character with every possible text-mode
       attribute: */
    attribute = 0;
    for (x = 0; x <= 15; x++)
    {
        for (y = 0; y <= 15; y++)
        {
            textattr (attribute++);
            cprintf ("*");
        }

        textattr (0);
        printf ("\n");
    }

    /* Revert to the standard text colors: */
    textcolor (7);
    textbackground (0);
}


void EnableBlinking ()
{
    unsigned char old_mode_ctrl_reg;

    /* Read from the Input Status #1 register and throw away the returned
       value.  This is done to tell the Attribute Controller's write port
       to accept an index byte next. */
    inportb (0x3DA);
    /* Tell the VGA that we want to access the Attribute Controller's Mode
       Control Register (AC Index 10h); also, prevent the clearing of the
       screen, by setting bit 5 on: */
    outportb (0x3C0, 0x10 | 0x20);
    /* Get the current value: */
    old_mode_ctrl_reg = inportb(0x3C1);

    inportb (0x3DA);               /* Reset circuitry again. */
    outportb (0x3C0, 0x10 | 0x20); /* Indicate that we want AC Index 10h. */

    /* Turn on bit 4 (the Enable Blink or Intensity bit): */
    outportb (0x3C0, old_mode_ctrl_reg | 0x08);
}


void EnableHighIntensityBackgrounds ()
{
    unsigned char old_mode_ctrl_reg;

    /* Read from the Input Status #1 register and throw away the returned
       value.  This is done to tell the Attribute Controller's write port
       to accept an index byte next. */
    inportb (0x3DA);
    /* Tell the VGA that we want to access the Attribute Controller's Mode
       Control Register (AC Index 10h); also, prevent the clearing of the
       screen, by setting bit 5 on: */
    outportb (0x3C0, 0x10 | 0x20);
    /* Get the current value: */
    old_mode_ctrl_reg = inportb(0x3C1);

    inportb (0x3DA);               /* Reset circuitry again. */
    outportb (0x3C0, 0x10 | 0x20); /* Indicate that we want AC Index 10h. */

    /* Turn off bit 4 (the Enable Blink or Intensity bit): */
    outportb (0x3C0, old_mode_ctrl_reg & 0xF7);
}

/* End of listing */

Remember that you need to use the textattr() function to use blinking or high-intensity background characters. The bit diagram for determining color and attribute codes was described previously.

This example program shows that, by using ports (and systems programming in general), we can do many interesting and "amazing" things. For another program, I was able to shift the image on the screen back and forth (distorting some of the colors in the process) by changing the timing settings for a horizontal retrace counter register. Admittedly, this doesn't have any practical uses, but I think it does fall into the "cool" category.

Summary

Hardware ports allow us to access registers and memory locations on certain hardware devices. In C/C++, we can use functions such as inport(), inportb(), inp(), and inpw() to read from ports. To write to ports, we can use function such as outport(), outportb(), out(), and outw(). With some devices, you may need to set up an index through one port and read or write through another (or, in the example presented in this chapter, index and read/write ports may be shared).

References to material (sources used)

Ferraro, Richard F. "Programmer's Guide to the EGA, VGA, and Super VGA Cards, Third Edition". Reading, MA, USA: Addison-Wesley Publishing Co., Inc., 1994. ISBN: 0-201-62490-7.

(This rather thick book contains descriptions of all of the VGA's registers, as well as information on all of the major Super VGA chipsets. One of the chapters contains a decent selection of sample code. This book has been criticized as being full of minor errors, and while I have spotted a number of errors, I don't think the problem is too serious.)

There is an older book about the VGA and its registers that I am aware of. I believe the author's name is Wilton. I haven't seen this book, but when I find more information, I'll put it here.

  

Copyright 1997, Kevin Matz, All Rights Reserved. Last revision date: Wed. Jun. 04, 1997.

Go back

A project