Mesen/Core/VsSystem.h

82 lines
2.8 KiB
C++

#pragma once
#include "stdafx.h"
#include "BaseMapper.h"
#include "VsControlManager.h"
class VsSystem : public BaseMapper
{
private:
uint8_t _prgChrSelectBit = 0;
protected:
virtual uint16_t GetPRGPageSize() override { return 0x2000; }
virtual uint16_t GetCHRPageSize() override { return 0x2000; }
virtual uint32_t GetWorkRamSize() override { return 0x800; }
virtual void InitMapper() override
{
//Force VS system if mapper 99 (since we assume VsControlManager exists below)
if(_prgSize >= 0x10000) {
//Assume DualSystem if PRG ROM is 64kb or larger
_gameSystem = GameSystem::VsDualSystem;
} else {
_gameSystem = GameSystem::VsUniSystem;
}
//"Note: unlike all other mappers, an undersize mapper 99 image implies open bus instead of mirroring."
//However, it doesn't look like any game actually rely on this behavior? So not implemented for now.
uint8_t prgOuter = _console->IsMaster() ? 0 : (GetPRGPageCount() / 2);
SelectPRGPage(0, 0 | prgOuter);
SelectPRGPage(1, 1 | prgOuter);
SelectPRGPage(2, 2 | prgOuter);
SelectPRGPage(3, 3 | prgOuter);
uint8_t chrOuter = _console->IsMaster() ? 0 : (GetCHRPageCount() / 2);
SelectCHRPage(0, 0 | chrOuter);
}
void Reset(bool softReset) override
{
BaseMapper::Reset(softReset);
UpdateMemoryAccess(0);
}
void StreamState(bool saving) override
{
BaseMapper::StreamState(saving);
Stream(_prgChrSelectBit);
}
void ProcessCpuClock() override
{
VsControlManager* controlManager = dynamic_cast<VsControlManager*>(_console->GetControlManager());
if(_prgChrSelectBit != controlManager->GetPrgChrSelectBit()) {
_prgChrSelectBit = controlManager->GetPrgChrSelectBit();
if(_prgSize > 0x8000 && _prgSize < 0x10000) {
//"Note: In case of games with 40KiB PRG - ROM(as found in VS Gumshoe), the above bit additionally changes 8KiB PRG - ROM at $8000 - $9FFF."
//"Only Vs. Gumshoe uses the 40KiB PRG variant; in the iNES encapsulation, the 8KiB banks are arranged as 0, 1, 2, 3, 0alternate, empty"
SelectPRGPage(0, _prgChrSelectBit << 2);
}
uint8_t chrOuter = _console->IsMaster() ? 0 : (GetCHRPageCount() / 2);
SelectCHRPage(0, _prgChrSelectBit | chrOuter);
}
}
public:
void UpdateMemoryAccess(uint8_t slaveMasterBit)
{
shared_ptr<Console> dualConsole = _console->GetDualConsole();
if(_console->IsMaster() && dualConsole) {
VsSystem* otherMapper = dynamic_cast<VsSystem*>(dualConsole->GetMapper());
//Give memory access to master CPU or slave CPU, based on "slaveMasterBit"
for(int i = 0; i < 4; i++) {
SetCpuMemoryMapping(0x6000 + i * 0x800, 0x67FF + i * 0x800, _workRam, slaveMasterBit ? MemoryAccessType::ReadWrite : MemoryAccessType::NoAccess);
otherMapper->SetCpuMemoryMapping(0x6000 + i * 0x800, 0x67FF + i * 0x800, _workRam, slaveMasterBit ? MemoryAccessType::NoAccess : MemoryAccessType::ReadWrite);
}
}
}
};