auto ICD::ppuHreset() -> void {
  hcounter = 0;
  vcounter++;
  if((n3)vcounter == 0) writeBank++;
}

auto ICD::ppuVreset() -> void {
  hcounter = 0;
  vcounter = 0;
}

auto ICD::ppuWrite(n2 color) -> void {
  auto x = (n8)hcounter++;
  auto y = (n3)vcounter;
  if(x >= 160) return;  //unverified behavior

  n11 address = writeBank * 512 + y * 2 + x / 8 * 16;
  output[address + 0] = output[address + 0] << 1 | color.bit(0);
  output[address + 1] = output[address + 1] << 1 | color.bit(1);
}

auto ICD::joypWrite(n1 p14, n1 p15) -> void {
  //joypad handling
  if (p15 && !previousP15) {
    joypID++;
    if (mltReq == 0) joypID &= 0;  //1-player mode
    if (mltReq == 1) joypID &= 1;  //2-player mode
    if (mltReq == 2) joypID &= 3;  //4-player mode (unverified; but the most likely behavior)
    if (mltReq == 3) joypID &= 3;  //4-player mode
  }
  previousP15 = p15;

  n8 joypad;
  if(joypID == 0) joypad = r6004;
  if(joypID == 1) joypad = r6005;
  if(joypID == 2) joypad = r6006;
  if(joypID == 3) joypad = r6007;

  n4 input = 0xf;
  if(p14 == 1 && p15 == 1) input -= joypID;
  if(p14 == 0) input &= joypad.bit(0,3);  //d-pad
  if(p15 == 0) input &= joypad.bit(4,7);  //buttons

  GameBoy::cpu.input(input);

  //packet handling
  if(p14 == 0 && p15 == 0) {  //pulse
    pulseLock = 0;
    packetOffset = 0;
    bitOffset = 0;
    strobeLock = 1;
    packetLock = 0;
    return;
  }

  if(pulseLock == 1) return;

  if(p14 == 1 && p15 == 1) {
    strobeLock = 0;
    return;
  }

  if(strobeLock == 1) {
    if(p14 == 1 || p15 == 1) {  //malformed packet
      packetLock = 0;
      pulseLock = 1;
      bitOffset = 0;
      packetOffset = 0;
    } else {
      return;
    }
  }

  //p14:0, p15:1 = 0
  //p14:1, p15:0 = 1
  bool bit = p15 == 0;
  strobeLock = 1;

  if(packetLock == 1) {
    if(p14 == 0 && p15 == 1) {
      packetReady = 1;
      packetLock = 0;
      pulseLock = 1;
    }
    return;
  }

  bitData = bit << 7 | bitData >> 1;
  if(++bitOffset) return;

  r7000[packetOffset] = bitData;
  if(++packetOffset) return;

  packetLock = 1;
}
