// Copyright Notice
// ================
// BOCHS is Copyright 1994-1999 by Kevin P. Lawton.
//
// BOCHS is commercial software.
//
// For more information, read the file 'LICENSE' included in the bochs
// distribution.  If you don't have access to this file, or have questions
// regarding the licensing policy, the author may be contacted via:
//
//     US Mail:  Kevin Lawton
//               439 Marrett Rd.
//               Lexington, MA 02421-7714
//
//     EMail:    bochs@world.std.com



#include "bochs.h"



#if BX_USE_PIC_SMF
bx_pic_c bx_pic;
#define this (&bx_pic)
#endif



bx_pic_c::bx_pic_c(void)
{
}

bx_pic_c::~bx_pic_c(void)
{
  // nothing for now
}


  void
bx_pic_c::init(bx_devices_c *d)
{
  BX_PIC_THIS devices = d;

  /* 8259 PIC (Programmable Interrupt Controller) */
  BX_PIC_THIS devices->register_io_read_handler(this, read_handler, 0x0020, "8259 PIC");
  BX_PIC_THIS devices->register_io_read_handler(this, read_handler, 0x0021, "8259 PIC");
  BX_PIC_THIS devices->register_io_read_handler(this, read_handler, 0x00A0, "8259 PIC");
  BX_PIC_THIS devices->register_io_read_handler(this, read_handler, 0x00A1, "8259 PIC");

  BX_PIC_THIS devices->register_io_write_handler(this, write_handler, 0x0020, "8259 PIC");
  BX_PIC_THIS devices->register_io_write_handler(this, write_handler, 0x0021, "8259 PIC");
  BX_PIC_THIS devices->register_io_write_handler(this, write_handler, 0x00A0, "8259 PIC");
  BX_PIC_THIS devices->register_io_write_handler(this, write_handler, 0x00A1, "8259 PIC");


  BX_PIC_THIS s.master_pic.single_PIC = 0;
  BX_PIC_THIS s.master_pic.interrupt_offset = 0x08; /* IRQ0 = INT 0x08 */
  /* slave PIC connected to IRQ2 of master */
  BX_PIC_THIS s.master_pic.u.slave_connect_mask = 0x04;
  BX_PIC_THIS s.master_pic.sfnm = 0; /* normal nested mode */
  BX_PIC_THIS s.master_pic.buffered_mode = 0; /* unbuffered mode */
  BX_PIC_THIS s.master_pic.master_slave  = 0; /* no meaning, buffered_mode=0 */
  BX_PIC_THIS s.master_pic.auto_eoi      = 0; /* manual EOI from CPU */
  BX_PIC_THIS s.master_pic.imr           = 0xFF; /* all IRQ's initially masked */
  BX_PIC_THIS s.master_pic.isr           = 0x00; /* no IRQ's in service */
  BX_PIC_THIS s.master_pic.irr           = 0x00; /* no IRQ's requested */
  BX_PIC_THIS s.master_pic.read_reg_select = 0; /* IRR */
  BX_PIC_THIS s.master_pic.irq = 0;
  BX_PIC_THIS s.master_pic.INT = 0;
  BX_PIC_THIS s.master_pic.init.in_init = 0;
  BX_PIC_THIS s.master_pic.init.requires_4 = 0;
  BX_PIC_THIS s.master_pic.init.byte_expected = 0;
  BX_PIC_THIS s.master_pic.special_mask = 0;

  BX_PIC_THIS s.slave_pic.single_PIC = 0;
  BX_PIC_THIS s.slave_pic.interrupt_offset = 0x70; /* IRQ8 = INT 0x70 */
  BX_PIC_THIS s.slave_pic.u.slave_id = 0x02; /* slave PIC connected to IRQ2 of master */
  BX_PIC_THIS s.slave_pic.sfnm       = 0; /* normal nested mode */
  BX_PIC_THIS s.slave_pic.buffered_mode = 0; /* unbuffered mode */
  BX_PIC_THIS s.slave_pic.master_slave  = 0; /* no meaning, buffered_mode=0 */
  BX_PIC_THIS s.slave_pic.auto_eoi      = 0; /* manual EOI from CPU */
  BX_PIC_THIS s.slave_pic.imr           = 0xFF; /* all IRQ's initially masked */
  BX_PIC_THIS s.slave_pic.isr           = 0x00; /* no IRQ's in service */
  BX_PIC_THIS s.slave_pic.irr           = 0x00; /* no IRQ's requested */
  BX_PIC_THIS s.slave_pic.read_reg_select = 0; /* IRR */
  BX_PIC_THIS s.slave_pic.irq = 0;
  BX_PIC_THIS s.slave_pic.INT = 0;
  BX_PIC_THIS s.slave_pic.init.in_init = 0;
  BX_PIC_THIS s.slave_pic.init.requires_4 = 0;
  BX_PIC_THIS s.slave_pic.init.byte_expected = 0;
  BX_PIC_THIS s.slave_pic.special_mask = 0;
}



  // static IO port read callback handler
  // redirects to non-static class handler to avoid virtual functions

  Bit32u
bx_pic_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
{
#if !BX_USE_PIC_SMF
  bx_pic_c *class_ptr = (bx_pic_c *) this_ptr;

  return( class_ptr->read(address, io_len) );
}



  Bit32u
bx_pic_c::read(Bit32u address, unsigned io_len)
{
#else
  UNUSED(this_ptr);
#endif // !BX_USE_PIC_SMF
  if (io_len > 1)
    bx_panic("pic: io read from port %04x, len=%u\n", (unsigned) address,
             (unsigned) io_len);

  if (bx_dbg.pic)
    bx_printf("pic: IO read from %04x\n", (unsigned) address);

  /*
   8259A PIC
   */

  switch (address) {
    case 0x20:
      if (BX_PIC_THIS s.master_pic.read_reg_select) { /* ISR */
        if (bx_dbg.pic) bx_printf("pic: read master ISR = %02x\n",
	                  (unsigned) BX_PIC_THIS s.master_pic.isr);
	return(BX_PIC_THIS s.master_pic.isr);
	}
      else { /* IRR */
        if (bx_dbg.pic) bx_printf("pic: read master IRR = %02x\n",
	                  (unsigned) BX_PIC_THIS s.master_pic.irr);
	return(BX_PIC_THIS s.master_pic.irr);
	}
      break;
    case 0x21:
      if (bx_dbg.pic) bx_printf("pic: read master IMR = %02x\n",
                        (unsigned) BX_PIC_THIS s.master_pic.imr);
      return(BX_PIC_THIS s.master_pic.imr);
      break;
    case 0xA0:
      if (BX_PIC_THIS s.slave_pic.read_reg_select) { /* ISR */
        if (bx_dbg.pic) bx_printf("pic: read slave ISR = %02x\n",
                          (unsigned) BX_PIC_THIS s.slave_pic.isr);
	return(BX_PIC_THIS s.slave_pic.isr);
	}
      else { /* IRR */
        if (bx_dbg.pic) bx_printf("pic: read slave IRR = %02x\n",
                          (unsigned) BX_PIC_THIS s.slave_pic.irr);
	return(BX_PIC_THIS s.slave_pic.irr);
	}
      break;
    case 0xA1:
      if (bx_dbg.pic) bx_printf("pic: read slave IMR = %02x\n",
                        (unsigned) BX_PIC_THIS s.slave_pic.imr);
      return(BX_PIC_THIS s.slave_pic.imr);
      break;
    }

  bx_panic("pic: io read to address %04x\n", (unsigned) address);
  return(0); /* default if not found above */
}


  // static IO port write callback handler
  // redirects to non-static class handler to avoid virtual functions

  void
bx_pic_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
{
#if !BX_USE_PIC_SMF
  bx_pic_c *class_ptr = (bx_pic_c *) this_ptr;

  class_ptr->write(address, value, io_len);
}

  void
bx_pic_c::write(Bit32u address, Bit32u value, unsigned io_len)
{
#else
  UNUSED(this_ptr);
#endif // !BX_USE_PIC_SMF
  int irq;

  if (io_len > 1)
    bx_panic("pic: io write to port %04x, len=%u\n", (unsigned) address,
             (unsigned) io_len);

  if (bx_dbg.pic)
    bx_printf("pic: IO write to %04x = %02x\n",
      (unsigned) address, (unsigned) value);

  /*
   8259A PIC
   */

  switch (address) {
    case 0x20:
      if (value & 0x10) { /* initialization command 1 */
	    // (mch) Ignore...
	    // bx_printf("pic:master: init command 1 found %02x\n", (unsigned) value);
        if (bx_dbg.pic) {
          bx_printf("pic:master: init command 1 found\n");
          bx_printf("            requires 4 = %u\n",
            (unsigned) (value & 0x01) );
          bx_printf("            cascade mode: [0=cascade,1=single] %u\n",
            (unsigned) ((value & 0x02) >> 1));
          }
        BX_PIC_THIS s.master_pic.init.in_init = 1;
        BX_PIC_THIS s.master_pic.init.requires_4 = (value & 0x01);
        BX_PIC_THIS s.master_pic.init.byte_expected = 2; /* operation command 2 */
        BX_PIC_THIS s.master_pic.imr           = 0xFF; /* all IRQ's initially masked */
        BX_PIC_THIS s.master_pic.isr           = 0x00; /* no IRQ's in service */
        BX_PIC_THIS s.master_pic.irr           = 0x00; /* no IRQ's requested */
        BX_PIC_THIS s.master_pic.INT = 0; /* reprogramming clears previous INTR request */
        if ( (value & 0x02) == 1 )
          bx_panic("pic:master: init command: single mode\n");
        BX_SET_INTR(0);
        return;
        }

      if ( (value & 0x18) == 0x08 ) { /* OCW3 */
        Bit8u special_mask, poll, read_op;

        special_mask = (value & 0x60) >> 5;
        poll         = (value & 0x04) >> 2;
        read_op      = (value & 0x03);
        if (poll)
          bx_panic("pic:master:OCW3: poll bit set\n");
        if (read_op == 0x02) /* read IRR */
	  BX_PIC_THIS s.master_pic.read_reg_select = 0;
        else if (read_op == 0x03) /* read ISR */
	  BX_PIC_THIS s.master_pic.read_reg_select = 1;
        if (special_mask == 0x02) { /* cancel special mask */
          BX_PIC_THIS s.master_pic.special_mask = 0;
          }
        else if (special_mask == 0x03) { /* set specific mask */
          BX_PIC_THIS s.master_pic.special_mask = 1;
          service_master_pic();
          }
        return;
        }

      /* OCW2 */
      switch (value) {
        case 0x00: // Rotate in Auto-EOI mode
          bx_panic("PIC: Rotate in Auto-EOI mode command received.\n");
	case 0x0A: /* select read interrupt request register */
	  BX_PIC_THIS s.master_pic.read_reg_select = 0;
	  break;
	case 0x0B: /* select read interrupt in-service register */
	  BX_PIC_THIS s.master_pic.read_reg_select = 1;
	  break;

	case 0x20: /* end of interrupt command */
          /* clear highest current in service bit */
          for (irq=0; irq<=7; irq++) {
            if (BX_PIC_THIS s.master_pic.isr & (1 << irq)) {
              BX_PIC_THIS s.master_pic.isr &= ~(1 << irq);
              break; /* out of for loop */
              }
            }
          service_master_pic();
	  break;

        case 0x60: /* specific EOI 0 */
        case 0x61: /* specific EOI 1 */
        case 0x62: /* specific EOI 2 */
        case 0x63: /* specific EOI 3 */
        case 0x64: /* specific EOI 4 */
        case 0x65: /* specific EOI 5 */
        case 0x66: /* specific EOI 6 */
        case 0x67: /* specific EOI 7 */
          BX_PIC_THIS s.master_pic.isr &= ~(1 << (value-0x60));
          service_master_pic();
	  break;

        // IRQ lowest priority commands
        case 0xC0: // 0 7 6 5 4 3 2 1
        case 0xC1: // 1 0 7 6 5 4 3 2
        case 0xC2: // 2 1 0 7 6 5 4 3
        case 0xC3: // 3 2 1 0 7 6 5 4
        case 0xC4: // 4 3 2 1 0 7 6 5
        case 0xC5: // 5 4 3 2 1 0 7 6
        case 0xC6: // 6 5 4 3 2 1 0 7
        case 0xC7: // 7 6 5 4 3 2 1 0
          // ignore for now
          bx_printf("pic: IRQ lowest command 0x%x\n", value);
          break;

        default:
          bx_panic("PIC: write to port 20h = %02x\n", value);
	} /* switch (value) */
      break;

    case 0x21:
      /* initialization mode operation */
      if (BX_PIC_THIS s.master_pic.init.in_init) {
        switch (BX_PIC_THIS s.master_pic.init.byte_expected) {
          case 2:
            BX_PIC_THIS s.master_pic.interrupt_offset = value & 0xf8;
            BX_PIC_THIS s.master_pic.init.byte_expected = 3;
	    if (bx_dbg.pic) {
		  bx_printf("pic:master: init command 2 = %02x\n", (unsigned) value);
		  bx_printf("            offset = INT %02x\n",
			    BX_PIC_THIS s.master_pic.interrupt_offset);
	    }
            return;
            break;
          case 3:
	    if (bx_dbg.pic)
		  bx_printf("pic:master: init command 3 = %02x\n", (unsigned) value);
            if (BX_PIC_THIS s.master_pic.init.requires_4) {
              BX_PIC_THIS s.master_pic.init.byte_expected = 4;
	      }
            else {
              BX_PIC_THIS s.master_pic.init.in_init = 0;
	      }
            return;
            break;
          case 4:
	    if (bx_dbg.pic) {
		  bx_printf("pic:master: init command 4 = %02x\n", (unsigned) value);
		  if (value & 0x02) bx_printf("pic:        auto EOI\n");
		  else bx_printf("pic: normal EOI interrupt\n");
	    }
	    if (value & 0x01) {
		  if (bx_dbg.pic)
			bx_printf("pic:        80x86 mode\n");
	    } else
		  bx_panic("pic:        not 80x86 mode\n");
            BX_PIC_THIS s.master_pic.init.in_init = 0;
            return;
            break;
          default:
            bx_panic("pic:master expecting bad init command\n");
          }
        }

      /* normal operation */
      if (bx_dbg.pic)
        bx_printf("pic: setting master pic IMR to %02x\n", value);
      BX_PIC_THIS s.master_pic.imr = value;
      service_master_pic();
      return;
      break;

    case 0xA0:
      if (value & 0x10) { /* initialization command 1 */
        if (bx_dbg.pic) {
          bx_printf("pic:slave: init command 1 found\n");
          bx_printf("           requires 4 = %u\n",
            (unsigned) (value & 0x01) );
          bx_printf("           cascade mode: [0=cascade,1=single] %u\n",
            (unsigned) ((value & 0x02) >> 1));
          }
        BX_PIC_THIS s.slave_pic.init.in_init = 1;
        BX_PIC_THIS s.slave_pic.init.requires_4 = (value & 0x01);
        BX_PIC_THIS s.slave_pic.init.byte_expected = 2; /* operation command 2 */
        BX_PIC_THIS s.slave_pic.imr           = 0xFF; /* all IRQ's initially masked */
        BX_PIC_THIS s.slave_pic.isr           = 0x00; /* no IRQ's in service */
        BX_PIC_THIS s.slave_pic.irr           = 0x00; /* no IRQ's requested */
        BX_PIC_THIS s.slave_pic.INT = 0; /* reprogramming clears previous INTR request */
        if ( (value & 0x02) == 1 )
          bx_panic("pic:slave: init command: single mode\n");
        return;
        }

      if ( (value & 0x18) == 0x08 ) { /* OCW3 */
        Bit8u special_mask, poll, read_op;

        special_mask = (value & 0x60) >> 5;
        poll         = (value & 0x04) >> 2;
        read_op      = (value & 0x03);
        if (poll)
          bx_panic("pic:slave:OCW3: poll bit set\n");
        if (read_op == 0x02) /* read IRR */
	  BX_PIC_THIS s.slave_pic.read_reg_select = 0;
        else if (read_op == 0x03) /* read ISR */
	  BX_PIC_THIS s.slave_pic.read_reg_select = 1;
        if (special_mask == 0x02) { /* cancel special mask */
          BX_PIC_THIS s.slave_pic.special_mask = 0;
          }
        else if (special_mask == 0x03) { /* set specific mask */
          BX_PIC_THIS s.slave_pic.special_mask = 1;
          service_slave_pic();
          bx_printf("pic:slave: OCW3 not implemented (%02x)\n",
            (unsigned) value);
          }
        return;
        }

      switch (value) {
	case 0x0A: /* select read interrupt request register */
	  BX_PIC_THIS s.slave_pic.read_reg_select = 0;
	  break;
	case 0x0B: /* select read interrupt in-service register */
	  BX_PIC_THIS s.slave_pic.read_reg_select = 1;
	  break;
	case 0x20: /* end of interrupt command */
          /* clear highest current in service bit */
          for (irq=0; irq<=7; irq++) {
            if (BX_PIC_THIS s.slave_pic.isr & (1 << irq)) {
              BX_PIC_THIS s.slave_pic.isr &= ~(1 << irq);
              break; /* out of for loop */
              }
            }
          service_slave_pic();
	  break;

        case 0x60: /* specific EOI 0 */
        case 0x61: /* specific EOI 1 */
        case 0x62: /* specific EOI 2 */
        case 0x63: /* specific EOI 3 */
        case 0x64: /* specific EOI 4 */
        case 0x65: /* specific EOI 5 */
        case 0x66: /* specific EOI 6 */
        case 0x67: /* specific EOI 7 */
          BX_PIC_THIS s.slave_pic.isr &= ~(1 << (value-0x60));
          service_slave_pic();
	  break;

        default:
          bx_panic("PIC: write to port A0h = %02x\n", value);
	} /* switch (value) */
      break;

    case 0xA1:
      /* initialization mode operation */
      if (BX_PIC_THIS s.slave_pic.init.in_init) {
        switch (BX_PIC_THIS s.slave_pic.init.byte_expected) {
          case 2:
            BX_PIC_THIS s.slave_pic.interrupt_offset = value & 0xf8;
            BX_PIC_THIS s.slave_pic.init.byte_expected = 3;
	    if (bx_dbg.pic) {
		  bx_printf("pic:slave: init command 2 = %02x\n", (unsigned) value);
		  bx_printf("           offset = INT %02x\n",
			    BX_PIC_THIS s.slave_pic.interrupt_offset);
	    }
            return;
            break;
          case 3:
		if (bx_dbg.pic)
		      bx_printf("pic:slave: init command 3 = %02x\n", (unsigned) value);
            if (BX_PIC_THIS s.slave_pic.init.requires_4) {
              BX_PIC_THIS s.slave_pic.init.byte_expected = 4;
	      }
            else {
              BX_PIC_THIS s.slave_pic.init.in_init = 0;
	      }
            return;
            break;
          case 4:
		if (bx_dbg.pic) {
		      bx_printf("pic:slave: init command 4 = %02x\n", (unsigned) value);
		      if (value & 0x02) bx_printf("pic:       auto EOI\n");
		      else bx_printf("pic: normal EOI interrupt\n");
		}
		if (value & 0x01) {
		      if (bx_dbg.pic)
			    bx_printf("pic:       80x86 mode\n");
		} else bx_panic("pic: not 80x86 mode\n");
            BX_PIC_THIS s.slave_pic.init.in_init = 0;
            return;
            break;
          default:
            bx_panic("pic:slave: expecting bad init command\n");
          }
        }

      /* normal operation */
      if (bx_dbg.pic)
        bx_printf("pic: setting slave pic IMR to %02x\n", value);
      BX_PIC_THIS s.slave_pic.imr = value;
      service_slave_pic();
      return;
      break;
    } /* switch (address) */

  return;
}

  void
bx_pic_c::trigger_irq(unsigned irq_no)
{
  int irq_no_bitmask;

#if BX_DEBUG
  if ( irq_no > 15 )
    bx_panic("trigger_irq: irq out of range\n");
#endif

  if (bx_dbg.pic)
    bx_printf("trigger_irq(%d decimal)\n", (unsigned) irq_no);

  if (irq_no <= 7) {
    irq_no_bitmask = 1 << irq_no;
    BX_PIC_THIS s.master_pic.irr |= irq_no_bitmask;
    service_master_pic();
    }
  else { // irq = 8..15
    irq_no_bitmask = 1 << (irq_no - 8);
    BX_PIC_THIS s.slave_pic.irr |= irq_no_bitmask;
    service_slave_pic();
    }
}

  void
bx_pic_c::untrigger_irq(unsigned irq_no)
{
  int irq_no_bitmask;

#if BX_DEBUG
  if ( irq_no > 15 )
    bx_panic("untrigger_irq: irq out of range\n");
#endif

  if (bx_dbg.pic)
    bx_printf("untrigger_irq(%d decimal)\n", (unsigned) irq_no);

  if (irq_no <= 7) {
    irq_no_bitmask = 1 << irq_no;
    if (BX_PIC_THIS s.master_pic.imr & irq_no_bitmask) {
      BX_PIC_THIS s.master_pic.irr &= ~irq_no_bitmask;
    }
  }
  else { // irq = 8..15
    irq_no_bitmask = 1 << (irq_no - 8);
    if (BX_PIC_THIS s.slave_pic.imr & irq_no_bitmask) {
      BX_PIC_THIS s.slave_pic.irr &= ~irq_no_bitmask;
    }
  }
}

  /* */
  void
bx_pic_c::service_master_pic(void)
{
  Bit8u unmasked_requests;
  int irq;
  Bit8u isr, max_irq;

  if (BX_PIC_THIS s.master_pic.INT) { /* last interrupt still not acknowleged */
    return;
    }

  if (BX_PIC_THIS s.master_pic.special_mask) {
    /* all priorities may be enabled.  check all IRR bits except ones
     * which have corresponding ISR bits set
     */
    max_irq = 7;
    }
  else { /* normal mode */
    /* Find the highest priority IRQ that is enabled due to current ISR */
    isr = BX_PIC_THIS s.master_pic.isr;
    if (isr) {
      max_irq = 0;
      while ( (isr & 0x01) == 0 ) {
        isr >>= 1;
        max_irq++;
        }
      if (max_irq == 0 ) return; /* IRQ0 in-service, no other priorities allowed */
      if (max_irq > 7) bx_panic("error in service_master_pic()\n");
      }
    else
      max_irq = 7; /* 0..7 bits in ISR are cleared */
    }


  /* now, see if there are any higher priority requests */
  if ((unmasked_requests = (BX_PIC_THIS s.master_pic.irr & ~BX_PIC_THIS s.master_pic.imr)) ) {
    for (irq=0; irq<=max_irq; irq++) {
      /* for special mode, since we're looking at all IRQ's, skip if
       * current IRQ is already in-service
       */
      if ( BX_PIC_THIS s.master_pic.special_mask && ((BX_PIC_THIS s.master_pic.isr >> irq) & 0x01) )
        continue;
      if (unmasked_requests & (1 << irq)) {
        if (bx_dbg.pic)
          bx_printf("pic: signalling IRQ(%u)\n",
            (unsigned) irq);
        BX_PIC_THIS s.master_pic.irr &= ~(1 << irq);
        /*??? do for slave too: BX_PIC_THIS s.master_pic.isr |=  (1 << irq);*/
        BX_PIC_THIS s.master_pic.INT = 1;
        BX_SET_INTR(1);
        BX_PIC_THIS s.master_pic.irq = irq;
        return;
        } /* if (unmasked_requests & ... */
      } /* for (irq=7 ... */
    } /* if (unmasked_requests = ... */
}


  void
bx_pic_c::service_slave_pic(void)
{
  Bit8u unmasked_requests;
  int irq;
  Bit8u isr, lowest_priority_irq;

  if (BX_PIC_THIS s.slave_pic.INT) { /* last interrupt still not acknowleged */
    return;
    }

  /* Find the highest priority IRQ that is enabled due to current ISR */
  isr = BX_PIC_THIS s.slave_pic.isr;
  if (isr) {
    lowest_priority_irq = 0;
    while ( !(isr & 0x01) ) {
      isr >>= 1;
      lowest_priority_irq++;
      }
    if (lowest_priority_irq > 7) bx_panic("error in service_slave_pic()\n");
    }
  else
    lowest_priority_irq = 8;


  /* now, see if there are any higher priority requests */
  if ((unmasked_requests = (BX_PIC_THIS s.slave_pic.irr & ~BX_PIC_THIS s.slave_pic.imr)) ) {
    for (irq=0; irq<lowest_priority_irq; irq++) {
      if (unmasked_requests & (1 << irq)) {
        if (bx_dbg.pic)
          bx_printf("pic(slave): signalling IRQ(%u)\n",
            (unsigned) 8 + irq);
        BX_PIC_THIS s.slave_pic.irr &= ~(1 << irq);
        BX_PIC_THIS s.slave_pic.INT = 1;
        BX_PIC_THIS s.master_pic.irr |= 0x04; /* request IRQ 2 on master pic */
        BX_PIC_THIS s.slave_pic.irq = irq;
        service_master_pic();
        return;
        } /* if (unmasked_requests & ... */
      } /* for (irq=7 ... */
    } /* if (unmasked_requests = ... */
}


  /* CPU handshakes with PIC after acknowledging interrupt */
  Bit8u
bx_pic_c::IAC(void)
{
  Bit8u vector;
  Bit8u irq;

  BX_SET_INTR(0);
  BX_PIC_THIS s.master_pic.INT = 0;
  BX_PIC_THIS s.master_pic.isr |= (1 << BX_PIC_THIS s.master_pic.irq);
  BX_PIC_THIS s.master_pic.irr &= ~(1 << BX_PIC_THIS s.master_pic.irq);

  if (BX_PIC_THIS s.master_pic.irq != 2) {
    irq    = BX_PIC_THIS s.master_pic.irq;
    vector = irq + BX_PIC_THIS s.master_pic.interrupt_offset;
    }
  else { /* IRQ2 = slave pic IRQ8..15 */
    BX_PIC_THIS s.slave_pic.INT = 0;
    irq    = BX_PIC_THIS s.slave_pic.irq;
    vector = irq + BX_PIC_THIS s.slave_pic.interrupt_offset;
    BX_PIC_THIS s.slave_pic.isr |= (1 << BX_PIC_THIS s.slave_pic.irq);
    BX_PIC_THIS s.slave_pic.irr &= ~(1 << BX_PIC_THIS s.slave_pic.irq);
    service_slave_pic();
    irq += 8; // for debug printing purposes
    }

  service_master_pic();

  BX_DBG_IAC_REPORT(vector, irq);
  return(vector);
}

  void
bx_pic_c::show_pic_state(void)
{
bx_printf("s.master_pic.imr = %02x\n", BX_PIC_THIS s.master_pic.imr);
bx_printf("s.master_pic.isr = %02x\n", BX_PIC_THIS s.master_pic.isr);
bx_printf("s.master_pic.irr = %02x\n", BX_PIC_THIS s.master_pic.irr);
bx_printf("s.master_pic.irq = %02x\n", BX_PIC_THIS s.master_pic.irq);
}
