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

📄 arm7tdmicpu.pas

📁 一个不出名的GBA模拟器
💻 PAS
📖 第 1 页 / 共 2 页
字号:
//////////////////////////////////////////////////////////////////////
//                                                                  //
// ARM7tdmiCPU.pas: CPU interface                                   //
//   Provides an interface to the CPU for whatever uses the core,   //
//   including code to actually run the CPU, graphics, and sound    //
//   modules, calling the appropriate decoder/executers as needed.  //
//                                                                  //
// The contents of this file are subject to the Bottled Light       //
// Public License Version 1.0 (the "License"); you may not use this //
// file except in compliance with the License. You may obtain a     //
// copy of the License at http://www.bottledlight.com/BLPL/         //
//                                                                  //
// Software distributed under the License is distributed on an      //
// "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or   //
// implied. See the License for the specific language governing     //
// rights and limitations under the License.                        //
//                                                                  //
// The Original Code is the Mappy VM Core, released April 1st, 2003 //
// The Initial Developer of the Original Code is Bottled Light,     //
// Inc. Portions created by Bottled Light, Inc. are Copyright       //
// (C) 2001 - 2003 Bottled Light, Inc. All Rights Reserved.         //
//                                                                  //
// Author(s):                                                       //
//   Michael Noland (joat), michael@bottledlight.com                //
//                                                                  //
// Changelog:                                                       //
//   1.0: First public release (April 1st, 2003)                    //
//                                                                  //
// Notes:                                                           //
//   Todo: Figure out a way to make vmStep really step a single     //
//   instruction.  Currently it will also run a single cycle of     //
//   any non-atomic action like a write to $04000301, which can     //
//   be muoy annoying.  The easiest way would probably be to make   //
//   vmStep run cycles until cpuStopped and cpuHalted are false,    //
//   but that could lead to an infinite loop if some idiot halts    //
//   the CPU without providing any wakeup conditions.               //
//                                                                  //
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
unit ARM7tdmiCPU; ////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
interface ////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

uses
  SysUtils, Math, nexus, AddressSpace, cpuMisc, cpuMemory,
  cpuGraphics, cpuSound, cpuARMCore, cpuThumbCore, cpuPeripherals;

//////////////////////////////////////////////////////////////////////
// Exported functions ////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

// vmReset returns the CPU to its initial state, as if it's reset pin
// were pulsed.
procedure vmReset;

// vmExecute runs the CPU for a number of cycles and returns the
// number of cycles actually executed, which could be less if a
// breakpoint were reached, or more if a long DMA or opcode occured.
function vmExecute(numCycles: integer): uint32;

// vmStep() executes a single instruction
procedure vmStep;

// vmGetRegister returns the contents of a single CPU register
function vmGetRegister(index: uint32): uint32;

// vmGetRegisters returns the contents of all CPU registers
procedure vmGetRegisters(var copy: TvmRegisterFile);

// vmSetRegister sets the contents of a single CPU register
procedure vmSetRegister(index, value: uint32);

// vmSetRegisters() sets the contents of all CPU registers
procedure vmSetRegisters(const copy: TvmRegisterFile);

// vmStartProfile() returns a profiling token that can be used to get
// the exact number of elapsed cycles between a call to
// vmStartProfile and vmStopProfile.  Its not good for anything else.
function vmStartProfile: TvmProfileToken;

// vmStopProfile() returns the number of MVM CPU cycles elapsed since
// the token passed in was created.  That token is no longer valid.
function vmStopProfile(const token: TvmProfileToken): int64;

// vmCurrentPC() returns the address of next instruction to execute
function vmCurrentPC: uint32;

// vmHitBP() returns true if the next instruction is a breakpoint.
function vmHitBP: boolean;

// vmRenderFrame() runs the CPU core for enough cycles to advance to
// the next frame boundary (1232*228 cycles).
procedure vmRenderFrame;

// 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;

// vmLoadSavestate() sets the entire MVM state from a savestate image
procedure vmLoadState(save: PvmSavestate);

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

exports
  vmReset,
  vmExecute,
  vmStep,
  vmGetRegister,
  vmGetRegisters,
  vmSetRegister,
  vmSetRegisters,
  vmStartProfile,
  vmStopProfile,
  vmCurrentPC,
  vmHitBP,
  vmRenderFrame,
  vmSaveState,
  vmLoadState;

//////////////////////////////////////////////////////////////////////
implementation ///////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

// Not valid during emulation, only from external code
function vmStartProfile: TvmProfileToken;
begin
  Result := pointer(cpuGlobalTicks);
end;

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

// Not valid during emulation, only from external code
function vmStopProfile(const token: TvmProfileToken): int64;
begin
  Result := uint32(cpuGlobalTicks - uint32(token));
end;

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

// vmCurrentPC() returns the address of next instruction to execute
function vmCurrentPC: uint32;
begin
  Result := regs[R15] - 4;
  if thumbMode then Inc(Result, 2);
end;

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

// vmHitBP() returns true if the next instruction is a breakpoint.
function vmHitBP: boolean;
begin
  Result := hitBreakpoint;
end;

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

// vmRenderFrame() runs the CPU core for enough cycles to advance to
// the next frame boundary (1232*228 cycles).
procedure vmRenderFrame;
const
  CYCS_PER_FRAME = 1232*228;
begin
  vmExecute(CYCS_PER_FRAME - cpuGlobalTicks mod CYCS_PER_FRAME);
end;

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

// vmReset returns the CPU to its initial state, as if it's reset pin
// were pulsed.
procedure vmReset;
var
  i: integer;
begin
  // When reset, the ARM7tdmi copies the current PC to R14_svc and the
  // current CPSR to SPSR_svc.  After this, it switches to supervisor
  // mode and sets the I and F bits.  It then forces the PC to the reset
  // vector and resumes execution in ARM mode
  cpuEnterException(MODE_SUPERVISOR, 0);
  irqDisabled := true;
  fiqDisabled := true;

  // Initialize the stack pointers (fixme: should be ditched once bios only)
  regs[R13_svc] := $03007FE0;
  regs[R13_irq] := $03007FA0;
  regs[R13] := $03007F00;

  // Initialize the I/O registers (fixme: should be removed once bios only)
  for i := 0 to REGISTERS_MASK do registers[i] := 0;
  registers[DISPLAY_CR] := $80;
  Puint16(@(registers[BG2_A]))^ := $0100;
  Puint16(@(registers[BG2_D]))^ := $0100;
  Puint16(@(registers[BG3_A]))^ := $0100;
  Puint16(@(registers[BG3_D]))^ := $0100;
  Puint32(@(registers[BG2_X_LATCH]))^ := 0;
  Puint32(@(registers[BG2_Y_LATCH]))^ := 0;
  Puint32(@(registers[BG3_X_LATCH]))^ := 0;
  Puint32(@(registers[BG3_Y_LATCH]))^ := 0;
  registers[BG2_X_DIRTY] := 0;
  registers[BG2_Y_DIRTY] := 0;
  registers[BG3_X_DIRTY] := 0;
  registers[BG3_Y_DIRTY] := 0;

  downkeys := $3FF;
  Puint16(@(registers[KEYS]))^ := downkeys;

  // Initialize RAM
  FillChar(VRAM, VRAM_MASK+1, 0);
  FillChar(WRAM, WRAM_MASK+1, 0);
  FillChar(OAM, OAM_MASK+1, 0);
  FillChar(Palette, PALETTE_MASK+1, 0);
  FillChar(cartRAM, SRAM_MASK+1, $FF);
  cartRAMdirty := false;

  // Event setup
  enteringHBlank := true;
  HBlankEvent := 960;
  eventCycleDelta := HBlankEvent;
  eventCyclesLeft := HBlankEvent;
  cpuGlobalTicks := 0;

  // CPU power save (04000301) support
  cpuStopped := false;
  cpuHalted := false;
end;

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

// vmExecute runs the CPU for a number of cycles and returns the
// number of cycles actually executed, which could be less if a
// breakpoint were reached, or more if a long DMA or opcode occured.
function vmExecute(numCycles: integer): uint32;
var

⌨️ 快捷键说明

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