SA-1: Implemented bitmap mode for BWRAM
Fixes SMRPG's level up screen
This commit is contained in:
parent
20fb875280
commit
4a7e6df39b
6 changed files with 202 additions and 19 deletions
|
@ -168,7 +168,9 @@
|
|||
<ClInclude Include="RomFinder.h" />
|
||||
<ClInclude Include="RomHandler.h" />
|
||||
<ClInclude Include="Sa1.h" />
|
||||
<ClInclude Include="Sa1BwRamHandler.h" />
|
||||
<ClInclude Include="Sa1Cpu.h" />
|
||||
<ClInclude Include="Sa1IRamHandler.h" />
|
||||
<ClInclude Include="Sa1Types.h" />
|
||||
<ClInclude Include="Sa1VectorHandler.h" />
|
||||
<ClInclude Include="SaveStateManager.h" />
|
||||
|
|
|
@ -485,6 +485,12 @@
|
|||
<ClInclude Include="PcmReader.h">
|
||||
<Filter>SNES\Coprocessors\MSU1</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Sa1IRamHandler.h">
|
||||
<Filter>SNES\Coprocessors\SA1</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Sa1BwRamHandler.h">
|
||||
<Filter>SNES\Coprocessors\SA1</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp" />
|
||||
|
|
47
Core/Sa1.cpp
47
Core/Sa1.cpp
|
@ -9,6 +9,8 @@
|
|||
#include "BaseCartridge.h"
|
||||
#include "RamHandler.h"
|
||||
#include "Sa1VectorHandler.h"
|
||||
#include "Sa1IRamHandler.h"
|
||||
#include "Sa1BwRamHandler.h"
|
||||
#include "CpuBwRamHandler.h"
|
||||
#include "MessageManager.h"
|
||||
#include "../Utilities/HexUtilities.h"
|
||||
|
@ -24,7 +26,8 @@ Sa1::Sa1(Console* console)
|
|||
_snesCpu = _console->GetCpu().get();
|
||||
|
||||
_iRam = new uint8_t[Sa1::InternalRamSize];
|
||||
_iRamHandler.reset(new RamHandler(_iRam, 0, 0x800, SnesMemoryType::Sa1InternalRam));
|
||||
_iRamHandler.reset(new Sa1IRamHandler(_iRam));
|
||||
_bwRamHandler.reset(new Sa1BwRamHandler(_cart->DebugGetSaveRam(), _cart->DebugGetSaveRamSize(), &_state));
|
||||
console->GetSettings()->InitializeRam(_iRam, 0x800);
|
||||
|
||||
//Register the SA1 in the CPU's memory space ($22xx-$23xx registers)
|
||||
|
@ -40,6 +43,16 @@ Sa1::Sa1(Console* console)
|
|||
_mappings.RegisterHandler(0x00, 0x3F, 0x0000, 0x0FFF, _iRamHandler.get());
|
||||
_mappings.RegisterHandler(0x80, 0xBF, 0x0000, 0x0FFF, _iRamHandler.get());
|
||||
|
||||
for(int i = 0; i <= 0x3F; i++) {
|
||||
//SA-1: 00-3F:6000-7FFF + 80-BF:6000-7FFF
|
||||
_mappings.RegisterHandler(i, i, 0x6000, 0x7FFF, _bwRamHandler.get());
|
||||
_mappings.RegisterHandler(i + 0x80, i + 0x80, 0x6000, 0x7FFF, _bwRamHandler.get());
|
||||
}
|
||||
for(int i = 0; i <= 0x0F; i++) {
|
||||
//SA-1: 60-6F:0000-FFFF
|
||||
_mappings.RegisterHandler(i + 0x60, i + 0x60, 0x0000, 0xFFFF, _bwRamHandler.get());
|
||||
}
|
||||
|
||||
vector<unique_ptr<IMemoryHandler>> &saveRamHandlers = _cart->GetSaveRamHandlers();
|
||||
for(unique_ptr<IMemoryHandler> &handler : saveRamHandlers) {
|
||||
_cpuBwRamHandlers.push_back(unique_ptr<IMemoryHandler>(new CpuBwRamHandler(handler.get(), &_state, this)));
|
||||
|
@ -417,8 +430,8 @@ void Sa1::ProcessInterrupts()
|
|||
void Sa1::WriteSa1(uint32_t addr, uint8_t value, MemoryOperationType type)
|
||||
{
|
||||
IMemoryHandler *handler = _mappings.GetHandler(addr);
|
||||
_console->ProcessMemoryWrite<CpuType::Sa1>(addr, value, type);
|
||||
if(handler) {
|
||||
_console->ProcessMemoryWrite<CpuType::Sa1>(addr, value, type);
|
||||
_lastAccessMemType = handler->GetMemoryType();
|
||||
_openBus = value;
|
||||
handler->Write(addr, value);
|
||||
|
@ -430,16 +443,17 @@ void Sa1::WriteSa1(uint32_t addr, uint8_t value, MemoryOperationType type)
|
|||
uint8_t Sa1::ReadSa1(uint32_t addr, MemoryOperationType type)
|
||||
{
|
||||
IMemoryHandler *handler = _mappings.GetHandler(addr);
|
||||
uint8_t value;
|
||||
if(handler) {
|
||||
uint8_t value = handler->Read(addr);
|
||||
value = handler->Read(addr);
|
||||
_lastAccessMemType = handler->GetMemoryType();
|
||||
_openBus = value;
|
||||
_console->ProcessMemoryRead<CpuType::Sa1>(addr, value, type);
|
||||
return value;
|
||||
} else {
|
||||
value = _openBus;
|
||||
LogDebug("[Debug] Read SA1 - missing handler: $" + HexUtilities::ToHex(addr));
|
||||
}
|
||||
return _openBus;
|
||||
_console->ProcessMemoryRead<CpuType::Sa1>(addr, value, type);
|
||||
return value;
|
||||
}
|
||||
|
||||
uint8_t Sa1::Read(uint32_t addr)
|
||||
|
@ -449,12 +463,8 @@ uint8_t Sa1::Read(uint32_t addr)
|
|||
|
||||
uint8_t Sa1::Peek(uint32_t addr)
|
||||
{
|
||||
IMemoryHandler *handler = _mappings.GetHandler(addr);
|
||||
if(handler) {
|
||||
return handler->Read(addr);
|
||||
}
|
||||
//Open bus
|
||||
return addr >> 16;
|
||||
//Not implemented
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Sa1::PeekBlock(uint8_t *output)
|
||||
|
@ -600,12 +610,13 @@ void Sa1::UpdateSaveRamMappings()
|
|||
{
|
||||
vector<unique_ptr<IMemoryHandler>> &saveRamHandlers = _cart->GetSaveRamHandlers();
|
||||
MemoryMappings* cpuMappings = _memoryManager->GetMemoryMappings();
|
||||
for(int i = 0; i < 0x3F; i++) {
|
||||
_mappings.RegisterHandler(i, i, 0x6000, 0x7FFF, saveRamHandlers, 0, (_state.Sa1BwBank & ((_cpuBwRamHandlers.size() / 2) - 1)) * 2);
|
||||
_mappings.RegisterHandler(i + 0x80, i + 0x80, 0x6000, 0x7FFF, saveRamHandlers, 0, (_state.Sa1BwBank & ((_cpuBwRamHandlers.size() / 2) - 1)) * 2);
|
||||
|
||||
cpuMappings->RegisterHandler(i, i, 0x6000, 0x7FFF, saveRamHandlers, 0, (_state.CpuBwBank & ((_cpuBwRamHandlers.size() / 2) - 1)) * 2);
|
||||
cpuMappings->RegisterHandler(i + 0x80, i + 0x80, 0x6000, 0x7FFF, saveRamHandlers, 0, (_state.CpuBwBank & ((_cpuBwRamHandlers.size() / 2) - 1)) * 2);
|
||||
uint32_t bankNumber = _state.CpuBwBank & ((_cpuBwRamHandlers.size() / 2) - 1);
|
||||
for(int i = 0; i <= 0x3F; i++) {
|
||||
//S-CPU: 00-3F:6000-7FFF + 80-BF:6000-7FFF
|
||||
cpuMappings->RegisterHandler(i, i, 0x6000, 0x6FFF, saveRamHandlers[bankNumber * 2].get());
|
||||
cpuMappings->RegisterHandler(i, i, 0x7000, 0x7FFF, saveRamHandlers[bankNumber * 2 + 1].get());
|
||||
cpuMappings->RegisterHandler(i + 0x80, i + 0x80, 0x6000, 0x6FFF, saveRamHandlers[bankNumber * 2].get());
|
||||
cpuMappings->RegisterHandler(i + 0x80, i + 0x80, 0x7000, 0x7FFF, saveRamHandlers[bankNumber * 2 + 1].get());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ class MemoryManager;
|
|||
class BaseCartridge;
|
||||
|
||||
//TODO: Implement write protection flags
|
||||
//TODO: Bitmap projection at $6000
|
||||
//TODO: Timers
|
||||
|
||||
class Sa1 : public BaseCoprocessor
|
||||
|
@ -32,6 +31,7 @@ private:
|
|||
uint8_t _openBus;
|
||||
|
||||
unique_ptr<IMemoryHandler> _iRamHandler;
|
||||
unique_ptr<IMemoryHandler> _bwRamHandler;
|
||||
unique_ptr<IMemoryHandler> _sa1VectorHandler;
|
||||
unique_ptr<IMemoryHandler> _cpuVectorHandler;
|
||||
|
||||
|
|
106
Core/Sa1BwRamHandler.h
Normal file
106
Core/Sa1BwRamHandler.h
Normal file
|
@ -0,0 +1,106 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "IMemoryHandler.h"
|
||||
#include "Sa1Cpu.h"
|
||||
#include "Sa1Types.h"
|
||||
#include "Sa1.h"
|
||||
|
||||
//Manages BWRAM access from the SA-1 CPU, for regions that can enable bitmap mode. e.g:
|
||||
//00-3F:6000-7FFF + 80-BF:6000-7FFF (optional bitmap mode + bank select)
|
||||
//60-6F:0000-FFFF (always bitmap mode)
|
||||
class Sa1BwRamHandler : public IMemoryHandler
|
||||
{
|
||||
private:
|
||||
uint8_t * _ram;
|
||||
uint32_t _mask;
|
||||
Sa1State* _state;
|
||||
|
||||
uint32_t GetBwRamAddress(uint32_t addr)
|
||||
{
|
||||
return ((_state->Sa1BwBank * 0x2000) | (addr & 0x1FFF));
|
||||
}
|
||||
|
||||
public:
|
||||
Sa1BwRamHandler(uint8_t* bwRam, uint32_t bwRamSize, Sa1State* state)
|
||||
{
|
||||
_ram = bwRam;
|
||||
_mask = bwRamSize - 1;
|
||||
_state = state;
|
||||
}
|
||||
|
||||
uint8_t Read(uint32_t addr) override
|
||||
{
|
||||
if((addr & 0x600000) == 0x600000) {
|
||||
return ReadBitmapMode(addr - 0x600000);
|
||||
} else {
|
||||
addr = GetBwRamAddress(addr);
|
||||
if(_state->Sa1BwMode) {
|
||||
//Bitmap mode is enabled
|
||||
return ReadBitmapMode(addr);
|
||||
} else {
|
||||
//Return regular memory content
|
||||
return _ram[addr & _mask];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t Peek(uint32_t addr) override
|
||||
{
|
||||
return Read(addr);
|
||||
}
|
||||
|
||||
void PeekBlock(uint8_t *output) override
|
||||
{
|
||||
for(int i = 0; i < 0x1000; i++) {
|
||||
output[i] = Read(i);
|
||||
}
|
||||
}
|
||||
|
||||
void Write(uint32_t addr, uint8_t value) override
|
||||
{
|
||||
if((addr & 0x600000) == 0x600000) {
|
||||
WriteBitmapMode(addr - 0x600000, value);
|
||||
} else {
|
||||
addr = GetBwRamAddress(addr);
|
||||
if(_state->Sa1BwMode) {
|
||||
WriteBitmapMode(addr, value);
|
||||
} else {
|
||||
_ram[addr & _mask] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ReadBitmapMode(uint32_t addr)
|
||||
{
|
||||
if(_state->BwRam2BppMode) {
|
||||
return (_ram[(addr >> 2) & _mask] >> ((addr & 0x03) * 2)) & 0x03;
|
||||
} else {
|
||||
return (_ram[(addr >> 1) & _mask] >> ((addr & 0x01) * 4)) & 0x0F;
|
||||
}
|
||||
}
|
||||
|
||||
void WriteBitmapMode(uint32_t addr, uint8_t value)
|
||||
{
|
||||
if(_state->BwRam2BppMode) {
|
||||
uint8_t shift = (addr & 0x03) * 2;
|
||||
addr = (addr >> 2) & _mask;
|
||||
_ram[addr] = (_ram[addr] & ~(0x03 << shift)) | ((value & 0x03) << shift);
|
||||
} else {
|
||||
uint8_t shift = (addr & 0x01) * 4;
|
||||
addr = (addr >> 1) & _mask;
|
||||
_ram[addr] = (_ram[addr] & ~(0x0F << shift)) | ((value & 0x0F) << shift);
|
||||
}
|
||||
}
|
||||
|
||||
AddressInfo GetAbsoluteAddress(uint32_t addr) override
|
||||
{
|
||||
AddressInfo info;
|
||||
if((addr & 0x600000) == 0x600000) {
|
||||
info.Address = addr - 0x600000;
|
||||
} else {
|
||||
addr = GetBwRamAddress(addr);
|
||||
}
|
||||
info.Type = SnesMemoryType::SaveRam;
|
||||
return info;
|
||||
}
|
||||
};
|
58
Core/Sa1IRamHandler.h
Normal file
58
Core/Sa1IRamHandler.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "IMemoryHandler.h"
|
||||
#include "DebugTypes.h"
|
||||
|
||||
class Sa1IRamHandler : public IMemoryHandler
|
||||
{
|
||||
private:
|
||||
uint8_t * _ram;
|
||||
|
||||
public:
|
||||
Sa1IRamHandler(uint8_t *ram)
|
||||
{
|
||||
_ram = ram;
|
||||
_memoryType = SnesMemoryType::Sa1InternalRam;
|
||||
}
|
||||
|
||||
uint8_t Read(uint32_t addr) override
|
||||
{
|
||||
if(addr & 0x800) {
|
||||
return 0;
|
||||
} else {
|
||||
return _ram[addr & 0x7FF];
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t Peek(uint32_t addr) override
|
||||
{
|
||||
return Read(addr);
|
||||
}
|
||||
|
||||
void PeekBlock(uint8_t *output) override
|
||||
{
|
||||
for(int i = 0; i < 0x1000; i++) {
|
||||
output[i] = Read(i);
|
||||
}
|
||||
}
|
||||
|
||||
void Write(uint32_t addr, uint8_t value) override
|
||||
{
|
||||
if(!(addr & 0x800)) {
|
||||
_ram[addr & 0x7FF] = value;
|
||||
}
|
||||
}
|
||||
|
||||
AddressInfo GetAbsoluteAddress(uint32_t addr) override
|
||||
{
|
||||
AddressInfo info;
|
||||
if(addr & 0x800) {
|
||||
info.Address = -1;
|
||||
info.Type = SnesMemoryType::CpuMemory;
|
||||
} else {
|
||||
info.Address = (addr & 0x7FF);
|
||||
info.Type = _memoryType;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
};
|
Loading…
Add table
Reference in a new issue