Listing 1: A unified device and interrupt controller management class

// a fifo implementation of some kind
class fifo_c {
public:
  fifo_c();
  void put (int c);
  int get (void);
};

// Part of a driver class for a hypothetical, memory-mapped, 
// interrupt driven serial i/o device tied to the host processor 
// through an interrupt controller chip.
class device_c {
private:
  // transmit buffer
  static fifo_c txbuf;

  // register map for the device
  enum {TR = 0, SR = 1, CR = 2};

  // the lsb of SR is the status of the transmitter
  // interrupt request signal; the lsb of CR is the
  // transmitter enable.
  enum {SR_TXI = 1, CR_TXE = 1};

  // the base memory address of the device
  volatile static char* devaddr;

  // commands for the interrupt controller hardware
  enum {ACK=0, EN=1, DIS=2};

  // the base memory address of the interrupt controller
  volatile static char* irqaddr;

  // a this-lookalike, for nonstatic data
  static device_c* me;

  // nonstatic interrupt counter
  int interrupts;

public:

  // the device interrupt handler
  static void isr (void);

  device_c (char* devioaddr, char* irqioaddr)
  {
    // Save our "this" pointer.
    me = this;

    // Save the device's hardware address.
    devaddr = devioaddr;

    // Save the address of the interrupt controller.
    irqaddr = irqioaddr;
  };

  void write (char c)
  {
    // Stuff the byte into the transmit buffer.
    txbuf.put(c);

    // Enable the transmitter.  The transmit interrupt
    // handler will subsequently grab the byte out
    // of the buffer and stuff it to the hardware.
    devaddr[CR] |= CR_TXE;
  }
};

#pragma interrupt
void device_c::isr (void)
{
  int c;

  // Count the interrupt.  The interrupt count
  // is non-static, thus we have to use our copied
  // "this" pointer to find it.
  me->interrupts++;

  // Acknowledge the interrupt request
  // to the interrupt controller chip.
  *irqaddr = ACK;

  // Figure out what the interrupt request is, and
  // service it.  We may have multiple requests
  // pending, so try to service them all.
  while (devaddr[SR]) {

    if (devaddr[SR] && SR_TXI) {
      // The transmitter wants another byte,
      // give it one if we have one.
      if ((c = txbuf.get()) != -1 )
        devaddr[TR] = c;
    }

    // Handle other types of device interrupts here.
    // ...
  }

  // Re-enable interrupt requests through the controller.
  *irqaddr = EN;

  // If the "interrupt" pragma is supported, then this
  // return is an RTE instead of an RTS. If the pragma
  // isn't supported then we'll need a wrapper function;
  // see the article text for an example.
  return;
}

device_c serial1((char*)0xffff0000, (char*)0xffffef00);
extern void (*interrupt_vector_table[])();
#define IRQ_DEVICE 1

int main ( void )
{
  const char* hello = "hello, world!\n";
  const char* hellop =  hello;
  
  interrupt_vector_table[IRQ_DEVICE] = serial1.isr;
  while (*hellop) serial1.write(*hellop++);
  return 0;
}
— End of Listing —