📄 arm7tdmicpu.pas
字号:
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 + -