Example #1
0
  /** Execute the specified number of Gameboy instructions. Use '-1' to execute forever */
  public final void execute(int numInstr) {
    terminate = false;
    running = true;
    graphicsChip.startTime = System.currentTimeMillis();
    int b1, b2, b3, offset;

    long t;
    for (int r = 0; (r != numInstr) && (!terminate); r++) {
      t = System.currentTimeMillis();

      instrCount++;

      b1 = JavaBoy.unsign(addressRead(pc));
      offset = addressRead(pc + 1);
      b3 = JavaBoy.unsign(addressRead(pc + 2));
      b2 = JavaBoy.unsign((short) offset);

      // stats.addExecution(b1);
      instructionManager.execute(b1, b2, b3, offset);

      if (ieDelay != -1) {
        if (ieDelay > 0) {
          ieDelay--;
        } else {
          interruptsEnabled = true;
          ieDelay = -1;
        }
      }

      if (interruptsEnabled) {
        checkInterrupts();
      }
      cartridge.update();
      initiateInterrupts();

      if ((t - initialTime) > checkpointTime) {
        initialTime = t;
        saveCheckpointInterrupt = true;
      }

      if (saveInterrupt) {
        saveState(".stsv");
        saveInterrupt = false;
      }
      if (loadStateInterrupt) {
        loadState(".stsv");
        loadStateInterrupt = false;
      }
      if (saveCheckpointInterrupt) {
        saveState(".cksv");
        saveCheckpointInterrupt = false;
      }
      if (loadCheckpointInterrupt) {
        loadState(".cksv");
        loadCheckpointInterrupt = false;
      }
    }
    running = false;
    terminate = false;
  }
Example #2
0
  /** Resets the CPU to it's power on state. Memory contents are not cleared. */
  public void reset() {

    checkEnableGbc();
    setDoubleSpeedCpu(false);
    graphicsChip.dispose();
    cartridge.reset();
    interruptsEnabled = false;
    ieDelay = -1;
    pc = 0x0100;
    sp = 0xFFFE;
    f = 0xB0;
    gbcRamBank = 1;
    instrCount = 0;

    if (gbcFeatures) {
      registers[a] = 0x11;
    } else {
      registers[a] = 0x01;
    }

    for (int r = 0; r < 0x8000; r++) {
      mainRam[r] = 0;
    }

    setBC(0x0013);
    setDE(0x00D8);
    setHL(0x014D);
    JavaBoy.debugLog("CPU reset");

    ioHandler.reset();
  }
Example #3
0
  /**
   * Performs a CPU address space write. Maps all of the relevant object into the right parts of
   * memory.
   */
  public final void addressWrite(int addr, int data) {
    switch (addr & 0xF000) {
      case 0x0000:
      case 0x1000:
      case 0x2000:
      case 0x3000:
      case 0x4000:
      case 0x5000:
      case 0x6000:
      case 0x7000:
        if (!running) {
          cartridge.debuggerAddressWrite(addr, data);
        } else {
          cartridge.addressWrite(addr, data);
        }
        break;

      case 0x8000:
      case 0x9000:
        graphicsChip.addressWrite(addr - 0x8000, (byte) data);
        break;

      case 0xA000:
      case 0xB000:
        cartridge.addressWrite(addr, data);
        break;

      case 0xC000:
        mainRam[addr - 0xC000] = (byte) data;
        break;

      case 0xD000:
        mainRam[addr - 0xD000 + (gbcRamBank * 0x1000)] = (byte) data;
        break;

      case 0xE000:
        mainRam[addr - 0xE000] = (byte) data;
        break;

      case 0xF000:
        if (addr < 0xFE00) {
          try {
            mainRam[addr - 0xE000] = (byte) data;
          } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("Address error: " + addr + " pc = " + JavaBoy.hexWord(pc));
          }
        } else if (addr < 0xFF00) {
          oam[addr - 0xFE00] = (byte) data;
        } else {
          ioHandler.ioWrite(addr - 0xFF00, (short) data);
        }
        break;
    }
  }
Example #4
0
 /** Performs a read of a register by internal register number */
 public final int registerRead(int regNum) {
   if ((regNum >= 0 && regNum <= 3) || regNum == 7) {
     return registers[regNum];
   } else {
     if (regNum == 4) {
       return (short) ((hl & 0xFF00) >> 8);
     } else if (regNum == 5) {
       return (short) (hl & 0x00FF);
     } else if (regNum == 6) {
       return JavaBoy.unsign(addressRead(hl));
     }
   }
   return -1;
 }
Example #5
0
  /**
   * Perform a CPU address space read. This maps all the relevant objects into the correct parts of
   * the memory
   */
  public final short addressRead(int addr) {
    addr = addr & 0xFFFF;

    switch ((addr & 0xF000)) {
      case 0x0000:
      case 0x1000:
      case 0x2000:
      case 0x3000:
      case 0x4000:
      case 0x5000:
      case 0x6000:
      case 0x7000:
        return cartridge.addressRead(addr);

      case 0x8000:
      case 0x9000:
        return graphicsChip.addressRead(addr - 0x8000);

      case 0xA000:
      case 0xB000:
        return cartridge.addressRead(addr);

      case 0xC000:
        return (mainRam[addr - 0xC000]);

      case 0xD000:
        return (mainRam[addr - 0xD000 + (gbcRamBank * 0x1000)]);

      case 0xE000:
        return mainRam[addr - 0xE000];

      case 0xF000:
        if (addr < 0xFE00) {
          return mainRam[addr - 0xE000];
        } else if (addr < 0xFF00) {
          return (short) (oam[addr - 0xFE00] & 0x00FF);
        } else {
          return ioHandler.ioRead(addr - 0xFF00);
        }

      default:
        System.out.println("Tried to read address " + addr + ".  pc = " + JavaBoy.hexWord(pc));
        return 0xFF;
    }
  }
  public void play(byte[] b, int length, int offset) {
    int val;

    if (totalLength != 0) {
      totalLength--;

      for (int r = offset; r < offset + length; r++) {

        int samplePos = (31 * cyclePos) / cycleLength;
        val = JavaBoy.unsign(waveform[samplePos % 32]) >> volumeShift << 1;
        //    System.out.print(" " + val);

        if ((channel & CHAN_LEFT) != 0) b[r * 2] += val;
        if ((channel & CHAN_RIGHT) != 0) b[r * 2 + 1] += val;
        if ((channel & CHAN_MONO) != 0) b[r] += val;

        //   System.out.print(val + " ");
        cyclePos = (cyclePos + 256) % cycleLength;
      }
    }
  }
Example #7
0
  /**
   * Output a disassembly of the specified number of instructions starting at the speicifed address.
   */
  public String disassemble(int address, int numInstr) {

    System.out.println("Addr  Data      Instruction");

    for (int r = 0; r < numInstr; r++) {
      short b1 = JavaBoy.unsign(addressRead(address));
      short offset = addressRead(address + 1);
      short b3 = JavaBoy.unsign(addressRead(address + 2));
      short b2 = JavaBoy.unsign(offset);

      String instr =
          new String("Unknown Opcode! (" + Integer.toHexString(JavaBoy.unsign(b1)) + ")");
      byte instrLength = 1;

      switch (b1) {
        case 0x00:
          instr = "NOP";
          break;
        case 0x01:
          instr = "LD BC, " + JavaBoy.hexWord((b3 << 8) + b2);
          instrLength = 3;
          break;
        case 0x02:
          instr = "LD (BC), A";
          break;
        case 0x03:
          instr = "INC BC";
          break;
        case 0x04:
          instr = "INC B";
          break;
        case 0x05:
          instr = "DEC B";
          break;
        case 0x06:
          instr = "LD B, " + JavaBoy.hexByte(b2);
          instrLength = 2;
          break;
        case 0x07:
          instr = "RLC A";
          break;
        case 0x08:
          instr = "LD (" + JavaBoy.hexWord((b3 << 8) + b2) + "), SP";
          instrLength = 3; // Non Z80
          break;
        case 0x09:
          instr = "ADD HL, BC";
          break;
        case 0x0A:
          instr = "LD A, (BC)";
          break;
        case 0x0B:
          instr = "DEC BC";
          break;
        case 0x0C:
          instr = "INC C";
          break;
        case 0x0D:
          instr = "DEC C";
          break;
        case 0x0E:
          instr = "LD C, " + JavaBoy.hexByte(b2);
          instrLength = 2;
          break;
        case 0x0F:
          instr = "RRC A";
          break;
        case 0x10:
          instr = "STOP";
          instrLength = 2; // STOP instruction must be followed by a NOP
          break;
        case 0x11:
          instr = "LD DE, " + JavaBoy.hexWord((b3 << 8) + b2);
          instrLength = 3;
          break;
        case 0x12:
          instr = "LD (DE), A";
          break;
        case 0x13:
          instr = "INC DE";
          break;
        case 0x14:
          instr = "INC D";
          break;
        case 0x15:
          instr = "DEC D";
          break;
        case 0x16:
          instr = "LD D, " + JavaBoy.hexByte(b2);
          instrLength = 2;
          break;
        case 0x17:
          instr = "RL A";
          break;
        case 0x18:
          instr = "JR " + JavaBoy.hexWord(address + 2 + offset);
          instrLength = 2;
          break;
        case 0x19:
          instr = "ADD HL, DE";
          break;
        case 0x1A:
          instr = "LD A, (DE)";
          break;
        case 0x1B:
          instr = "DEC DE";
          break;
        case 0x1C:
          instr = "INC E";
          break;
        case 0x1D:
          instr = "DEC E";
          break;
        case 0x1E:
          instr = "LD E, " + JavaBoy.hexByte(b2);
          instrLength = 2;
          break;
        case 0x1F:
          instr = "RR A";
          break;
        case 0x20:
          instr = "JR NZ, " + JavaBoy.hexWord(address + 2 + offset) + ": " + offset;

          instrLength = 2;
          break;
        case 0x21:
          instr = "LD HL, " + JavaBoy.hexWord((b3 << 8) + b2);
          instrLength = 3;
          break;
        case 0x22:
          instr = "LD (HL+), A"; // Non Z80
          break;
        case 0x23:
          instr = "INC HL";
          break;
        case 0x24:
          instr = "INC H";
          break;
        case 0x25:
          instr = "DEC H";
          break;
        case 0x26:
          instr = "LD H, " + JavaBoy.hexByte(b2);
          instrLength = 2;
          break;
        case 0x27:
          instr = "DAA";
          break;
        case 0x28:
          instr = "JR Z, " + JavaBoy.hexWord(address + 2 + offset);
          instrLength = 2;
          break;
        case 0x29:
          instr = "ADD HL, HL";
          break;
        case 0x2A:
          instr = "LDI A, (HL)";
          break;
        case 0x2B:
          instr = "DEC HL";
          break;
        case 0x2C:
          instr = "INC L";
          break;
        case 0x2D:
          instr = "DEC L";
          break;
        case 0x2E:
          instr = "LD L, " + JavaBoy.hexByte(b2);
          instrLength = 2;
          break;
        case 0x2F:
          instr = "CPL";
          break;
        case 0x30:
          instr = "JR NC, " + JavaBoy.hexWord(address + 2 + offset);
          instrLength = 2;
          break;
        case 0x31:
          instr = "LD SP, " + JavaBoy.hexWord((b3 << 8) + b2);
          instrLength = 3;
          break;
        case 0x32:
          instr = "LD (HL-), A";
          break;
        case 0x33:
          instr = "INC SP";
          break;
        case 0x34:
          instr = "INC (HL)";
          break;
        case 0x35:
          instr = "DEC (HL)";
          break;
        case 0x36:
          instr = "LD (HL), " + JavaBoy.hexByte(b2);
          instrLength = 2;
          break;
        case 0x37:
          instr = "SCF"; // Set carry flag?
          break;
        case 0x38:
          instr = "JR C, " + JavaBoy.hexWord(address + 2 + offset);
          instrLength = 2;
          break;
        case 0x39:
          instr = "ADD HL, SP";
          break;
        case 0x3A:
          instr = "LD A, (HL-)";
          break;
        case 0x3B:
          instr = "DEC SP";
          break;
        case 0x3C:
          instr = "INC A";
          break;
        case 0x3D:
          instr = "DEC A";
          break;
        case 0x3E:
          instr = "LD A, " + JavaBoy.hexByte(JavaBoy.unsign(b2));
          instrLength = 2;
          break;
        case 0x3F:
          instr = "CCF"; // Clear carry flag?
          break;

        case 0x76:
          instr = "HALT";
          break;

          // 0x40 - 0x7F = LD Reg, Reg - see below
          // 0x80 - 0xBF = ALU ops - see below

        case 0xC0:
          instr = "RET NZ";
          break;
        case 0xC1:
          instr = "POP BC";
          break;
        case 0xC2:
          instr = "JP NZ, " + JavaBoy.hexWord((b3 << 8) + b2);
          instrLength = 3;
          break;
        case 0xC3:
          instr = "JP " + JavaBoy.hexWord((b3 << 8) + b2);
          instrLength = 3;
          break;
        case 0xC4:
          instr = "CALL NZ, " + JavaBoy.hexWord((b3 << 8) + b2);
          instrLength = 3;
          break;
        case 0xC5:
          instr = "PUSH BC";
          break;
        case 0xC6:
          instr = "ADD A, " + JavaBoy.hexByte(b2);
          instrLength = 2;
          break;
        case 0xC7:
          instr = "RST 00"; // Is this an interrupt call?
          break;
        case 0xC8:
          instr = "RET Z";
          break;
        case 0xC9:
          instr = "RET";
          break;
        case 0xCA:
          instr = "JP Z, " + JavaBoy.hexWord((b3 << 8) + b2);
          instrLength = 3;
          break;

          // 0xCB = Shifts (see below)

        case 0xCC:
          instr = "CALL Z, " + JavaBoy.hexWord((b3 << 8) + b2);
          instrLength = 3;
          break;
        case 0xCD:
          instr = "CALL " + JavaBoy.hexWord((b3 << 8) + b2);
          instrLength = 3;
          break;
        case 0xCE:
          instr = "ADC A, " + JavaBoy.hexByte(b2); // Signed or unsigned?
          instrLength = 2;
          break;
        case 0xCF:
          instr = "RST 08"; // Is this an interrupt call?
          break;
        case 0xD0:
          instr = "RET NC";
          break;
        case 0xD1:
          instr = "POP DE";
          break;
        case 0xD2:
          instr = "JP NC, " + JavaBoy.hexWord((b3 << 8) + b2);
          instrLength = 3;
          break;

          // 0xD3: Unknown

        case 0xD4:
          instr = "CALL NC, " + JavaBoy.hexWord((b3 << 8) + b2);
          instrLength = 3;
          break;
        case 0xD5:
          instr = "PUSH DE";
          break;
        case 0xD6:
          instr = "SUB A, " + JavaBoy.hexByte(b2);
          instrLength = 2;
          break;
        case 0xD7:
          instr = "RST 10";
          break;
        case 0xD8:
          instr = "RET C";
          break;
        case 0xD9:
          instr = "RETI";
          break;
        case 0xDA:
          instr = "JP C, " + JavaBoy.hexWord((b3 << 8) + b2);
          instrLength = 3;
          break;

          // 0xDB: Unknown

        case 0xDC:
          instr = "CALL C, " + JavaBoy.hexWord((b3 << 8) + b2);
          instrLength = 3;
          break;

          // 0xDD: Unknown

        case 0xDE:
          instr = "SBC A, " + JavaBoy.hexByte(b2);
          instrLength = 2;
          break;
        case 0xDF:
          instr = "RST 18";
          break;
        case 0xE0:
          instr = "LDH (FF" + JavaBoy.hexByte(b2 & 0xFF) + "), A";
          instrLength = 2;
          break;
        case 0xE1:
          instr = "POP HL";
          break;
        case 0xE2:
          instr = "LDH (FF00 + C), A";
          break;

          // 0xE3 - 0xE4: Unknown

        case 0xE5:
          instr = "PUSH HL";
          break;
        case 0xE6:
          instr = "AND " + JavaBoy.hexByte(b2);
          instrLength = 2;
          break;
        case 0xE7:
          instr = "RST 20";
          break;
        case 0xE8:
          instr = "ADD SP, " + JavaBoy.hexByte(offset);
          instrLength = 2;
          break;
        case 0xE9:
          instr = "JP (HL)";
          break;
        case 0xEA:
          instr = "LD (" + JavaBoy.hexWord((b3 << 8) + b2) + "), A";
          instrLength = 3;
          break;

          // 0xEB - 0xED: Unknown

        case 0xEE:
          instr = "XOR " + JavaBoy.hexByte(b2);
          instrLength = 2;
          break;
        case 0xEF:
          instr = "RST 28";
          break;
        case 0xF0:
          instr = "LDH A, (FF" + JavaBoy.hexByte(b2) + ")";
          instrLength = 2;
          break;
        case 0xF1:
          instr = "POP AF";
          break;
        case 0xF2:
          instr = "LD A, (FF00 + C)"; // What's this for?
          break;
        case 0xF3:
          instr = "DI";
          break;

          // 0xF4: Unknown

        case 0xF5:
          instr = "PUSH AF";
          break;
        case 0xF6:
          instr = "OR " + JavaBoy.hexByte(b2);
          instrLength = 2;
          break;
        case 0xF7:
          instr = "RST 30";
          break;
        case 0xF8:
          instr = "LD HL, SP + " + JavaBoy.hexByte(offset); // Check this
          // one, docs
          // disagree
          instrLength = 2;
          break;
        case 0xF9:
          instr = "LD SP, HL";
          break;
        case 0xFA:
          instr = "LD A, (" + JavaBoy.hexWord((b3 << 8) + b2) + ")";
          instrLength = 3;
          break;
        case 0xFB:
          instr = "EI";
          break;

          // 0xFC - 0xFD: Unknown

        case 0xFE:
          instr = "CP " + JavaBoy.hexByte(b2);
          instrLength = 2;
          break;
        case 0xFF:
          instr = "RST 38";
          break;
      }

      // The following section handles LD Reg, Reg instructions
      // Bit 7 6 5 4 3 2 1 0 D = Dest register
      //     0 1 D D D S S S S = Source register
      // The exception to this rule is 0x76, which is HALT, and takes
      // the place of LD (HL), (HL)

      if ((JavaBoy.unsign(b1) >= 0x40)
          && (JavaBoy.unsign(b1) <= 0x7F)
          && ((JavaBoy.unsign(b1) != 0x76))) {
        /* 0x76 is HALT, and takes the place of LD (HL), (HL) */
        int sourceRegister = b1 & 0x07; /* Lower 3 bits */
        int destRegister = (b1 & 0x38) >> 3; /* Bits 5 - 3 */

        // System.out.println("LD Op src" + sourceRegister + " dest " +
        // destRegister);

        instr = "LD " + registerNames[destRegister] + ", " + registerNames[sourceRegister];
      }

      // The following section handles arithmetic instructions
      // Bit 7 6 5 4 3 2 1 0 Operation Opcode
      //     1 0 0 0 0 R R R Add ADD
      //     1 0 0 0 1 R R R Add with carry ADC
      //     1 0 0 1 0 R R R Subtract SUB
      //     1 0 0 1 1 R R R Sub with carry SBC
      //     1 0 1 0 0 R R R Logical and AND
      //     1 0 1 0 1 R R R Logical xor XOR
      //     1 0 1 1 0 R R R Logical or OR
      //     1 0 1 1 1 R R R Compare? CP

      if ((JavaBoy.unsign(b1) >= 0x80) && (JavaBoy.unsign(b1) <= 0xBF)) {
        int sourceRegister = JavaBoy.unsign(b1) & 0x07;
        int operation = (JavaBoy.unsign(b1) & 0x38) >> 3;

        // System.out.println("ALU Op " + operation + " reg " +
        // sourceRegister);

        instr = aluOperations[operation] + " A, " + registerNames[sourceRegister];
      }

      // The following section handles shift instructions
      // These are formed by the byte 0xCB followed by the this:
      // Bit 7 6 5 4 3 2 1 0 Operation Opcode
      //     0 0 0 0 0 R R R Rotate Left Carry RLC
      //     0 0 0 0 1 R R R Rotate Right Carry RRC
      //     0 0 0 1 0 R R R Rotate Left RL
      //     0 0 0 1 1 R R R Rotate Right RR
      //     0 0 1 0 0 R R R Arith. Shift Left SLA
      //     0 0 1 0 1 R R R Arith. Shift Right SRA
      //     0 0 1 1 0 R R R Hi/Lo Nibble Swap SWAP
      //     0 0 1 1 1 R R R Shift Right Logical SRL
      //     0 1 N N N R R R Bit Test n BIT
      //     1 0 N N N R R R Reset Bit n RES
      //     1 1 N N N R R R Set Bit n SET

      if (JavaBoy.unsign(b1) == 0xCB) {
        int operation;
        int sourceRegister;
        int bitNumber;

        instrLength = 2;

        switch ((JavaBoy.unsign(b2) & 0xC0) >> 6) {
          case 0:
            operation = (JavaBoy.unsign(b2) & 0x38) >> 3;
            sourceRegister = JavaBoy.unsign(b2) & 0x07;
            instr = shiftOperations[operation] + " " + registerNames[sourceRegister];
            break;
          case 1:
            bitNumber = (JavaBoy.unsign(b2) & 0x38) >> 3;
            sourceRegister = JavaBoy.unsign(b2) & 0x07;
            instr = "BIT " + bitNumber + ", " + registerNames[sourceRegister];
            break;
          case 2:
            bitNumber = (JavaBoy.unsign(b2) & 0x38) >> 3;
            sourceRegister = JavaBoy.unsign(b2) & 0x07;
            instr = "RES " + bitNumber + ", " + registerNames[sourceRegister];
            break;
          case 3:
            bitNumber = (JavaBoy.unsign(b2) & 0x38) >> 3;
            sourceRegister = JavaBoy.unsign(b2) & 0x07;
            instr = "SET " + bitNumber + ", " + registerNames[sourceRegister];
            break;
        }
      }

      System.out.print(JavaBoy.hexWord(address) + ": " + JavaBoy.hexByte(JavaBoy.unsign(b1)));

      if (instrLength >= 2) {
        System.out.print(" " + JavaBoy.hexByte(JavaBoy.unsign(b2)));
      } else {
        System.out.print("   ");
      }

      if (instrLength == 3) {
        System.out.print(" " + JavaBoy.hexByte(JavaBoy.unsign(b3)) + "  ");
      } else {
        System.out.print("     ");
      }

      System.out.println(instr);
      address += instrLength;
    }

    return null;
  }
Example #8
0
  /** Check for interrupts that need to be initiated */
  public final void initiateInterrupts() {
    if (timaEnabled && ((instrCount % instrsPerTima) == 0)) {
      if (JavaBoy.unsign(ioHandler.registers[05]) == 0) {
        ioHandler.registers[05] = ioHandler.registers[06]; // Set TIMA
        // modulo
        if ((ioHandler.registers[0xFF] & INT_TIMA) != 0) triggerInterrupt(INT_TIMA);
      }
      ioHandler.registers[05]++;
    }

    if ((instrCount % INSTRS_PER_DIV) == 0) {
      ioHandler.registers[04]++;
    }

    if ((instrCount % INSTRS_PER_HBLANK) == 0) {

      // LCY Coincidence
      // The +1 is due to the LCY register being just about to be incremented
      int cline = JavaBoy.unsign(ioHandler.registers[0x44]) + 1;
      if (cline == 152) cline = 0;

      if (((ioHandler.registers[0xFF] & INT_LCDC) != 0)
          && ((ioHandler.registers[0x41] & 64) != 0)
          && (JavaBoy.unsign(ioHandler.registers[0x45]) == cline)
          && ((ioHandler.registers[0x40] & 0x80) != 0)
          && (cline < 0x90)) {
        triggerInterrupt(INT_LCDC);
      }

      // Trigger on every line
      if (((ioHandler.registers[0xFF] & INT_LCDC) != 0)
          && ((ioHandler.registers[0x41] & 0x8) != 0)
          && ((ioHandler.registers[0x40] & 0x80) != 0)
          && (cline < 0x90)) {
        triggerInterrupt(INT_LCDC);
      }

      if ((gbcFeatures) && (ioHandler.hdmaRunning)) {
        ioHandler.performHdma();
      }

      if (JavaBoy.unsign(ioHandler.registers[0x44]) == 143) {
        for (int r = 144; r < 170; r++) {
          graphicsChip.notifyScanline(r);
        }
        if (((ioHandler.registers[0x40] & 0x80) != 0)
            && ((ioHandler.registers[0xFF] & INT_VBLANK) != 0)) {
          triggerInterrupt(INT_VBLANK);
          if (((ioHandler.registers[0x41] & 16) != 0)
              && ((ioHandler.registers[0xFF] & INT_LCDC) != 0)) {
            triggerInterrupt(INT_LCDC);
          }
        }

        boolean speedThrottle = true;
        if (!JavaBoy.runningAsApplet) {
          GameBoyScreen g = (GameBoyScreen) applet;
          speedThrottle = g.viewSpeedThrottle.getState();
        }
        if ((speedThrottle) && (graphicsChip.frameWaitTime >= 0)) {
          try {
            java.lang.Thread.sleep(graphicsChip.frameWaitTime);
          } catch (InterruptedException e) {
            // Nothing.
          }
        }
      }

      graphicsChip.notifyScanline(JavaBoy.unsign(ioHandler.registers[0x44]));
      ioHandler.registers[0x44] = (byte) (JavaBoy.unsign(ioHandler.registers[0x44]) + 1);

      if (JavaBoy.unsign(ioHandler.registers[0x44]) >= 153) {
        ioHandler.registers[0x44] = 0;
        if (soundChip != null) soundChip.outputSound();
        graphicsChip.frameDone = false;
        if (JavaBoy.runningAsApplet) {
          ((JavaBoy) (applet)).drawNextFrame();
        } else {
          ((GameBoyScreen) (applet)).repaint();
        }
        try {
          while (!graphicsChip.frameDone) {
            java.lang.Thread.sleep(1);
          }
        } catch (InterruptedException e) {
          // Nothing.
        }
      }
    }
  }