Memory manager refactoring
This commit is contained in:
parent
cc8ddabf88
commit
4ee2c42663
13 changed files with 521 additions and 305 deletions
|
@ -54,7 +54,7 @@ void BaseCartridge::Init()
|
|||
//throw std::runtime_error("invalid rom (?)");
|
||||
}
|
||||
|
||||
_cartInfo = *(SnesCartInformation*)(&_prgRom[headerOffset]);
|
||||
memcpy(&_cartInfo, _prgRom + headerOffset, sizeof(SnesCartInformation));
|
||||
|
||||
_saveRamSize = _cartInfo.SramSize > 0 ? 1024 * (1 << _cartInfo.SramSize) : 0;
|
||||
_saveRam = new uint8_t[_saveRamSize];
|
||||
|
@ -62,6 +62,14 @@ void BaseCartridge::Init()
|
|||
LoadBattery();
|
||||
}
|
||||
|
||||
RomInfo BaseCartridge::GetRomInfo()
|
||||
{
|
||||
RomInfo info;
|
||||
info.Header = _cartInfo;
|
||||
info.RomPath = _romPath;
|
||||
return info;
|
||||
}
|
||||
|
||||
void BaseCartridge::LoadBattery()
|
||||
{
|
||||
if(_saveRamSize > 0) {
|
||||
|
@ -135,11 +143,11 @@ void BaseCartridge::MapBanks(MemoryManager &mm, vector<unique_ptr<IMemoryHandler
|
|||
void BaseCartridge::RegisterHandlers(MemoryManager &mm)
|
||||
{
|
||||
for(uint32_t i = 0; i < _prgRomSize; i += 0x1000) {
|
||||
_prgRomHandlers.push_back(unique_ptr<RomHandler>(new RomHandler(_prgRom + i)));
|
||||
_prgRomHandlers.push_back(unique_ptr<RomHandler>(new RomHandler(_prgRom, i, SnesMemoryType::PrgRom)));
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < _saveRamSize; i += 0x1000) {
|
||||
_saveRamHandlers.push_back(unique_ptr<RamHandler>(new RamHandler(_saveRam + i)));
|
||||
_saveRamHandlers.push_back(unique_ptr<RamHandler>(new RamHandler(_saveRam, i, SnesMemoryType::SaveRam)));
|
||||
}
|
||||
|
||||
if(GetCartFlags() & CartFlags::LoRom) {
|
||||
|
|
|
@ -28,6 +28,12 @@ struct SnesCartInformation
|
|||
uint8_t Checksum[2];
|
||||
};
|
||||
|
||||
struct RomInfo
|
||||
{
|
||||
SnesCartInformation Header;
|
||||
string RomPath;
|
||||
};
|
||||
|
||||
namespace CartFlags
|
||||
{
|
||||
enum CartFlags
|
||||
|
@ -69,6 +75,8 @@ public:
|
|||
|
||||
CartFlags::CartFlags GetCartFlags();
|
||||
|
||||
RomInfo GetRomInfo();
|
||||
|
||||
void RegisterHandlers(MemoryManager &mm);
|
||||
|
||||
uint8_t* DebugGetPrgRom() { return _prgRom; }
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include "ControlManager.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "DmaController.h"
|
||||
#include "BaseCartridge.h"
|
||||
#include "RamHandler.h"
|
||||
#include "Debugger.h"
|
||||
#include "NotificationManager.h"
|
||||
#include "SoundMixer.h"
|
||||
|
@ -21,6 +23,10 @@
|
|||
#include "../Utilities/PlatformUtilities.h"
|
||||
#include "../Utilities/FolderUtilities.h"
|
||||
|
||||
Console::~Console()
|
||||
{
|
||||
}
|
||||
|
||||
void Console::Initialize()
|
||||
{
|
||||
_notificationManager.reset(new NotificationManager());
|
||||
|
@ -86,10 +92,12 @@ void Console::Stop()
|
|||
debugger->Run();
|
||||
}
|
||||
|
||||
_debugger.reset();
|
||||
|
||||
_runLock.WaitForRelease();
|
||||
|
||||
//Make sure we release both pointers to destroy the debugger before everything else
|
||||
_debugger.reset();
|
||||
debugger.reset();
|
||||
|
||||
_cpu.reset();
|
||||
_ppu.reset();
|
||||
_spc.reset();
|
||||
|
|
|
@ -44,6 +44,8 @@ private:
|
|||
atomic<bool> _stopFlag;
|
||||
|
||||
public:
|
||||
~Console();
|
||||
|
||||
void Initialize();
|
||||
void Release();
|
||||
|
||||
|
|
|
@ -10,4 +10,39 @@ enum class SnesMemoryType
|
|||
VideoRam,
|
||||
SpriteRam,
|
||||
CGRam,
|
||||
};
|
||||
};
|
||||
|
||||
struct AddressInfo
|
||||
{
|
||||
int32_t Address;
|
||||
SnesMemoryType Type;
|
||||
};
|
||||
|
||||
namespace CdlFlags
|
||||
{
|
||||
enum CdlFlags : uint8_t
|
||||
{
|
||||
None = 0x00,
|
||||
Code = 0x01,
|
||||
Data = 0x02,
|
||||
JumpTarget = 0x04,
|
||||
SubEntryPoint = 0x08,
|
||||
|
||||
IndexMode8 = 0x10,
|
||||
MemoryMode8 = 0x20,
|
||||
};
|
||||
}
|
||||
|
||||
enum class CdlStripFlag
|
||||
{
|
||||
StripNone = 0,
|
||||
StripUnused,
|
||||
StripUsed,
|
||||
};
|
||||
|
||||
struct CdlRatios
|
||||
{
|
||||
float CodeRatio;
|
||||
float DataRatio;
|
||||
float PrgRatio;
|
||||
};
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "DebugTypes.h"
|
||||
|
||||
class IMemoryHandler
|
||||
{
|
||||
public:
|
||||
virtual uint8_t Read(uint32_t addr) = 0;
|
||||
virtual uint8_t Peek(uint32_t addr) = 0;
|
||||
virtual void Write(uint32_t addr, uint8_t value) = 0;
|
||||
|
||||
virtual AddressInfo GetAbsoluteAddress(uint32_t address) = 0;
|
||||
|
||||
//virtual void GetMemoryRanges(MemoryRanges &ranges) = 0;
|
||||
//virtual uint8_t PeekRAM(uint16_t addr) { return 0; }
|
||||
|
||||
|
|
258
Core/MemoryManager.cpp
Normal file
258
Core/MemoryManager.cpp
Normal file
|
@ -0,0 +1,258 @@
|
|||
#include "stdafx.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "Console.h"
|
||||
#include "BaseCartridge.h"
|
||||
#include "Cpu.h"
|
||||
#include "Ppu.h"
|
||||
#include "Spc.h"
|
||||
#include "RegisterHandlerA.h"
|
||||
#include "RegisterHandlerB.h"
|
||||
#include "RamHandler.h"
|
||||
#include "MessageManager.h"
|
||||
#include "DebugTypes.h"
|
||||
#include "../Utilities/HexUtilities.h"
|
||||
|
||||
void MemoryManager::Initialize(shared_ptr<Console> console)
|
||||
{
|
||||
_lastMasterClock = 0;
|
||||
_masterClock = 0;
|
||||
_console = console;
|
||||
_regs = console->GetInternalRegisters().get();
|
||||
_ppu = console->GetPpu();
|
||||
|
||||
_workRam = new uint8_t[MemoryManager::WorkRamSize];
|
||||
|
||||
_registerHandlerA.reset(new RegisterHandlerA(
|
||||
console->GetDmaController().get(),
|
||||
console->GetInternalRegisters().get(),
|
||||
console->GetControlManager().get()
|
||||
));
|
||||
|
||||
_registerHandlerB.reset(new RegisterHandlerB(
|
||||
_ppu.get(),
|
||||
console->GetSpc().get(),
|
||||
_workRam
|
||||
));
|
||||
|
||||
memset(_handlers, 0, sizeof(_handlers));
|
||||
//memset(_workRam, 0, 128 * 1024);
|
||||
|
||||
for(uint32_t i = 0; i < 128 * 1024; i += 0x1000) {
|
||||
_workRamHandlers.push_back(unique_ptr<RamHandler>(new RamHandler(_workRam, i, SnesMemoryType::WorkRam)));
|
||||
RegisterHandler(0x7E0000 | i, 0x7E0000 | (i + 0xFFF), _workRamHandlers[_workRamHandlers.size() - 1].get());
|
||||
}
|
||||
|
||||
for(int i = 0; i <= 0x3F; i++) {
|
||||
RegisterHandler((i << 16) | 0x2000, (i << 16) | 0x2FFF, _registerHandlerB.get());
|
||||
RegisterHandler(((i | 0x80) << 16) | 0x2000, ((i | 0x80) << 16) | 0x2FFF, _registerHandlerB.get());
|
||||
|
||||
RegisterHandler((i << 16) | 0x4000, (i << 16) | 0x4FFF, _registerHandlerA.get());
|
||||
RegisterHandler(((i | 0x80) << 16) | 0x4000, ((i | 0x80) << 16) | 0x4FFF, _registerHandlerA.get());
|
||||
}
|
||||
|
||||
for(int i = 0; i < 0x3F; i++) {
|
||||
RegisterHandler((i << 16) | 0x0000, (i << 16) | 0x0FFF, _workRamHandlers[0].get());
|
||||
RegisterHandler((i << 16) | 0x1000, (i << 16) | 0x1FFF, _workRamHandlers[1].get());
|
||||
}
|
||||
|
||||
for(int i = 0x80; i < 0xBF; i++) {
|
||||
RegisterHandler((i << 16) | 0x0000, (i << 16) | 0x0FFF, _workRamHandlers[0].get());
|
||||
RegisterHandler((i << 16) | 0x1000, (i << 16) | 0x1FFF, _workRamHandlers[1].get());
|
||||
}
|
||||
|
||||
console->GetCartridge()->RegisterHandlers(*this);
|
||||
|
||||
GenerateMasterClockTable();
|
||||
}
|
||||
|
||||
MemoryManager::~MemoryManager()
|
||||
{
|
||||
delete[] _workRam;
|
||||
}
|
||||
|
||||
void MemoryManager::RegisterHandler(uint32_t startAddr, uint32_t endAddr, IMemoryHandler * handler)
|
||||
{
|
||||
if((startAddr & 0xFFF) != 0 || (endAddr & 0xFFF) != 0xFFF) {
|
||||
throw std::runtime_error("invalid start/end address");
|
||||
}
|
||||
|
||||
for(uint32_t addr = startAddr; addr < endAddr; addr += 0x1000) {
|
||||
if(_handlers[addr >> 12]) {
|
||||
throw std::runtime_error("handler already set");
|
||||
}
|
||||
|
||||
_handlers[addr >> 12] = handler;
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryManager::GenerateMasterClockTable()
|
||||
{
|
||||
//This is incredibly inaccurate
|
||||
for(int j = 0; j < 2; j++) {
|
||||
for(int i = 0; i < 0x10000; i++) {
|
||||
uint8_t bank = (i & 0xFF00) >> 8;
|
||||
if(bank >= 0x40 && bank <= 0x7F) {
|
||||
//Slow
|
||||
_masterClockTable[j][i] = 8;
|
||||
} else if(bank >= 0xCF) {
|
||||
//Slow or fast (depending on register)
|
||||
_masterClockTable[j][i] = j == 1 ? 6 : 8;
|
||||
} else {
|
||||
uint8_t page = (i & 0xFF);
|
||||
if(page <= 0x1F) {
|
||||
//Slow
|
||||
_masterClockTable[j][i] = 6;
|
||||
} else if(page >= 0x20 && page <= 0x3F) {
|
||||
//Fast
|
||||
_masterClockTable[j][i] = 6;
|
||||
} else if(page == 0x40 || page == 0x41) {
|
||||
//Extra slow
|
||||
_masterClockTable[j][i] = 12;
|
||||
} else if(page >= 0x42 && page <= 0x5F) {
|
||||
//Fast
|
||||
_masterClockTable[j][i] = 6;
|
||||
} else if(page >= 0x60 && page <= 0x7F) {
|
||||
//Slow
|
||||
_masterClockTable[j][i] = 8;
|
||||
} else {
|
||||
//page >= $80
|
||||
//Slow or fast (depending on register)
|
||||
_masterClockTable[j][i] = j == 1 ? 6 : 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryManager::IncrementMasterClock(uint32_t addr)
|
||||
{
|
||||
_previousSpeed = _masterClockTable[(uint8_t)_regs->IsFastRomEnabled()][addr >> 8];
|
||||
_masterClock += _previousSpeed;
|
||||
while(_lastMasterClock < _masterClock - 3) {
|
||||
_ppu->Exec();
|
||||
_lastMasterClock += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryManager::IncrementMasterClockValue(uint16_t value)
|
||||
{
|
||||
_masterClock += value;
|
||||
while(_lastMasterClock < _masterClock - 3) {
|
||||
_ppu->Exec();
|
||||
_lastMasterClock += 4;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t MemoryManager::Read(uint32_t addr, MemoryOperationType type)
|
||||
{
|
||||
IncrementMasterClock(addr);
|
||||
|
||||
uint8_t value;
|
||||
if(_handlers[addr >> 12]) {
|
||||
value = _handlers[addr >> 12]->Read(addr);
|
||||
} else {
|
||||
//open bus
|
||||
value = (addr >> 12);
|
||||
|
||||
MessageManager::DisplayMessage("Debug", "Read - missing handler: $" + HexUtilities::ToHex(addr));
|
||||
}
|
||||
_console->ProcessCpuRead(addr, value, type);
|
||||
return value;
|
||||
}
|
||||
|
||||
uint8_t MemoryManager::ReadDma(uint32_t addr)
|
||||
{
|
||||
IncrementMasterClockValue<4>();
|
||||
uint8_t value;
|
||||
if(_handlers[addr >> 12]) {
|
||||
value = _handlers[addr >> 12]->Read(addr);
|
||||
} else {
|
||||
//open bus
|
||||
value = (addr >> 12);
|
||||
MessageManager::DisplayMessage("Debug", "Read - missing handler: $" + HexUtilities::ToHex(addr));
|
||||
}
|
||||
_console->ProcessCpuRead(addr, value, MemoryOperationType::DmaRead);
|
||||
return value;
|
||||
}
|
||||
|
||||
uint8_t MemoryManager::Peek(uint32_t addr)
|
||||
{
|
||||
//Read, without triggering side-effects
|
||||
uint8_t value = 0;
|
||||
if(_handlers[addr >> 12]) {
|
||||
value = _handlers[addr >> 12]->Peek(addr);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void MemoryManager::Write(uint32_t addr, uint8_t value, MemoryOperationType type)
|
||||
{
|
||||
IncrementMasterClock(addr);
|
||||
|
||||
_console->ProcessCpuWrite(addr, value, type);
|
||||
if(_handlers[addr >> 12]) {
|
||||
return _handlers[addr >> 12]->Write(addr, value);
|
||||
} else {
|
||||
MessageManager::DisplayMessage("Debug", "Write - missing handler: $" + HexUtilities::ToHex(addr) + " = " + HexUtilities::ToHex(value));
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryManager::WriteDma(uint32_t addr, uint8_t value)
|
||||
{
|
||||
IncrementMasterClockValue<4>();
|
||||
|
||||
_console->ProcessCpuWrite(addr, value, MemoryOperationType::DmaWrite);
|
||||
if(_handlers[addr >> 12]) {
|
||||
return _handlers[addr >> 12]->Write(addr, value);
|
||||
} else {
|
||||
MessageManager::DisplayMessage("Debug", "Write - missing handler: $" + HexUtilities::ToHex(addr) + " = " + HexUtilities::ToHex(value));
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t MemoryManager::GetMasterClock()
|
||||
{
|
||||
return _masterClock;
|
||||
}
|
||||
|
||||
uint8_t * MemoryManager::DebugGetWorkRam()
|
||||
{
|
||||
return _workRam;
|
||||
}
|
||||
|
||||
AddressInfo MemoryManager::GetAbsoluteAddress(uint32_t addr)
|
||||
{
|
||||
if(_handlers[addr >> 12]) {
|
||||
return _handlers[addr >> 12]->GetAbsoluteAddress(addr);
|
||||
} else {
|
||||
return { -1, SnesMemoryType::CpuMemory };
|
||||
}
|
||||
}
|
||||
|
||||
int MemoryManager::GetRelativeAddress(AddressInfo &address, int32_t cpuAddress)
|
||||
{
|
||||
uint16_t startPosition;
|
||||
if(cpuAddress < 0) {
|
||||
uint8_t bank = _console->GetCpu()->GetState().K;
|
||||
startPosition = ((bank & 0xC0) << 4);
|
||||
} else {
|
||||
startPosition = (cpuAddress >> 12) & 0xF00;
|
||||
}
|
||||
|
||||
for(int i = startPosition; i <= 0xFFF; i++) {
|
||||
if(_handlers[i]) {
|
||||
AddressInfo addrInfo = _handlers[i]->GetAbsoluteAddress(address.Address & 0xFFF);
|
||||
if(addrInfo.Type == address.Type && addrInfo.Address == address.Address) {
|
||||
return (i << 12) | (address.Address & 0xFFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < startPosition; i++) {
|
||||
if(_handlers[i]) {
|
||||
AddressInfo addrInfo = _handlers[i]->GetAbsoluteAddress(address.Address & 0xFFF);
|
||||
if(addrInfo.Type == address.Type && addrInfo.Address == address.Address) {
|
||||
return (i << 12) | (address.Address & 0xFFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
|
@ -1,86 +1,16 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "Console.h"
|
||||
#include "DebugTypes.h"
|
||||
#include "Ppu.h"
|
||||
#include "Spc.h"
|
||||
#include "RamHandler.h"
|
||||
#include "DmaController.h"
|
||||
#include "BaseCartridge.h"
|
||||
#include "ControlManager.h"
|
||||
#include "InternalRegisters.h"
|
||||
#include "IMemoryHandler.h"
|
||||
#include "MessageManager.h"
|
||||
#include "../Utilities/HexUtilities.h"
|
||||
|
||||
class CpuRegisterHandler : public IMemoryHandler
|
||||
{
|
||||
private:
|
||||
Ppu *_ppu;
|
||||
Spc *_spc;
|
||||
DmaController *_dmaController;
|
||||
InternalRegisters *_regs;
|
||||
ControlManager *_controlManager;
|
||||
uint8_t *_workRam;
|
||||
uint32_t _wramPosition;
|
||||
|
||||
public:
|
||||
CpuRegisterHandler(Ppu *ppu, Spc *spc, DmaController *dmaController, InternalRegisters *regs, ControlManager *controlManager, uint8_t *workRam)
|
||||
{
|
||||
_ppu = ppu;
|
||||
_spc = spc;
|
||||
_regs = regs;
|
||||
_dmaController = dmaController;
|
||||
_controlManager = controlManager;
|
||||
|
||||
_workRam = workRam;
|
||||
_wramPosition = 0;
|
||||
}
|
||||
|
||||
uint8_t Read(uint32_t addr) override
|
||||
{
|
||||
addr &= 0xFFFF;
|
||||
if(addr >= 0x2140 && addr <= 0x217F) {
|
||||
return _spc->Read(addr & 0x03);
|
||||
} else if(addr == 0x2180) {
|
||||
return _workRam[_wramPosition++];
|
||||
} else if(addr == 0x4016 || addr == 0x4017) {
|
||||
return _controlManager->Read(addr);
|
||||
} else if(addr < 0x4200) {
|
||||
return _ppu->Read(addr);
|
||||
} else if(addr >= 0x4300) {
|
||||
return _dmaController->Read(addr);
|
||||
} else {
|
||||
return _regs->Read(addr);
|
||||
}
|
||||
}
|
||||
|
||||
void Write(uint32_t addr, uint8_t value) override
|
||||
{
|
||||
addr &= 0xFFFF;
|
||||
if(addr >= 0x2140 && addr <= 0x217F) {
|
||||
return _spc->Write(addr & 0x03, value);
|
||||
} if(addr >= 0x2180 && addr <= 0x2183) {
|
||||
switch(addr & 0xFFFF) {
|
||||
case 0x2180:
|
||||
_workRam[_wramPosition] = value;
|
||||
_wramPosition = (_wramPosition + 1) & (0x1FFFF);
|
||||
break;
|
||||
|
||||
case 0x2181: _wramPosition = (_wramPosition & 0x1FF00) | value; break;
|
||||
case 0x2182: _wramPosition = (_wramPosition & 0x100FF) | (value << 8); break;
|
||||
case 0x2183: _wramPosition = (_wramPosition & 0xFFFF) | ((value & 0x01) << 16); break;
|
||||
}
|
||||
} else if(addr == 0x4016) {
|
||||
return _controlManager->Write(addr, value);
|
||||
} else if(addr == 0x420B || addr == 0x420C || addr >= 0x4300) {
|
||||
_dmaController->Write(addr, value);
|
||||
} else if(addr < 0x4200) {
|
||||
_ppu->Write(addr, value);
|
||||
} else {
|
||||
_regs->Write(addr, value);
|
||||
}
|
||||
}
|
||||
};
|
||||
class IMemoryHandler;
|
||||
class RegisterHandlerA;
|
||||
class RegisterHandlerB;
|
||||
class InternalRegisters;
|
||||
class RamHandler;
|
||||
class Console;
|
||||
class Ppu;
|
||||
enum class MemoryOperationType;
|
||||
|
||||
class MemoryManager
|
||||
{
|
||||
|
@ -90,7 +20,9 @@ public:
|
|||
private:
|
||||
shared_ptr<Console> _console;
|
||||
|
||||
shared_ptr<CpuRegisterHandler> _cpuRegisterHandler;
|
||||
shared_ptr<RegisterHandlerA> _registerHandlerA;
|
||||
shared_ptr<RegisterHandlerB> _registerHandlerB;
|
||||
|
||||
InternalRegisters* _regs;
|
||||
shared_ptr<Ppu> _ppu;
|
||||
|
||||
|
@ -105,210 +37,37 @@ private:
|
|||
uint8_t _masterClockTable[2][0x10000];
|
||||
|
||||
public:
|
||||
void Initialize(shared_ptr<Console> console)
|
||||
{
|
||||
_lastMasterClock = 0;
|
||||
_masterClock = 0;
|
||||
_console = console;
|
||||
_regs = console->GetInternalRegisters().get();
|
||||
_ppu = console->GetPpu();
|
||||
void Initialize(shared_ptr<Console> console);
|
||||
~MemoryManager();
|
||||
|
||||
_workRam = new uint8_t[MemoryManager::WorkRamSize];
|
||||
void RegisterHandler(uint32_t startAddr, uint32_t endAddr, IMemoryHandler* handler);
|
||||
|
||||
_cpuRegisterHandler.reset(new CpuRegisterHandler(
|
||||
_ppu.get(),
|
||||
console->GetSpc().get(),
|
||||
console->GetDmaController().get(),
|
||||
console->GetInternalRegisters().get(),
|
||||
console->GetControlManager().get(),
|
||||
_workRam
|
||||
));
|
||||
|
||||
memset(_handlers, 0, sizeof(_handlers));
|
||||
//memset(_workRam, 0, 128 * 1024);
|
||||
|
||||
for(uint32_t i = 0; i < 128 * 1024; i += 0x1000) {
|
||||
_workRamHandlers.push_back(unique_ptr<RamHandler>(new RamHandler(_workRam + i)));
|
||||
RegisterHandler(0x7E0000 | i, 0x7E0000 | (i + 0xFFF), _workRamHandlers[_workRamHandlers.size() - 1].get());
|
||||
}
|
||||
|
||||
for(int i = 0; i <= 0x3F; i++) {
|
||||
RegisterHandler((i << 16) | 0x2000, (i << 16) | 0x2FFF, _cpuRegisterHandler.get());
|
||||
RegisterHandler(((i | 0x80) << 16) | 0x2000, ((i | 0x80) << 16) | 0x2FFF, _cpuRegisterHandler.get());
|
||||
|
||||
RegisterHandler((i << 16) | 0x4000, (i << 16) | 0x4FFF, _cpuRegisterHandler.get());
|
||||
RegisterHandler(((i | 0x80) << 16) | 0x4000, ((i | 0x80) << 16) | 0x4FFF, _cpuRegisterHandler.get());
|
||||
}
|
||||
|
||||
for(int i = 0; i < 0x3F; i++) {
|
||||
RegisterHandler((i << 16) | 0x0000, (i << 16) | 0x0FFF, _workRamHandlers[0].get());
|
||||
RegisterHandler((i << 16) | 0x1000, (i << 16) | 0x1FFF, _workRamHandlers[1].get());
|
||||
}
|
||||
|
||||
for(int i = 0x80; i < 0xBF; i++) {
|
||||
RegisterHandler((i << 16) | 0x0000, (i << 16) | 0x0FFF, _workRamHandlers[0].get());
|
||||
RegisterHandler((i << 16) | 0x1000, (i << 16) | 0x1FFF, _workRamHandlers[1].get());
|
||||
}
|
||||
|
||||
console->GetCartridge()->RegisterHandlers(*this);
|
||||
|
||||
GenerateMasterClockTable();
|
||||
}
|
||||
|
||||
~MemoryManager()
|
||||
{
|
||||
delete[] _workRam;
|
||||
}
|
||||
|
||||
void RegisterHandler(uint32_t startAddr, uint32_t endAddr, IMemoryHandler* handler)
|
||||
{
|
||||
if((startAddr & 0xFFF) != 0 || (endAddr & 0xFFF) != 0xFFF) {
|
||||
throw std::runtime_error("invalid start/end address");
|
||||
}
|
||||
|
||||
for(uint32_t addr = startAddr; addr < endAddr; addr += 0x1000) {
|
||||
if(_handlers[addr >> 12]) {
|
||||
throw std::runtime_error("handler already set");
|
||||
}
|
||||
|
||||
_handlers[addr >> 12] = handler;
|
||||
}
|
||||
}
|
||||
|
||||
void GenerateMasterClockTable()
|
||||
{
|
||||
//This is incredibly inaccurate
|
||||
for(int j = 0; j < 2; j++) {
|
||||
for(int i = 0; i < 0x10000; i++) {
|
||||
uint8_t bank = (i & 0xFF00) >> 8;
|
||||
if(bank >= 0x40 && bank <= 0x7F) {
|
||||
//Slow
|
||||
_masterClockTable[j][i] = 8;
|
||||
} else if(bank >= 0xCF) {
|
||||
//Slow or fast (depending on register)
|
||||
_masterClockTable[j][i] = j == 1 ? 6 : 8;
|
||||
} else {
|
||||
uint8_t page = (i & 0xFF);
|
||||
if(page <= 0x1F) {
|
||||
//Slow
|
||||
_masterClockTable[j][i] = 6;
|
||||
} else if(page >= 0x20 && page <= 0x3F) {
|
||||
//Fast
|
||||
_masterClockTable[j][i] = 6;
|
||||
} else if(page == 0x40 || page == 0x41) {
|
||||
//Extra slow
|
||||
_masterClockTable[j][i] = 12;
|
||||
} else if(page >= 0x42 && page <= 0x5F) {
|
||||
//Fast
|
||||
_masterClockTable[j][i] = 6;
|
||||
} else if(page >= 0x60 && page <= 0x7F) {
|
||||
//Slow
|
||||
_masterClockTable[j][i] = 8;
|
||||
} else {
|
||||
//page >= $80
|
||||
//Slow or fast (depending on register)
|
||||
_masterClockTable[j][i] = j == 1 ? 6 : 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IncrementMasterClock(uint32_t addr)
|
||||
{
|
||||
_previousSpeed = _masterClockTable[(uint8_t)_regs->IsFastRomEnabled()][addr >> 8];
|
||||
_masterClock += _previousSpeed;
|
||||
while(_lastMasterClock < _masterClock - 3) {
|
||||
_ppu->Exec();
|
||||
_lastMasterClock += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void GenerateMasterClockTable();
|
||||
void IncrementMasterClock(uint32_t addr);
|
||||
template<uint16_t value>
|
||||
void IncrementMasterClockValue()
|
||||
{
|
||||
_masterClock += value;
|
||||
while(_lastMasterClock < _masterClock - 3) {
|
||||
_ppu->Exec();
|
||||
_lastMasterClock += 4;
|
||||
}
|
||||
void IncrementMasterClockValue();
|
||||
void IncrementMasterClockValue(uint16_t value);
|
||||
|
||||
uint8_t Read(uint32_t addr, MemoryOperationType type);
|
||||
uint8_t ReadDma(uint32_t addr);
|
||||
uint8_t Peek(uint32_t addr);
|
||||
|
||||
void Write(uint32_t addr, uint8_t value, MemoryOperationType type);
|
||||
void WriteDma(uint32_t addr, uint8_t value);
|
||||
|
||||
uint64_t GetMasterClock();
|
||||
uint8_t* DebugGetWorkRam();
|
||||
|
||||
AddressInfo GetAbsoluteAddress(uint32_t addr);
|
||||
int GetRelativeAddress(AddressInfo &address, int32_t cpuAddress = -1);
|
||||
};
|
||||
|
||||
template<uint16_t value>
|
||||
void MemoryManager::IncrementMasterClockValue()
|
||||
{
|
||||
_masterClock += value;
|
||||
while(_lastMasterClock < _masterClock - 3) {
|
||||
_ppu->Exec();
|
||||
_lastMasterClock += 4;
|
||||
}
|
||||
|
||||
void IncrementMasterClockValue(uint16_t value)
|
||||
{
|
||||
_masterClock += value;
|
||||
while(_lastMasterClock < _masterClock - 3) {
|
||||
_ppu->Exec();
|
||||
_lastMasterClock += 4;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t Read(uint32_t addr, MemoryOperationType type)
|
||||
{
|
||||
IncrementMasterClock(addr);
|
||||
|
||||
uint8_t value;
|
||||
if(_handlers[addr >> 12]) {
|
||||
value = _handlers[addr >> 12]->Read(addr);
|
||||
} else {
|
||||
//open bus
|
||||
value = (addr>> 12);
|
||||
|
||||
MessageManager::DisplayMessage("Debug", "Read - missing handler: $" + HexUtilities::ToHex(addr));
|
||||
}
|
||||
_console->ProcessCpuRead(addr, value, type);
|
||||
return value;
|
||||
}
|
||||
|
||||
uint8_t ReadDma(uint32_t addr)
|
||||
{
|
||||
IncrementMasterClockValue<4>();
|
||||
uint8_t value;
|
||||
if(_handlers[addr >> 12]) {
|
||||
value = _handlers[addr >> 12]->Read(addr);
|
||||
} else {
|
||||
//open bus
|
||||
value = (addr >> 12);
|
||||
MessageManager::DisplayMessage("Debug", "Read - missing handler: $" + HexUtilities::ToHex(addr));
|
||||
}
|
||||
_console->ProcessCpuRead(addr, value, MemoryOperationType::DmaRead);
|
||||
return value;
|
||||
}
|
||||
|
||||
uint8_t Peek(uint32_t addr)
|
||||
{
|
||||
//Read, without triggering side-effects
|
||||
uint8_t value = 0;
|
||||
if(_handlers[addr >> 12]) {
|
||||
value = _handlers[addr >> 12]->Read(addr);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void Write(uint32_t addr, uint8_t value, MemoryOperationType type)
|
||||
{
|
||||
IncrementMasterClock(addr);
|
||||
|
||||
_console->ProcessCpuWrite(addr, value, type);
|
||||
if(_handlers[addr >> 12]) {
|
||||
return _handlers[addr >> 12]->Write(addr, value);
|
||||
} else {
|
||||
MessageManager::DisplayMessage("Debug", "Write - missing handler: $" + HexUtilities::ToHex(addr) + " = " + HexUtilities::ToHex(value));
|
||||
}
|
||||
}
|
||||
|
||||
void WriteDma(uint32_t addr, uint8_t value)
|
||||
{
|
||||
IncrementMasterClockValue<4>();
|
||||
|
||||
_console->ProcessCpuWrite(addr, value, MemoryOperationType::DmaWrite);
|
||||
if(_handlers[addr >> 12]) {
|
||||
return _handlers[addr >> 12]->Write(addr, value);
|
||||
} else {
|
||||
MessageManager::DisplayMessage("Debug", "Write - missing handler: $" + HexUtilities::ToHex(addr) + " = " + HexUtilities::ToHex(value));
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t GetMasterClock() { return _masterClock; }
|
||||
uint8_t* DebugGetWorkRam() { return _workRam; }
|
||||
};
|
||||
}
|
|
@ -8,6 +8,9 @@
|
|||
#include "ControlManager.h"
|
||||
#include "VideoDecoder.h"
|
||||
#include "NotificationManager.h"
|
||||
#include "DmaController.h"
|
||||
#include "MessageManager.h"
|
||||
#include "../Utilities/HexUtilities.h"
|
||||
|
||||
Ppu::Ppu(shared_ptr<Console> console)
|
||||
{
|
||||
|
|
|
@ -1,16 +1,21 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "IMemoryHandler.h"
|
||||
#include "DebugTypes.h"
|
||||
|
||||
class RamHandler : public IMemoryHandler
|
||||
{
|
||||
private:
|
||||
uint8_t * _ram;
|
||||
uint32_t _offset;
|
||||
SnesMemoryType _memoryType;
|
||||
|
||||
public:
|
||||
RamHandler(uint8_t *ram)
|
||||
RamHandler(uint8_t *ram, uint32_t offset, SnesMemoryType memoryType)
|
||||
{
|
||||
_ram = ram;
|
||||
_ram = ram + offset;
|
||||
_offset = offset;
|
||||
_memoryType = memoryType;
|
||||
}
|
||||
|
||||
uint8_t Read(uint32_t addr) override
|
||||
|
@ -18,8 +23,21 @@ public:
|
|||
return _ram[addr & 0xFFF];
|
||||
}
|
||||
|
||||
uint8_t Peek(uint32_t addr) override
|
||||
{
|
||||
return _ram[addr & 0xFFF];
|
||||
}
|
||||
|
||||
void Write(uint32_t addr, uint8_t value) override
|
||||
{
|
||||
_ram[addr & 0xFFF] = value;
|
||||
}
|
||||
|
||||
AddressInfo GetAbsoluteAddress(uint32_t address) override
|
||||
{
|
||||
AddressInfo info;
|
||||
info.Address = _offset + (address & 0xFFF);
|
||||
info.Type = _memoryType;
|
||||
return info;
|
||||
}
|
||||
};
|
57
Core/RegisterHandlerA.h
Normal file
57
Core/RegisterHandlerA.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "IMemoryHandler.h"
|
||||
#include "DmaController.h"
|
||||
#include "InternalRegisters.h"
|
||||
#include "ControlManager.h"
|
||||
|
||||
class RegisterHandlerA : public IMemoryHandler
|
||||
{
|
||||
private:
|
||||
DmaController *_dmaController;
|
||||
InternalRegisters *_regs;
|
||||
ControlManager *_controlManager;
|
||||
|
||||
public:
|
||||
RegisterHandlerA(DmaController *dmaController, InternalRegisters *regs, ControlManager *controlManager)
|
||||
{
|
||||
_regs = regs;
|
||||
_dmaController = dmaController;
|
||||
_controlManager = controlManager;
|
||||
}
|
||||
|
||||
uint8_t Read(uint32_t addr) override
|
||||
{
|
||||
addr &= 0xFFFF;
|
||||
if(addr == 0x4016 || addr == 0x4017) {
|
||||
return _controlManager->Read(addr);
|
||||
} else if(addr >= 0x4300) {
|
||||
return _dmaController->Read(addr);
|
||||
} else {
|
||||
return _regs->Read(addr);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t Peek(uint32_t addr) override
|
||||
{
|
||||
//Avoid side effects for now
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Write(uint32_t addr, uint8_t value) override
|
||||
{
|
||||
addr &= 0xFFFF;
|
||||
if(addr == 0x4016) {
|
||||
return _controlManager->Write(addr, value);
|
||||
} else if(addr == 0x420B || addr == 0x420C || addr >= 0x4300) {
|
||||
_dmaController->Write(addr, value);
|
||||
} else {
|
||||
_regs->Write(addr, value);
|
||||
}
|
||||
}
|
||||
|
||||
AddressInfo GetAbsoluteAddress(uint32_t address) override
|
||||
{
|
||||
return { -1, SnesMemoryType::CpuMemory };
|
||||
}
|
||||
};
|
67
Core/RegisterHandlerB.h
Normal file
67
Core/RegisterHandlerB.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "IMemoryHandler.h"
|
||||
#include "Ppu.h"
|
||||
#include "Spc.h"
|
||||
|
||||
class RegisterHandlerB : public IMemoryHandler
|
||||
{
|
||||
private:
|
||||
Ppu * _ppu;
|
||||
Spc *_spc;
|
||||
uint8_t *_workRam;
|
||||
uint32_t _wramPosition;
|
||||
|
||||
public:
|
||||
RegisterHandlerB(Ppu *ppu, Spc *spc, uint8_t *workRam)
|
||||
{
|
||||
_ppu = ppu;
|
||||
_spc = spc;
|
||||
_workRam = workRam;
|
||||
_wramPosition = 0;
|
||||
}
|
||||
|
||||
uint8_t Read(uint32_t addr) override
|
||||
{
|
||||
addr &= 0xFFFF;
|
||||
if(addr >= 0x2140 && addr <= 0x217F) {
|
||||
return _spc->Read(addr & 0x03);
|
||||
} else if(addr == 0x2180) {
|
||||
return _workRam[_wramPosition++];
|
||||
} else {
|
||||
return _ppu->Read(addr);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t Peek(uint32_t addr) override
|
||||
{
|
||||
//Avoid side effects for now
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Write(uint32_t addr, uint8_t value) override
|
||||
{
|
||||
addr &= 0xFFFF;
|
||||
if(addr >= 0x2140 && addr <= 0x217F) {
|
||||
return _spc->Write(addr & 0x03, value);
|
||||
} if(addr >= 0x2180 && addr <= 0x2183) {
|
||||
switch(addr & 0xFFFF) {
|
||||
case 0x2180:
|
||||
_workRam[_wramPosition] = value;
|
||||
_wramPosition = (_wramPosition + 1) & (0x1FFFF);
|
||||
break;
|
||||
|
||||
case 0x2181: _wramPosition = (_wramPosition & 0x1FF00) | value; break;
|
||||
case 0x2182: _wramPosition = (_wramPosition & 0x100FF) | (value << 8); break;
|
||||
case 0x2183: _wramPosition = (_wramPosition & 0xFFFF) | ((value & 0x01) << 16); break;
|
||||
}
|
||||
} else {
|
||||
_ppu->Write(addr, value);
|
||||
}
|
||||
}
|
||||
|
||||
AddressInfo GetAbsoluteAddress(uint32_t address) override
|
||||
{
|
||||
return { -1, SnesMemoryType::CpuMemory };
|
||||
}
|
||||
};
|
|
@ -1,22 +1,11 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "IMemoryHandler.h"
|
||||
#include "RamHandler.h"
|
||||
|
||||
class RomHandler : public IMemoryHandler
|
||||
class RomHandler : public RamHandler
|
||||
{
|
||||
private:
|
||||
uint8_t * _rom;
|
||||
|
||||
public:
|
||||
RomHandler(uint8_t *rom)
|
||||
{
|
||||
_rom = rom;
|
||||
}
|
||||
|
||||
uint8_t Read(uint32_t addr) override
|
||||
{
|
||||
return _rom[addr & 0xFFF];
|
||||
}
|
||||
using RamHandler::RamHandler;
|
||||
|
||||
void Write(uint32_t addr, uint8_t value) override
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue