public static int runToAddressOrNextInputFrameLimit(State initial, int move, int limit, int... addresses) {
    int expectedRet = -2;
    if ((move & 0b00001111) == 0) {
      expectedRet = runToAddressOrNextInputFrameHiOrLoLimit(initial, curGb.rom.readJoypadInputHi, limit, addresses);
      return expectedRet;
    } else if ((move & 0b11110000) == 0) {
      expectedRet = runToAddressOrNextInputFrameHiOrLoLimit(initial, curGb.rom.readJoypadInputLo, limit, addresses);
      return expectedRet;
    }

    int initialSteps = curGb.stepCount;
    if (initial == null)
      initial = curGb.newState();

    if (runToNextInputFrameLimit(move, limit) == 0) {
//      if (expectedRet != -2 && expectedRet != -1)
//        throw new RuntimeException("-1 != " + Util.toHex(expectedRet));
//      return -1;
      return expectedRet != -2 ? expectedRet : -1;
    }
    int inputSteps = curGb.stepCount;

    curGb.restore(initial);
    int actualRet = runToAddressLimit(0, 0, inputSteps - initialSteps, addresses); // run at most to the input frame
    if (expectedRet != -2 && actualRet != expectedRet)
      throw new RuntimeException(Util.toHex(actualRet) + " != " + Util.toHex(expectedRet));
    return actualRet;
  }