public static void executeDualGb(Gameboy gbL, Gameboy gbR, int[] movesL, int[] movesR) {
    // finish unfinished frames
    if (!gbL.onFrameBoundaries)
      gbL.step();
    if (!gbR.onFrameBoundaries)
      gbR.step();

    System.out.println("executeDualGb: initial steps " + gbL.stepCount + " - " + gbR.stepCount);

    // align to same frame
    while(gbL.stepCount < gbR.stepCount)
      gbL.step();
    while(gbR.stepCount < gbL.stepCount)
      gbR.step();

    // do and log moves
    for (int i = 0; i < Math.max(movesL.length, movesR.length); i++) {
      int moveL = i < movesL.length ? movesL[i] : 0;
      int moveR = i < movesR.length ? movesR[i] : 0;
      Gb.stepDual(gbL.gb, gbR.gb, moveL, moveR);
      if (Math.max(movesL.length, movesR.length) - i < 200)
        try {
          Thread.sleep(5);
        } catch (InterruptedException e) {}
      gbL.logInput(moveL);
      gbR.logInput(moveR);
    }

    // clean up gb state
    gbL.clearCache();
    gbR.clearCache();
  }