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