2019-02-11 22:41:34 -05:00
|
|
|
#pragma once
|
|
|
|
#include "stdafx.h"
|
2019-02-12 22:13:09 -05:00
|
|
|
#include "Console.h"
|
2019-02-13 13:32:21 -05:00
|
|
|
#include "Ppu.h"
|
2019-02-16 11:23:01 -05:00
|
|
|
#include "Spc.h"
|
2019-02-17 14:42:35 -05:00
|
|
|
#include "RamHandler.h"
|
2019-02-15 00:08:50 -05:00
|
|
|
#include "DmaController.h"
|
2019-02-15 21:33:13 -05:00
|
|
|
#include "BaseCartridge.h"
|
2019-02-17 19:54:29 -05:00
|
|
|
#include "ControlManager.h"
|
2019-02-17 15:37:31 -05:00
|
|
|
#include "InternalRegisters.h"
|
2019-02-15 21:33:13 -05:00
|
|
|
#include "IMemoryHandler.h"
|
2019-02-17 14:42:35 -05:00
|
|
|
#include "MessageManager.h"
|
2019-02-12 22:13:09 -05:00
|
|
|
#include "../Utilities/HexUtilities.h"
|
2019-02-11 22:41:34 -05:00
|
|
|
|
2019-02-13 13:32:21 -05:00
|
|
|
class CpuRegisterHandler : public IMemoryHandler
|
|
|
|
{
|
|
|
|
private:
|
2019-02-16 01:16:57 -05:00
|
|
|
Ppu *_ppu;
|
2019-02-16 11:23:01 -05:00
|
|
|
Spc *_spc;
|
2019-02-16 01:16:57 -05:00
|
|
|
DmaController *_dmaController;
|
2019-02-17 15:37:31 -05:00
|
|
|
InternalRegisters *_regs;
|
2019-02-17 19:54:29 -05:00
|
|
|
ControlManager *_controlManager;
|
2019-02-17 14:42:35 -05:00
|
|
|
uint8_t *_workRam;
|
|
|
|
uint32_t _wramPosition;
|
2019-02-13 13:32:21 -05:00
|
|
|
|
|
|
|
public:
|
2019-02-17 19:54:29 -05:00
|
|
|
CpuRegisterHandler(Ppu *ppu, Spc *spc, DmaController *dmaController, InternalRegisters *regs, ControlManager *controlManager, uint8_t *workRam)
|
2019-02-13 13:32:21 -05:00
|
|
|
{
|
2019-02-16 01:16:57 -05:00
|
|
|
_ppu = ppu;
|
2019-02-16 11:23:01 -05:00
|
|
|
_spc = spc;
|
2019-02-17 15:37:31 -05:00
|
|
|
_regs = regs;
|
2019-02-16 01:16:57 -05:00
|
|
|
_dmaController = dmaController;
|
2019-02-17 19:54:29 -05:00
|
|
|
_controlManager = controlManager;
|
2019-02-17 14:42:35 -05:00
|
|
|
|
|
|
|
_workRam = workRam;
|
|
|
|
_wramPosition = 0;
|
2019-02-13 13:32:21 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t Read(uint32_t addr) override
|
|
|
|
{
|
2019-02-16 11:23:01 -05:00
|
|
|
addr &= 0xFFFF;
|
|
|
|
if(addr >= 0x2140 && addr <= 0x217F) {
|
|
|
|
return _spc->Read(addr & 0x03);
|
2019-02-21 07:27:47 -05:00
|
|
|
} else if(addr == 0x2180) {
|
|
|
|
return _workRam[_wramPosition++];
|
2019-02-17 19:54:29 -05:00
|
|
|
} else if(addr == 0x4016 || addr == 0x4017) {
|
|
|
|
return _controlManager->Read(addr);
|
2019-02-17 15:37:31 -05:00
|
|
|
} else if(addr < 0x4200) {
|
2019-02-16 11:23:01 -05:00
|
|
|
return _ppu->Read(addr);
|
2019-02-17 15:37:31 -05:00
|
|
|
} else {
|
|
|
|
return _regs->Read(addr);
|
2019-02-16 11:23:01 -05:00
|
|
|
}
|
2019-02-13 13:32:21 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void Write(uint32_t addr, uint8_t value) override
|
|
|
|
{
|
2019-02-16 11:23:01 -05:00
|
|
|
addr &= 0xFFFF;
|
|
|
|
if(addr >= 0x2140 && addr <= 0x217F) {
|
|
|
|
return _spc->Write(addr & 0x03, value);
|
2019-02-17 14:42:35 -05:00
|
|
|
} 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;
|
|
|
|
}
|
2019-02-17 19:54:29 -05:00
|
|
|
} else if(addr == 0x4016) {
|
|
|
|
return _controlManager->Write(addr, value);
|
2019-02-17 14:42:35 -05:00
|
|
|
} else if(addr == 0x420B || addr == 0x420C || addr >= 0x4300) {
|
|
|
|
_dmaController->Write(addr, value);
|
2019-02-17 15:37:31 -05:00
|
|
|
} else if(addr < 0x4200) {
|
2019-02-16 11:23:01 -05:00
|
|
|
_ppu->Write(addr, value);
|
2019-02-17 15:37:31 -05:00
|
|
|
} else {
|
|
|
|
_regs->Write(addr, value);
|
2019-02-16 11:23:01 -05:00
|
|
|
}
|
2019-02-13 13:32:21 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-02-11 22:41:34 -05:00
|
|
|
class MemoryManager
|
|
|
|
{
|
2019-02-15 21:33:13 -05:00
|
|
|
public:
|
|
|
|
constexpr static uint32_t WorkRamSize = 0x20000;
|
|
|
|
|
2019-02-11 22:41:34 -05:00
|
|
|
private:
|
2019-02-12 22:13:09 -05:00
|
|
|
shared_ptr<Console> _console;
|
|
|
|
|
|
|
|
shared_ptr<BaseCartridge> _cart;
|
2019-02-13 13:32:21 -05:00
|
|
|
shared_ptr<CpuRegisterHandler> _cpuRegisterHandler;
|
|
|
|
shared_ptr<Ppu> _ppu;
|
2019-02-15 00:08:50 -05:00
|
|
|
|
2019-02-17 14:42:35 -05:00
|
|
|
IMemoryHandler* _handlers[0x100 * 0x10];
|
|
|
|
vector<unique_ptr<RamHandler>> _workRamHandlers;
|
|
|
|
|
|
|
|
uint8_t * _workRam;
|
2019-02-13 13:32:21 -05:00
|
|
|
|
|
|
|
uint64_t _masterClock;
|
|
|
|
uint64_t _lastMasterClock;
|
2019-02-11 22:41:34 -05:00
|
|
|
|
|
|
|
public:
|
2019-02-16 01:16:57 -05:00
|
|
|
void Initialize(shared_ptr<Console> console)
|
2019-02-11 22:41:34 -05:00
|
|
|
{
|
2019-02-13 13:32:21 -05:00
|
|
|
_lastMasterClock = 0;
|
|
|
|
_masterClock = 0;
|
2019-02-12 22:13:09 -05:00
|
|
|
_console = console;
|
2019-02-16 01:16:57 -05:00
|
|
|
_cart = console->GetCartridge();
|
2019-02-13 13:32:21 -05:00
|
|
|
_ppu = console->GetPpu();
|
|
|
|
|
2019-02-17 14:42:35 -05:00
|
|
|
_workRam = new uint8_t[MemoryManager::WorkRamSize];
|
|
|
|
|
2019-02-19 21:09:12 -05:00
|
|
|
_cpuRegisterHandler.reset(new CpuRegisterHandler(
|
|
|
|
_ppu.get(),
|
|
|
|
console->GetSpc().get(),
|
|
|
|
console->GetDmaController().get(),
|
|
|
|
console->GetInternalRegisters().get(),
|
|
|
|
console->GetControlManager().get(),
|
|
|
|
_workRam
|
|
|
|
));
|
2019-02-11 22:41:34 -05:00
|
|
|
|
2019-02-12 22:13:09 -05:00
|
|
|
memset(_handlers, 0, sizeof(_handlers));
|
2019-02-15 00:08:50 -05:00
|
|
|
//memset(_workRam, 0, 128 * 1024);
|
2019-02-14 19:00:17 -05:00
|
|
|
|
2019-02-11 22:41:34 -05:00
|
|
|
for(uint32_t i = 0; i < 128 * 1024; i += 0x1000) {
|
2019-02-17 14:42:35 -05:00
|
|
|
_workRamHandlers.push_back(unique_ptr<RamHandler>(new RamHandler(_workRam + i)));
|
2019-02-11 22:41:34 -05:00
|
|
|
RegisterHandler(0x7E0000 | i, 0x7E0000 | (i + 0xFFF), _workRamHandlers[_workRamHandlers.size() - 1].get());
|
|
|
|
}
|
|
|
|
|
2019-02-13 13:32:21 -05:00
|
|
|
for(int i = 0; i <= 0x3F; i++) {
|
2019-02-13 18:44:39 -05:00
|
|
|
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());
|
2019-02-13 13:32:21 -05:00
|
|
|
}
|
|
|
|
|
2019-02-17 14:42:35 -05:00
|
|
|
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());
|
|
|
|
}
|
2019-02-11 22:41:34 -05:00
|
|
|
|
2019-02-17 14:42:35 -05:00
|
|
|
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());
|
2019-02-11 22:41:34 -05:00
|
|
|
}
|
2019-02-17 14:42:35 -05:00
|
|
|
|
|
|
|
_cart->RegisterHandlers(*this);
|
2019-02-11 22:41:34 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
~MemoryManager()
|
|
|
|
{
|
2019-02-16 01:16:57 -05:00
|
|
|
delete[] _workRam;
|
2019-02-11 22:41:34 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void RegisterHandler(uint32_t startAddr, uint32_t endAddr, IMemoryHandler* handler)
|
|
|
|
{
|
|
|
|
if((startAddr & 0xFFF) != 0 || (endAddr & 0xFFF) != 0xFFF) {
|
|
|
|
throw new std::runtime_error("invalid start/end address");
|
|
|
|
}
|
|
|
|
|
|
|
|
for(uint32_t addr = startAddr; addr < endAddr; addr += 0x1000) {
|
2019-02-17 14:42:35 -05:00
|
|
|
if(_handlers[addr >> 12]) {
|
|
|
|
throw new std::runtime_error("handler already set");
|
|
|
|
}
|
|
|
|
|
2019-02-11 22:41:34 -05:00
|
|
|
_handlers[addr >> 12] = handler;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-13 13:32:21 -05:00
|
|
|
void IncrementMasterClock(uint32_t addr)
|
|
|
|
{
|
|
|
|
//This is incredibly inaccurate
|
|
|
|
uint8_t bank = (addr & 0xFF0000) >> 8;
|
|
|
|
if(bank >= 0x40 && bank <= 0x7F) {
|
|
|
|
//Slow
|
|
|
|
_masterClock += 8;
|
|
|
|
} else if(bank >= 0xCF) {
|
|
|
|
//Slow or fast (depending on register)
|
|
|
|
//Use slow
|
|
|
|
_masterClock += 8;
|
|
|
|
} else {
|
|
|
|
uint8_t page = (addr & 0xFF00) >> 8;
|
|
|
|
if(page <= 0x1F) {
|
|
|
|
//Slow
|
|
|
|
_masterClock += 6;
|
|
|
|
} else if(page >= 0x20 && page <= 0x3F) {
|
|
|
|
//Fast
|
|
|
|
_masterClock += 6;
|
|
|
|
} else if(page == 0x40 || page == 0x41) {
|
|
|
|
//extra slow
|
|
|
|
_masterClock += 12;
|
|
|
|
} else if(page >= 0x42 && page <= 0x5F) {
|
|
|
|
//Fast
|
|
|
|
_masterClock += 6;
|
|
|
|
} else if(page >= 0x60 && page <= 0x7F) {
|
|
|
|
//Slow
|
|
|
|
_masterClock += 8;
|
|
|
|
} else {
|
|
|
|
//Slow or fast (depending on register)
|
|
|
|
//Use slow
|
|
|
|
_masterClock += 8;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while(_lastMasterClock < _masterClock - 3) {
|
|
|
|
_ppu->Exec();
|
|
|
|
_lastMasterClock += 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-12 22:13:09 -05:00
|
|
|
uint8_t Read(uint32_t addr, MemoryOperationType type)
|
2019-02-11 22:41:34 -05:00
|
|
|
{
|
2019-02-13 13:32:21 -05:00
|
|
|
IncrementMasterClock(addr);
|
|
|
|
|
2019-02-12 22:13:09 -05:00
|
|
|
uint8_t value = 0;
|
2019-02-11 22:41:34 -05:00
|
|
|
if(_handlers[addr >> 12]) {
|
2019-02-12 22:13:09 -05:00
|
|
|
value = _handlers[addr >> 12]->Read(addr);
|
2019-02-11 22:41:34 -05:00
|
|
|
} else {
|
2019-02-17 14:42:35 -05:00
|
|
|
//open bus
|
|
|
|
value = (addr>> 12);
|
|
|
|
|
|
|
|
MessageManager::DisplayMessage("Debug", "Read - missing handler: $" + HexUtilities::ToHex(addr));
|
2019-02-11 22:41:34 -05:00
|
|
|
}
|
2019-02-12 22:13:09 -05:00
|
|
|
_console->ProcessCpuRead(addr, value, type);
|
|
|
|
return value;
|
2019-02-11 22:41:34 -05:00
|
|
|
}
|
|
|
|
|
2019-02-12 22:13:09 -05:00
|
|
|
uint8_t Peek(uint32_t addr)
|
2019-02-11 22:41:34 -05:00
|
|
|
{
|
2019-02-12 22:13:09 -05:00
|
|
|
//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)
|
|
|
|
{
|
2019-02-13 13:32:21 -05:00
|
|
|
IncrementMasterClock(addr);
|
|
|
|
|
2019-02-12 22:13:09 -05:00
|
|
|
_console->ProcessCpuWrite(addr, value, type);
|
2019-02-11 22:41:34 -05:00
|
|
|
if(_handlers[addr >> 12]) {
|
|
|
|
return _handlers[addr >> 12]->Write(addr, value);
|
2019-02-12 22:13:09 -05:00
|
|
|
} else {
|
2019-02-17 14:42:35 -05:00
|
|
|
MessageManager::DisplayMessage("Debug", "Write - missing handler: $" + HexUtilities::ToHex(addr) + " = " + HexUtilities::ToHex(value));
|
2019-02-11 22:41:34 -05:00
|
|
|
}
|
|
|
|
}
|
2019-02-15 21:33:13 -05:00
|
|
|
|
2019-02-16 11:23:01 -05:00
|
|
|
uint64_t GetMasterClock() { return _masterClock; }
|
2019-02-15 21:33:13 -05:00
|
|
|
uint8_t* DebugGetWorkRam() { return _workRam; }
|
2019-02-11 22:41:34 -05:00
|
|
|
};
|