// A uniform framework for device interrupt handlers.
class irq_handler_c {
public: virtual void isr (void) {return;}
};
// Code to manage a hypothetical interrupt
// controller chip, through which a device
// of type device_c and others is connected.
class irq_controller_c {
private:
// Table of device interrupt handlers.
static irq_handler_c* device_table[];
// Memory address of the controller chip.
volatile static char* irqaddr;
// Commands recognized by the controller chip.
enum {ACK = 0, EN = 1, DIS = 2};
public:
// The controller's interrupt handler. The microprocessor gives
// control to this function whenever any device connected to the
// controller issues an interrupt request.
static void isr (void);
irq_controller_c (char* irqioaddr) {irqaddr = irqioaddr;};
// When a device handler wants interrupt requests for a device,
// it registers with us using this function.
void register_handler (int irq, irq_handler_c* handler)
{
device_table[irq] = handler;
return;
}
};
#pragma interrupt
void irq_controller_c::isr (void)
{
int irq;
// Tell the controller we're starting interrupt processing.
*irqaddr = ACK;
// determine which device is reqesting service
irq = *irqaddr;
// Invoke the interrupt handler for the requesting device.
device_table[irq]->isr(irq);
// We're done, reenable the interrupt request line.
*irqaddr = EN;
return;
}
// The interrupt controller chip has 16 request lines.
irq_handler_c* irq_controller_c::device_table[16];
// The reimplemented device_c class, with interrupt
// controller management-related code removed since
// that responsibility now goes to irq_controller_c.
class device_c : public irq_handler_c {
private:
fifo_c txbuf;
enum {TR = 0, SR = 1, CR = 2};
enum {SR_TXI = 1, CR_TXE = 1};
volatile static char* devaddr;
int interrupts;
public:
void isr (int irq);
device_c (char* devioaddr) {devaddr = devioaddr;}
void write (char c) {txbuf.put(c); devaddr[CR] |= CR_TXE;}
};
void device_c::isr (void)
{
int c;
interrupts++;
while (devaddr[SR]) {
if (devaddr[SR] && SR_TXI) {
if ((c = txbuf.get()) != -1 )
devaddr[TR] = c;
}
// ...
}
return;
}
extern void (*interrupt_vector_table[])();
// The irq controller chip is tied to entry 100
// of the host microprocessor's interrupt vector table.
// The controller chip is located at address 0xfffffe00.
#define IRQ_CONTROLLER 100
irq_controller_c irqctl((char*)0xfffffe00);
// The serial device is tied to pin 1 of the interrupt controller,
// and is located at address 0xffff0000.
#define IRQ_DEVICE 1
device_c serial1((char*)0xffff0000);
int main ( void )
{
const char* hello = "hello, world!\n";
const char* hellop = hello;
irqctl.register_handler(IRQ_DEVICE, &serial1);
interrupt_vector_table[IRQ_CONTROLLER] = irqctl.isr;
while (*hellop) serial1.write(*hellop++);
return 0;
}
End of Listing