I/O Access using Inline Assembly


About This Guide
System Requirments
Introduction
The Basics
Things to Remember
An Example
Related Sites

About This Guide

The basis for this guide was sent to me by Armin Bauer(thanks!). It shows the basics on accessing hardware I/O ports using inline asm with GCC based compilers.

System Requirments

The code in this guide requires:

  • Intel compatible 386 or greater cpu
  • GCC/DJGPP
  • DOS (for some of the examples)

Introduction

This guide show how, using inline assembly, to preform hardware I/O access from within a single C source file. If the assembly syntax looks strange to you, it's because it's in AT&T syntax. GCC's built in assebler, GAS, uses AT&T syntax assembly. Take a look at Related Sites if you'd like to learn more about using inline assemble with GCC/DJGPP.

The Basics

The following code is the basis of all our C based I/O access:

// --------------------------------------------------------------------------
// From NOPE-OS
// --------------------------------------------------------------------------
// [email protected]
// --------------------------------------------------------------------------


/* Input a byte from a port */
inline unsigned char inportb(unsigned int port)
{
   unsigned char ret;
   asm volatile ("inb %%dx,%%al":"=a" (ret):"d" (port));
   return ret;
}

/* Output a byte to a port */
/* July 6, 2001 added space between :: to make code compatible with gpp */

inline void outportb(unsigned int port,unsigned char value)
{
   asm volatile ("outb %%al,%%dx": :"d" (port), "a" (value));
}

First this is the Sourcecode to acces I/O-Ports. You'll need this Routines to acces I/O Ports, but not to access Memory (like Screen Memory). If you don't know, what inline means: Inline make's your compiler not to create a function. this let's the compiler insert the code in the line where the inline function is called.

-Armin Bauer

Things to Remember

The above code only reads and write bytes. If you need to read or write words or double word, all you have to do is change the function names, the size of the accumlative register (al, ax, eax), and the return and argument types for each function. Also remember that some hardware devices must have interrupts disabled while accessing them.

An Example

The following example shows how to read the CMOS's extended memory count value. It's meant to be run under DOS/Win(because of the printf). If you want to try this example out under DOS, don't forget a DPMI extender that's required for all DJGPP apps.

#include <stdio.h>

/* Input a byte from a port */

inline unsigned char inportb(unsigned int port)
{
   unsigned char ret;
   asm volatile ("inb %%dx,%%al":"=a" (ret):"d" (port));
   return ret;
}


/* Output a byte to a port */
/* July 6, 2001 added space between :: to make code compatible with gpp */

inline void outportb(unsigned int port,unsigned char value)
{
   asm volatile ("outb %%al,%%dx": :"d" (port), "a" (value));
}


/* Stop Interrupts */
inline void stopints()
{
  asm ("cli");
}

unsigned char highmem, lowmem;
unsigned int mem;


int main()
{

/* need to stop ints before accessing the CMOS chip */
  stopints();

/* write to port 0x70 with the CMOS register we want to read */
/* 0x30 is the CMOS reg that hold the low byte of the mem count */
  outportb(0x70,0x30);


/* read CMOS values from port 0x71 */
  lowmem = inportb(0x71);


/* write to port 0x70 with the CMOS register we want to read */
/* 0x31 is the CMOS reg that hold the high byte of the mem count */
  outportb(0x70,0x31);


/* read CMOS values from port 0x71 */
  highmem = inportb(0x71);


/* fix the low and high bytes into one value */
  mem = highmem;
  mem = mem<<8;
  mem += lowmem;

  printf("\nOld style CMOS extended memory count is %uk.\n", mem);
}
Source code is here and a precompiled binary is here.

Related Sites

DJGPP QuickAsm Programming Guide
Inline Assembler in DJGPP