Mesen-SX/Core/Sdd1.cpp
2020-12-19 23:30:09 +03:00

141 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};
}