Mesen-S/Core/Sdd1.cpp
Sour 6539b92502 SA-1: Fixed timing regressions
Memory handlers did not have the _memoryType value set, which caused some memory accesses to be much faster than expected
2020-03-01 18:24:33 -05:00

121 lines
3.9 KiB
C++

#include "stdafx.h"
#include "Sdd1.h"
#include "Sdd1Mmc.h"
#include "Console.h"
#include "BaseCartridge.h"
#include "MemoryManager.h"
#include "MemoryMappings.h"
Sdd1::Sdd1(Console* console) : BaseCoprocessor(SnesMemoryType::Register)
{
//This handler is used to dynamically map the ROM based on the banking registers
_sdd1Mmc.reset(new Sdd1Mmc(_state, console->GetCartridge().get()));
MemoryMappings *cpuMappings = console->GetMemoryManager()->GetMemoryMappings();
vector<unique_ptr<IMemoryHandler>> &prgRomHandlers = console->GetCartridge()->GetPrgRomHandlers();
vector<unique_ptr<IMemoryHandler>> &saveRamHandlers = console->GetCartridge()->GetSaveRamHandlers();
//Regular A Bus register handler, keep a reference to it, it'll be overwritten below
_cpuRegisterHandler = cpuMappings->GetHandler(0x4000);
//Based on forum thread info: https://forums.nesdev.com/viewtopic.php?f=12&t=14156
cpuMappings->RegisterHandler(0x00, 0x3F, 0x6000, 0x7FFF, saveRamHandlers);
cpuMappings->RegisterHandler(0x80, 0xBF, 0x6000, 0x7FFF, saveRamHandlers);
cpuMappings->RegisterHandler(0x70, 0x73, 0x0000, 0xFFFF, saveRamHandlers);
//S-DD1 registers (0x4800-0x4807)
cpuMappings->RegisterHandler(0x00, 0x3F, 0x4000, 0x4FFF, this);
cpuMappings->RegisterHandler(0x80, 0xBF, 0x4000, 0x4FFF, this);
cpuMappings->RegisterHandler(0x00, 0x3F, 0x8000, 0xFFFF, prgRomHandlers);
cpuMappings->RegisterHandler(0x80, 0xBF, 0x8000, 0xFFFF, prgRomHandlers);
//Override these segments to implement the miroring that $4805/$4807 cause
cpuMappings->RegisterHandler(0x20, 0x3F, 0x8000, 0xFFFF, _sdd1Mmc.get());
cpuMappings->RegisterHandler(0xA0, 0xBF, 0x8000, 0xFFFF, _sdd1Mmc.get());
//Regular bank switched mappings
cpuMappings->RegisterHandler(0xC0, 0xFF, 0x0000, 0xFFFF, _sdd1Mmc.get());
Reset();
}
void Sdd1::Reset()
{
_state = {};
_state.NeedInit = true;
_state.SelectedBanks[0] = 0;
_state.SelectedBanks[1] = 1;
_state.SelectedBanks[2] = 2;
_state.SelectedBanks[3] = 3;
}
uint8_t Sdd1::Read(uint32_t addr)
{
if((uint16_t)addr >= 0x4800 && (uint16_t)addr <= 0x4807) {
switch(addr & 0x07) {
case 0: return _state.AllowDmaProcessing;
case 1: return _state.ProcessNextDma;
case 4: case 5: case 6: case 7:
return _state.SelectedBanks[addr & 0x03];
}
}
return _cpuRegisterHandler->Read(addr);
}
void Sdd1::Write(uint32_t addr, uint8_t value)
{
if((uint16_t)addr >= 0x4800 && (uint16_t)addr <= 0x4807) {
//S-DD1 registers
switch(addr & 0x07) {
case 0: _state.AllowDmaProcessing = value; break;
case 1: _state.ProcessNextDma = value; break;
case 4: case 5: case 6: case 7:
_state.SelectedBanks[addr & 0x03] = value;
break;
}
} else {
if((uint16_t)addr >= 0x4300 && (uint16_t)addr <= 0x437A) {
//Keep track of writes to the DMA controller to know which address/length the DMAs will use
uint8_t ch = (addr >> 4) & 0x07;
switch(addr & 0x0F) {
case 0x02: _state.DmaAddress[ch] = (_state.DmaAddress[ch] & 0xFFFF00) | value; break;
case 0x03: _state.DmaAddress[ch] = (_state.DmaAddress[ch] & 0xFF00FF) | (value << 8); break;
case 0x04: _state.DmaAddress[ch] = (_state.DmaAddress[ch] & 0x00FFFF) | (value << 16); break;
case 0x05: _state.DmaLength[ch] = (_state.DmaLength[ch] & 0xFF00) | value; break;
case 0x06: _state.DmaLength[ch] = (_state.DmaLength[ch] & 0x00FF) | (value << 8); break;
}
}
//Forward everything else to the regular handler
_cpuRegisterHandler->Write(addr, value);
}
}
void Sdd1::Serialize(Serializer &s)
{
s.Stream(_state.AllowDmaProcessing, _state.ProcessNextDma, _state.NeedInit);
s.StreamArray(_state.DmaAddress, 8);
s.StreamArray(_state.DmaLength, 8);
s.StreamArray(_state.SelectedBanks, 4);
s.Stream(_sdd1Mmc.get());
}
uint8_t Sdd1::Peek(uint32_t addr)
{
return 0;
}
void Sdd1::PeekBlock(uint32_t addr, uint8_t* output)
{
memset(output, 0, 0x1000);
}
AddressInfo Sdd1::GetAbsoluteAddress(uint32_t address)
{
return { -1, SnesMemoryType::Register };
}