NES: Added Rainbow support (mapper 682)

This commit is contained in:
Sour 2024-10-08 21:32:12 +09:00
parent 8e6846eaf6
commit d751502a58
43 changed files with 2283 additions and 284 deletions

View file

@ -20,6 +20,10 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="NES\Epsm.h" />
<ClInclude Include="NES\Mappers\Homebrew\Rainbow.h" />
<ClInclude Include="NES\Mappers\Homebrew\RainbowAudio.h" />
<ClInclude Include="NES\Debugger\IExtModeMapperDebug.h" />
<ClInclude Include="NES\Mappers\Homebrew\FlashS29.h" />
<ClInclude Include="NES\OpnInterface.h" />
<ClInclude Include="SMS\Input\ColecoVisionController.h" />
<ClInclude Include="Debugger\AddressInfo.h" />
@ -852,6 +856,7 @@
<ClCompile Include="NES\APU\BaseExpansionAudio.cpp" />
<ClCompile Include="NES\Loaders\StudyBoxLoader.cpp" />
<ClCompile Include="NES\Loaders\UnifLoader.cpp" />
<ClCompile Include="NES\Mappers\Homebrew\Rainbow.cpp" />
<ClCompile Include="Shared\Utilities\emu2413.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='PGO Profile|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>

View file

@ -2928,6 +2928,18 @@
<ClInclude Include="NES\OpnInterface.h">
<Filter>NES</Filter>
</ClInclude>
<ClInclude Include="NES\Mappers\Homebrew\Rainbow.h">
<Filter>NES\Mappers\Homebrew</Filter>
</ClInclude>
<ClInclude Include="NES\Mappers\Homebrew\RainbowAudio.h">
<Filter>NES\Mappers\Homebrew</Filter>
</ClInclude>
<ClInclude Include="NES\Debugger\IExtModeMapperDebug.h">
<Filter>NES\Mappers\Homebrew</Filter>
</ClInclude>
<ClInclude Include="NES\Mappers\Homebrew\FlashS29.h">
<Filter>NES\Mappers\Homebrew</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Shared\Video\RotateFilter.cpp">
@ -3266,6 +3278,9 @@
<ClCompile Include="NES\Epsm.cpp">
<Filter>NES</Filter>
</ClCompile>
<ClCompile Include="NES\Mappers\Homebrew\Rainbow.cpp">
<Filter>NES\Mappers\Homebrew</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="PCE">

View file

@ -101,6 +101,7 @@ public:
case MemoryType::NesInternalRam:
case MemoryType::NesMemory:
case MemoryType::NesNametableRam:
case MemoryType::NesMapperRam:
case MemoryType::NesPaletteRam:
case MemoryType::NesPpuMemory:
case MemoryType::NesPrgRom:

View file

@ -242,12 +242,12 @@ public:
void GetTileView(GetTileViewOptions options, uint8_t *source, uint32_t srcSize, const uint32_t* palette, uint32_t *outBuffer);
virtual DebugTilemapTileInfo GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState) = 0;
virtual DebugTilemapTileInfo GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState, BaseState& ppuToolsState) = 0;
virtual FrameInfo GetTilemapSize(GetTilemapOptions options, BaseState& state) = 0;
virtual DebugTilemapInfo GetTilemap(GetTilemapOptions options, BaseState& state, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer) = 0;
virtual DebugTilemapInfo GetTilemap(GetTilemapOptions options, BaseState& state, BaseState& ppuToolsState, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer) = 0;
virtual DebugSpritePreviewInfo GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& state) = 0;
virtual void GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview) = 0;
virtual DebugSpritePreviewInfo GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& state, BaseState& ppuToolsState) = 0;
virtual void GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, BaseState& ppuToolsState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview) = 0;
int32_t GetTilePixel(AddressInfo tileAddress, TileFormat format, int32_t x, int32_t y);
void SetTilePixel(AddressInfo tileAddress, TileFormat format, int32_t x, int32_t y, int32_t color);

View file

@ -15,7 +15,7 @@ void GbaPpuTools::SetMemoryAccessData(uint16_t scanline, uint8_t* data)
memcpy(_memoryAccess + scanline * 308 * 4, data, 308 * 4);
}
DebugTilemapInfo GbaPpuTools::GetTilemap(GetTilemapOptions options, BaseState& baseState, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer)
DebugTilemapInfo GbaPpuTools::GetTilemap(GetTilemapOptions options, BaseState& baseState, BaseState& ppuToolsState, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer)
{
GbaPpuState& state = (GbaPpuState&)baseState;
FrameInfo outputSize = GetTilemapSize(options, state);
@ -256,7 +256,7 @@ FrameInfo GbaPpuTools::GetTilemapSize(GetTilemapOptions options, BaseState& base
return { 0, 0 };
}
DebugTilemapTileInfo GbaPpuTools::GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState)
DebugTilemapTileInfo GbaPpuTools::GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState, BaseState& ppuToolsState)
{
DebugTilemapTileInfo result = {};
@ -397,7 +397,7 @@ void GbaPpuTools::GetSpritePreview(GetSpritePreviewOptions options, BaseState& b
}
}
DebugSpritePreviewInfo GbaPpuTools::GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& state)
DebugSpritePreviewInfo GbaPpuTools::GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& state, BaseState& ppuToolsState)
{
DebugSpritePreviewInfo info = {};
info.Height = 256;
@ -586,7 +586,7 @@ void GbaPpuTools::GetSpriteInfo(DebugSpriteInfo& sprite, uint32_t* spritePreview
}
}
void GbaPpuTools::GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview)
void GbaPpuTools::GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, BaseState& ppuToolsState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview)
{
GbaPpuState& state = (GbaPpuState&)baseState;
for(int i = 0; i < 128; i++) {

View file

@ -20,12 +20,12 @@ public:
void SetMemoryAccessData(uint16_t scanline, uint8_t* data);
DebugTilemapInfo GetTilemap(GetTilemapOptions options, BaseState& state, uint8_t* vram, uint32_t* palette, uint32_t *outBuffer) override;
DebugTilemapInfo GetTilemap(GetTilemapOptions options, BaseState& state, BaseState& ppuToolsState, uint8_t* vram, uint32_t* palette, uint32_t *outBuffer) override;
FrameInfo GetTilemapSize(GetTilemapOptions options, BaseState& state) override;
DebugTilemapTileInfo GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState) override;
DebugTilemapTileInfo GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState, BaseState& ppuToolsState) override;
DebugSpritePreviewInfo GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& state) override;
void GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview) override;
DebugSpritePreviewInfo GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& state, BaseState& ppuToolsState) override;
void GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, BaseState& ppuToolsState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview) override;
DebugPaletteInfo GetPaletteInfo(GetPaletteInfoOptions options) override;
void SetPaletteColor(int32_t colorIndex, uint32_t color) override;

View file

@ -10,7 +10,7 @@ GbPpuTools::GbPpuTools(Debugger* debugger, Emulator *emu) : PpuTools(debugger, e
{
}
DebugTilemapInfo GbPpuTools::GetTilemap(GetTilemapOptions options, BaseState& baseState, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer)
DebugTilemapInfo GbPpuTools::GetTilemap(GetTilemapOptions options, BaseState& baseState, BaseState& ppuToolsState, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer)
{
GbPpuState& state = (GbPpuState&)baseState;
uint32_t offset = options.Layer == 1 ? 0x1C00 : 0x1800;
@ -108,7 +108,7 @@ FrameInfo GbPpuTools::GetTilemapSize(GetTilemapOptions options, BaseState& state
return { 256, 256 };
}
DebugTilemapTileInfo GbPpuTools::GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState)
DebugTilemapTileInfo GbPpuTools::GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState, BaseState& ppuToolsState)
{
DebugTilemapTileInfo result = {};
@ -158,7 +158,7 @@ DebugTilemapTileInfo GbPpuTools::GetTilemapTileInfo(uint32_t x, uint32_t y, uint
return result;
}
DebugSpritePreviewInfo GbPpuTools::GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& state)
DebugSpritePreviewInfo GbPpuTools::GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& state, BaseState& ppuToolsState)
{
DebugSpritePreviewInfo info = {};
info.Height = 256;
@ -241,7 +241,7 @@ void GbPpuTools::GetSpriteInfo(DebugSpriteInfo& sprite, uint32_t* spritePreview,
}
}
void GbPpuTools::GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview)
void GbPpuTools::GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, BaseState& ppuToolsState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview)
{
GbPpuState& state = (GbPpuState&)baseState;
for(int i = 0; i < 40; i++) {

View file

@ -16,12 +16,12 @@ private:
public:
GbPpuTools(Debugger* debugger, Emulator *emu);
DebugTilemapInfo GetTilemap(GetTilemapOptions options, BaseState& state, uint8_t* vram, uint32_t* palette, uint32_t *outBuffer) override;
DebugTilemapInfo GetTilemap(GetTilemapOptions options, BaseState& state, BaseState& ppuToolsState, uint8_t* vram, uint32_t* palette, uint32_t *outBuffer) override;
FrameInfo GetTilemapSize(GetTilemapOptions options, BaseState& state) override;
DebugTilemapTileInfo GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState) override;
DebugTilemapTileInfo GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState, BaseState& ppuToolsState) override;
DebugSpritePreviewInfo GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& state) override;
void GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview) override;
DebugSpritePreviewInfo GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& state, BaseState& ppuToolsState) override;
void GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, BaseState& ppuToolsState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview) override;
DebugPaletteInfo GetPaletteInfo(GetPaletteInfoOptions options) override;
void SetPaletteColor(int32_t colorIndex, uint32_t color) override;

View file

@ -138,14 +138,24 @@ void BaseMapper::SetCpuMemoryMapping(uint16_t startAddr, uint16_t endAddr, PrgMe
case PrgMemoryType::PrgRom: source = _prgRom; sourceSize = _prgSize; break;
case PrgMemoryType::SaveRam: source = _saveRam; sourceSize = _saveRamSize; break;
case PrgMemoryType::WorkRam: source = _workRam; sourceSize = _workRamSize; break;
case PrgMemoryType::MapperRam: source = _mapperRam; sourceSize = _mapperRamSize; break;
}
int firstSlot = startAddr >> 8;
int slotCount = (endAddr - startAddr + 1) >> 8;
for(int i = 0; i < slotCount; i++) {
_prgMemoryOffset[firstSlot + i] = sourceOffset + i * 0x100;
_prgMemoryType[firstSlot + i] = type;
_prgMemoryAccess[firstSlot + i] = (MemoryAccessType)accessType;
if(sourceSize == 0) {
_prgPages[i] = nullptr;
_prgMemoryAccess[i] = MemoryAccessType::NoAccess;
} else {
while(sourceOffset >= sourceSize) {
sourceOffset -= sourceSize;
}
_prgPages[firstSlot + i] = source + sourceOffset;
_prgMemoryOffset[firstSlot + i] = sourceOffset + i * 0x100;
_prgMemoryType[firstSlot + i] = type;
_prgMemoryAccess[firstSlot + i] = (MemoryAccessType)accessType;
}
}
SetCpuMemoryMapping(startAddr, endAddr, source, sourceOffset, sourceSize, accessType);
@ -233,6 +243,9 @@ void BaseMapper::SetPpuMemoryMapping(uint16_t startAddr, uint16_t endAddr, uint1
pageCount = _nametableCount;
defaultAccessType |= MemoryAccessType::Write;
break;
default:
throw new std::runtime_error("Invalid parameter");
}
if(pageCount == 0) {
@ -285,14 +298,27 @@ void BaseMapper::SetPpuMemoryMapping(uint16_t startAddr, uint16_t endAddr, ChrMe
sourceMemory = _nametableRam;
sourceSize = _ntRamSize;
break;
case ChrMemoryType::MapperRam:
sourceMemory = _mapperRam;
sourceSize = _mapperRamSize;
break;
}
int firstSlot = startAddr >> 8;
int slotCount = (endAddr - startAddr + 1) >> 8;
for(int i = 0; i < slotCount; i++) {
_chrMemoryOffset[firstSlot + i] = sourceOffset + i * 256;
_chrMemoryType[firstSlot + i] = type;
_chrMemoryAccess[firstSlot + i] = (MemoryAccessType)accessType;
if(sourceSize == 0) {
_chrPages[i] = nullptr;
_chrMemoryAccess[i] = MemoryAccessType::NoAccess;
} else {
while(sourceOffset >= sourceSize) {
sourceOffset -= sourceSize;
}
_chrMemoryOffset[firstSlot + i] = sourceOffset + i * 256;
_chrMemoryType[firstSlot + i] = type;
_chrMemoryAccess[firstSlot + i] = (MemoryAccessType)accessType;
}
}
SetPpuMemoryMapping(startAddr, endAddr, sourceMemory, sourceOffset, sourceSize, accessType);
@ -534,6 +560,7 @@ void BaseMapper::Serialize(Serializer& s)
SVArray(_chrRam, _chrRamSize);
SVArray(_workRam, _workRamSize);
SVArray(_saveRam, _saveRamSize);
SVArray(_mapperRam, _mapperRamSize);
SVArray(_nametableRam, _ntRamSize);
SVArray(_prgMemoryOffset, 0x100);
@ -647,8 +674,13 @@ void BaseMapper::Initialize(NesConsole* console, RomData& romData)
_workRam = new uint8_t[_workRamSize];
_emu->RegisterMemory(MemoryType::NesWorkRam, _workRam, _workRamSize);
_mapperRamSize = GetMapperRamSize();
_mapperRam = new uint8_t[_mapperRamSize];
_emu->RegisterMemory(MemoryType::NesMapperRam, _mapperRam, _mapperRamSize);
_console->InitializeRam(_saveRam, _saveRamSize);
_console->InitializeRam(_workRam, _workRamSize);
_console->InitializeRam(_mapperRam, _mapperRamSize);
_nametableCount = GetNametableCount();
if(_nametableCount == 0) {
@ -728,6 +760,7 @@ BaseMapper::~BaseMapper()
delete[] _prgRom;
delete[] _saveRam;
delete[] _workRam;
delete[] _mapperRam;
delete[] _nametableRam;
}
@ -941,7 +974,16 @@ void BaseMapper::DebugWriteVram(uint16_t addr, uint8_t value, bool disableSideEf
void BaseMapper::WriteVram(uint16_t addr, uint8_t value)
{
_emu->ProcessPpuWrite<CpuType::Nes>(addr, value, MemoryType::NesPpuMemory);
MapperWriteVram(addr, value);
}
void BaseMapper::MapperWriteVram(uint16_t addr, uint8_t value)
{
InternalWriteVram(addr, value);
}
void BaseMapper::InternalWriteVram(uint16_t addr, uint8_t value)
{
if(_chrMemoryAccess[addr >> 8] & MemoryAccessType::Write) {
_chrPages[addr >> 8][(uint8_t)addr] = value;
}
@ -969,16 +1011,19 @@ AddressInfo BaseMapper::GetAbsoluteAddress(uint16_t relativeAddr)
info.Address = relativeAddr & _internalRamMask;
info.Type = MemoryType::NesInternalRam;
} else {
uint8_t *prgAddr = _prgPages[relativeAddr >> 8] + (uint8_t)relativeAddr;
if(prgAddr >= _prgRom && prgAddr < _prgRom + _prgSize) {
info.Address = (uint32_t)(prgAddr - _prgRom);
uint8_t *addr = _prgPages[relativeAddr >> 8] + (uint8_t)relativeAddr;
if(addr >= _prgRom && addr < _prgRom + _prgSize) {
info.Address = (uint32_t)(addr - _prgRom);
info.Type = MemoryType::NesPrgRom;
} else if(prgAddr >= _workRam && prgAddr < _workRam + _workRamSize) {
info.Address = (uint32_t)(prgAddr - _workRam);
} else if(addr >= _workRam && addr < _workRam + _workRamSize) {
info.Address = (uint32_t)(addr - _workRam);
info.Type = MemoryType::NesWorkRam;
} else if(prgAddr >= _saveRam && prgAddr < _saveRam + _saveRamSize) {
info.Address = (uint32_t)(prgAddr - _saveRam);
} else if(addr >= _saveRam && addr < _saveRam + _saveRamSize) {
info.Address = (uint32_t)(addr - _saveRam);
info.Type = MemoryType::NesSaveRam;
} else if(addr >= _mapperRam && addr < _mapperRam + _mapperRamSize) {
info.Address = (uint32_t)(addr - _mapperRam);
info.Type = MemoryType::NesMapperRam;
} else {
info.Address = -1;
info.Type = MemoryType::None;
@ -1000,6 +1045,9 @@ void BaseMapper::GetPpuAbsoluteAddress(uint16_t relativeAddr, AddressInfo& info)
} else if(addr >= _chrRam && addr < _chrRam + _chrRamSize) {
info.Address = (uint32_t)(addr - _chrRam);
info.Type = MemoryType::NesChrRam;
} else if(addr >= _mapperRam && addr < _mapperRam + _mapperRamSize) {
info.Address = (uint32_t)(addr - _mapperRam);
info.Type = MemoryType::NesMapperRam;
} else if(addr >= _nametableRam && addr < _nametableRam + _nametableCount * BaseMapper::NametableSize) {
info.Address = (uint32_t)(addr - _nametableRam);
info.Type = MemoryType::NesNametableRam;
@ -1025,6 +1073,7 @@ AddressInfo BaseMapper::GetRelativeAddress(AddressInfo& addr)
case MemoryType::NesPrgRom: ptrAddress = _prgRom; break;
case MemoryType::NesWorkRam: ptrAddress = _workRam; break;
case MemoryType::NesSaveRam: ptrAddress = _saveRam; break;
case MemoryType::NesMapperRam: ptrAddress = _mapperRam; break;
case MemoryType::NesInternalRam: return { (int32_t)(addr.Address & _internalRamMask), MemoryType::NesMemory };
default: return { GetPpuRelativeAddress(addr), MemoryType::NesPpuMemory };
}
@ -1049,6 +1098,7 @@ int32_t BaseMapper::GetPpuRelativeAddress(AddressInfo& addr)
case MemoryType::NesChrRom: ptrAddress = _chrRom; break;
case MemoryType::NesChrRam: ptrAddress = _chrRam; break;
case MemoryType::NesNametableRam: ptrAddress = _nametableRam; break;
case MemoryType::NesMapperRam: ptrAddress = _mapperRam; break;
case MemoryType::NesPaletteRam: return 0x3F00 | (addr.Address & 0x1F); break;
default: return -1;
}
@ -1106,6 +1156,7 @@ CartridgeState BaseMapper::GetState()
state.SaveRamPageSize = GetSaveRamPageSize();
vector<MapperStateEntry> entries = GetMapperStateEntries();
assert(entries.size() <= 200);
state.CustomEntryCount = (uint32_t)entries.size();
for(int i = 0; i < entries.size(); i++) {
state.CustomEntries[i] = entries[i];

View file

@ -81,6 +81,9 @@ protected:
bool _hasChrBattery = false;
int16_t _vramOpenBusValue = -1;
uint8_t* _mapperRam = nullptr;
uint32_t _mapperRamSize = 0;
virtual void InitMapper() = 0;
virtual void InitMapper(RomData &romData);
virtual uint16_t GetPrgPageSize() = 0;
@ -104,6 +107,8 @@ protected:
virtual uint32_t GetWorkRamSize() { return 0x2000; }
virtual uint32_t GetWorkRamPageSize() { return 0x2000; }
virtual uint32_t GetMapperRamSize() { return 0; }
virtual uint16_t RegisterStartAddress() { return 0x8000; }
virtual uint16_t RegisterEndAddress() { return 0xFFFF; }
virtual bool AllowRegisterRead() { return false; }
@ -140,7 +145,7 @@ protected:
void RemovePpuMemoryMapping(uint16_t startAddr, uint16_t endAddr);
bool HasBattery();
void LoadBattery();
virtual void LoadBattery();
string GetBatteryFilename();
uint32_t GetPrgPageCount();
@ -168,6 +173,8 @@ protected:
void SetMirroringType(MirroringType type);
MirroringType GetMirroringType();
void InternalWriteVram(uint16_t addr, uint8_t value);
__forceinline uint8_t InternalReadVram(uint16_t addr)
{
if(_chrMemoryAccess[addr >> 8] & MemoryAccessType::Read) {
@ -222,7 +229,8 @@ public:
void WritePrgRam(uint16_t addr, uint8_t value);
virtual uint8_t MapperReadVram(uint16_t addr, MemoryOperationType operationType);
virtual void MapperWriteVram(uint16_t addr, uint8_t value);
__forceinline uint8_t ReadVram(uint16_t addr, MemoryOperationType type = MemoryOperationType::PpuRenderingRead)
{
uint8_t value;

View file

@ -0,0 +1,63 @@
#pragma once
#include "pch.h"
struct NtExtConfig
{
uint16_t SourceOffset;
bool AttrExtMode;
bool BgExtMode;
bool FillMode;
};
struct ExtModeConfig
{
NtExtConfig Nametables[5];
bool SpriteExtMode;
uint8_t ChrSource;
uint8_t WindowBank;
uint8_t WindowScrollX;
uint8_t WindowScrollY;
uint8_t BgExtBank;
uint8_t SpriteExtBank;
uint8_t SpriteExtData[64];
uint8_t ExtRam[0x2000];
};
class IExtModeMapperDebug
{
public:
virtual ExtModeConfig GetExModeConfig()
{
return {};
}
virtual bool HasExtendedAttributes(ExtModeConfig& extCfg, uint8_t ntIndex)
{
return false;
}
virtual bool HasExtendedBackground(ExtModeConfig& extCfg, uint8_t ntIndex)
{
return false;
}
virtual bool HasExtendedSprites(ExtModeConfig& extCfg)
{
return false;
}
virtual uint8_t GetExAttributePalette(ExtModeConfig& extCfg, uint8_t ntIndex, uint16_t ntAddr)
{
return 0;
}
virtual uint8_t GetExBackgroundChrData(ExtModeConfig& extCfg, uint8_t ntIndex, uint16_t ntAddr, uint16_t chrAddr)
{
return 0;
}
virtual uint8_t GetExSpriteChrData(ExtModeConfig& extCfg, uint8_t spriteIndex, uint16_t chrAddr)
{
return 0;
}
};

View file

@ -1,125 +1,136 @@
#include "pch.h"
#include "NES/Debugger/NesPpuTools.h"
#include "NES/Mappers/Nintendo/MMC5.h"
#include "NES/Debugger/IExtModeMapperDebug.h"
#include "NES/BaseMapper.h"
#include "NES/BaseNesPpu.h"
#include "NES/NesConsole.h"
#include "NES/NesConstants.h"
#include "NES/NesTypes.h"
#include "NES/NesDefaultVideoFilter.h"
#include "NES/Mappers/Homebrew/Rainbow.h"
#include "Debugger/DebugTypes.h"
#include "Debugger/MemoryDumper.h"
#include "Debugger/MemoryAccessCounter.h"
#include "Shared/SettingTypes.h"
static constexpr uint32_t grayscalePalette[4] = { 0xFF000000, 0xFF808080, 0xFFC0C0C0, 0xFFFFFFFF };
NesPpuTools::NesPpuTools(Debugger* debugger, Emulator *emu, NesConsole* console) : PpuTools(debugger, emu)
{
_console = console;
_mapper = console->GetMapper();
}
DebugTilemapInfo NesPpuTools::GetTilemap(GetTilemapOptions options, BaseState& baseState, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer)
void NesPpuTools::GetPpuToolsState(BaseState& state)
{
MMC5* mmc5 = dynamic_cast<MMC5*>(_mapper);
NesPpuToolsState nesState = {};
IExtModeMapperDebug* exMode = dynamic_cast<IExtModeMapperDebug*>(_mapper);
if(exMode) {
nesState.ExtConfig = exMode->GetExModeConfig();
}
(NesPpuToolsState&)state = nesState;
}
void NesPpuTools::DrawNametable(uint8_t* ntSource, uint32_t ntBaseAddr, uint8_t ntIndex, GetTilemapOptions options, NesPpuState& state, IExtModeMapperDebug* exMode, ExtModeConfig& extCfg, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer, uint32_t bufferWidth)
{
uint16_t baseAttributeAddr = ntBaseAddr + 960;
for(uint8_t row = 0; row < 30; row++) {
for(uint8_t column = 0; column < 32; column++) {
uint16_t ntOffset = (row << 5) + column;
uint16_t attributeAddress = baseAttributeAddr + ((row & 0xFC) << 1) + (column >> 2);
uint8_t tileIndex = ntSource[ntBaseAddr + ntOffset];
uint8_t attribute = ntSource[attributeAddress];
uint8_t shift = (column & 0x02) | ((row & 0x02) << 1);
uint8_t paletteBaseAddr;
if(exMode && exMode->HasExtendedAttributes(extCfg, ntIndex)) {
paletteBaseAddr = exMode->GetExAttributePalette(extCfg, ntIndex, ntOffset) << 2;
} else {
paletteBaseAddr = ((attribute >> shift) & 0x03) << 2;
}
uint16_t tileAddr = state.Control.BackgroundPatternAddr + (tileIndex << 4);
if(options.DisplayMode == TilemapDisplayMode::AttributeView) {
for(uint8_t y = 0; y < 8; y++) {
for(uint8_t x = 0; x < 8; x++) {
uint8_t color = ((x & 0x04) >> 2) + ((y & 0x04) >> 1);
outBuffer[(row*bufferWidth*8) + (column << 3) + (y*bufferWidth) + x] = palette[paletteBaseAddr + color];
}
}
} else {
for(uint8_t y = 0; y < 8; y++) {
uint8_t lowByte, highByte;
if(exMode && exMode->HasExtendedBackground(extCfg, ntIndex)) {
lowByte = exMode->GetExBackgroundChrData(extCfg, ntIndex, ntOffset, tileAddr + y);
highByte = exMode->GetExBackgroundChrData(extCfg, ntIndex, ntOffset, tileAddr + y + 8);
} else {
lowByte = vram[tileAddr + y];
highByte = vram[tileAddr + y + 8];
}
uint32_t offset = (row*bufferWidth*8) + (column << 3) + (y*bufferWidth);
for(uint8_t x = 0; x < 8; x++) {
uint8_t color = ((lowByte >> (7 - x)) & 0x01) | (((highByte >> (7 - x)) & 0x01) << 1);
if(options.DisplayMode == TilemapDisplayMode::Grayscale) {
outBuffer[offset + x] = grayscalePalette[color];
} else {
outBuffer[offset + x] = palette[paletteBaseAddr + color];
}
}
}
}
}
}
}
DebugTilemapInfo NesPpuTools::GetWindowTilemap(GetTilemapOptions options, NesPpuState& state, IExtModeMapperDebug* exMode, ExtModeConfig& extCfg, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer)
{
uint16_t baseAddr = extCfg.WindowBank * 0x400;
DrawNametable(extCfg.ExtRam, baseAddr, 4, options, state, exMode, extCfg, vram, palette, outBuffer, 256);
DebugTilemapInfo result = {};
result.Bpp = 2;
result.Format = TileFormat::NesBpp2;
result.TileWidth = 8;
result.TileHeight = 8;
result.ColumnCount = 32;
result.RowCount = 30;
result.TilemapAddress = extCfg.WindowBank * 0x400;
result.TilesetAddress = state.Control.BackgroundPatternAddr;
result.ScrollWidth = NesConstants::ScreenWidth;
result.ScrollHeight = NesConstants::ScreenHeight;
result.ScrollX = extCfg.WindowScrollX;
result.ScrollY = extCfg.WindowScrollY;
return result;
}
DebugTilemapInfo NesPpuTools::GetTilemap(GetTilemapOptions options, BaseState& baseState, BaseState& ppuToolsState, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer)
{
IExtModeMapperDebug* exMode = dynamic_cast<IExtModeMapperDebug*>(_mapper);
NesPpuState& state = (NesPpuState&)baseState;
uint16_t bgAddr = state.Control.BackgroundPatternAddr;
ExtModeConfig& extCfg = ((NesPpuToolsState&)ppuToolsState).ExtConfig;
for(int i = 0; i < 32; i+=4) {
palette[i] = palette[0];
}
AddressCounters* accessCounters = options.AccessCounters;
uint8_t* prevVram = options.CompareVram != nullptr ? options.CompareVram : vram;
if(options.Layer == 1 && exMode) {
return GetWindowTilemap(options, state, exMode, extCfg, vram, palette, outBuffer);
}
uint64_t masterClock = options.MasterClock;
uint32_t clockRate = _console->GetMasterClockRate() / _console->GetFps();
auto isHighlighted = [&](uint16_t addr, TilemapHighlightMode mode) -> bool {
switch(mode) {
default:
case TilemapHighlightMode::None: return false;
//Highlight if modified since the last update
case TilemapHighlightMode::Changes: return prevVram[addr] != vram[addr];
//Highlight if modified in the last frame
case TilemapHighlightMode::Writes: return accessCounters && masterClock - accessCounters[addr].WriteStamp < clockRate;
}
};
constexpr uint32_t grayscalePalette[4] = { 0xFF000000, 0xFF808080, 0xFFC0C0C0, 0xFFFFFFFF };
for(int nametableIndex = 0; nametableIndex < 4; nametableIndex++) {
uint16_t baseAddr = 0x2000 + nametableIndex * 0x400;
uint16_t baseAttributeAddr = baseAddr + 960;
uint32_t bufferOffset = ((nametableIndex & 0x01) ? 256 : 0) + ((nametableIndex & 0x02) ? 512 * 240 : 0);
for(uint8_t row = 0; row < 30; row++) {
for(uint8_t column = 0; column < 32; column++) {
uint16_t ntIndex = (row << 5) + column;
uint16_t attributeAddress = baseAttributeAddr + ((row & 0xFC) << 1) + (column >> 2);
uint8_t tileIndex = vram[baseAddr + ntIndex];
uint8_t attribute = vram[attributeAddress];
bool tileHighlighted = isHighlighted(baseAddr + ntIndex, options.TileHighlightMode);
bool attrHighlighted = isHighlighted(attributeAddress, options.AttributeHighlightMode);
uint8_t shift = (column & 0x02) | ((row & 0x02) << 1);
uint8_t paletteBaseAddr;
if(mmc5 && mmc5->IsExtendedAttributes()) {
paletteBaseAddr = mmc5->GetExAttributeNtPalette(ntIndex) << 2;
} else {
paletteBaseAddr = ((attribute >> shift) & 0x03) << 2;
}
uint16_t tileAddr = bgAddr + (tileIndex << 4);
if(options.DisplayMode == TilemapDisplayMode::AttributeView) {
for(uint8_t y = 0; y < 8; y++) {
for(uint8_t x = 0; x < 8; x++) {
uint8_t color = ((x & 0x04) >> 2) + ((y & 0x04) >> 1);
outBuffer[bufferOffset + (row << 12) + (column << 3) + (y << 9) + x] = palette[paletteBaseAddr + color];
}
}
} else {
for(uint8_t y = 0; y < 8; y++) {
uint8_t lowByte, highByte;
if(mmc5 && mmc5->IsExtendedAttributes()) {
lowByte = mmc5->GetExAttributeTileData(ntIndex, tileAddr + y);
highByte = mmc5->GetExAttributeTileData(ntIndex, tileAddr + y + 8);
} else {
lowByte = vram[tileAddr + y];
highByte = vram[tileAddr + y + 8];
}
uint32_t offset = bufferOffset + (row << 12) + (column << 3) + (y << 9);
for(uint8_t x = 0; x < 8; x++) {
uint8_t color = ((lowByte >> (7 - x)) & 0x01) | (((highByte >> (7 - x)) & 0x01) << 1);
if(options.DisplayMode == TilemapDisplayMode::Grayscale) {
outBuffer[offset+x] = grayscalePalette[color];
} else {
outBuffer[offset+x] = palette[paletteBaseAddr + color];
}
if(tileHighlighted) {
static constexpr uint32_t tileChangedColor = 0x80FF0000;
if(x == 0 || y == 0 || x == 7 || y == 7) {
outBuffer[offset + x] = 0xFF000000 | tileChangedColor;
} else {
BlendColors((uint8_t*)&outBuffer[offset + x], (uint8_t*)&tileChangedColor);
}
}
if(attrHighlighted) {
static constexpr uint32_t attrChangedColor = 0x80FFFF00;
bool isEdge = (
((column & 3) == 0 && x == 0) ||
((row & 3) == 0 && y == 0) ||
((column & 3) == 3 && x == 7) ||
((row & 3) == 3 && y == 7)
);
if(isEdge) {
outBuffer[offset + x] = 0xFF000000 | attrChangedColor;
} else {
BlendColors((uint8_t*)&outBuffer[offset + x], (uint8_t*)&attrChangedColor);
}
}
}
}
}
DrawNametable(vram, baseAddr, nametableIndex, options, state, exMode, extCfg, vram, palette, outBuffer+bufferOffset, 512);
if(options.DisplayMode != TilemapDisplayMode::AttributeView) {
if(options.TileHighlightMode != TilemapHighlightMode::None || options.AttributeHighlightMode != TilemapHighlightMode::None) {
ApplyHighlights(options, nametableIndex, vram, outBuffer);
}
}
}
@ -132,7 +143,7 @@ DebugTilemapInfo NesPpuTools::GetTilemap(GetTilemapOptions options, BaseState& b
result.ColumnCount = 64;
result.RowCount = 60;
result.TilemapAddress = 0x2000;
result.TilesetAddress = bgAddr;
result.TilesetAddress = state.Control.BackgroundPatternAddr;
result.ScrollWidth = NesConstants::ScreenWidth;
result.ScrollHeight = NesConstants::ScreenHeight;
@ -190,6 +201,74 @@ DebugTilemapInfo NesPpuTools::GetTilemap(GetTilemapOptions options, BaseState& b
return result;
}
void NesPpuTools::ApplyHighlights(GetTilemapOptions options, uint8_t nametableIndex, uint8_t* vram, uint32_t* outBuffer)
{
uint16_t baseAddr = 0x2000 + nametableIndex * 0x400;
uint16_t baseAttributeAddr = baseAddr + 960;
uint32_t bufferOffset = ((nametableIndex & 0x01) ? 256 : 0) + ((nametableIndex & 0x02) ? 512 * 240 : 0);
AddressCounters* accessCounters = options.AccessCounters;
uint8_t* prevVram = options.CompareVram != nullptr ? options.CompareVram : vram;
uint64_t masterClock = options.MasterClock;
uint32_t clockRate = _console->GetMasterClockRate() / _console->GetFps();
auto isHighlighted = [&](uint16_t addr, TilemapHighlightMode mode) -> bool {
switch(mode) {
default:
case TilemapHighlightMode::None: return false;
//Highlight if modified since the last update
case TilemapHighlightMode::Changes: return prevVram[addr] != vram[addr];
//Highlight if modified in the last frame
case TilemapHighlightMode::Writes: return accessCounters && masterClock - accessCounters[addr].WriteStamp < clockRate;
}
};
for(uint8_t row = 0; row < 30; row++) {
for(uint8_t column = 0; column < 32; column++) {
uint16_t ntOffset = (row << 5) + column;
uint16_t attributeAddress = baseAttributeAddr + ((row & 0xFC) << 1) + (column >> 2);
bool tileHighlighted = isHighlighted(baseAddr + ntOffset, options.TileHighlightMode);
bool attrHighlighted = isHighlighted(attributeAddress, options.AttributeHighlightMode);
if(!tileHighlighted && !attrHighlighted) {
break;
}
for(uint8_t y = 0; y < 8; y++) {
uint32_t offset = bufferOffset + (row << 12) + (column << 3) + (y << 9);
for(uint8_t x = 0; x < 8; x++) {
if(tileHighlighted) {
static constexpr uint32_t tileChangedColor = 0x80FF0000;
if(x == 0 || y == 0 || x == 7 || y == 7) {
outBuffer[offset + x] = 0xFF000000 | tileChangedColor;
} else {
BlendColors((uint8_t*)&outBuffer[offset + x], (uint8_t*)&tileChangedColor);
}
}
if(attrHighlighted) {
static constexpr uint32_t attrChangedColor = 0x80FFFF00;
bool isEdge = (
((column & 3) == 0 && x == 0) ||
((row & 3) == 0 && y == 0) ||
((column & 3) == 3 && x == 7) ||
((row & 3) == 3 && y == 7)
);
if(isEdge) {
outBuffer[offset + x] = 0xFF000000 | attrChangedColor;
} else {
BlendColors((uint8_t*)&outBuffer[offset + x], (uint8_t*)&attrChangedColor);
}
}
}
}
}
}
}
void NesPpuTools::GetSpritePreview(GetSpritePreviewOptions options, BaseState& baseState, DebugSpriteInfo* sprites, uint32_t* spritePreviews, uint32_t* palette, uint32_t* outBuffer)
{
uint32_t bgColor = GetSpriteBackgroundColor(options.Background, palette, false);
@ -222,10 +301,15 @@ void NesPpuTools::GetSpritePreview(GetSpritePreviewOptions options, BaseState& b
FrameInfo NesPpuTools::GetTilemapSize(GetTilemapOptions options, BaseState& state)
{
return { 512, 480 };
if(options.Layer == 0) {
return { 512, 480 };
} else if(options.Layer == 1 && dynamic_cast<IExtModeMapperDebug*>(_mapper)) {
return { 256, 240 };
}
return { 0,0 };
}
DebugTilemapTileInfo NesPpuTools::GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState)
DebugTilemapTileInfo NesPpuTools::GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState, BaseState& ppuToolsState)
{
DebugTilemapTileInfo result = {};
@ -243,20 +327,21 @@ DebugTilemapTileInfo NesPpuTools::GetTilemapTileInfo(uint32_t x, uint32_t y, uin
row -= 30;
}
MMC5* mmc5 = dynamic_cast<MMC5*>(_mapper);
IExtModeMapperDebug* exMode = dynamic_cast<IExtModeMapperDebug*>(_mapper);
ExtModeConfig& extCfg = ((NesPpuToolsState&)ppuToolsState).ExtConfig;
NesPpuState& state = (NesPpuState&)baseState;
uint16_t bgAddr = state.Control.BackgroundPatternAddr;
uint16_t baseAddr = 0x2000 + nametableIndex * 0x400;
uint16_t baseAttributeAddr = baseAddr + 960;
uint16_t ntIndex = (row << 5) + column;
uint16_t ntOffset = (row << 5) + column;
uint16_t attributeAddress = baseAttributeAddr + ((row & 0xFC) << 1) + (column >> 2);
uint8_t attribute = vram[attributeAddress];
uint8_t shift = (column & 0x02) | ((row & 0x02) << 1);
uint8_t paletteBaseAddr;
if(mmc5 && mmc5->IsExtendedAttributes()) {
paletteBaseAddr = mmc5->GetExAttributeNtPalette(ntIndex) << 2;
if(exMode && exMode->HasExtendedAttributes(extCfg, nametableIndex)) {
paletteBaseAddr = exMode->GetExAttributePalette(extCfg, nametableIndex, ntOffset) << 2;
} else {
paletteBaseAddr = ((attribute >> shift) & 0x03) << 2;
}
@ -265,7 +350,7 @@ DebugTilemapTileInfo NesPpuTools::GetTilemapTileInfo(uint32_t x, uint32_t y, uin
result.Column = column;
result.Width = 8;
result.Height = 8;
result.TileMapAddress = baseAddr + ntIndex;
result.TileMapAddress = baseAddr + ntOffset;
result.TileIndex = vram[result.TileMapAddress];
result.TileAddress = bgAddr + (result.TileIndex << 4);
result.PaletteIndex = paletteBaseAddr >> 2;
@ -276,8 +361,11 @@ DebugTilemapTileInfo NesPpuTools::GetTilemapTileInfo(uint32_t x, uint32_t y, uin
return result;
}
void NesPpuTools::GetSpriteInfo(DebugSpriteInfo& sprite, uint32_t* spritePreview, uint32_t i, GetSpritePreviewOptions& options, NesPpuState& state, uint8_t* vram, uint8_t* oamRam, uint32_t* palette)
void NesPpuTools::GetSpriteInfo(DebugSpriteInfo& sprite, uint32_t* spritePreview, uint32_t i, GetSpritePreviewOptions& options, NesPpuState& state, NesPpuToolsState& ppuToolsState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette)
{
IExtModeMapperDebug* exMode = dynamic_cast<IExtModeMapperDebug*>(_mapper);
ExtModeConfig& extCfg = ppuToolsState.ExtConfig;
sprite.Bpp = 2;
sprite.Format = TileFormat::NesBpp2;
sprite.SpriteIndex = i;
@ -329,8 +417,17 @@ void NesPpuTools::GetSpriteInfo(DebugSpriteInfo& sprite, uint32_t* spritePreview
}
for(int x = 0; x < 8; x++) {
uint8_t shift = horizontalMirror ? (7 - x) : x;
uint8_t color = GetTilePixelColor<TileFormat::NesBpp2>(vram, 0x3FFF, pixelStart, shift);
uint8_t lowByte, highByte;
if(exMode && exMode->HasExtendedSprites(extCfg)) {
lowByte = exMode->GetExSpriteChrData(extCfg, i, pixelStart);
highByte = exMode->GetExSpriteChrData(extCfg, i, pixelStart + 8);
} else {
lowByte = vram[pixelStart];
highByte = vram[pixelStart + 8];
}
uint8_t shift = horizontalMirror ? x : (7 - x);
uint8_t color = ((lowByte >> shift) & 0x01) | (((highByte >> shift) & 0x01) << 1);
uint32_t outOffset = (y * 8) + x;
if(color > 0) {
@ -342,18 +439,19 @@ void NesPpuTools::GetSpriteInfo(DebugSpriteInfo& sprite, uint32_t* spritePreview
}
}
void NesPpuTools::GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview)
void NesPpuTools::GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, BaseState& ppuToolsState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview)
{
NesPpuState& state = (NesPpuState&)baseState;
NesPpuToolsState& nesToolsState = (NesPpuToolsState&)ppuToolsState;
for(int i = 0; i < 64; i++) {
outBuffer[i].Init();
GetSpriteInfo(outBuffer[i], spritePreviews+i*_spritePreviewSize, i, options, state, vram, oamRam, palette);
GetSpriteInfo(outBuffer[i], spritePreviews+i*_spritePreviewSize, i, options, state, nesToolsState, vram, oamRam, palette);
}
GetSpritePreview(options, baseState, outBuffer, spritePreviews, palette, screenPreview);
}
DebugSpritePreviewInfo NesPpuTools::GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& state)
DebugSpritePreviewInfo NesPpuTools::GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& state, BaseState& ppuToolsState)
{
DebugSpritePreviewInfo info = {};
info.Height = 256;

View file

@ -1,6 +1,7 @@
#pragma once
#include "pch.h"
#include "Debugger/PpuTools.h"
#include "NES/Debugger/IExtModeMapperDebug.h"
class Debugger;
class Emulator;
@ -8,23 +9,35 @@ class BaseMapper;
class NesConsole;
struct NesPpuState;
struct NesPpuToolsState
{
ExtModeConfig ExtConfig;
};
class NesPpuTools final : public PpuTools
{
private:
NesConsole* _console = nullptr;
BaseMapper* _mapper = nullptr;
void GetSpriteInfo(DebugSpriteInfo& sprite, uint32_t* spritePreview, uint32_t spriteIndex, GetSpritePreviewOptions& options, NesPpuState& state, uint8_t* vram, uint8_t* oamRam, uint32_t* palette);
void GetSpriteInfo(DebugSpriteInfo& sprite, uint32_t* spritePreview, uint32_t spriteIndex, GetSpritePreviewOptions& options, NesPpuState& state, NesPpuToolsState& ppuToolsState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette);
void GetSpritePreview(GetSpritePreviewOptions options, BaseState& state, DebugSpriteInfo* sprites, uint32_t* spritePreviews, uint32_t* palette, uint32_t *outBuffer);
DebugTilemapInfo GetWindowTilemap(GetTilemapOptions options, NesPpuState& state, IExtModeMapperDebug* exMode, ExtModeConfig& extCfg, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer);
void DrawNametable(uint8_t* ntSource, uint32_t ntBaseAddr, uint8_t ntIndex, GetTilemapOptions options, NesPpuState& state, IExtModeMapperDebug* exMode, ExtModeConfig& extCfg, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer, uint32_t bufferWidth);
void ApplyHighlights(GetTilemapOptions options, uint8_t nametableIndex, uint8_t* vram, uint32_t* outBuffer);
public:
NesPpuTools(Debugger* debugger, Emulator *emu, NesConsole* console);
DebugTilemapInfo GetTilemap(GetTilemapOptions options, BaseState& state, uint8_t* vram, uint32_t* palette, uint32_t *outBuffer) override;
FrameInfo GetTilemapSize(GetTilemapOptions options, BaseState& state) override;
DebugTilemapTileInfo GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState) override;
void GetPpuToolsState(BaseState& state) override;
DebugSpritePreviewInfo GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& state) override;
void GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreview, uint32_t* screenPreview) override;
DebugTilemapInfo GetTilemap(GetTilemapOptions options, BaseState& state, BaseState& ppuToolsState, uint8_t* vram, uint32_t* palette, uint32_t *outBuffer) override;
FrameInfo GetTilemapSize(GetTilemapOptions options, BaseState& state) override;
DebugTilemapTileInfo GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState, BaseState& ppuToolsState) override;
DebugSpritePreviewInfo GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& state, BaseState& ppuToolsState) override;
void GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, BaseState& ppuToolsState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreview, uint32_t* screenPreview) override;
DebugPaletteInfo GetPaletteInfo(GetPaletteInfoOptions options) override;
void SetPaletteColor(int32_t colorIndex, uint32_t color) override;

View file

@ -22,6 +22,7 @@
#include "NES/Mappers/Homebrew/Cheapocabra.h"
#include "NES/Mappers/Homebrew/FaridSlrom.h"
#include "NES/Mappers/Homebrew/FaridUnrom.h"
#include "NES/Mappers/Homebrew/Rainbow.h"
#include "NES/Mappers/Homebrew/SealieComputing.h"
#include "NES/Mappers/Homebrew/UnRom512.h"
#include "NES/Mappers/Homebrew/UnlDripGame.h"
@ -320,6 +321,8 @@ BaseMapper* MapperFactory::GetMapperFromID(RomData &romData)
case 1: return new Nina01();
case 2: return new BnRom();
}
break;
case 35: return new Mapper35();
case 36: return new Txc22000();
case 37: return new MMC3_37();
@ -614,6 +617,8 @@ BaseMapper* MapperFactory::GetMapperFromID(RomData &romData)
case 528: break; //831128C
case 529: return new T230();
case 530: return new Ax5705();
case 682: return new Rainbow();
case UnifBoards::Ac08: return new Ac08(); //mapper 42?
case UnifBoards::Cc21: return new Cc21();

View file

@ -0,0 +1,220 @@
#pragma once
#include "pch.h"
#include "Utilities/ISerializable.h"
#include "Utilities/Serializer.h"
#include "Shared/MessageManager.h"
class FlashS29 final : public ISerializable
{
private:
enum class ChipMode
{
WaitingForCommand,
Write,
Erase
};
enum class ChipModel
{
S29AL008,
S29AL016,
S29JL032,
S29GL064S
};
ChipModel _model = {};
ChipMode _mode = ChipMode::WaitingForCommand;
uint8_t _cycle = 0;
bool _softwareId = false;
bool _unlockBypass = false;
//ROM data and size
uint8_t* _data = nullptr;
uint32_t _size = 0;
void ProcessUnlockBypassMode(uint8_t value)
{
if(_cycle == 0) {
if(value == 0xA0) {
//1st write of unlock bypass write
_mode = ChipMode::Write;
} else if(value == 0x90) {
//1st write of unlock bypass reset
_cycle++;
} else {
ResetState();
}
} else if(_cycle == 1) {
if(value == 0x00) {
//2nd write of unlock bypass reset
_unlockBypass = false;
}
ResetState();
}
}
protected:
void Serialize(Serializer& s)
{
SV(_mode);
SV(_cycle);
SV(_softwareId);
SV(_unlockBypass);
}
public:
FlashS29(uint8_t* data, uint32_t size)
{
_data = data;
_size = size;
switch(_size) {
case 0x100000: _model = ChipModel::S29AL008; break;
case 0x200000: _model = ChipModel::S29AL016; break;
case 0x400000: _model = ChipModel::S29JL032; break;
case 0x800000: _model = ChipModel::S29GL064S; break;
}
}
bool IsSoftwareIdMode()
{
return _softwareId;
}
int16_t Read(uint32_t addr)
{
if(_softwareId) {
switch(addr & 0x1FF) {
case 0x00: return 0x01;
case 0x02: {
switch(_model) {
case ChipModel::S29AL008: return 0x5B;
case ChipModel::S29AL016: return 0x49;
case ChipModel::S29JL032: return 0x7E;
case ChipModel::S29GL064S: return 0x7E;
default: return 0xFF;
}
}
case 0x1C: {
switch(_model) {
case ChipModel::S29JL032: return 0x0A;
case ChipModel::S29GL064S: return 0x10;
default: return 0xFF;
}
}
case 0x1E: {
switch(_model) {
case ChipModel::S29JL032: return 0x00;
case ChipModel::S29GL064S: return 0x00;
default: return 0xFF;
}
}
default: return 0xFF;
}
}
return -1;
}
void ResetState()
{
_mode = ChipMode::WaitingForCommand;
_cycle = 0;
}
void Write(uint32_t addr, uint8_t value)
{
uint16_t cmd = addr & 0xFFF;
if(_mode == ChipMode::WaitingForCommand) {
if(_unlockBypass) {
ProcessUnlockBypassMode(value);
return;
}
if(_cycle == 0) {
if(cmd == 0xAAA && value == 0xAA) {
//1st write, $AAA = $AA
_cycle++;
} else if(value == 0xF0) {
//Software ID exit
ResetState();
_softwareId = false;
}
} else if(_cycle == 1 && cmd == 0x555 && value == 0x55) {
//2nd write, $555 = $55
_cycle++;
} else if(_cycle == 2 && cmd == 0xAAA) {
//3rd write, determines command type
_cycle++;
switch(value) {
case 0x20: ResetState(); _unlockBypass = true; break;
case 0x80: _mode = ChipMode::Erase; break;
case 0x90: ResetState(); _softwareId = true; break;
case 0xA0: _mode = ChipMode::Write; break;
case 0xF0: ResetState(); _softwareId = false; break;
}
} else {
_cycle = 0;
}
} else if(_mode == ChipMode::Write) {
//Write a single byte
if(addr < _size) {
_data[addr] &= value;
}
ResetState();
} else if(_mode == ChipMode::Erase) {
if(_cycle == 3) {
//4th write for erase command, $AAA = $AA
if(cmd == 0xAAA && value == 0xAA) {
_cycle++;
} else {
ResetState();
}
} else if(_cycle == 4) {
//5th write for erase command, $555 = $55
if(cmd == 0x555 && value == 0x55) {
_cycle++;
} else {
ResetState();
}
} else if(_cycle == 5) {
if(cmd == 0xAAA && value == 0x10) {
//Chip erase
memset(_data, 0xFF, _size);
} else if(value == 0x30) {
//Sector erase
uint32_t pageCount = _size / 0x10000;
uint32_t page = addr / 0x10000;
if(page == pageCount - 1) {
//Last sector is split into multiple smaller sectors
vector<int> sectorSizes;
switch(_model) {
case ChipModel::S29AL008: sectorSizes = vector<int> { 32, 8, 8, 16 }; break;
case ChipModel::S29AL016: sectorSizes = vector<int> { 32, 8, 8, 16 }; break;
case ChipModel::S29JL032: sectorSizes = vector<int> { 8, 8, 8, 8, 8, 8, 8, 8 }; break;
case ChipModel::S29GL064S: sectorSizes = vector<int> { 8, 8, 8, 8, 8, 8, 8, 8 }; break;
}
uint32_t offsetKb = (addr & 0xFFFF) / 1024;
uint32_t segOffset = 0;
uint32_t segSize = 0;
for(int i = 0; i < sectorSizes.size(); i++) {
if(segOffset + sectorSizes[i] > offsetKb) {
break;
}
segOffset += sectorSizes[i];
segSize = sectorSizes[i];
}
memset(_data + page * 0x10000 + segOffset * 1024, 0xFF, segSize * 1024);
} else {
memset(_data + page * 0x10000, 0xFF, 0x10000);
}
}
ResetState();
}
}
}
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,184 @@
#pragma once
#include "pch.h"
#include "NES/BaseMapper.h"
#include "NES/Debugger/IExtModeMapperDebug.h"
class RainbowAudio;
class FlashS29;
class Rainbow : public BaseMapper, public IExtModeMapperDebug
{
private:
struct NtControl
{
bool AttrExtMode;
bool BgExtMode;
uint8_t FpgaRamSrc;
bool FillMode;
uint8_t Source;
uint8_t ToByte()
{
return (
((uint8_t)AttrExtMode << 0) |
((uint8_t)BgExtMode << 1) |
(FpgaRamSrc << 2) |
((uint8_t)FillMode << 5) |
(Source << 6)
);
}
};
unique_ptr<RainbowAudio> _audio;
unique_ptr<FlashS29> _prgFlash;
unique_ptr<FlashS29> _chrFlash;
vector<uint8_t> _orgPrgRom;
vector<uint8_t> _orgChrRom;
uint16_t _highBanks[8] = {};
uint16_t _lowBanks[2] = {};
uint16_t _chrBanks[16] = {};
uint8_t _fpgaRamBank = 0;
uint8_t _highMode = 0;
uint8_t _lowMode = 0;
uint8_t _chrMode = 0;
uint8_t _chrSource = 0;
bool _windowEnabled = false;
bool _spriteExtMode = false;
uint8_t _bgExtModeOffset = 0;
uint8_t _ntBanks[4] = {};
NtControl _ntControl[4] = {};
uint8_t _fillModeTileIndex = 0;
uint8_t _fillModeAttrIndex = 0;
NtControl _windowControl = {};
uint8_t _windowBank = 0;
uint8_t _windowX1 = 0;
uint8_t _windowX2 = 0;
uint8_t _windowY1 = 0;
uint8_t _windowY2 = 0;
uint8_t _windowScrollX = 0;
uint8_t _windowScrollY = 0;
bool _inWindow = false;
bool _slIrqEnabled = false;
bool _slIrqPending = false;
uint8_t _slIrqScanline = 0;
uint8_t _slIrqOffset = 0;
uint16_t _lastPpuReadAddr = 0;
int16_t _scanlineCounter = 0;
uint8_t _ppuIdleCounter = 0;
uint8_t _ntReadCounter = 0;
uint8_t _ppuReadCounter = 0;
bool _inFrame = false;
bool _inHBlank = false;
uint8_t _jitterCounter = 0;
uint16_t _cpuIrqCounter = 0;
uint16_t _cpuIrqReloadValue = 0;
bool _cpuIrqEnabled = false;
bool _cpuIrqPending = false;
bool _cpuIrqEnableAfterAck = false;
bool _cpuIrqAckOn4011 = false;
uint16_t _fpgaRamAddr = 0;
uint8_t _fpgaRamInc = 0;
bool _nmiVectorEnabled = false;
bool _irqVectorEnabled = false;
uint16_t _nmiVectorAddr = 0;
uint16_t _irqVectorAddr = 0;
bool _overrideTileFetch = false;
uint8_t _extData = 0;
uint8_t _ntFetchCounter = 0;
uint8_t _spriteExtData[64] = {};
uint8_t _oamPosY[64] = {};
uint8_t _oamMappings[8] = {};
uint8_t _spriteExtBank = 0;
bool _largeSprites = false;
uint8_t _oamAddr = 0;
uint8_t _oamExtUpdatePage = 0;
uint8_t _oamSlowUpdatePage = 0;
uint8_t _oamCode[0x506] = {};
bool _oamCodeLocked = false;
bool _espEnabled = false;
bool _wifiIrqEnabled = false;
bool _wifiIrqPending = false;
bool _dataSent = false;
bool _dataReceived = false;
bool _dataReady = false;
uint8_t _sendSrcAddr = 0;
uint8_t _recvDstAddr = 0;
uint8_t ReadChr(uint32_t addr);
void UpdateInWindowFlag();
void UpdateIrqStatus();
void AckCpuIrq();
void ProcessSpriteEval();
void DetectScanlineStart(uint16_t addr);
void GenerateOamClear();
void GenerateExtUpdate();
void GenerateOamSlowUpdate();
PrgMemoryType GetWorkRamType();
void SelectHighBank(uint16_t start, uint16_t size, uint8_t reg);
void SelectLowBank(uint16_t start, uint16_t size, uint8_t reg);
void SelectChrBank(uint16_t start, uint16_t size, uint8_t reg);
void UpdateState();
void ApplySaveData();
protected:
uint16_t GetPrgPageSize() override { return 0x1000; }
uint16_t GetChrPageSize() override { return 0x200; }
uint32_t GetMapperRamSize() override { return 0x2000; }
uint16_t RegisterStartAddress() override { return 0x4100; }
uint16_t RegisterEndAddress() override { return 0x4785; }
bool AllowRegisterRead() override { return true; }
bool EnableCpuClockHook() override { return true; }
bool EnableCustomVramRead() override { return true; }
void InitMapper() override;
void SaveBattery() override;
void Reset(bool softReset) override;
void OnAfterResetPowerOn() override;
uint8_t MapperReadVram(uint16_t addr, MemoryOperationType memoryOperationType) override;
void MapperWriteVram(uint16_t addr, uint8_t value) override;
public:
Rainbow();
void WriteRam(uint16_t addr, uint8_t value) override;
uint8_t ReadRam(uint16_t addr) override;
void ProcessCpuClock() override;
uint8_t ReadRegister(uint16_t addr) override;
void WriteRegister(uint16_t addr, uint8_t value) override;
//Debugger
vector<MapperStateEntry> GetMapperStateEntries() override;
bool HasExtendedAttributes(ExtModeConfig& cfg, uint8_t ntIndex) override;
bool HasExtendedBackground(ExtModeConfig& cfg, uint8_t ntIndex) override;
bool HasExtendedSprites(ExtModeConfig& cfg) override;
uint8_t DebugReadChr(ExtModeConfig& cfg, uint32_t addr);
uint8_t GetExAttributePalette(ExtModeConfig& cfg, uint8_t ntIndex, uint16_t ntOffset) override;
uint8_t GetExBackgroundChrData(ExtModeConfig& cfg, uint8_t ntIndex, uint16_t ntOffset, uint16_t chrAddr) override;
uint8_t GetExSpriteChrData(ExtModeConfig& cfg, uint8_t spriteIndex, uint16_t chrAddr) override;
ExtModeConfig GetExModeConfig() override;
void Serialize(Serializer& s) override;
};

View file

@ -0,0 +1,91 @@
#pragma once
#include "NES/APU/BaseExpansionAudio.h"
#include "NES/Mappers/Audio/Vrc6Pulse.h"
#include "NES/Mappers/Audio/Vrc6Saw.h"
#include "NES/APU/NesApu.h"
#include "NES/NesConsole.h"
#include "Utilities/Serializer.h"
class RainbowAudio : public BaseExpansionAudio
{
private:
Vrc6Pulse _pulse1;
Vrc6Pulse _pulse2;
Vrc6Saw _saw;
bool _outputExpPin6 = false;
bool _outputExpPin9 = false;
bool _outputTo4011 = false;
uint8_t _volume = 0;
uint8_t _lastOutput = 0;
protected:
void Serialize(Serializer& s) override
{
SV(_pulse1);
SV(_pulse2);
SV(_saw);
SV(_outputExpPin6);
SV(_outputExpPin9);
SV(_outputTo4011);
SV(_volume);
SV(_lastOutput);
}
void ClockAudio() override
{
_pulse1.Clock();
_pulse2.Clock();
_saw.Clock();
uint8_t outputLevel = _pulse1.GetVolume() + _pulse2.GetVolume() + _saw.GetVolume();
if(_outputExpPin6 || _outputExpPin9) {
_console->GetApu()->AddExpansionAudioDelta(AudioChannel::VRC6, (int16_t)outputLevel - (int16_t)_lastOutput);
}
_lastOutput = outputLevel;
}
public:
RainbowAudio(NesConsole* console) : BaseExpansionAudio(console)
{
Reset();
}
void Reset()
{
_lastOutput = 0;
}
uint8_t GetLastOutput()
{
return _lastOutput;
}
void WriteRegister(uint16_t addr, uint8_t value)
{
addr &= 0x0F;
switch(addr) {
case 0x00: case 0x01: case 0x02:
_pulse1.WriteReg(addr, value);
break;
case 0x03: case 0x04: case 0x05:
_pulse2.WriteReg(addr - 0x03, value);
break;
case 0x06: case 0x07: case 0x08:
_saw.WriteReg(addr - 0x06, value);
break;
case 0x09:
_outputExpPin6 = value & 0x01;
_outputExpPin9 = value & 0x02;
_outputTo4011 = value & 0x04;
break;
case 0x0A:
_volume = value & 0x0F;
break;
}
}
};

View file

@ -4,19 +4,18 @@
#include "NES/NesConsole.h"
#include "NES/NesCpu.h"
#include "NES/Mappers/Audio/Mmc5Audio.h"
#include "NES/Debugger/IExtModeMapperDebug.h"
#include "NES/Mappers/Nintendo/Mmc5MemoryHandler.h"
#include "Utilities/HexUtilities.h"
class MMC5 : public BaseMapper
class MMC5 : public BaseMapper, public IExtModeMapperDebug
{
private:
static constexpr int ExRamSize = 0x400;
unique_ptr<Mmc5Audio> _audio;
unique_ptr<Mmc5MemoryHandler> _mmc5MemoryHandler;
uint8_t* _fillNametable;
uint8_t* _emptyNametable;
uint8_t* _fillNametable = nullptr;
uint8_t* _emptyNametable = nullptr;
uint8_t _prgRamProtect1 = 0;
uint8_t _prgRamProtect2 = 0;
@ -93,34 +92,18 @@ private:
// 1x 8kb : 0 0 0 0 - - - -
// 2x 8kb : 0 0 0 0 1 1 1 1
// 1x 32kb : 0 1 2 3 - - - -
int32_t realWorkRamSize = _workRamSize - (HasBattery() ? 0 : MMC5::ExRamSize);
int32_t realSaveRamSize = _saveRamSize - (!HasBattery() ? 0 : MMC5::ExRamSize);
if(IsNes20() || _romInfo.IsInDatabase) {
memoryType = PrgMemoryType::WorkRam;
if(HasBattery() && (bankNumber <= 3 || realSaveRamSize > 0x2000)) {
if(HasBattery() && (bankNumber <= 3 || _saveRamSize > 0x2000)) {
memoryType = PrgMemoryType::SaveRam;
}
if(realSaveRamSize + realWorkRamSize != 0x4000 && bankNumber >= 4) {
if(_saveRamSize + _workRamSize != 0x4000 && bankNumber >= 4) {
//When not 2x 8kb (=16kb), banks 4/5/6/7 select the empty socket and return open bus
accessType = MemoryAccessType::NoAccess;
}
} else {
memoryType = HasBattery() ? PrgMemoryType::SaveRam : PrgMemoryType::WorkRam;
}
if(memoryType == PrgMemoryType::WorkRam) {
//Properly mirror work ram (by ignoring the extra 1kb ExRAM section)
bankNumber &= (realWorkRamSize / 0x2000) - 1;
if(_workRamSize == MMC5::ExRamSize) {
accessType = MemoryAccessType::NoAccess;
}
} else if(memoryType == PrgMemoryType::SaveRam) {
//Properly mirror work ram (by ignoring the extra 1kb ExRAM section)
bankNumber &= (realSaveRamSize / 0x2000) - 1;
if(_saveRamSize == MMC5::ExRamSize) {
accessType = MemoryAccessType::NoAccess;
}
}
} else {
accessType = MemoryAccessType::Read;
@ -253,8 +236,7 @@ private:
SetNametable(i, nametableId);
} else if(nametableId == 2) {
if(_extendedRamMode <= 1) {
uint8_t* source = HasBattery() ? (_saveRam + (_saveRamSize - MMC5::ExRamSize)) : (_workRam + (_workRamSize - MMC5::ExRamSize));
SetPpuMemoryMapping(0x2000 + i * 0x400, 0x2000 + i * 0x400 + 0x3FF, source, 0, MMC5::ExRamSize, MemoryAccessType::ReadWrite);
SetPpuMemoryMapping(0x2000 + i * 0x400, 0x2000 + i * 0x400 + 0x3FF, ChrMemoryType::MapperRam, 0, MemoryAccessType::ReadWrite);
} else {
SetPpuMemoryMapping(0x2000 + i * 0x400, 0x2000 + i * 0x400 + 0x3FF, _emptyNametable, 0, BaseMapper::NametableSize, MemoryAccessType::Read);
}
@ -281,11 +263,7 @@ private:
accessType = MemoryAccessType::Read;
}
if(HasBattery()) {
SetCpuMemoryMapping(0x5C00, 0x5FFF, PrgMemoryType::SaveRam, _saveRamSize - MMC5::ExRamSize, accessType);
} else {
SetCpuMemoryMapping(0x5C00, 0x5FFF, PrgMemoryType::WorkRam, _workRamSize - MMC5::ExRamSize, accessType);
}
SetCpuMemoryMapping(0x5C00, 0x5FFF, PrgMemoryType::MapperRam, 0, accessType);
SetNametableMapping(_nametableMapping);
}
@ -306,6 +284,7 @@ private:
protected:
uint16_t GetPrgPageSize() override { return 0x2000; }
uint16_t GetChrPageSize() override { return 0x400; }
uint32_t GetMapperRamSize() override { return 0x400; }
uint16_t RegisterStartAddress() override { return 0x5000; }
uint16_t RegisterEndAddress() override { return 0x5206; }
uint32_t GetSaveRamPageSize() override { return 0x2000; }
@ -327,12 +306,6 @@ protected:
//Emulate as if a single 64k block of work/save ram existed
size = _romInfo.HasBattery ? 0x10000 : 0;
}
if(HasBattery()) {
//If there's a battery on the board, exram gets saved, too.
size += MMC5::ExRamSize;
}
return size;
}
@ -347,10 +320,6 @@ protected:
//Emulate as if a single 64k block of work/save ram existed (+ 1kb of ExRAM)
size = (_romInfo.HasBattery ? 0 : 0x10000);
}
if(!HasBattery()) {
size += MMC5::ExRamSize;
}
return size;
}
@ -393,6 +362,27 @@ protected:
_console->GetMemoryManager()->RegisterWriteHandler(_mmc5MemoryHandler.get(), 0x2000, 0x2007);
}
void LoadBattery() override
{
if(HasBattery() && _saveRamSize > 0) {
//Load EXRAM and save ram from the same file
vector<uint8_t> data(_saveRamSize + _mapperRamSize);
_emu->GetBatteryManager()->LoadBattery(".sav", _saveRam, _saveRamSize + _mapperRamSize);
memcpy(_saveRam, data.data(), _saveRamSize);
memcpy(_mapperRam, data.data()+_saveRamSize, _mapperRamSize);
}
}
void SaveBattery() override
{
if(HasBattery()) {
//Save EXRAM and save ram to the same file
vector<uint8_t> data(_saveRam, _saveRam + _saveRamSize);
data.insert(data.end(), _mapperRam, _mapperRam + _mapperRamSize);
_emu->GetBatteryManager()->SaveBattery(".sav", data.data(), (uint32_t)data.size());
}
}
void Serialize(Serializer& s) override
{
BaseMapper::Serialize(s);
@ -681,31 +671,52 @@ protected:
}
public:
bool IsExtendedAttributes()
bool HasExtendedAttributes(ExtModeConfig& cfg, uint8_t ntIndex) override
{
return _extendedRamMode == 1;
return cfg.Nametables[0].AttrExtMode;
}
bool HasExtendedBackground(ExtModeConfig& cfg, uint8_t ntIndex) override
{
if(ntIndex == 4) {
return true;
}
return cfg.Nametables[0].BgExtMode;
}
uint8_t GetExAttributeNtPalette(uint16_t ntAddr)
uint8_t GetExAttributePalette(ExtModeConfig& cfg, uint8_t ntIndex, uint16_t ntOffset) override
{
ntAddr &= 0x3FF;
uint8_t value = InternalReadRam(0x5C00 + ntAddr);
uint8_t value = cfg.ExtRam[ntOffset];
return (value & 0xC0) >> 6;
}
uint32_t GetExAttributeAbsoluteTileAddr(uint16_t ntAddr, uint16_t chrAddr)
uint8_t GetExBackgroundChrData(ExtModeConfig& cfg, uint8_t ntIndex, uint16_t ntOffset, uint16_t chrAddr) override
{
ntAddr &= 0x3FF;
uint8_t value = InternalReadRam(0x5C00 + ntAddr);
//"The pattern fetches ignore the standard CHR banking bits, and instead use the top two bits of $5130 and the bottom 6 bits from Expansion RAM to choose a 4KB bank to select the tile from."
uint16_t chrBank = (value & 0x3F) | (_chrUpperBits << 6);
return (chrBank << 12) + (chrAddr & 0xFFF);
if(ntIndex == 4) {
//Split mode
return ReadFromChr((cfg.Nametables[4].SourceOffset << 12) + (chrAddr & 0xFFF));
} else {
uint8_t value = cfg.ExtRam[ntOffset];
uint16_t chrBank = (value & 0x3F) | (cfg.BgExtBank << 6);
uint32_t addr = (chrBank << 12) + (chrAddr & 0xFFF);
return ReadFromChr(addr);
}
}
uint8_t GetExAttributeTileData(uint16_t ntAddr, uint16_t chrAddr)
ExtModeConfig GetExModeConfig() override
{
return ReadFromChr(GetExAttributeAbsoluteTileAddr(ntAddr, chrAddr));
ExtModeConfig cfg = {};
cfg.Nametables[0].AttrExtMode = _extendedRamMode == 1;
cfg.Nametables[0].BgExtMode = _extendedRamMode == 1;
cfg.BgExtBank = _chrUpperBits;
cfg.Nametables[4].SourceOffset = _verticalSplitBank;
cfg.WindowScrollY = _verticalSplitScroll;
memcpy(cfg.ExtRam, _mapperRam, _mapperRamSize);
return cfg;
}
};

View file

@ -60,7 +60,7 @@ void NesMemoryManager::InitializeMemoryHandlers(INesMemoryHandler** memoryHandle
{
for(uint16_t address : *addresses) {
if(!allowOverride && memoryHandlers[address] != &_openBusHandler && memoryHandlers[address] != handler) {
throw std::runtime_error("Not supported");
throw std::runtime_error("Can't override existing mapping");
}
memoryHandlers[address] = handler;
}
@ -77,11 +77,18 @@ void NesMemoryManager::RegisterIODevice(INesMemoryHandler*handler)
void NesMemoryManager::RegisterWriteHandler(INesMemoryHandler* handler, uint32_t start, uint32_t end)
{
for(uint32_t i = start; i < end; i++) {
for(uint32_t i = start; i <= end; i++) {
_ramWriteHandlers[i] = handler;
}
}
void NesMemoryManager::RegisterReadHandler(INesMemoryHandler* handler, uint32_t start, uint32_t end)
{
for(uint32_t i = start; i <= end; i++) {
_ramReadHandlers[i] = handler;
}
}
void NesMemoryManager::UnregisterIODevice(INesMemoryHandler*handler)
{
MemoryRanges ranges;

View file

@ -45,6 +45,7 @@ public:
void Reset(bool softReset);
void RegisterIODevice(INesMemoryHandler* handler);
void RegisterWriteHandler(INesMemoryHandler* handler, uint32_t start, uint32_t end);
void RegisterReadHandler(INesMemoryHandler* handler, uint32_t start, uint32_t end);
void UnregisterIODevice(INesMemoryHandler* handler);
uint8_t DebugRead(uint16_t addr);

View file

@ -59,6 +59,7 @@ enum class PrgMemoryType
PrgRom,
SaveRam,
WorkRam,
MapperRam,
};
enum class ChrMemoryType
@ -66,7 +67,8 @@ enum class ChrMemoryType
Default,
ChrRom,
ChrRam,
NametableRam
NametableRam,
MapperRam,
};
enum MemoryAccessType
@ -165,7 +167,7 @@ struct CartridgeState
bool HasBattery = false;
uint32_t CustomEntryCount = 0;
MapperStateEntry CustomEntries[100] = {};
MapperStateEntry CustomEntries[200] = {};
};
struct PPUStatusFlags

View file

@ -29,7 +29,7 @@ FrameInfo PceVdcTools::GetTilemapSize(GetTilemapOptions options, BaseState& base
}
}
DebugTilemapTileInfo PceVdcTools::GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState)
DebugTilemapTileInfo PceVdcTools::GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState, BaseState& ppuToolsState)
{
DebugTilemapTileInfo result = {};
@ -61,7 +61,7 @@ DebugTilemapTileInfo PceVdcTools::GetTilemapTileInfo(uint32_t x, uint32_t y, uin
return result;
}
DebugTilemapInfo PceVdcTools::GetTilemap(GetTilemapOptions options, BaseState& baseState, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer)
DebugTilemapInfo PceVdcTools::GetTilemap(GetTilemapOptions options, BaseState& baseState, BaseState& ppuToolsState, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer)
{
PceVdcState& state = options.Layer == 0 ? ((PceVideoState&)baseState).Vdc : ((PceVideoState&)baseState).Vdc2;
@ -296,7 +296,7 @@ void PceVdcTools::InternalGetSpriteInfo(DebugSpriteInfo& sprite, uint32_t* sprit
}
}
void PceVdcTools::GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview)
void PceVdcTools::GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, BaseState& ppuToolsState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview)
{
PceVdcState& state = ((PceVideoState&)baseState).Vdc;
for(int i = 0, len = _console->IsSuperGrafx() ? 128 : 64; i < len; i++) {
@ -307,7 +307,7 @@ void PceVdcTools::GetSpriteList(GetSpritePreviewOptions options, BaseState& base
GetSpritePreview(options, baseState, outBuffer, spritePreviews, palette, screenPreview);
}
DebugSpritePreviewInfo PceVdcTools::GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& baseState)
DebugSpritePreviewInfo PceVdcTools::GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& baseState, BaseState& ppuToolsState)
{
PceVdcState& state = ((PceVideoState&)baseState).Vdc;

View file

@ -27,12 +27,12 @@ public:
void SetViewerUpdateTiming(uint32_t viewerId, uint16_t scanline, uint16_t cycle) override;
DebugTilemapInfo GetTilemap(GetTilemapOptions options, BaseState& state, uint8_t* vram, uint32_t* palette, uint32_t *outBuffer) override;
DebugTilemapInfo GetTilemap(GetTilemapOptions options, BaseState& state, BaseState& ppuToolsState, uint8_t* vram, uint32_t* palette, uint32_t *outBuffer) override;
FrameInfo GetTilemapSize(GetTilemapOptions options, BaseState& state) override;
DebugTilemapTileInfo GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState) override;
DebugTilemapTileInfo GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState, BaseState& ppuToolsState) override;
DebugSpritePreviewInfo GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& state) override;
void GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview) override;
DebugSpritePreviewInfo GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& state, BaseState& ppuToolsState) override;
void GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, BaseState& ppuToolsState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview) override;
DebugPaletteInfo GetPaletteInfo(GetPaletteInfoOptions options) override;
void SetPaletteColor(int32_t colorIndex, uint32_t color) override;

View file

@ -19,7 +19,7 @@ FrameInfo SmsVdpTools::GetTilemapSize(GetTilemapOptions options, BaseState& base
return { isTextMode ? 240u : 256u, state.NametableHeight };
}
DebugTilemapInfo SmsVdpTools::GetTilemap(GetTilemapOptions options, BaseState& baseState, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer)
DebugTilemapInfo SmsVdpTools::GetTilemap(GetTilemapOptions options, BaseState& baseState, BaseState& ppuToolsState, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer)
{
SmsVdpState& state = (SmsVdpState&)baseState;
@ -149,7 +149,7 @@ DebugTilemapInfo SmsVdpTools::GetTilemap(GetTilemapOptions options, BaseState& b
return result;
}
DebugTilemapTileInfo SmsVdpTools::GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState)
DebugTilemapTileInfo SmsVdpTools::GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState, BaseState& ppuToolsState)
{
DebugTilemapTileInfo result = {};
@ -277,7 +277,7 @@ void SmsVdpTools::GetSpritePreview(GetSpritePreviewOptions options, BaseState& b
}
}
DebugSpritePreviewInfo SmsVdpTools::GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& baseState)
DebugSpritePreviewInfo SmsVdpTools::GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& baseState, BaseState& ppuToolsState)
{
SmsVdpState& state = (SmsVdpState&)baseState;
DebugSpritePreviewInfo info = {};
@ -391,7 +391,7 @@ void SmsVdpTools::GetSpriteInfo(DebugSpriteInfo& sprite, uint32_t* spritePreview
}
}
void SmsVdpTools::GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview)
void SmsVdpTools::GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, BaseState& ppuToolsState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview)
{
SmsVdpState& state = (SmsVdpState&)baseState;
int spriteCount = state.UseMode4 ? 64 : 32;

View file

@ -18,12 +18,12 @@ private:
public:
SmsVdpTools(Debugger* debugger, Emulator *emu, SmsConsole* console);
DebugTilemapInfo GetTilemap(GetTilemapOptions options, BaseState& state, uint8_t* vram, uint32_t* palette, uint32_t *outBuffer) override;
DebugTilemapInfo GetTilemap(GetTilemapOptions options, BaseState& state, BaseState& ppuToolsState, uint8_t* vram, uint32_t* palette, uint32_t *outBuffer) override;
FrameInfo GetTilemapSize(GetTilemapOptions options, BaseState& state) override;
DebugTilemapTileInfo GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState) override;
DebugTilemapTileInfo GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState, BaseState& ppuToolsState) override;
DebugSpritePreviewInfo GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& state) override;
void GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview) override;
DebugSpritePreviewInfo GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& state, BaseState& ppuToolsState) override;
void GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, BaseState& ppuToolsState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview) override;
DebugPaletteInfo GetPaletteInfo(GetPaletteInfoOptions options) override;
void SetPaletteColor(int32_t colorIndex, uint32_t color) override;

View file

@ -40,7 +40,7 @@ void SnesPpuTools::SetPpuRowBuffers(uint16_t scanline, uint16_t xStart, uint16_t
}
}
DebugTilemapInfo SnesPpuTools::GetTilemap(GetTilemapOptions options, BaseState& baseState, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer)
DebugTilemapInfo SnesPpuTools::GetTilemap(GetTilemapOptions options, BaseState& baseState, BaseState& ppuToolsState, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer)
{
SnesPpuState& state = (SnesPpuState&)baseState;
FrameInfo outputSize = GetTilemapSize(options, state);
@ -229,10 +229,10 @@ static constexpr uint8_t _oamSizes[8][2][2] = {
{ { 2, 4 }, { 4, 4 } } //16x32 + 32x32
};
void SnesPpuTools::GetSpritePreview(GetSpritePreviewOptions options, BaseState& baseState, DebugSpriteInfo* sprites, uint32_t* spritePreviews, uint32_t* palette, uint32_t* outBuffer)
void SnesPpuTools::GetSpritePreview(GetSpritePreviewOptions options, BaseState& baseState, BaseState& ppuToolsState, DebugSpriteInfo* sprites, uint32_t* spritePreviews, uint32_t* palette, uint32_t* outBuffer)
{
SnesPpuState& state = (SnesPpuState&)baseState;
DebugSpritePreviewInfo size = GetSpritePreviewInfo(options, state);
DebugSpritePreviewInfo size = GetSpritePreviewInfo(options, state, ppuToolsState);
uint32_t bgColor = GetSpriteBackgroundColor(options.Background, palette, false);
std::fill(outBuffer, outBuffer + size.Width * size.Height, GetSpriteBackgroundColor(options.Background, palette, true));
@ -393,7 +393,7 @@ void SnesPpuTools::GetSpriteInfo(DebugSpriteInfo& sprite, uint32_t* spritePrevie
}
}
void SnesPpuTools::GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview)
void SnesPpuTools::GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, BaseState& ppuToolsState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview)
{
SnesPpuState& state = (SnesPpuState&)baseState;
for(int i = 0; i < 128; i++) {
@ -401,7 +401,7 @@ void SnesPpuTools::GetSpriteList(GetSpritePreviewOptions options, BaseState& bas
GetSpriteInfo(outBuffer[i], spritePreviews + (i * _spritePreviewSize), i, options, state, vram, oamRam, palette);
}
GetSpritePreview(options, baseState, outBuffer, spritePreviews, palette, screenPreview);
GetSpritePreview(options, baseState, ppuToolsState, outBuffer, spritePreviews, palette, screenPreview);
}
FrameInfo SnesPpuTools::GetTilemapSize(GetTilemapOptions options, BaseState& baseState)
@ -444,7 +444,7 @@ FrameInfo SnesPpuTools::GetTilemapSize(GetTilemapOptions options, BaseState& bas
return size;
}
DebugTilemapTileInfo SnesPpuTools::GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState)
DebugTilemapTileInfo SnesPpuTools::GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState, BaseState& ppuToolsState)
{
DebugTilemapTileInfo result = {};
@ -514,7 +514,7 @@ DebugTilemapTileInfo SnesPpuTools::GetTilemapTileInfo(uint32_t x, uint32_t y, ui
return result;
}
DebugSpritePreviewInfo SnesPpuTools::GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& baseState)
DebugSpritePreviewInfo SnesPpuTools::GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& baseState, BaseState& ppuToolsState)
{
SnesPpuState& state = (SnesPpuState&)baseState;

View file

@ -34,7 +34,7 @@ private:
template<TileFormat format> void RenderTilemap(GetTilemapOptions& options, int rowCount, LayerConfig& layer, int columnCount, uint8_t* vram, int tileHeight, int tileWidth, bool largeTileHeight, bool largeTileWidth, uint8_t bpp, uint32_t* outBuffer, FrameInfo outputSize, const uint32_t* palette, uint16_t basePaletteOffset);
DebugTilemapInfo RenderScreenView(uint8_t layer, uint32_t* outBuffer);
void GetSpritePreview(GetSpritePreviewOptions options, BaseState& state, DebugSpriteInfo* sprites, uint32_t* spritePreviews, uint32_t* palette, uint32_t* outBuffer);
void GetSpritePreview(GetSpritePreviewOptions options, BaseState& state, BaseState& ppuToolsState, DebugSpriteInfo* sprites, uint32_t* spritePreviews, uint32_t* palette, uint32_t* outBuffer);
public:
SnesPpuTools(Debugger* debugger, Emulator *emu);
@ -44,12 +44,12 @@ public:
void SetPpuScanlineState(uint16_t scanline, uint8_t mode, int32_t mode7startX, int32_t mode7startY, int32_t mode7endX, int32_t mode7endY);
void SetPpuRowBuffers(uint16_t scanline, uint16_t xStart, uint16_t xEnd, uint16_t mainScreenRowBuffer[256], uint16_t subScreenRowBuffer[256]);
DebugTilemapInfo GetTilemap(GetTilemapOptions options, BaseState& state, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer) override;
DebugTilemapInfo GetTilemap(GetTilemapOptions options, BaseState& state, BaseState& ppuToolsState, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer) override;
FrameInfo GetTilemapSize(GetTilemapOptions options, BaseState& state) override;
DebugTilemapTileInfo GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState) override;
DebugTilemapTileInfo GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState, BaseState& ppuToolsState) override;
void GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview) override;
DebugSpritePreviewInfo GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& state) override;
void GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, BaseState& ppuToolsState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview) override;
DebugSpritePreviewInfo GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& state, BaseState& ppuToolsState) override;
DebugPaletteInfo GetPaletteInfo(GetPaletteInfoOptions options) override;
void SetPaletteColor(int32_t colorIndex, uint32_t color) override;

View file

@ -48,6 +48,7 @@ enum class MemoryType
NesWorkRam,
NesSaveRam,
NesNametableRam,
NesMapperRam,
NesSpriteRam,
NesSecondarySpriteRam,
NesPaletteRam,

View file

@ -17,7 +17,7 @@ FrameInfo WsPpuTools::GetTilemapSize(GetTilemapOptions options, BaseState& baseS
return { 256, 256 };
}
DebugTilemapInfo WsPpuTools::GetTilemap(GetTilemapOptions options, BaseState& baseState, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer)
DebugTilemapInfo WsPpuTools::GetTilemap(GetTilemapOptions options, BaseState& baseState, BaseState& ppuToolsState, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer)
{
WsPpuState& state = (WsPpuState&)baseState;
@ -115,7 +115,7 @@ DebugTilemapInfo WsPpuTools::GetTilemap(GetTilemapOptions options, BaseState& ba
return result;
}
DebugTilemapTileInfo WsPpuTools::GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState)
DebugTilemapTileInfo WsPpuTools::GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState, BaseState& ppuToolsState)
{
DebugTilemapTileInfo result = {};
@ -200,7 +200,7 @@ void WsPpuTools::GetSpritePreview(GetSpritePreviewOptions options, BaseState& ba
}
}
DebugSpritePreviewInfo WsPpuTools::GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& baseState)
DebugSpritePreviewInfo WsPpuTools::GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& baseState, BaseState& ppuToolsState)
{
DebugSpritePreviewInfo info = {};
info.Height = 256;
@ -318,7 +318,7 @@ void WsPpuTools::GetSpriteInfo(DebugSpriteInfo& sprite, uint32_t* spritePreview,
}
}
void WsPpuTools::GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview)
void WsPpuTools::GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, BaseState& ppuToolsState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview)
{
WsPpuState& state = (WsPpuState&)baseState;
int spriteCount = 128;

View file

@ -18,12 +18,12 @@ private:
public:
WsPpuTools(Debugger* debugger, Emulator *emu, WsConsole* console);
DebugTilemapInfo GetTilemap(GetTilemapOptions options, BaseState& state, uint8_t* vram, uint32_t* palette, uint32_t *outBuffer) override;
DebugTilemapInfo GetTilemap(GetTilemapOptions options, BaseState& state, BaseState& ppuToolsState, uint8_t* vram, uint32_t* palette, uint32_t *outBuffer) override;
FrameInfo GetTilemapSize(GetTilemapOptions options, BaseState& state) override;
DebugTilemapTileInfo GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState) override;
DebugTilemapTileInfo GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState, BaseState& ppuToolsState) override;
DebugSpritePreviewInfo GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& state) override;
void GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview) override;
DebugSpritePreviewInfo GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& state, BaseState& ppuToolsState) override;
void GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, BaseState& ppuToolsState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview) override;
DebugPaletteInfo GetPaletteInfo(GetPaletteInfoOptions options) override;
void SetPaletteColor(int32_t colorIndex, uint32_t color) override;

View file

@ -159,12 +159,12 @@ extern "C"
DllExport void __stdcall GetTileView(CpuType cpuType, GetTileViewOptions options, uint8_t* source, uint32_t srcSize, uint32_t* colors, uint32_t* buffer) { WithToolVoid(GetPpuTools(cpuType), GetTileView(options, source, srcSize, colors, buffer)); }
DllExport void __stdcall GetPpuToolsState(CpuType cpuType, BaseState& state) { return WithToolVoid(GetPpuTools(cpuType), GetPpuToolsState(state)); }
DllExport DebugTilemapInfo __stdcall GetTilemap(CpuType cpuType, GetTilemapOptions options, BaseState& state, uint8_t* vram, uint32_t* palette, uint32_t* outputBuffer) { return WithTool(DebugTilemapInfo, GetPpuTools(cpuType), GetTilemap(options, state, vram, palette, outputBuffer)); }
DllExport DebugTilemapInfo __stdcall GetTilemap(CpuType cpuType, GetTilemapOptions options, BaseState& state, BaseState& ppuToolsState, uint8_t* vram, uint32_t* palette, uint32_t* outputBuffer) { return WithTool(DebugTilemapInfo, GetPpuTools(cpuType), GetTilemap(options, state, ppuToolsState, vram, palette, outputBuffer)); }
DllExport FrameInfo __stdcall GetTilemapSize(CpuType cpuType, GetTilemapOptions options, BaseState& state) { return WithTool(FrameInfo, GetPpuTools(cpuType), GetTilemapSize(options, state)); }
DllExport DebugTilemapTileInfo __stdcall GetTilemapTileInfo(uint32_t x, uint32_t y, CpuType cpuType, GetTilemapOptions options, uint8_t* vram, BaseState& state) { return WithTool(DebugTilemapTileInfo, GetPpuTools(cpuType), GetTilemapTileInfo(x, y, vram, options, state)); }
DllExport DebugTilemapTileInfo __stdcall GetTilemapTileInfo(uint32_t x, uint32_t y, CpuType cpuType, GetTilemapOptions options, uint8_t* vram, BaseState& state, BaseState& ppuToolsState) { return WithTool(DebugTilemapTileInfo, GetPpuTools(cpuType), GetTilemapTileInfo(x, y, vram, options, state, ppuToolsState)); }
DllExport DebugSpritePreviewInfo __stdcall GetSpritePreviewInfo(CpuType cpuType, GetSpritePreviewOptions options, BaseState& state) { return WithTool(DebugSpritePreviewInfo, GetPpuTools(cpuType), GetSpritePreviewInfo(options, state)); }
DllExport void __stdcall GetSpriteList(CpuType cpuType, GetSpritePreviewOptions options, BaseState& state, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo sprites[], uint32_t* spritePreviews, uint32_t* screenPreview) { WithToolVoid(GetPpuTools(cpuType), GetSpriteList(options, state, vram, oamRam, palette, sprites, spritePreviews, screenPreview)); }
DllExport DebugSpritePreviewInfo __stdcall GetSpritePreviewInfo(CpuType cpuType, GetSpritePreviewOptions options, BaseState& state, BaseState& ppuToolsState) { return WithTool(DebugSpritePreviewInfo, GetPpuTools(cpuType), GetSpritePreviewInfo(options, state, ppuToolsState)); }
DllExport void __stdcall GetSpriteList(CpuType cpuType, GetSpritePreviewOptions options, BaseState& state, BaseState& ppuToolsState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo sprites[], uint32_t* spritePreviews, uint32_t* screenPreview) { WithToolVoid(GetPpuTools(cpuType), GetSpriteList(options, state, ppuToolsState, vram, oamRam, palette, sprites, spritePreviews, screenPreview)); }
DllExport DebugPaletteInfo __stdcall GetPaletteInfo(CpuType cpuType, GetPaletteInfoOptions options) { return WithTool(DebugPaletteInfo, GetPpuTools(cpuType), GetPaletteInfo(options)); }
DllExport void __stdcall SetPaletteColor(CpuType cpuType, int32_t colorIndex, uint32_t color) { WithToolVoid(GetPpuTools(cpuType), SetPaletteColor(colorIndex, color)); }

View file

@ -54,6 +54,7 @@ namespace Mesen.Config
case MemoryType.GbVideoRam:
case MemoryType.GbSpriteRam:
case MemoryType.NesNametableRam:
case MemoryType.NesMapperRam:
case MemoryType.NesSpriteRam:
case MemoryType.NesSecondarySpriteRam:
case MemoryType.NesPaletteRam:

View file

@ -494,7 +494,8 @@
{ "name": "nes", "description": "NES - Main CPU - 2A03 (6502)" },
{ "name": "pce", "description": "PC Engine - Main CPU - HuC6280" },
{ "name": "sms", "description": "SMS - Main CPU - Z80" },
{ "name": "gba", "description": "GBA - Main CPU - ARM7TDMI" }
{ "name": "gba", "description": "GBA - Main CPU - ARM7TDMI" },
{ "name": "ws", "description": "WS - Main CPU - NEC V30MZ" },
]
},
{
@ -540,6 +541,7 @@
{ "name": "pceMemory", "description": "PC Engine - CPU memory" },
{ "name": "smsMemory", "description": "SMS - CPU memory" },
{ "name": "gbaMemory", "description": "GBA - CPU memory" },
{ "name": "wsMemory", "description": "WS - CPU memory" },
{ "name": "snesDebug", "description": "SNES - S-CPU memory (no read/write side-effects)" },
{ "name": "spcDebug", "description": "SNES - SPC memory (no read/write side-effects)" },
@ -553,6 +555,7 @@
{ "name": "pceDebug", "description": "PC Engine - CPU memory (no read/write side-effects)" },
{ "name": "smsDebug", "description": "SMS - CPU memory (no read/write side-effects)" },
{ "name": "gbaDebug", "description": "GBA - CPU memory (no read/write side-effects)" },
{ "name": "wsDebug", "description": "WS - CPU memory (no read/write side-effects)" },
{ "name": "snesPrgRom", "description": "SNES - PRG ROM" },
{ "name": "snesWorkRam", "description": "SNES - Work RAM" },
@ -584,6 +587,7 @@
{ "name": "nesWorkRam", "description": "NES - Work RAM" },
{ "name": "nesSaveRam", "description": "NES - Save RAM" },
{ "name": "nesNametableRam", "description": "NES - Nametable RAM (CIRAM)" },
{ "name": "nesMapperRam", "description": "NES - Mapper RAM (EXRAM)" },
{ "name": "nesSpriteRam", "description": "NES - Sprite RAM (OAM)" },
{ "name": "nesSecondarySpriteRam", "description": "NES - Secondary Sprite RAM" },
{ "name": "nesPaletteRam", "description": "NES - Palette RAM" },
@ -619,6 +623,14 @@
{ "name": "gbaVideoRam", "description": "GBA - Video RAM" },
{ "name": "gbaSpriteRam", "description": "GBA - Sprite RAM" },
{ "name": "gbaPaletteRam", "description": "GBA - Palette RAM" }
{ "name": "wsPrgRom", "description": "WS - ROM" }
{ "name": "wsWorkRam", "description": "WS - Work RAM" }
{ "name": "wsCartRam", "description": "WS - Save RAM" }
{ "name": "wsCartEeprom", "description": "WS - Cart EEPROM" }
{ "name": "wsBootRom", "description": "WS - Boot ROM" }
{ "name": "wsInternalEeprom", "description": "WS - Internal EEPROM" }
{ "name": "wsPort", "description": "WS - I/O Port" }
]
},
{

View file

@ -74,18 +74,21 @@ namespace Mesen.Debugger.ViewModels
Dictionary<NesPrgMemoryType, Color> mainColors = new() {
{ NesPrgMemoryType.WorkRam, Color.FromRgb(0xCD, 0xDC, 0xFA) },
{ NesPrgMemoryType.SaveRam, Color.FromRgb(0xFA, 0xDC, 0xCD) },
{ NesPrgMemoryType.PrgRom, Color.FromRgb(0xC4, 0xE7, 0xD4) }
{ NesPrgMemoryType.PrgRom, Color.FromRgb(0xC4, 0xE7, 0xD4) },
{ NesPrgMemoryType.MapperRam, Color.FromRgb(0xFF, 0xEB, 0x6F) }
};
Dictionary<NesPrgMemoryType, Color> altColors = new() {
{ NesPrgMemoryType.WorkRam, Color.FromRgb(0xBD, 0xCC, 0xEA) },
{ NesPrgMemoryType.SaveRam, Color.FromRgb(0xEA, 0xCC, 0xBD) },
{ NesPrgMemoryType.PrgRom, Color.FromRgb(0xA4, 0xD7, 0xB4) }
{ NesPrgMemoryType.PrgRom, Color.FromRgb(0xA4, 0xD7, 0xB4) },
{ NesPrgMemoryType.MapperRam, Color.FromRgb(0xEF, 0xDB, 0x5F) }
};
Dictionary<NesPrgMemoryType, string> blockNames = new() {
{ NesPrgMemoryType.WorkRam, "WRAM" },
{ NesPrgMemoryType.SaveRam, "SRAM" },
{ NesPrgMemoryType.MapperRam, "EXRAM" },
{ NesPrgMemoryType.PrgRom, "" }
};
@ -121,7 +124,8 @@ namespace Mesen.Debugger.ViewModels
int page = memoryType.Value switch {
NesPrgMemoryType.WorkRam => (int)(state.PrgMemoryOffset[startIndex] / state.WorkRamPageSize),
NesPrgMemoryType.SaveRam => (int)(state.PrgMemoryOffset[startIndex] / state.SaveRamPageSize),
_ or NesPrgMemoryType.PrgRom => (int)(state.PrgMemoryOffset[startIndex] / state.PrgPageSize)
NesPrgMemoryType.PrgRom => (int)(state.PrgMemoryOffset[startIndex] / state.PrgPageSize),
_ => -1
};
mappings.Add(new MemoryMappingBlock() { Length = currentSize, Name = blockNames[memoryType.Value], Page = page, Note = accessNotes[accessType], Color = color });
@ -166,13 +170,15 @@ namespace Mesen.Debugger.ViewModels
Dictionary<NesChrMemoryType, Color> mainColors = new() {
{ NesChrMemoryType.NametableRam, Color.FromRgb(0xF4, 0xC7, 0xD4) },
{ NesChrMemoryType.ChrRom, Color.FromRgb(0xC4, 0xE7, 0xD4) },
{ NesChrMemoryType.ChrRam, Color.FromRgb(0xC4, 0xE0, 0xF4) }
{ NesChrMemoryType.ChrRam, Color.FromRgb(0xC4, 0xE0, 0xF4) },
{ NesChrMemoryType.MapperRam, Color.FromRgb(0xFF, 0xEB, 0x6F) }
};
Dictionary<NesChrMemoryType, Color> altColors = new() {
{ NesChrMemoryType.NametableRam, Color.FromRgb(0xD4, 0xA7, 0xB4) },
{ NesChrMemoryType.ChrRom, Color.FromRgb(0xA4, 0xD7, 0xB4) },
{ NesChrMemoryType.ChrRam, Color.FromRgb(0xB4, 0xD0, 0xE4) }
{ NesChrMemoryType.ChrRam, Color.FromRgb(0xB4, 0xD0, 0xE4) },
{ NesChrMemoryType.MapperRam, Color.FromRgb(0xEF, 0xDB, 0x5F) }
};
Dictionary<NesMemoryAccessType, string> accessNotes = new() {
@ -202,13 +208,16 @@ namespace Mesen.Debugger.ViewModels
int page = memoryType.Value switch {
NesChrMemoryType.NametableRam => (int)(state.ChrMemoryOffset[startIndex] / 0x400),
NesChrMemoryType.ChrRom => (int)(state.ChrMemoryOffset[startIndex] / state.ChrPageSize),
_ or NesChrMemoryType.ChrRam => (int)(state.ChrMemoryOffset[startIndex] / state.ChrRamPageSize),
NesChrMemoryType.ChrRam => (int)(state.ChrMemoryOffset[startIndex] / state.ChrRamPageSize),
_ => -1
};
string name = "";
if(memoryType == NesChrMemoryType.NametableRam) {
name = "NT" + page.ToString();
page = -1;
} else if(memoryType == NesChrMemoryType.MapperRam) {
name = "EXRAM";
}
mappings.Add(new MemoryMappingBlock() { Length = currentSize, Name = name, Page = page, Note = accessNotes[accessType], Color = color });

View file

@ -495,6 +495,7 @@ namespace Mesen.Debugger.ViewModels
{
lock(_updateLock) {
_coreData.PpuState = DebugApi.GetPpuState(CpuType);
_coreData.PpuToolsState = DebugApi.GetPpuToolsState(CpuType);
UpdateVramData();
@ -534,7 +535,7 @@ namespace Mesen.Debugger.ViewModels
_coreData.CopyTo(_data);
}
if(_data.PpuState == null || _data.Palette == null) {
if(_data.PpuState == null || _data.Palette == null || _data.PpuToolsState == null) {
return;
}
@ -542,7 +543,7 @@ namespace Mesen.Debugger.ViewModels
Background = Config.Background
};
DebugSpritePreviewInfo previewInfo = DebugApi.GetSpritePreviewInfo(CpuType, options, _data.PpuState);
DebugSpritePreviewInfo previewInfo = DebugApi.GetSpritePreviewInfo(CpuType, options, _data.PpuState, _data.PpuToolsState);
InitBitmap((int)previewInfo.Width, (int)previewInfo.Height);
UInt32[] palette = _data.Palette.Value.GetRgbPalette();
@ -553,7 +554,7 @@ namespace Mesen.Debugger.ViewModels
BottomClipSize = Config.ShowOffscreenRegions ? 0 : (int)(previewInfo.Height - (previewInfo.VisibleHeight + previewInfo.VisibleY));
using(var framebuffer = ViewerBitmap.Lock(true)) {
DebugApi.GetSpriteList(ref _spriteList, ref _spritePreviews, CpuType, options, _data.PpuState, _data.Vram, _data.SpriteRam, palette, framebuffer.FrameBuffer.Address);
DebugApi.GetSpriteList(ref _spriteList, ref _spritePreviews, CpuType, options, _data.PpuState, _data.PpuToolsState, _data.Vram, _data.SpriteRam, palette, framebuffer.FrameBuffer.Address);
}
InitPreviews(_spriteList, _spritePreviews, previewInfo);
@ -672,6 +673,7 @@ namespace Mesen.Debugger.ViewModels
public class SpriteViewerData
{
public BaseState? PpuState;
public BaseState? PpuToolsState;
public byte[] SpriteRam = Array.Empty<byte>();
public byte[] Vram = Array.Empty<byte>();
public DebugPaletteInfo? Palette = null;
@ -680,6 +682,7 @@ namespace Mesen.Debugger.ViewModels
{
dst.PpuState = PpuState;
dst.Palette = Palette;
dst.PpuToolsState = PpuToolsState;
CopyArray(SpriteRam, ref dst.SpriteRam);
CopyArray(Vram, ref dst.Vram);
}

View file

@ -332,6 +332,19 @@ namespace Mesen.Debugger.ViewModels
break;
case CpuType.Nes:
FrameInfo size = DebugApi.GetTilemapSize(CpuType.Nes, new GetTilemapOptions() { Layer = 1 }, new NesPpuState());
if(size.Width != 0 && size.Height != 0) {
Tabs = new List<TilemapViewerTab>() {
new() { Title = "Nametables", Layer = 0 },
new() { Title = "Window", Layer = 1 }
};
} else {
Tabs = new List<TilemapViewerTab>() {
new() { Title = "", Layer = 0 }
};
}
break;
case CpuType.Sms:
Tabs = new List<TilemapViewerTab>() {
new() { Title = "", Layer = 0 }
@ -384,7 +397,7 @@ namespace Mesen.Debugger.ViewModels
private DebugTilemapTileInfo? GetSelectedTileInfo()
{
if(_data.PpuState == null || _data.Vram == null) {
if(_data.PpuState == null || _data.PpuToolsState == null || _data.Vram == null) {
return null;
} else {
PixelPoint p;
@ -396,7 +409,7 @@ namespace Mesen.Debugger.ViewModels
}
p = PixelPoint.FromPoint(SelectionRect.TopLeft, 1);
}
return DebugApi.GetTilemapTileInfo((uint)p.X, (uint)p.Y, CpuType, GetOptions(SelectedTab), _data.Vram, _data.PpuState);
return DebugApi.GetTilemapTileInfo((uint)p.X, (uint)p.Y, CpuType, GetOptions(SelectedTab), _data.Vram, _data.PpuState, _data.PpuToolsState);
}
}
@ -471,7 +484,7 @@ namespace Mesen.Debugger.ViewModels
_coreData.CopyTo(_data);
}
if(_data.PpuState == null) {
if(_data.PpuState == null || _data.PpuToolsState == null) {
return;
}
@ -500,7 +513,7 @@ namespace Mesen.Debugger.ViewModels
InitBitmap((int)size.Width, (int)size.Height);
using(var framebuffer = ViewerBitmap.Lock()) {
_data.TilemapInfo = DebugApi.GetTilemap(CpuType, options, _data.PpuState, _data.Vram, _data.RgbPalette, framebuffer.FrameBuffer.Address);
_data.TilemapInfo = DebugApi.GetTilemap(CpuType, options, _data.PpuState, _data.PpuToolsState, _data.Vram, _data.RgbPalette, framebuffer.FrameBuffer.Address);
}
if(_data.TilemapInfo.Bpp == 0) {
@ -559,11 +572,11 @@ namespace Mesen.Debugger.ViewModels
public DynamicTooltip? GetPreviewPanel(PixelPoint p, DynamicTooltip? tooltipToUpdate)
{
if(_data.PpuState == null) {
if(_data.PpuState == null || _data.PpuToolsState == null) {
return null;
}
DebugTilemapTileInfo? result = DebugApi.GetTilemapTileInfo((uint)p.X, (uint)p.Y, CpuType, GetOptions(SelectedTab), _data.Vram, _data.PpuState);
DebugTilemapTileInfo? result = DebugApi.GetTilemapTileInfo((uint)p.X, (uint)p.Y, CpuType, GetOptions(SelectedTab), _data.Vram, _data.PpuState, _data.PpuToolsState);
if(result == null) {
return null;
}
@ -667,7 +680,7 @@ namespace Mesen.Debugger.ViewModels
private void EditTileGrid(int columnCount, int rowCount, Window wnd)
{
if(_data.PpuState == null) {
if(_data.PpuState == null || _data.PpuToolsState == null) {
return;
}
@ -677,7 +690,7 @@ namespace Mesen.Debugger.ViewModels
int palette = -1;
for(int row = 0; row < rowCount; row++) {
for(int col = 0; col < columnCount; col++) {
DebugTilemapTileInfo? tile = DebugApi.GetTilemapTileInfo((uint)(p.X + GridSizeX*col), (uint)(p.Y + GridSizeY*row), CpuType, GetOptions(SelectedTab), _data.Vram, _data.PpuState);
DebugTilemapTileInfo? tile = DebugApi.GetTilemapTileInfo((uint)(p.X + GridSizeX*col), (uint)(p.Y + GridSizeY*row), CpuType, GetOptions(SelectedTab), _data.Vram, _data.PpuState, _data.PpuToolsState);
if(tile == null) {
return;
}

View file

@ -13,6 +13,9 @@ namespace Mesen.Debugger.Windows
{
public class BreakpointEditWindow : MesenWindow
{
[Obsolete("For designer only")]
public BreakpointEditWindow() : this(new BreakpointEditViewModel()) { }
public BreakpointEditWindow(BreakpointEditViewModel model)
{
DataContext = model;

View file

@ -101,6 +101,7 @@ public enum NesPrgMemoryType
PrgRom,
SaveRam,
WorkRam,
MapperRam,
}
public enum NesChrMemoryType
@ -108,7 +109,8 @@ public enum NesChrMemoryType
Default,
ChrRom,
ChrRam,
NametableRam
NametableRam,
MapperRam,
}
public enum NesMemoryAccessType
@ -210,7 +212,7 @@ public struct NesCartridgeState
public bool HasBattery;
public UInt32 CustomEntryCount;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 200)]
public MapperStateEntry[] CustomEntries;
}
@ -337,3 +339,32 @@ public struct NesApuState
public NesApuDmcState Dmc;
public NesApuFrameCounterState FrameCounter;
}
public struct NtExtConfig
{
public UInt16 SourceOffset;
[MarshalAs(UnmanagedType.I1)] public bool AttrExtMode;
[MarshalAs(UnmanagedType.I1)] public bool BgExtMode;
[MarshalAs(UnmanagedType.I1)] public bool FillMode;
};
public struct ExtModeConfig
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
public NtExtConfig[] Nametables;
[MarshalAs(UnmanagedType.I1)] public bool SpriteExtMode;
public byte BgExtBank;
public byte SpriteExtBank;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
public byte[] SpriteExtData;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x2000)]
public byte[] ExtRam;
};
public struct NesPpuToolsState : BaseState
{
public ExtModeConfig ExtConfig;
}

View file

@ -138,7 +138,7 @@ namespace Mesen.Interop
{
return cpuType switch {
CpuType.Snes => GetPpuToolsState<SnesPpuToolsState>(cpuType),
CpuType.Nes => GetPpuToolsState<EmptyPpuToolsState>(cpuType),
CpuType.Nes => GetPpuToolsState<NesPpuToolsState>(cpuType),
CpuType.Gameboy => GetPpuToolsState<EmptyPpuToolsState>(cpuType),
CpuType.Pce => GetPpuToolsState<EmptyPpuToolsState>(cpuType),
CpuType.Sms => GetPpuToolsState<EmptyPpuToolsState>(cpuType),
@ -283,8 +283,8 @@ namespace Mesen.Interop
DebugApi.GetMemoryStateWrapper(type, dst);
}
[DllImport(DllPath)] private static extern DebugTilemapInfo GetTilemap(CpuType cpuType, InteropGetTilemapOptions options, IntPtr state, byte[] vram, UInt32[] palette, IntPtr outputBuffer);
public unsafe static DebugTilemapInfo GetTilemap(CpuType cpuType, GetTilemapOptions options, BaseState state, byte[] vram, UInt32[] palette, IntPtr outputBuffer)
[DllImport(DllPath)] private static extern DebugTilemapInfo GetTilemap(CpuType cpuType, InteropGetTilemapOptions options, IntPtr state, IntPtr ppuToolsState, byte[] vram, UInt32[] palette, IntPtr outputBuffer);
public unsafe static DebugTilemapInfo GetTilemap(CpuType cpuType, GetTilemapOptions options, BaseState state, BaseState ppuToolsState, byte[] vram, UInt32[] palette, IntPtr outputBuffer)
{
Debug.Assert(state.GetType().IsValueType);
Debug.Assert(IsValidPpuState(ref state, cpuType));
@ -293,10 +293,14 @@ namespace Mesen.Interop
fixed(AddressCounters* accessCounters = options.AccessCounters) {
byte* stateBuffer = stackalloc byte[GetStateSize(state)];
Marshal.StructureToPtr(state, (IntPtr)stateBuffer, false);
byte* ppuToolsStateBuffer = stackalloc byte[GetStateSize(ppuToolsState)];
Marshal.StructureToPtr(ppuToolsState, (IntPtr)ppuToolsStateBuffer, false);
InteropGetTilemapOptions interopOptions = options.ToInterop();
interopOptions.CompareVram = (IntPtr)compareVramPtr;
interopOptions.AccessCounters = (IntPtr)accessCounters;
return DebugApi.GetTilemap(cpuType, interopOptions, (IntPtr)stateBuffer, vram, palette, outputBuffer);
return DebugApi.GetTilemap(cpuType, interopOptions, (IntPtr)stateBuffer, (IntPtr)ppuToolsStateBuffer, vram, palette, outputBuffer);
}
}
}
@ -309,36 +313,45 @@ namespace Mesen.Interop
byte* ptr = stackalloc byte[GetStateSize(state)];
Marshal.StructureToPtr(state, (IntPtr)ptr, false);
return DebugApi.GetTilemapSize(cpuType, options.ToInterop(), (IntPtr)ptr);
}
[DllImport(DllPath)] private static extern DebugTilemapTileInfo GetTilemapTileInfo(UInt32 x, UInt32 y, CpuType cpuType, InteropGetTilemapOptions options, byte[] vram, IntPtr state);
public unsafe static DebugTilemapTileInfo? GetTilemapTileInfo(UInt32 x, UInt32 y, CpuType cpuType, GetTilemapOptions options, byte[] vram, BaseState state)
[DllImport(DllPath)] private static extern DebugTilemapTileInfo GetTilemapTileInfo(UInt32 x, UInt32 y, CpuType cpuType, InteropGetTilemapOptions options, byte[] vram, IntPtr state, IntPtr ppuToolsState);
public unsafe static DebugTilemapTileInfo? GetTilemapTileInfo(UInt32 x, UInt32 y, CpuType cpuType, GetTilemapOptions options, byte[] vram, BaseState state, BaseState ppuToolsState)
{
Debug.Assert(state.GetType().IsValueType);
Debug.Assert(IsValidPpuState(ref state, cpuType));
byte* ptr = stackalloc byte[GetStateSize(state)];
Marshal.StructureToPtr(state, (IntPtr)ptr, false);
DebugTilemapTileInfo info = DebugApi.GetTilemapTileInfo(x, y, cpuType, options.ToInterop(), vram, (IntPtr)ptr);
byte* ppuToolsStateBuffer = stackalloc byte[GetStateSize(ppuToolsState)];
Marshal.StructureToPtr(ppuToolsState, (IntPtr)ppuToolsStateBuffer, false);
DebugTilemapTileInfo info = DebugApi.GetTilemapTileInfo(x, y, cpuType, options.ToInterop(), vram, (IntPtr)ptr, (IntPtr)ppuToolsStateBuffer);
return info.Row >= 0 ? info : null;
}
[DllImport(DllPath)] public static extern void GetTileView(CpuType cpuType, GetTileViewOptions options, byte[] source, int srcSize, UInt32[] palette, IntPtr buffer);
[DllImport(DllPath)] private static extern DebugSpritePreviewInfo GetSpritePreviewInfo(CpuType cpuType, GetSpritePreviewOptions options, IntPtr state);
public unsafe static DebugSpritePreviewInfo GetSpritePreviewInfo(CpuType cpuType, GetSpritePreviewOptions options, BaseState state)
[DllImport(DllPath)] private static extern DebugSpritePreviewInfo GetSpritePreviewInfo(CpuType cpuType, GetSpritePreviewOptions options, IntPtr state, IntPtr ppuToolsState);
public unsafe static DebugSpritePreviewInfo GetSpritePreviewInfo(CpuType cpuType, GetSpritePreviewOptions options, BaseState state, BaseState ppuToolsState)
{
Debug.Assert(state.GetType().IsValueType);
Debug.Assert(IsValidPpuState(ref state, cpuType));
byte* ptr = stackalloc byte[GetStateSize(state)];
Marshal.StructureToPtr(state, (IntPtr)ptr, false);
return DebugApi.GetSpritePreviewInfo(cpuType, options, (IntPtr)ptr);
byte* ppuToolsStateBuffer = stackalloc byte[GetStateSize(ppuToolsState)];
Marshal.StructureToPtr(ppuToolsState, (IntPtr)ppuToolsStateBuffer, false);
return DebugApi.GetSpritePreviewInfo(cpuType, options, (IntPtr)ptr, (IntPtr)ppuToolsStateBuffer);
}
[DllImport(DllPath)] private static extern void GetSpriteList(CpuType cpuType, GetSpritePreviewOptions options, IntPtr state, byte[] vram, byte[]? spriteRam, UInt32[] palette, IntPtr sprites, IntPtr spritePreviews, IntPtr screenPreview);
public unsafe static void GetSpriteList(ref DebugSpriteInfo[] result, ref UInt32[] spritePreviews, CpuType cpuType, GetSpritePreviewOptions options, BaseState state, byte[] vram, byte[] spriteRam, UInt32[] palette, IntPtr screenPreview)
[DllImport(DllPath)] private static extern void GetSpriteList(CpuType cpuType, GetSpritePreviewOptions options, IntPtr state, IntPtr ppuToolsState, byte[] vram, byte[]? spriteRam, UInt32[] palette, IntPtr sprites, IntPtr spritePreviews, IntPtr screenPreview);
public unsafe static void GetSpriteList(ref DebugSpriteInfo[] result, ref UInt32[] spritePreviews, CpuType cpuType, GetSpritePreviewOptions options, BaseState state, BaseState ppuToolsState, byte[] vram, byte[] spriteRam, UInt32[] palette, IntPtr screenPreview)
{
Debug.Assert(state.GetType().IsValueType);
Debug.Assert(IsValidPpuState(ref state, cpuType));
@ -346,7 +359,10 @@ namespace Mesen.Interop
byte* statePtr = stackalloc byte[GetStateSize(state)];
Marshal.StructureToPtr(state, (IntPtr)statePtr, false);
int count = (int)GetSpritePreviewInfo(cpuType, options, (IntPtr)statePtr).SpriteCount;
byte* ppuToolsStateBuffer = stackalloc byte[GetStateSize(ppuToolsState)];
Marshal.StructureToPtr(ppuToolsState, (IntPtr)ppuToolsStateBuffer, false);
int count = (int)GetSpritePreviewInfo(cpuType, options, (IntPtr)statePtr, (IntPtr)ppuToolsStateBuffer).SpriteCount;
if(count != result.Length) {
Array.Resize(ref result, count);
}
@ -357,7 +373,7 @@ namespace Mesen.Interop
fixed(DebugSpriteInfo* spritesPtr = result) {
fixed(UInt32* spritePreviewsPtr = spritePreviews) {
DebugApi.GetSpriteList(cpuType, options, (IntPtr)statePtr, vram, spriteRam.Length > 0 ? spriteRam : null, palette, (IntPtr)spritesPtr, (IntPtr)spritePreviewsPtr, screenPreview);
DebugApi.GetSpriteList(cpuType, options, (IntPtr)statePtr, (IntPtr)ppuToolsStateBuffer, vram, spriteRam.Length > 0 ? spriteRam : null, palette, (IntPtr)spritesPtr, (IntPtr)spritePreviewsPtr, screenPreview);
}
}
}
@ -614,6 +630,7 @@ namespace Mesen.Interop
NesWorkRam,
NesSaveRam,
NesNametableRam,
NesMapperRam,
NesSpriteRam,
NesSecondarySpriteRam,
NesPaletteRam,

View file

@ -49,6 +49,7 @@ namespace Mesen.Interop
case MemoryType.NesChrRom:
case MemoryType.NesInternalRam:
case MemoryType.NesNametableRam:
case MemoryType.NesMapperRam:
case MemoryType.NesPaletteRam:
case MemoryType.NesSpriteRam:
case MemoryType.NesPpuMemory:
@ -272,6 +273,7 @@ namespace Mesen.Interop
case MemoryType.NesWorkRam:
case MemoryType.NesSaveRam:
case MemoryType.NesInternalRam:
case MemoryType.NesMapperRam:
case MemoryType.NesMemory:
//PC Engine
@ -455,6 +457,7 @@ namespace Mesen.Interop
MemoryType.NesPrgRom => "PRG",
MemoryType.NesWorkRam => "WRAM",
MemoryType.NesSaveRam => "SRAM",
MemoryType.NesMapperRam => "EXRAM",
MemoryType.NesInternalRam => "RAM",
MemoryType.NesSpriteRam => "SPR",

View file

@ -336,7 +336,7 @@
<Control ID="chkDisablePpu2004Reads">Disable PPU $2004 reads (Famicom behavior)</Control>
<Control ID="chkDisablePpuReset">Do not reset PPU when resetting console (Famicom behavior)</Control>
<Control ID="chkDisableGameGenieBusConflicts">Disable Game Genie bus conflict emulation</Control>
<Control ID="chkDisableFlashSaves">Disable flash saves (UNROM512 / GTROM)</Control>
<Control ID="chkDisableFlashSaves">Disable flash saves (UNROM512 / GTROM / Rainbow)</Control>
<Control ID="chkEnableDmcSampleDuplicationGlitch">Enable DMC sample duplication glitch (late-G &amp; H CPU behavior)</Control>
<Control ID="chkEnableCpuTestMode">Enable CPU test mode registers</Control>
<Control ID="lblConsoleType">Console model:</Control>
@ -2716,6 +2716,7 @@ E
<Value ID="NesWorkRam">Work RAM</Value>
<Value ID="NesSaveRam">Save RAM</Value>
<Value ID="NesNametableRam">Nametable RAM (CIRAM)</Value>
<Value ID="NesMapperRam">Mapper RAM (EXRAM)</Value>
<Value ID="NesSpriteRam">Sprite RAM (OAM)</Value>
<Value ID="NesSecondarySpriteRam">Secondary OAM RAM</Value>
<Value ID="NesChrRom">CHR ROM</Value>

View file

@ -177,7 +177,7 @@ vector<uint8_t> IpsPatcher::CreatePatch(vector<uint8_t> originalData, vector<uin
patchRecord.RepeatCount = rleCount;
patchRecord.Value = rleByte;
} else {
patchRecord.Replacement = vector<uint8_t>(&newData[patchRecord.Address], &newData[patchRecord.Address + patchRecord.Length]);
patchRecord.Replacement = vector<uint8_t>(newData.data() + patchRecord.Address, newData.data() + patchRecord.Address + patchRecord.Length);
}
patchRecord.WriteRecord(patchFile);
}