📄 cpumemory.pas
字号:
//////////////////////////////////////////////////////////////////////
// //
// cpuMemory.pas: CPU memory subsystem //
// This handles all memory access and cartridge control //
// //
// 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) //
// //
// Greets: //
// Forgotten provided C code to handle EEPROM access which I used //
// to fix my version. This was before VBA was released under the //
// GPL. //
// //
// Changelog: //
// 1.0: First public release //
// //
// Notes: //
// CPU writes currently trigger a log write, thanks to my attempt //
// to support the e-Reader. This involves a ROM writes to a high //
// address that needs to succeed (i.e. portions of the ROM space //
// for the e-Reader are actually RAM or control registers, or at //
// the very least, a single word). In addition, at least the //
// american version of the e-Reader has strangely banked Flash //
// ROM, using a typical Flash control sequence ($B0 $xx, which //
// would normally be just $B0 to suspend a prior flash sector //
// erase command, but instead switches to bank xx) to bankswitch //
// between two 64 KB pages. I've yet to test if all 8 bits are //
// used, or only the LSB, but I'd wager its only the LSB. //
// Right now, the e-Reader support is disabled, see //
// WriteROMBaby32 if you're interested in re-enabling the ROM //
// as RAM emulation. I didn't keep it there because I didn't //
// find out the extents of the special address space, only a //
// single address seems to be currently used. //
// //
// The code in vmAddBreakpoint and vmRemoveBreakpoint could be //
// simplified a bit by altering the code in the breakpoint class. //
// The toggle primitive is a remenant from when the code was all //
// a single project, no core seperation, and at the time it was //
// all that was needed. //
// //
// I'm pretty sure the SRAM support is broken, or at least dodgy. //
//
// There is some preliminary signature support, which would allow //
// the user interface to display which regions of ROM are data, //
// and which regions contain either ARM or Thumb opcodes. It is //
// currently IDFEF'ed out, and the sig writes were never added to //
// data accesses. In any event, theres no mechanism for the user //
// interface to access the sig array right now. //
// //
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
unit cpuMemory; //////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
interface ////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
uses
Math, nexus, AddressSpace;
//////////////////////////////////////////////////////////////////////
procedure SetWaitStates;
function memReadByte(address: uint32): uint32;
procedure memWriteByte(address: uint32; data: uint32);
function memReadHalfWord(address: uint32): uint32;
procedure memWriteHalfWord(address: uint32; data: uint32);
function memReadWord(address: uint32): uint32;
// Does the rotation shiz
function memLoadWord(address: uint32): uint32;
procedure memWriteWord(address: uint32; data: uint32);
function memReadHalfWordUnc(address: uint32): uint32;
function memReadWordUnc(address: uint32): uint32;
procedure memWriteHalfWordUnc(address: uint32; data: uint32);
procedure memWriteWordUnc(address: uint32; data: uint32);
function memStopAtAddy(address: uint32): boolean;
procedure InitMemory;
procedure cpuMemFree;
//////////////////////////////////////////////////////////////////////
// Exported functions ////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
function vmReadByte(address: uint32): uint8;
function vmReadHalfword(address: uint32): uint16;
function vmReadWord(address: uint32): uint32;
procedure vmWriteByte(address: uint32; data: uint8);
procedure vmWriteHalfword(address: uint32; data: uint16);
procedure vmWriteWord(address: uint32; data: uint32);
procedure vmAddBreakpoint(address: uint32; soft: boolean);
procedure vmRemoveBreakpoint(address: uint32; mask: TBreakpointModes);
procedure vmSoftBreakpoints(active: boolean);
function vmIsBreakpoint(address: uint32): TBreakpointModes;
procedure vmInsertCartridge(data: pointer; size: integer);
procedure vmRemoveCartridge;
procedure vmLockMemory(var banks: TvmMemoryLock1);
procedure vmUnlockMemory(const banks: TvmMemoryLock1);
function vmGetCartInfo(info: PvmOpaqueChunk): integer;
procedure vmSetCartInfo(size: integer; info: PvmOpaqueChunk);
//////////////////////////////////////////////////////////////////////
exports
vmReadByte,
vmReadHalfword,
vmReadWord,
vmWriteByte,
vmWriteHalfword,
vmWriteWord,
vmAddBreakpoint,
vmRemoveBreakpoint,
vmSoftBreakpoints,
vmIsBreakpoint,
vmInsertCartridge,
vmRemoveCartridge,
vmLockMemory,
vmUnlockMemory,
vmGetCartInfo,
vmSetCartInfo;
//////////////////////////////////////////////////////////////////////
type
TEepromMode = (emIdle, emReadAddress, emReadData, emReadData2, emWriteData);
TFlashMode = (fmIdle, fmWriteData, fmProductID, fmExtended, fmErase, fmSectorErase, fmBankswitch);
//////////////////////////////////////////////////////////////////////
// State Variables ///////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
var
// Memory spaces
systemROM: array[0..SYSTEM_ROM_MASK] of byte; // 00000000h..00003FFFh
exWRAM: array[0..EX_WRAM_MASK] of byte; // 02000000h..0203FFFFh
WRAM: array[0..WRAM_MASK] of byte; // 03000000h..03007FFFh
registers: array[0..REGISTERS_MASK] of byte; // 04000000h..
palette: array[0..PALETTE_MASK] of byte; // 05000000h..050003FFh
VRAM: array[0..VRAM_MASK] of byte; // 06000000h..06017FFFh
OAM: array[0..OAM_MASK] of byte; // 07000000h..070003FFh
cartRAM: array[0..(SRAM_MASK+1)*2-1] of byte; // 0E000000h..
cartRAMdirty: boolean;
lastAddress: uint32;
// CPU status
cpuGlobalTicks: uint32;
cpuStopped, cpuHalted: boolean;
irqPending: boolean;
regs: array[0..36+2] of uint32;
SPSR: uint32;
// Events
HBlankEvent: integer;
enteringHBlank: boolean;
eventCycleDelta: integer;
eventCyclesLeft: integer;
// Sound
soundA, soundB: TDSoundRecord;
sound1: TSoundChannel1;
sound2: TSoundChannel2;
sound3: TSoundChannel3;
sound4: TSoundChannel4;
//////////////////////////////////////////////////////////////////////
// Globals shared between the emulation functions ////////////////////
//////////////////////////////////////////////////////////////////////
// CPSR components (packed into regs[CPSR] for savestates)
carry: boolean;
overflow: boolean;
negative: boolean;
zero: boolean;
irqDisabled: boolean;
fiqDisabled: boolean;
thumbMode: boolean;
cpuMode: integer;
//////////////////////////////////////////////////////////////////////
// Not saved /////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
var
// Only used in the decoders
cpuCurrentOpcode: uint32;
hitBreakpoint: boolean;
barrelCarry: boolean;
haveFlippedThumb: boolean;
// Must be zero outside of vmExecute code path
quota: integer;
soundCyclesUndone: integer;
soundQuotaAtLastFlush: integer;
timerQuotaAtLastFlush: integer;
// Maybe should be saved, but isn't right now
eepromIndex, eepromByte, eepromAddress: uint32;
eepromMode: TeepromMode;
flashMode: TFlashMode;
eepromBuffer: array[0..15] of byte;
flashIndex: uint32;
cartLoaded: boolean;
cartROM1, cartROM2: Puint8Array;
cartSize1, cartSize2: uint32;
cartMask1, cartMask2: uint32;
downKeys: uint16;
cpuSourceDebug: boolean;
//////////////////////////////////////////////////////////////////////
// Signature support (will be used for smart disassembly)
// Note: no support has been added to the memory read/write code yet
//////////////////////////////////////////////////////////////////////
{$IFDEF SIGNATURES}
const
ARM_READ = 1;
THUMB_READ = 2;
DATA_READ = 4;
DATA_WRITE = 8;
var
sigs: array[0..16777215] of byte;
{$ENDIF}
//////////////////////////////////////////////////////////////////////
implementation ///////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
uses
SysUtils, cpuMisc, cpuGraphics, cpuSound, cpuPeripherals;
//////////////////////////////////////////////////////////////////////
type
TBreakpointMemory = class
private
bpBanks: array[$0..$F] of Puint8Array;
bpBankMasks: array[$0..$F] of uint32;
FCartSize1, FCartSize2: uint32;
bcartROM1, bcartROM2: Puint8Array;
bsystemROM: array[0..(SYSTEM_ROM_MASK+1) shr 4-1] of byte; // 00000000h..00003FFFh
bexWRAM: array[0..(EX_WRAM_MASK+1) shr 4-1] of byte; // 02000000h..0203FFFFh
bWRAM: array[0..(WRAM_MASK+1) shr 4-1] of byte; // 03000000h..03007FFFh
bpalette: array[0..(PALETTE_MASK+1) shr 4-1] of byte; // 05000000h..050003FFh
bVRAM: array[0..(VRAM_MASK+1) shr 4-1] of byte; // 06000000h..06017FFFh
bOAM: array[0..(OAM_MASK+1) shr 4-1] of byte; // 07000000h..070003FFh
null: uint32;
procedure SetCartSize1(const Value: uint32);
procedure SetCartSize2(const Value: uint32);
public
constructor Create;
destructor Destroy; override;
property cartSize1: uint32 read FCartSize1 write SetCartSize1;
property cartSize2: uint32 read FCartSize2 write SetCartSize2;
function isBreakpoint(address: uint32): boolean;
function toggleBreakpoint(address: uint32): boolean;
end;
//////////////////////////////////////////////////////////////////////
// Non-state Variables (all regenerated) /////////////////////////////
//////////////////////////////////////////////////////////////////////
var
bankNTimes: array[$0..$F] of byte;
bankSTimes: array[$0..$F] of byte;
interestingAddresses: TBreakpointMemory;
breakpoints, sourcePoints: TBreakpointMemory;
ReadByteFuncs, ReadHalfFuncs, ReadWordFuncs: array[0..$F] of function (address: uint32): uint32;
WriteByteFuncs, WriteHalfFuncs, WriteWordFuncs: array[0..$F] of procedure (address, data: uint32);
memBanks: array[0..15] of pointer;
memMasks: array[0..15] of uint32;
curBank: byte;
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
function ReadNOP(address: uint32): uint32;
begin
Result := 0;
end;
//////////////////////////////////////////////////////////////////////
procedure WriteNOP(address, data: uint32);
begin
//
end;
//////////////////////////////////////////////////////////////////////
// TODO: This is in-progress code for the e-Reader support
// also: see the table set functions which reference these
//////////////////////////////////////////////////////////////////////
procedure WriteROMBaby8(address, data: uint32);
begin
logWriteLn(Format('ROM[%8.8x]=%2.2x at %8.8x', [address, data, regs[R15]]));
end;
procedure WriteROMBaby16(address, data: uint32);
begin
logWriteLn(Format('ROM[%8.8x]=%4.4x at %8.8x', [address, data, regs[R15]]));
end;
procedure WriteROMBaby32(address, data: uint32);
begin
// if cartMask1 > 0 then Puint32(@(cartROM1^[address and cartMask1]))^ := data;
logWriteLn(Format('ROM[%8.8x]=%8.8x at %8.8x', [address, data, regs[R15]]));
end;
//////////////////////////////////////////////////////////////////////
function ReadBIOS_08(address: uint32): uint32;
begin
Dec(quota);
if regs[R15] < $02000000 then
Result := systemROM[address and SYSTEM_ROM_MASK]
else
Result := 0;
end;
//////////////////////////////////////////////////////////////////////
function ReadBIOS_16(address: uint32): uint32;
begin
Dec(quota);
if regs[R15] < $02000000 then
Result := Puint16(@(systemROM[address and SYSTEM_ROM_MASK]))^
else
Result := 0;
end;
//////////////////////////////////////////////////////////////////////
function ReadBIOS_32(address: uint32): uint32;
begin
Dec(quota);
if regs[R15] < $02000000 then
Result := Puint32(@(systemROM[address and SYSTEM_ROM_MASK]))^
else
Result := 0;
end;
//////////////////////////////////////////////////////////////////////
function ReadExWRAM_08(address: uint32): uint32;
begin
Dec(quota, 3);
Result := exWRAM[address and EX_WRAM_MASK];
end;
//////////////////////////////////////////////////////////////////////
function ReadExWRAM_16(address: uint32): uint32;
begin
Dec(quota, 3);
Result := Puint16(@(exWRAM[address and EX_WRAM_MASK]))^;
end;
//////////////////////////////////////////////////////////////////////
function ReadExWRAM_32(address: uint32): uint32;
begin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -