Beispiel #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;
  }
Beispiel #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();
  }
Beispiel #3
0
  public void saveState(String extension) {
    String directory = (cartridge.romFileName + extension);

    try {
      FileOutputStream fl = new FileOutputStream(directory);
      DataOutputStream sv = new DataOutputStream(fl);

      saveData(sv, directory);

      // write battery ram
      cartridge.saveData(sv, directory);

      // write graphic memory
      graphicsChip.saveData(sv, directory);

      // write io state
      ioHandler.saveData(sv, directory);

      // stats.printStats();

      sv.close();
      fl.close();

    } catch (FileNotFoundException e) {
      System.out.println("Dmgcpu.saveState: Could not open file " + directory);
      System.out.println("Error Message: " + e.getMessage());
      System.exit(-1);
    } catch (IOException e) {
      System.out.println("Dmgcpu.saveState: Could not write to file " + directory);
      System.out.println("Error Message: " + e.getMessage());
      System.exit(-1);
    }

    System.out.println("Saved stage!");
  }
Beispiel #4
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;
    }
  }
Beispiel #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;
    }
  }
Beispiel #6
0
  public void loadState(String extension) {
    String directory = cartridge.romFileName + extension;

    try {
      reset();

      FileInputStream fl = new FileInputStream(directory);
      DataInputStream sv = new DataInputStream(fl);

      // write cpu data
      loadData(sv, directory);

      // write battery ram
      cartridge.loadData(sv, directory);

      // write graphic memory
      graphicsChip.loadData(sv, directory);

      // writes io state
      ioHandler.loadData(sv, directory);

      sv.close();
      fl.close();

    } catch (FileNotFoundException ex) {
      System.out.println("Dmgcpu.loadState: Could not open file " + directory);
      System.out.println("Error Message: " + ex.getMessage());
      System.exit(-1);
    } catch (IOException ex) {
      System.out.println("Dmgcpu.loadState: Could not read file " + directory);
      System.out.println("Error Message: " + ex.getMessage());
      System.exit(-1);
    }

    System.out.println("Loaded stage!");
  }
Beispiel #7
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.
        }
      }
    }
  }
Beispiel #8
0
 /** Clear up memory */
 public void dispose() {
   graphicsChip.dispose();
 }