⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 arm7tdmicpu.pas

📁 一个不出名的GBA模拟器
💻 PAS
📖 第 1 页 / 共 2 页
字号:
  quotaLeft: integer;
  cyclesForThisQuota: integer;
begin
  hitBreakpoint := false;
  quotaLeft := numCycles;
  repeat
    // Activate an IRQ if queued
    if irqPending then begin
      if cpuHalted then begin
        if Puint16(@(registers[IRQ_FLAGS]))^ and IRQ_KEY <> 0 then begin
          cpuHalted := false;
          cpuStopped := false;
        end;
      end else
        cpuStopped := false;

      if not irqDisabled then begin
        irqPending := false;
//        logWriteLn('Entering IRQ from ' + IntToHex(vmCurrentPC, 8));
        cpuEnterException(MODE_IRQ, IRQ_VECTOR);
        irqDisabled := true;
      end;
    end;

    // Run a slice of opcodes
    quota := Min(eventCyclesLeft, quotaLeft);
    cyclesForThisQuota := quota;
    soundQuotaAtLastFlush := cyclesForThisQuota;
    timerQuotaAtLastFlush := cyclesForThisQuota;

    if cpuStopped then
      quota := 0
    else begin
      if thumbMode then EmulateThumb else EmulateArm;
      thumbMode := thumbMode xor haveFlippedThumb;
      haveFlippedThumb := false;
    end;

    flushTimers;

    // Update the counters by (cyclesForThisQuota - quota) cycles
    Dec(cyclesForThisQuota, quota);
    Dec(quotaLeft, cyclesForThisQuota);
    Dec(eventCyclesLeft, cyclesForThisQuota);
    Inc(soundCyclesUndone, cyclesForThisQuota);

    quota := 0;
    soundQuotaAtLastFlush := 0;
    timerQuotaAtLastFlush := 0;

    // Process any outstanding events
    if eventCyclesLeft <= 0 then begin
      // (eventCycleDelta - eventCyclesLeft) cycles since the last event
      Dec(eventCycleDelta, eventCyclesLeft);
      Dec(HBlankEvent, eventCycleDelta);

      // Take care of the raster clock events
      while HBlankEvent <= 0 do HBlank;
      eventCycleDelta := HBlankEvent;
      eventCyclesLeft := eventCycleDelta;
    end;
  until (quotaLeft <= 0) or (hitBreakpoint);

  // Flush the sound data to the system
  soundChanging;

  // Return the number of cycles executed and update the global count
  Result := numCycles - quotaLeft;
  Inc(cpuGlobalTicks, Result);
end;

//////////////////////////////////////////////////////////////////////

// vmGetRegister returns the contents of a single CPU register
function vmGetRegister(index: uint32): uint32;
begin
  if index = CPSR then Result := cpuReadCPSR else Result := regs[index];
end;

//////////////////////////////////////////////////////////////////////

// vmGetRegisters returns the contents of all CPU registers
procedure vmGetRegisters(var copy: TvmRegisterFile);
begin
  regs[CPSR] := cpuReadCPSR;
  Move(regs, copy, SizeOf(TvmRegisterFile));
end;

//////////////////////////////////////////////////////////////////////

// vmSetRegister sets the contents of a single CPU register
procedure vmSetRegister(index, value: uint32);
var
  oldMode: boolean;
begin
  if index = R15 then begin
    regs[R15] := value;
    if thumbMode then FlushPipeThumb else FlushPipeARM;
  end else if index = CPSR then begin
    oldMode := thumbMode;
    cpuWriteCPSR(value);
    if thumbMode <> oldMode then begin
      if oldMode then Dec(regs[R15], 2) else Dec(regs[R15], 4);
      if thumbMode then FlushPipeThumb else FlushPipeARM;
    end;
  end else
    regs[index] := value;
end;

//////////////////////////////////////////////////////////////////////

// vmSetRegisters() sets the contents of all CPU registers
procedure vmSetRegisters(const copy: TvmRegisterFile);
begin
  Move(copy, regs, SizeOf(TvmRegisterFile));
end;

//////////////////////////////////////////////////////////////////////

// vmStep() executes a single instruction
// TODO: figure out a way to make this really do that, it will also
// run a single cycle of something like a write to 0x04000301, which
// can be muoy annoying.
procedure vmStep;
begin
  vmExecute(1);
end;

//////////////////////////////////////////////////////////////////////

// vmSaveState() is used to save the entire MVM state.  If nil is
// passed in, it returns the required amount of memory for the save
// buffer.  Otherwise, it stores a savestate image in the buffer.
function vmSaveState(save: PvmSavestate): integer;
begin
  Result := SizeOf(TvmSavestate1);
  if save = nil then Exit;

  save^.magic := $DEAF4242;
  save^.version := 1;
  save^.size := Result;

  // Memory space
  Move(systemROM, save^.systemROM, SYSTEM_ROM_MASK+1);
  Move(exWRAM, save^.exWRAM, EX_WRAM_MASK+1);
  Move(WRAM, save^.WRAM, WRAM_MASK+1);
  Move(registers, save^.registers, REGISTERS_MASK+1);
  Move(palette, save^.palette, PALETTE_MASK+1);
  Move(VRAM, save^.VRAM, VRAM_MASK+1);
  Move(OAM, save^.OAM, OAM_MASK+1);
  Move(cartRAM, save^.cartRAM, SRAM_MASK+1);
  save^.cartRAMdirty := cartRAMdirty;
  save^.lastAddress := lastAddress;
  save^.cartLoaded := cartLoaded;

  // CPU status
  save^.cpuGlobalTicks := cpuGlobalTicks;
  save^.cpuStopped := cpuStopped;
  save^.cpuHalted := cpuHalted;
  save^.irqPending := irqPending;
  save^.SPSR := SPSR;

  regs[CPSR] := cpuReadCPSR;
  Move(regs, save^.regs, SizeOf(regs));

  // Events
  save^.HBlankEvent := HBlankEvent;
  save^.enteringHBlank := enteringHBlank;
  save^.eventCycleDelta := eventCycleDelta;
  save^.eventCyclesLeft := eventCyclesLeft;

  // Sound
  Move(soundA, save^.soundA, SizeOf(soundA));
  Move(soundB, save^.soundB, SizeOf(soundB));
  Move(sound1, save^.sound1, SizeOf(sound1));
  Move(sound2, save^.sound2, SizeOf(sound2));
  Move(sound3, save^.sound3, SizeOf(sound3));
  Move(sound4, save^.sound4, SizeOf(sound4));
end;

//////////////////////////////////////////////////////////////////////

// vmLoadSavestate() sets the entire MVM state from a savestate image
procedure vmLoadState(save: PvmSavestate);
begin
  if (save^.magic <> $DEAF4242) or (save^.version <> 1) or (save^.size <> SizeOf(TvmSavestate1)) then begin
    logWriteLn('Invalid Savestate (only version 1 files are currently supported');
    Exit;
  end;

  // Memory space
  Move(save^.systemROM, systemROM, SYSTEM_ROM_MASK+1);
  Move(save^.exWRAM, exWRAM, EX_WRAM_MASK+1);
  Move(save^.WRAM, WRAM, WRAM_MASK+1);
  Move(save^.registers, registers, REGISTERS_MASK+1);
  Move(save^.palette, palette, PALETTE_MASK+1);
  Move(save^.VRAM, VRAM, VRAM_MASK+1);
  Move(save^.OAM, OAM, OAM_MASK+1);
  Move(save^.cartRAM, cartRAM, SRAM_MASK+1);
  cartRAMdirty := save^.cartRAMdirty;
  lastAddress := save^.lastAddress;

  // CPU status
  cpuGlobalTicks := save^.cpuGlobalTicks;
  cpuStopped := save^.cpuStopped;
  cpuHalted := save^.cpuHalted;
  irqPending := save^.irqPending;
  SPSR := save^.SPSR;
  Move(save^.regs, regs, SizeOf(regs));
  cpuMode := regs[CPSR] and $1F;
  cpuWriteCPSR(regs[CPSR]);

  // Events
  HBlankEvent := save^.HBlankEvent;
  enteringHBlank := save^.enteringHBlank;
  eventCycleDelta := save^.eventCycleDelta;
  eventCyclesLeft := save^.eventCyclesLeft;

  // Sound
  Move(save^.soundA, soundA, SizeOf(soundA));
  Move(save^.soundB, soundB, SizeOf(soundB));
  Move(save^.sound1, sound1, SizeOf(sound1));
  Move(save^.sound2, sound2, SizeOf(sound2));
  Move(save^.sound3, sound3, SizeOf(sound3));
  Move(save^.sound4, sound4, SizeOf(sound4));

  // Etc...
  SetWaitStates;
end;

//////////////////////////////////////////////////////////////////////

end.

//////////////////////////////////////////////////////////////////////

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -