struct VRC3 : Chip {

uint4 prg_bank;
bool irq_mode;
bool irq_enable;
bool irq_acknowledge;
uint16 irq_latch;
struct {
  union {
    uint16 w;
    struct { uint8 order_lsb2(l, h); };
  };
} irq_counter;
bool irq_line;

void main() {
  while(true) {
    if(scheduler.sync == Scheduler::SynchronizeMode::All) {
      scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
    }

    if(irq_enable) {
      if(irq_mode == 0) {  //16-bit
        if(++irq_counter.w == 0) {
          irq_line = 1;
          irq_enable = irq_acknowledge;
          irq_counter.w = irq_latch;
        }
      }
      if(irq_mode == 1) {  //8-bit
        if(++irq_counter.l == 0) {
          irq_line = 1;
          irq_enable = irq_acknowledge;
          irq_counter.l = irq_latch;
        }
      }
    }

    cpu.set_irq_line(irq_line);
    tick();
  }
}

unsigned prg_addr(unsigned addr) const {
  unsigned bank = (addr < 0xc000 ? (unsigned)prg_bank : 0x0f);
  return (bank * 0x4000) + (addr & 0x3fff);
}

void reg_write(unsigned addr, uint8 data) {
  switch(addr & 0xf000) {
  case 0x8000: irq_latch = (irq_latch & 0xfff0) | ((data & 0x0f) <<  0); break;
  case 0x9000: irq_latch = (irq_latch & 0xff0f) | ((data & 0x0f) <<  4); break;
  case 0xa000: irq_latch = (irq_latch & 0xf0ff) | ((data & 0x0f) <<  8); break;
  case 0xb000: irq_latch = (irq_latch & 0x0fff) | ((data & 0x0f) << 12); break;

  case 0xc000:
    irq_mode = data & 0x04;
    irq_enable = data & 0x02;
    irq_acknowledge = data & 0x01;
    if(irq_enable) irq_counter.w = irq_latch;
    break;

  case 0xd000:
    irq_line = 0;
    irq_enable = irq_acknowledge;
    break;

  case 0xf000:
    prg_bank = data & 0x0f;
    break;
  }
}

void power() {
}

void reset() {
  prg_bank = 0;
  irq_mode = 0;
  irq_enable = 0;
  irq_acknowledge = 0;
  irq_latch = 0;
  irq_counter.w = 0;
  irq_line = 0;
}

void serialize(serializer& s) {
  s.integer(prg_bank);
  s.integer(irq_mode);
  s.integer(irq_enable);
  s.integer(irq_acknowledge);
  s.integer(irq_latch);
  s.integer(irq_counter.w);
  s.integer(irq_line);
}

VRC3(Board& board) : Chip(board) {
}

};
