2016-05-01 00:08:53 +00:00
|
|
|
#pragma once
|
|
|
|
#include "stdafx.h"
|
2022-07-25 10:36:08 +00:00
|
|
|
#include <memory>
|
2016-05-01 00:08:53 +00:00
|
|
|
#include "BaseMapper.h"
|
|
|
|
#include "VsControlManager.h"
|
|
|
|
|
|
|
|
class VsSystem : public BaseMapper
|
|
|
|
{
|
|
|
|
private:
|
2018-07-03 01:32:59 +00:00
|
|
|
uint8_t _prgChrSelectBit = 0;
|
2016-05-01 00:08:53 +00:00
|
|
|
|
|
|
|
protected:
|
2016-12-18 04:14:47 +00:00
|
|
|
virtual uint16_t GetPRGPageSize() override { return 0x2000; }
|
|
|
|
virtual uint16_t GetCHRPageSize() override { return 0x2000; }
|
2018-07-03 01:32:59 +00:00
|
|
|
virtual uint32_t GetWorkRamSize() override { return 0x800; }
|
2016-05-01 00:08:53 +00:00
|
|
|
|
2016-12-18 04:14:47 +00:00
|
|
|
virtual void InitMapper() override
|
2016-05-01 00:08:53 +00:00
|
|
|
{
|
2018-07-07 18:52:51 +00:00
|
|
|
if(!IsNes20()) {
|
|
|
|
//Force VS system if mapper 99
|
|
|
|
_romInfo.System = GameSystem::VsSystem;
|
2018-07-08 00:50:31 +00:00
|
|
|
if(_prgSize >= 0x10000) {
|
|
|
|
_romInfo.VsType = VsSystemType::VsDualSystem;
|
|
|
|
} else {
|
|
|
|
_romInfo.VsType = VsSystemType::Default;
|
|
|
|
}
|
2018-07-03 01:32:59 +00:00
|
|
|
}
|
|
|
|
|
2016-07-10 13:05:41 +00:00
|
|
|
//"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.
|
2018-07-08 23:05:57 +00:00
|
|
|
bool initialized = false;
|
|
|
|
if(_prgSize == 0xC000) {
|
|
|
|
//48KB rom == unpadded dualsystem rom
|
|
|
|
if(_romInfo.VsType == VsSystemType::VsDualSystem) {
|
|
|
|
uint8_t prgOuter = _console->IsMaster() ? 0 : 3;
|
|
|
|
SelectPRGPage(1, 0 + prgOuter);
|
|
|
|
SelectPRGPage(2, 1 + prgOuter);
|
|
|
|
SelectPRGPage(3, 2 + prgOuter);
|
|
|
|
initialized = true;
|
|
|
|
} else if(_romInfo.VsType == VsSystemType::RaidOnBungelingBayProtection) {
|
|
|
|
if(_console->IsMaster()) {
|
|
|
|
SelectPRGPage(0, 0);
|
|
|
|
SelectPRGPage(1, 1);
|
|
|
|
SelectPRGPage(2, 2);
|
|
|
|
SelectPRGPage(3, 3);
|
|
|
|
} else {
|
|
|
|
//Slave CPU
|
|
|
|
SelectPRGPage(0, 4);
|
|
|
|
}
|
|
|
|
initialized = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!initialized) {
|
|
|
|
uint8_t prgOuter = _console->IsMaster() ? 0 : 4;
|
|
|
|
SelectPRGPage(0, 0 | prgOuter);
|
|
|
|
SelectPRGPage(1, 1 | prgOuter);
|
|
|
|
SelectPRGPage(2, 2 | prgOuter);
|
|
|
|
SelectPRGPage(3, 3 | prgOuter);
|
|
|
|
}
|
2016-05-01 00:08:53 +00:00
|
|
|
|
2018-07-08 00:50:31 +00:00
|
|
|
uint8_t chrOuter = _console->IsMaster() ? 0 : 2;
|
2018-07-03 01:32:59 +00:00
|
|
|
SelectCHRPage(0, 0 | chrOuter);
|
|
|
|
}
|
2016-07-10 13:05:41 +00:00
|
|
|
|
2018-07-03 01:32:59 +00:00
|
|
|
void Reset(bool softReset) override
|
|
|
|
{
|
|
|
|
BaseMapper::Reset(softReset);
|
|
|
|
UpdateMemoryAccess(0);
|
2016-05-01 00:08:53 +00:00
|
|
|
}
|
|
|
|
|
2016-12-18 04:14:47 +00:00
|
|
|
void StreamState(bool saving) override
|
2016-06-22 02:13:26 +00:00
|
|
|
{
|
|
|
|
BaseMapper::StreamState(saving);
|
|
|
|
Stream(_prgChrSelectBit);
|
|
|
|
}
|
|
|
|
|
2016-12-18 04:14:47 +00:00
|
|
|
void ProcessCpuClock() override
|
2016-05-01 00:08:53 +00:00
|
|
|
{
|
2018-07-01 19:21:05 +00:00
|
|
|
VsControlManager* controlManager = dynamic_cast<VsControlManager*>(_console->GetControlManager());
|
2018-07-07 18:52:51 +00:00
|
|
|
if(controlManager && _prgChrSelectBit != controlManager->GetPrgChrSelectBit()) {
|
2018-07-01 19:21:05 +00:00
|
|
|
_prgChrSelectBit = controlManager->GetPrgChrSelectBit();
|
2016-07-10 13:05:41 +00:00
|
|
|
|
2018-07-08 00:50:31 +00:00
|
|
|
if(_romInfo.VsType == VsSystemType::Default && _prgSize > 0x8000) {
|
2016-07-10 13:05:41 +00:00
|
|
|
//"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);
|
|
|
|
}
|
|
|
|
|
2018-07-08 00:50:31 +00:00
|
|
|
uint8_t chrOuter = _console->IsMaster() ? 0 : 2;
|
2018-07-03 01:32:59 +00:00
|
|
|
SelectCHRPage(0, _prgChrSelectBit | chrOuter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
void UpdateMemoryAccess(uint8_t slaveMasterBit)
|
|
|
|
{
|
2022-07-25 10:36:08 +00:00
|
|
|
std::shared_ptr<Console> dualConsole = _console->GetDualConsole();
|
2018-07-03 01:32:59 +00:00
|
|
|
if(_console->IsMaster() && dualConsole) {
|
|
|
|
VsSystem* otherMapper = dynamic_cast<VsSystem*>(dualConsole->GetMapper());
|
|
|
|
|
|
|
|
//Give memory access to master CPU or slave CPU, based on "slaveMasterBit"
|
2020-04-28 00:47:28 +00:00
|
|
|
if(_saveRamSize == 0 && _workRamSize == 0) {
|
|
|
|
RemoveCpuMemoryMapping(0x6000, 0x7FFF);
|
|
|
|
otherMapper->RemoveCpuMemoryMapping(0x6000, 0x7FFF);
|
|
|
|
}
|
|
|
|
|
2018-07-03 01:32:59 +00:00
|
|
|
for(int i = 0; i < 4; i++) {
|
2020-04-28 00:47:28 +00:00
|
|
|
SetCpuMemoryMapping(0x6000 + i * 0x800, 0x67FF + i * 0x800, HasBattery() ? _saveRam : _workRam, slaveMasterBit ? MemoryAccessType::ReadWrite : MemoryAccessType::NoAccess);
|
|
|
|
otherMapper->SetCpuMemoryMapping(0x6000 + i * 0x800, 0x67FF + i * 0x800, HasBattery() ? _saveRam : _workRam, slaveMasterBit ? MemoryAccessType::NoAccess : MemoryAccessType::ReadWrite);
|
2018-07-03 01:32:59 +00:00
|
|
|
}
|
2016-05-01 00:08:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|