mirror of
https://github.com/SourMesen/Mesen2.git
synced 2025-04-02 10:21:44 -04:00
PCE: SuperGrafx support
This commit is contained in:
parent
6d0fb13cdc
commit
0a6a8e92b2
45 changed files with 842 additions and 218 deletions
|
@ -19,6 +19,7 @@
|
|||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="PCE\PceVpc.h" />
|
||||
<ClInclude Include="PCE\Input\PceAvenuePad6.h" />
|
||||
<ClInclude Include="PCE\Input\PceTurboTap.h" />
|
||||
<ClInclude Include="PCE\Debugger\DummyPceCpu.h" />
|
||||
|
@ -469,6 +470,7 @@
|
|||
<ClCompile Include="PCE\PceSf2RomMapper.cpp" />
|
||||
<ClCompile Include="PCE\PceTimer.cpp" />
|
||||
<ClCompile Include="PCE\PceVce.cpp" />
|
||||
<ClCompile Include="PCE\PceVpc.cpp" />
|
||||
<ClCompile Include="Shared\BaseControlManager.cpp" />
|
||||
<ClCompile Include="NES\NesDefaultVideoFilter.cpp" />
|
||||
<ClCompile Include="NES\BaseMapper.cpp" />
|
||||
|
|
|
@ -1814,6 +1814,9 @@
|
|||
<ClInclude Include="PCE\PceVce.h">
|
||||
<Filter>PCE</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PCE\PceVpc.h">
|
||||
<Filter>PCE</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Shared\Video\RotateFilter.cpp">
|
||||
|
@ -1894,6 +1897,7 @@
|
|||
<ClCompile Include="PCE\PceVce.cpp">
|
||||
<Filter>PCE</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PCE\PceVpc.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="PCE">
|
||||
|
|
|
@ -110,8 +110,10 @@ public:
|
|||
case MemoryType::PceCardRam:
|
||||
case MemoryType::PceAdpcmRam:
|
||||
case MemoryType::PceVideoRam:
|
||||
case MemoryType::PceVideoRamVdc2:
|
||||
case MemoryType::PcePaletteRam:
|
||||
case MemoryType::PceSpriteRam:
|
||||
case MemoryType::PceSpriteRamVdc2:
|
||||
return CpuType::Pce;
|
||||
|
||||
default:
|
||||
|
@ -149,8 +151,10 @@ public:
|
|||
return true;
|
||||
|
||||
case MemoryType::PceVideoRam:
|
||||
case MemoryType::PceVideoRamVdc2:
|
||||
case MemoryType::PcePaletteRam:
|
||||
case MemoryType::PceSpriteRam:
|
||||
case MemoryType::PceSpriteRamVdc2:
|
||||
return true;
|
||||
|
||||
default:
|
||||
|
|
|
@ -34,8 +34,8 @@ unordered_map<string, int64_t>& ExpressionEvaluator::GetPceTokens()
|
|||
|
||||
int64_t ExpressionEvaluator::GetPceTokenValue(int64_t token, EvalResultType& resultType)
|
||||
{
|
||||
auto ppu = [this]() -> PceVdcState {
|
||||
PceVdcState ppu;
|
||||
auto ppu = [this]() -> PceVideoState {
|
||||
PceVideoState ppu;
|
||||
((PceDebugger*)_cpuDebugger)->GetPpuState(ppu);
|
||||
return ppu;
|
||||
};
|
||||
|
@ -52,13 +52,13 @@ int64_t ExpressionEvaluator::GetPceTokenValue(int64_t token, EvalResultType& res
|
|||
/*case EvalValues::Nmi: return ReturnBool(s.NMIFlag, resultType);
|
||||
case EvalValues::Irq: return ReturnBool(s.IRQFlag, resultType);*/
|
||||
|
||||
case EvalValues::PpuFrameCount: return ppu().FrameCount;
|
||||
case EvalValues::PpuCycle: return ppu().HClock;
|
||||
case EvalValues::PpuScanline: return ppu().Scanline;
|
||||
case EvalValues::PpuFrameCount: return ppu().Vdc.FrameCount;
|
||||
case EvalValues::PpuCycle: return ppu().Vdc.HClock;
|
||||
case EvalValues::PpuScanline: return ppu().Vdc.Scanline;
|
||||
|
||||
case EvalValues::Sprite0Hit: return ReturnBool(ppu().Sprite0Hit, resultType);
|
||||
case EvalValues::SpriteOverflow: return ReturnBool(ppu().SpriteOverflow, resultType);
|
||||
case EvalValues::VerticalBlank: return ReturnBool(ppu().VerticalBlank, resultType);
|
||||
case EvalValues::Sprite0Hit: return ReturnBool(ppu().Vdc.Sprite0Hit, resultType);
|
||||
case EvalValues::SpriteOverflow: return ReturnBool(ppu().Vdc.SpriteOverflow, resultType);
|
||||
case EvalValues::VerticalBlank: return ReturnBool(ppu().Vdc.VerticalBlank, resultType);
|
||||
|
||||
case EvalValues::RegPS_Carry: return ReturnBool(s.PS & PceCpuFlags::Carry, resultType);
|
||||
case EvalValues::RegPS_Zero: return ReturnBool(s.PS & PceCpuFlags::Zero, resultType);
|
||||
|
|
|
@ -54,6 +54,7 @@ struct DebugSpriteInfo
|
|||
bool HorizontalMirror;
|
||||
bool VerticalMirror;
|
||||
bool Visible;
|
||||
bool UseExtendedVram;
|
||||
NullableBoolean UseSecondTable;
|
||||
|
||||
uint32_t SpritePreview[64 * 64];
|
||||
|
|
|
@ -170,6 +170,7 @@ void GbPpuTools::GetSpriteInfo(DebugSpriteInfo& sprite, uint16_t i, GetSpritePre
|
|||
sprite.Bpp = 2;
|
||||
sprite.Format = TileFormat::Bpp2;
|
||||
sprite.SpriteIndex = i;
|
||||
sprite.UseExtendedVram = false;
|
||||
|
||||
sprite.Y = oamRam[i*4];
|
||||
sprite.X = oamRam[i * 4 + 1];
|
||||
|
|
|
@ -56,8 +56,10 @@ enum class MemoryType
|
|||
PceCardRam,
|
||||
PceAdpcmRam,
|
||||
PceVideoRam,
|
||||
PcePaletteRam,
|
||||
PceVideoRamVdc2,
|
||||
PceSpriteRam,
|
||||
PceSpriteRamVdc2,
|
||||
PcePaletteRam,
|
||||
|
||||
Register
|
||||
};
|
|
@ -236,11 +236,13 @@ void NesPpuTools::GetSpriteInfo(DebugSpriteInfo& sprite, uint32_t i, GetSpritePr
|
|||
sprite.Bpp = 2;
|
||||
sprite.Format = TileFormat::NesBpp2;
|
||||
sprite.SpriteIndex = i;
|
||||
sprite.UseExtendedVram = false;
|
||||
sprite.Y = oamRam[i * 4];
|
||||
sprite.X = oamRam[i * 4 + 3];
|
||||
sprite.RawY = sprite.Y;
|
||||
sprite.RawX = sprite.X;
|
||||
sprite.TileIndex = oamRam[i * 4 + 1];
|
||||
sprite.UseSecondTable = NullableBoolean::Undefined;
|
||||
|
||||
uint8_t attributes = oamRam[i * 4 + 2];
|
||||
sprite.Palette = (attributes & 0x03);
|
||||
|
|
|
@ -106,6 +106,7 @@ void NesConsole::Stop()
|
|||
void NesConsole::Reset()
|
||||
{
|
||||
_memoryManager->Reset(true);
|
||||
//TODO option to not reset ppu on reset
|
||||
_ppu->Reset();
|
||||
_apu->Reset(true);
|
||||
_cpu->Reset(true, ConsoleRegion::Ntsc);
|
||||
|
|
|
@ -351,7 +351,7 @@ BaseState& PceDebugger::GetState()
|
|||
|
||||
void PceDebugger::GetPpuState(BaseState& state)
|
||||
{
|
||||
(PceVdcState&)state = _vdc->GetState();
|
||||
(PceVideoState&)state = _console->GetVideoState();
|
||||
}
|
||||
|
||||
void PceDebugger::SetPpuState(BaseState& state)
|
||||
|
|
|
@ -19,6 +19,7 @@ PceEventManager::PceEventManager(Debugger *debugger, PceConsole *console)
|
|||
_emu = debugger->GetEmulator();
|
||||
_cpu = console->GetCpu();
|
||||
_vdc = console->GetVdc();
|
||||
_vpc = console->GetVpc();
|
||||
_memoryManager = console->GetMemoryManager();
|
||||
|
||||
_ppuBuffer = new uint16_t[PceConstants::MaxScreenWidth * PceConstants::ScreenHeight];
|
||||
|
@ -136,16 +137,16 @@ uint32_t PceEventManager::TakeEventSnapshot()
|
|||
|
||||
constexpr uint32_t size = PceConstants::MaxScreenWidth * PceConstants::ScreenHeight;
|
||||
if(scanline < 14 || scanline >= 256) {
|
||||
memcpy(_ppuBuffer, _vdc->GetScreenBuffer(), size * sizeof(uint16_t));
|
||||
memcpy(_rowClockDividers, _vdc->GetRowClockDividers(), PceConstants::ScreenHeight);
|
||||
memcpy(_ppuBuffer, _vpc->GetScreenBuffer(), size * sizeof(uint16_t));
|
||||
memcpy(_rowClockDividers, _vpc->GetRowClockDividers(), PceConstants::ScreenHeight);
|
||||
} else {
|
||||
uint32_t scanlineOffset = (scanline - 14);
|
||||
uint32_t offset = PceConstants::MaxScreenWidth * scanlineOffset;
|
||||
memcpy(_ppuBuffer, _vdc->GetScreenBuffer(), offset * sizeof(uint16_t));
|
||||
memcpy(_ppuBuffer + offset, _vdc->GetPreviousScreenBuffer() + offset, (size - offset) * sizeof(uint16_t));
|
||||
memcpy(_ppuBuffer, _vpc->GetScreenBuffer(), offset * sizeof(uint16_t));
|
||||
memcpy(_ppuBuffer + offset, _vpc->GetPreviousScreenBuffer() + offset, (size - offset) * sizeof(uint16_t));
|
||||
|
||||
memcpy(_rowClockDividers, _vdc->GetRowClockDividers(), scanlineOffset);
|
||||
memcpy(_rowClockDividers + scanlineOffset, _vdc->GetPreviousRowClockDividers() + scanlineOffset, (PceConstants::ScreenHeight - scanlineOffset));
|
||||
memcpy(_rowClockDividers, _vpc->GetRowClockDividers(), scanlineOffset);
|
||||
memcpy(_rowClockDividers + scanlineOffset, _vpc->GetPreviousRowClockDividers() + scanlineOffset, (PceConstants::ScreenHeight - scanlineOffset));
|
||||
}
|
||||
|
||||
_snapshotCurrentFrame = _debugEvents;
|
||||
|
@ -177,7 +178,7 @@ void PceEventManager::DrawScreen(uint32_t *buffer)
|
|||
|
||||
for(uint32_t x = 0; x < PceConstants::ClockPerScanline; x++) {
|
||||
int srcOffset = (scanline * PceConstants::MaxScreenWidth) + (x / divider);
|
||||
buffer[(y + 14*2) * PceConstants::ClockPerScanline + x] = palette[src[srcOffset]];
|
||||
buffer[(y + 14*2) * PceConstants::ClockPerScanline + x] = palette[src[srcOffset] & 0x3FF];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ class Emulator;
|
|||
class PceConsole;
|
||||
class PceCpu;
|
||||
class PceVdc;
|
||||
class PceVpc;
|
||||
class Debugger;
|
||||
class PceMemoryManager;
|
||||
|
||||
|
@ -38,10 +39,11 @@ class PceEventManager final : public BaseEventManager
|
|||
private:
|
||||
PceEventViewerConfig _config;
|
||||
Emulator* _emu;
|
||||
PceCpu * _cpu;
|
||||
PceVdc *_vdc;
|
||||
PceCpu* _cpu;
|
||||
PceVdc* _vdc;
|
||||
PceVpc* _vpc;
|
||||
PceMemoryManager* _memoryManager;
|
||||
Debugger *_debugger;
|
||||
Debugger* _debugger;
|
||||
|
||||
uint16_t* _ppuBuffer = nullptr;
|
||||
uint8_t _rowClockDividers[PceConstants::ScreenHeight] = {};
|
||||
|
|
|
@ -10,12 +10,17 @@
|
|||
|
||||
PceVdcTools::PceVdcTools(Debugger* debugger, Emulator *emu, PceConsole* console) : PpuTools(debugger, emu)
|
||||
{
|
||||
_console = console;
|
||||
}
|
||||
|
||||
FrameInfo PceVdcTools::GetTilemapSize(GetTilemapOptions options, BaseState& baseState)
|
||||
{
|
||||
PceVdcState& state = (PceVdcState&)baseState;
|
||||
return { (uint32_t)state.ColumnCount * 8, (uint32_t)state.RowCount * 8 };
|
||||
PceVideoState& state = (PceVideoState&)baseState;
|
||||
if(options.Layer == 0) {
|
||||
return { (uint32_t)state.Vdc.ColumnCount * 8, (uint32_t)state.Vdc.RowCount * 8 };
|
||||
} else {
|
||||
return { (uint32_t)state.Vdc2.ColumnCount * 8, (uint32_t)state.Vdc2.RowCount * 8 };
|
||||
}
|
||||
}
|
||||
|
||||
DebugTilemapTileInfo PceVdcTools::GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState)
|
||||
|
@ -27,7 +32,7 @@ DebugTilemapTileInfo PceVdcTools::GetTilemapTileInfo(uint32_t x, uint32_t y, uin
|
|||
return result;
|
||||
}
|
||||
|
||||
PceVdcState& state = (PceVdcState&)baseState;
|
||||
PceVdcState& state = options.Layer == 0 ? ((PceVideoState&)baseState).Vdc : ((PceVideoState&)baseState).Vdc2;
|
||||
|
||||
uint32_t row = y / 8;
|
||||
uint32_t column = x / 8;
|
||||
|
@ -52,7 +57,7 @@ DebugTilemapTileInfo PceVdcTools::GetTilemapTileInfo(uint32_t x, uint32_t y, uin
|
|||
|
||||
DebugTilemapInfo PceVdcTools::GetTilemap(GetTilemapOptions options, BaseState& baseState, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer)
|
||||
{
|
||||
PceVdcState& state = (PceVdcState&)baseState;
|
||||
PceVdcState& state = options.Layer == 0 ? ((PceVideoState&)baseState).Vdc : ((PceVideoState&)baseState).Vdc2;
|
||||
|
||||
DebugTilemapInfo result = {};
|
||||
result.Bpp = 4;
|
||||
|
@ -92,7 +97,7 @@ DebugTilemapInfo PceVdcTools::GetTilemap(GetTilemapOptions options, BaseState& b
|
|||
|
||||
void PceVdcTools::GetSpritePreview(GetSpritePreviewOptions options, BaseState& baseState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, uint32_t* outBuffer)
|
||||
{
|
||||
PceVdcState& state = (PceVdcState&)baseState;
|
||||
PceVdcState& state = ((PceVideoState&)baseState).Vdc;
|
||||
|
||||
uint32_t screenWidth = std::min<uint32_t>(PceConstants::MaxScreenWidth, (state.HvLatch.HorizDisplayWidth + 1) * 8);
|
||||
std::fill(outBuffer, outBuffer + 1024*1024, 0xFF333333);
|
||||
|
@ -100,9 +105,11 @@ void PceVdcTools::GetSpritePreview(GetSpritePreviewOptions options, BaseState& b
|
|||
std::fill(outBuffer + i * 1024 + 32, outBuffer + i * 1024 + 32 + screenWidth, 0xFF666666);
|
||||
}
|
||||
|
||||
int spriteCount = _console->IsSuperGrafx() ? 128 : 64;
|
||||
|
||||
DebugSpriteInfo sprite;
|
||||
for(int i = 63; i >= 0; i--) {
|
||||
GetSpriteInfo(sprite, i, options, state, vram, oamRam, palette);
|
||||
for(int i = spriteCount - 1; i >= 0; i--) {
|
||||
GetSpriteInfo(sprite, i, options, vram, oamRam, palette);
|
||||
|
||||
for(int y = 0; y < sprite.Height; y++) {
|
||||
if(sprite.Y + y >= 1024) {
|
||||
|
@ -123,7 +130,7 @@ void PceVdcTools::GetSpritePreview(GetSpritePreviewOptions options, BaseState& b
|
|||
}
|
||||
}
|
||||
|
||||
void PceVdcTools::GetSpriteInfo(DebugSpriteInfo& sprite, uint16_t spriteIndex, GetSpritePreviewOptions& options, PceVdcState& state, uint8_t* vram, uint8_t* oamRam, uint32_t* palette)
|
||||
void PceVdcTools::GetSpriteInfo(DebugSpriteInfo& sprite, uint16_t spriteIndex, GetSpritePreviewOptions& options, uint8_t* vram, uint8_t* oamRam, uint32_t* palette)
|
||||
{
|
||||
uint16_t addr = (spriteIndex * 8);
|
||||
|
||||
|
@ -154,6 +161,7 @@ void PceVdcTools::GetSpriteInfo(DebugSpriteInfo& sprite, uint16_t spriteIndex, G
|
|||
sprite.Bpp = 4;
|
||||
sprite.Format = TileFormat::PceSpriteBpp4;
|
||||
sprite.SpriteIndex = spriteIndex;
|
||||
sprite.UseExtendedVram = spriteIndex >= 64;
|
||||
sprite.X = spriteX;
|
||||
sprite.Y = spriteY;
|
||||
sprite.RawX = spriteX;
|
||||
|
@ -167,6 +175,12 @@ void PceVdcTools::GetSpriteInfo(DebugSpriteInfo& sprite, uint16_t spriteIndex, G
|
|||
sprite.HorizontalMirror = (flags & 0x800) != 0;
|
||||
sprite.VerticalMirror = (flags & 0x8000) != 0;
|
||||
sprite.Visible = visible;
|
||||
sprite.UseSecondTable = NullableBoolean::Undefined;
|
||||
|
||||
if(sprite.UseExtendedVram) {
|
||||
//Sprite for VDC2, use VRAM from VDC2
|
||||
vram += 0x10000;
|
||||
}
|
||||
|
||||
if(width == 32) {
|
||||
tileIndex &= ~0x01;
|
||||
|
@ -231,10 +245,9 @@ void PceVdcTools::GetSpriteInfo(DebugSpriteInfo& sprite, uint16_t spriteIndex, G
|
|||
|
||||
void PceVdcTools::GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[])
|
||||
{
|
||||
PceVdcState& state = (PceVdcState&)baseState;
|
||||
for(int i = 0; i < 64; i++) {
|
||||
for(int i = 0, len = _console->IsSuperGrafx() ? 128 : 64; i < len; i++) {
|
||||
outBuffer[i].Init();
|
||||
GetSpriteInfo(outBuffer[i], i, options, state, vram, oamRam, palette);
|
||||
GetSpriteInfo(outBuffer[i], i, options, vram, oamRam, palette);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -242,8 +255,8 @@ DebugSpritePreviewInfo PceVdcTools::GetSpritePreviewInfo(GetSpritePreviewOptions
|
|||
{
|
||||
DebugSpritePreviewInfo info = {};
|
||||
info.Height = 1024;
|
||||
info.Width = 1024;
|
||||
info.SpriteCount = 64;
|
||||
info.Width = 1024;
|
||||
info.SpriteCount = _console->IsSuperGrafx() ? 128 : 64;
|
||||
info.CoordOffsetX = 0;
|
||||
info.CoordOffsetY = 0;
|
||||
return info;
|
||||
|
|
|
@ -10,7 +10,9 @@ struct PceVdcState;
|
|||
class PceVdcTools final : public PpuTools
|
||||
{
|
||||
private:
|
||||
void GetSpriteInfo(DebugSpriteInfo& sprite, uint16_t spriteIndex, GetSpritePreviewOptions& options, PceVdcState& state, uint8_t* vram, uint8_t* oamRam, uint32_t* palette);
|
||||
PceConsole* _console = nullptr;
|
||||
|
||||
void GetSpriteInfo(DebugSpriteInfo& sprite, uint16_t spriteIndex, GetSpritePreviewOptions& options, uint8_t* vram, uint8_t* oamRam, uint32_t* palette);
|
||||
|
||||
public:
|
||||
PceVdcTools(Debugger* debugger, Emulator *emu, PceConsole* console);
|
||||
|
|
|
@ -8,8 +8,10 @@
|
|||
#include "PCE/PceCpu.h"
|
||||
#include "PCE/PceVdc.h"
|
||||
#include "PCE/PceVce.h"
|
||||
#include "PCE/PceVpc.h"
|
||||
#include "PCE/PcePsg.h"
|
||||
#include "PCE/PceConstants.h"
|
||||
#include "Utilities/CRC32.h"
|
||||
#include "MemoryType.h"
|
||||
#include "FirmwareHelper.h"
|
||||
|
||||
|
@ -37,6 +39,7 @@ void PceConsole::OnBeforeRun()
|
|||
LoadRomResult PceConsole::LoadRom(VirtualFile& romFile)
|
||||
{
|
||||
PcEngineConfig& cfg = _emu->GetSettings()->GetPcEngineConfig();
|
||||
PceConsoleType consoleType = cfg.ConsoleType;
|
||||
|
||||
vector<uint8_t> romData;
|
||||
if(romFile.GetFileExtension() == ".cue") {
|
||||
|
@ -57,6 +60,10 @@ LoadRomResult PceConsole::LoadRom(VirtualFile& romFile)
|
|||
romData.erase(romData.begin(), romData.begin() + 512);
|
||||
}
|
||||
|
||||
if(consoleType == PceConsoleType::Auto) {
|
||||
consoleType = GetRomConsoleType(romData);
|
||||
}
|
||||
|
||||
if(cfg.EnableCdRomForHuCardGames) {
|
||||
DiscInfo emptyDisc = {};
|
||||
_cdrom.reset(new PceCdRom(_emu, this, emptyDisc));
|
||||
|
@ -65,9 +72,17 @@ LoadRomResult PceConsole::LoadRom(VirtualFile& romFile)
|
|||
|
||||
_controlManager.reset(new PceControlManager(_emu));
|
||||
_vce.reset(new PceVce(_emu, this));
|
||||
_vdc.reset(new PceVdc(_emu, this, _vce.get()));
|
||||
_vpc.reset(new PceVpc(_emu, this, _vce.get()));
|
||||
|
||||
_vdc.reset(new PceVdc(_emu, this, _vpc.get(), _vce.get(), false));
|
||||
if(consoleType == PceConsoleType::SuperGrafx) {
|
||||
_vdc2.reset(new PceVdc(_emu, this, _vpc.get(), _vce.get(), true));
|
||||
}
|
||||
|
||||
_vpc->ConnectVdc(_vdc.get(), _vdc2.get());
|
||||
|
||||
_psg.reset(new PcePsg(_emu));
|
||||
_memoryManager.reset(new PceMemoryManager(_emu, this, _vdc.get(), _vce.get(), _controlManager.get(), _psg.get(), _cdrom.get(), romData));
|
||||
_memoryManager.reset(new PceMemoryManager(_emu, this, _vpc.get(), _vce.get(), _controlManager.get(), _psg.get(), _cdrom.get(), romData));
|
||||
_cpu.reset(new PceCpu(_emu, this, _memoryManager.get()));
|
||||
|
||||
MessageManager::Log("-----------------");
|
||||
|
@ -77,6 +92,17 @@ LoadRomResult PceConsole::LoadRom(VirtualFile& romFile)
|
|||
return LoadRomResult::Success;
|
||||
}
|
||||
|
||||
PceConsoleType PceConsole::GetRomConsoleType(vector<uint8_t>& romData)
|
||||
{
|
||||
uint32_t crc32 = CRC32::GetCRC(romData);
|
||||
if(crc32 == 0xB486A8ED || crc32 == 0x1F041166 || crc32 == 0x3B13AF61 || crc32 == 0x4C2126B0 || crc32 == 0x8C4588E2) {
|
||||
//These are the 5 SuperGrafx-exclusive games
|
||||
return PceConsoleType::SuperGrafx;
|
||||
}
|
||||
|
||||
return PceConsoleType::TurboGrafx;
|
||||
}
|
||||
|
||||
void PceConsole::Init()
|
||||
{
|
||||
}
|
||||
|
@ -126,6 +152,11 @@ PceVdc* PceConsole::GetVdc()
|
|||
return _vdc.get();
|
||||
}
|
||||
|
||||
PceVpc* PceConsole::GetVpc()
|
||||
{
|
||||
return _vpc.get();
|
||||
}
|
||||
|
||||
PceMemoryManager* PceConsole::GetMemoryManager()
|
||||
{
|
||||
return _memoryManager.get();
|
||||
|
@ -143,8 +174,8 @@ uint32_t PceConsole::GetMasterClockRate()
|
|||
|
||||
double PceConsole::GetFps()
|
||||
{
|
||||
//59.82609786
|
||||
return (double)PceConstants::MasterClockRate / PceConstants::ClockPerScanline / PceConstants::ScanlineCount;
|
||||
//Varies depending on VCE setting (263 or 262 scanlines)
|
||||
return (double)PceConstants::MasterClockRate / PceConstants::ClockPerScanline / _vce->GetState().ScanlineCount;
|
||||
}
|
||||
|
||||
BaseVideoFilter* PceConsole::GetVideoFilter()
|
||||
|
@ -171,7 +202,7 @@ PpuFrameInfo PceConsole::GetPpuFrame()
|
|||
frame.FirstScanline = 0;
|
||||
frame.ScanlineCount = PceConstants::ScanlineCount;
|
||||
|
||||
frame.FrameBuffer = (uint8_t*)_vdc->GetScreenBuffer();
|
||||
frame.FrameBuffer = (uint8_t*)_vpc->GetScreenBuffer();
|
||||
frame.Height = PceConstants::ScreenHeight;
|
||||
frame.Width = PceConstants::MaxScreenWidth;
|
||||
return frame;
|
||||
|
@ -184,6 +215,7 @@ RomFormat PceConsole::GetRomFormat()
|
|||
|
||||
AudioTrackInfo PceConsole::GetAudioTrackInfo()
|
||||
{
|
||||
//TODO HES file support
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -204,15 +236,30 @@ AddressInfo PceConsole::GetRelativeAddress(AddressInfo& absAddress, CpuType cpuT
|
|||
return _memoryManager->GetRelativeAddress(absAddress);
|
||||
}
|
||||
|
||||
PceVideoState PceConsole::GetVideoState()
|
||||
{
|
||||
PceVideoState state;
|
||||
state.Vdc = _vdc->GetState();
|
||||
state.Vce = _vce->GetState();
|
||||
state.Vpc = _vpc->GetState();
|
||||
|
||||
if(_vdc2) {
|
||||
state.Vdc2 = _vdc2->GetState();
|
||||
} else {
|
||||
state.Vdc2 = {};
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
void PceConsole::GetConsoleState(BaseState& baseState, ConsoleType consoleType)
|
||||
{
|
||||
PceState& state = (PceState&)baseState;
|
||||
state.Cpu = _cpu->GetState();
|
||||
state.Vdc = _vdc->GetState();
|
||||
state.Vce = _vce->GetState();
|
||||
state.Video = GetVideoState();
|
||||
state.MemoryManager = _memoryManager->GetState();
|
||||
state.Psg = _psg->GetState();
|
||||
for(int i = 0; i < 6; i++) {
|
||||
state.PsgChannels[i] = _psg->GetChannelState(i);
|
||||
}
|
||||
state.IsSuperGrafx = _vdc2 != nullptr;
|
||||
}
|
||||
|
|
|
@ -4,12 +4,15 @@
|
|||
|
||||
class PceCpu;
|
||||
class PceVdc;
|
||||
class PceVpc;
|
||||
class PceVce;
|
||||
class PcePsg;
|
||||
class PceCdRom;
|
||||
class PceMemoryManager;
|
||||
class PceControlManager;
|
||||
class Emulator;
|
||||
struct PceVideoState;
|
||||
enum class PceConsoleType;
|
||||
|
||||
class PceConsole final: public IConsole
|
||||
{
|
||||
|
@ -18,11 +21,15 @@ private:
|
|||
|
||||
unique_ptr<PceCpu> _cpu;
|
||||
unique_ptr<PceVdc> _vdc;
|
||||
unique_ptr<PceVdc> _vdc2;
|
||||
unique_ptr<PceVpc> _vpc;
|
||||
unique_ptr<PceVce> _vce;
|
||||
unique_ptr<PcePsg> _psg;
|
||||
unique_ptr<PceMemoryManager> _memoryManager;
|
||||
unique_ptr<PceControlManager> _controlManager;
|
||||
unique_ptr<PceCdRom> _cdrom;
|
||||
|
||||
PceConsoleType GetRomConsoleType(vector<uint8_t>& romData);
|
||||
|
||||
public:
|
||||
PceConsole(Emulator* emu);
|
||||
|
@ -47,7 +54,10 @@ public:
|
|||
|
||||
PceCpu* GetCpu();
|
||||
PceVdc* GetVdc();
|
||||
PceVpc* GetVpc();
|
||||
PceMemoryManager* GetMemoryManager();
|
||||
|
||||
bool IsSuperGrafx() { return _vdc2 != nullptr; }
|
||||
|
||||
uint64_t GetMasterClock() override;
|
||||
uint32_t GetMasterClockRate() override;
|
||||
|
@ -65,5 +75,6 @@ public:
|
|||
AddressInfo GetAbsoluteAddress(AddressInfo& relAddress) override;
|
||||
AddressInfo GetRelativeAddress(AddressInfo& absAddress, CpuType cpuType) override;
|
||||
|
||||
PceVideoState GetVideoState();
|
||||
void GetConsoleState(BaseState& state, ConsoleType consoleType) override;
|
||||
};
|
|
@ -15,7 +15,7 @@ private:
|
|||
protected:
|
||||
uint32_t GetPixel(uint16_t* ppuFrame, uint32_t offset)
|
||||
{
|
||||
return _calculatedPalette[ppuFrame[offset]];
|
||||
return _calculatedPalette[ppuFrame[offset] & 0x3FF];
|
||||
}
|
||||
|
||||
void InitLookupTable()
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#include "stdafx.h"
|
||||
#include "MemoryOperationType.h"
|
||||
#include "PCE/PceConsole.h"
|
||||
#include "PCE/PceVdc.h"
|
||||
#include "PCE/PceVpc.h"
|
||||
#include "PCE/PceVce.h"
|
||||
#include "PCE/PceTimer.h"
|
||||
#include "PCE/PcePsg.h"
|
||||
|
@ -26,7 +26,7 @@ private:
|
|||
Emulator* _emu = nullptr;
|
||||
CheatManager* _cheatManager = nullptr;
|
||||
PceConsole* _console = nullptr;
|
||||
PceVdc* _vdc = nullptr;
|
||||
PceVpc* _vpc = nullptr;
|
||||
PceVce* _vce = nullptr;
|
||||
PcePsg* _psg = nullptr;
|
||||
PceControlManager* _controlManager = nullptr;
|
||||
|
@ -43,7 +43,7 @@ private:
|
|||
MemoryType _bankMemType[0x100] = {};
|
||||
|
||||
uint8_t* _workRam = nullptr;
|
||||
uint32_t _workRamSize = 0x2000;
|
||||
uint32_t _workRamSize = 0;
|
||||
|
||||
uint8_t* _cdromRam = nullptr;
|
||||
uint32_t _cdromRamSize = 0;
|
||||
|
@ -57,18 +57,19 @@ private:
|
|||
uint8_t* _unmappedBank = nullptr;
|
||||
|
||||
public:
|
||||
PceMemoryManager(Emulator* emu, PceConsole* console, PceVdc* vdc, PceVce* vce, PceControlManager* controlManager, PcePsg* psg, PceCdRom* cdrom, vector<uint8_t> romData)
|
||||
PceMemoryManager(Emulator* emu, PceConsole* console, PceVpc* vpc, PceVce* vce, PceControlManager* controlManager, PcePsg* psg, PceCdRom* cdrom, vector<uint8_t> romData)
|
||||
{
|
||||
_emu = emu;
|
||||
_cheatManager = _emu->GetCheatManager();
|
||||
_console = console;
|
||||
_vdc = vdc;
|
||||
_vpc = vpc;
|
||||
_vce = vce;
|
||||
_psg = psg;
|
||||
_cdrom = cdrom;
|
||||
_controlManager = controlManager;
|
||||
_prgRomSize = (uint32_t)romData.size();
|
||||
_prgRom = new uint8_t[_prgRomSize];
|
||||
_workRamSize = console->IsSuperGrafx() ? 0x8000 : 0x2000;
|
||||
_workRam = new uint8_t[_workRamSize];
|
||||
|
||||
_unmappedBank = new uint8_t[0x2000];
|
||||
|
@ -204,8 +205,8 @@ public:
|
|||
|
||||
for(int i = 0; i < 4; i++) {
|
||||
//F8 - FB
|
||||
_readBanks[0xF8 + i] = _workRam;
|
||||
_writeBanks[0xF8 + i] = _workRam;
|
||||
_readBanks[0xF8 + i] = _workRam + ((i * 0x2000) % _workRamSize);
|
||||
_writeBanks[0xF8 + i] = _workRam + ((i * 0x2000) % _workRamSize);
|
||||
_bankMemType[0xF8 + i] = MemoryType::PceWorkRam;
|
||||
}
|
||||
|
||||
|
@ -246,7 +247,7 @@ public:
|
|||
{
|
||||
_state.CycleCount += 3;
|
||||
_timer->Exec();
|
||||
_vdc->Exec();
|
||||
_vpc->Exec();
|
||||
if(_cdrom) {
|
||||
_cdrom->Exec();
|
||||
}
|
||||
|
@ -264,11 +265,11 @@ public:
|
|||
if(addr <= 0x3FF) {
|
||||
//VDC
|
||||
Exec(); //CPU is delayed by 1 CPU cycle when reading/writing to VDC/VCE
|
||||
return _vdc->ReadRegister(addr);
|
||||
return _vpc->Read(addr);
|
||||
} else if(addr <= 0x7FF) {
|
||||
//VCE
|
||||
Exec(); //CPU is delayed by 1 CPU cycle when reading/writing to VDC/VCE
|
||||
_vdc->DrawScanline();
|
||||
_vpc->DrawScanline();
|
||||
return _vce->Read(addr);
|
||||
} else if(addr <= 0xBFF) {
|
||||
//PSG
|
||||
|
@ -360,10 +361,10 @@ public:
|
|||
}
|
||||
} else {
|
||||
if(addr <= 0x3FF) {
|
||||
_vdc->WriteRegister(addr, value);
|
||||
_vpc->Write(addr, value);
|
||||
Exec(); //CPU is delayed by 1 CPU cycle when reading/writing to VDC/VCE
|
||||
} else if(addr <= 0x7FF) {
|
||||
_vdc->DrawScanline();
|
||||
_vpc->DrawScanline();
|
||||
_vce->Write(addr, value);
|
||||
Exec(); //CPU is delayed by 1 CPU cycle when reading/writing to VDC/VCE
|
||||
} else if(addr <= 0xBFF) {
|
||||
|
@ -405,7 +406,7 @@ public:
|
|||
if(_state.Mpr[0] == 0xFF) {
|
||||
_emu->ProcessMemoryWrite<CpuType::Pce>(addr, value, MemoryOperationType::Write);
|
||||
}
|
||||
_vdc->WriteRegister(addr, value);
|
||||
_vpc->StVdcWrite(addr, value);
|
||||
Exec(); //CPU is delayed by 1 CPU cycle when reading/writing to VDC/VCE
|
||||
}
|
||||
|
||||
|
|
|
@ -212,12 +212,53 @@ struct PcePsgChannelState
|
|||
uint8_t NoiseFrequency;
|
||||
};
|
||||
|
||||
enum class PceVpcPriorityMode
|
||||
{
|
||||
Default = 0,
|
||||
Vdc2SpritesAboveVdc1Bg = 1,
|
||||
Vdc1SpritesBelowVdc2Bg = 2,
|
||||
};
|
||||
|
||||
enum class PceVpcPixelWindow
|
||||
{
|
||||
NoWindow,
|
||||
Window1,
|
||||
Window2,
|
||||
Both
|
||||
};
|
||||
|
||||
struct PceVpcPriorityConfig
|
||||
{
|
||||
PceVpcPriorityMode PriorityMode;
|
||||
bool Vdc1Enabled;
|
||||
bool Vdc2Enabled;
|
||||
};
|
||||
|
||||
struct PceVpcState
|
||||
{
|
||||
PceVpcPriorityConfig WindowCfg[(int)PceVpcPixelWindow::Both + 1];
|
||||
uint8_t Priority1;
|
||||
uint8_t Priority2;
|
||||
uint16_t Window1;
|
||||
uint16_t Window2;
|
||||
bool StToVdc2Mode;
|
||||
};
|
||||
|
||||
struct PceVideoState : BaseState
|
||||
{
|
||||
PceVdcState Vdc;
|
||||
PceVceState Vce;
|
||||
PceVpcState Vpc;
|
||||
PceVdcState Vdc2;
|
||||
};
|
||||
|
||||
struct PceState
|
||||
{
|
||||
PceCpuState Cpu;
|
||||
PceVdcState Vdc;
|
||||
PceVceState Vce;
|
||||
PceVideoState Video;
|
||||
PceMemoryManagerState MemoryManager;
|
||||
PcePsgState Psg;
|
||||
PcePsgChannelState PsgChannels[6];
|
||||
|
||||
bool IsSuperGrafx;
|
||||
};
|
|
@ -73,12 +73,12 @@ void PceVce::Write(uint16_t addr, uint8_t value)
|
|||
case 0x03: _state.PalAddr = (_state.PalAddr & 0xFF) | ((value & 0x01) << 8); break;
|
||||
|
||||
case 0x04:
|
||||
_emu->ProcessPpuWrite<CpuType::Pce>((_state.PalAddr << 1), value, MemoryType::PceVideoRam);
|
||||
_emu->ProcessPpuWrite<CpuType::Pce>((_state.PalAddr << 1), value, MemoryType::PcePaletteRam);
|
||||
_paletteRam[_state.PalAddr] = (_paletteRam[_state.PalAddr] & 0x100) | value;
|
||||
break;
|
||||
|
||||
case 0x05:
|
||||
_emu->ProcessPpuWrite<CpuType::Pce>((_state.PalAddr << 1) + 1, value, MemoryType::PceVideoRam);
|
||||
_emu->ProcessPpuWrite<CpuType::Pce>((_state.PalAddr << 1) + 1, value, MemoryType::PcePaletteRam);
|
||||
_paletteRam[_state.PalAddr] = (_paletteRam[_state.PalAddr] & 0xFF) | ((value & 0x01) << 8);
|
||||
_state.PalAddr = (_state.PalAddr + 1) & 0x1FF;
|
||||
break;
|
||||
|
|
|
@ -1,31 +1,22 @@
|
|||
#include "stdafx.h"
|
||||
#include "PCE/PceVdc.h"
|
||||
#include "PCE/PceVce.h"
|
||||
#include "PCE/PceVpc.h"
|
||||
#include "PCE/PceMemoryManager.h"
|
||||
#include "PCE/PceControlManager.h"
|
||||
#include "PCE/PceConstants.h"
|
||||
#include "PCE/PceConsole.h"
|
||||
#include "Shared/EmuSettings.h"
|
||||
#include "Shared/RewindManager.h"
|
||||
#include "Shared/Video/VideoDecoder.h"
|
||||
#include "Shared/NotificationManager.h"
|
||||
#include "EventType.h"
|
||||
|
||||
PceVdc::PceVdc(Emulator* emu, PceConsole* console, PceVce* vce)
|
||||
PceVdc::PceVdc(Emulator* emu, PceConsole* console, PceVpc* vpc, PceVce* vce, bool isVdc2)
|
||||
{
|
||||
_emu = emu;
|
||||
_console = console;
|
||||
_vpc = vpc;
|
||||
_vce = vce;
|
||||
|
||||
_vram = new uint16_t[0x8000];
|
||||
_spriteRam = new uint16_t[0x100];
|
||||
|
||||
_outBuffer[0] = new uint16_t[PceConstants::MaxScreenWidth * PceConstants::ScreenHeight];
|
||||
_outBuffer[1] = new uint16_t[PceConstants::MaxScreenWidth * PceConstants::ScreenHeight];
|
||||
_currentOutBuffer = _outBuffer[0];
|
||||
|
||||
memset(_outBuffer[0], 0, PceConstants::MaxScreenWidth * PceConstants::ScreenHeight * sizeof(uint16_t));
|
||||
memset(_outBuffer[1], 0, PceConstants::MaxScreenWidth * PceConstants::ScreenHeight * sizeof(uint16_t));
|
||||
|
||||
_emu->GetSettings()->InitializeRam(_vram, 0x10000);
|
||||
_emu->GetSettings()->InitializeRam(_spriteRam, 0x200);
|
||||
|
@ -40,16 +31,17 @@ PceVdc::PceVdc(Emulator* emu, PceConsole* console, PceVce* vce)
|
|||
_state.HvReg.VertDisplayWidth = 239;
|
||||
_state.HvLatch.VertDisplayWidth = 239;
|
||||
|
||||
_emu->RegisterMemory(MemoryType::PceVideoRam, _vram, 0x8000 * sizeof(uint16_t));
|
||||
_emu->RegisterMemory(MemoryType::PceSpriteRam, _spriteRam, 0x100 * sizeof(uint16_t));
|
||||
_isVdc2 = isVdc2;
|
||||
_vramType = isVdc2 ? MemoryType::PceVideoRamVdc2 : MemoryType::PceVideoRam;
|
||||
_spriteRamType = isVdc2 ? MemoryType::PceSpriteRamVdc2 : MemoryType::PceSpriteRam;
|
||||
_emu->RegisterMemory(_vramType, _vram, 0x8000 * sizeof(uint16_t));
|
||||
_emu->RegisterMemory(_spriteRamType, _spriteRam, 0x100 * sizeof(uint16_t));
|
||||
}
|
||||
|
||||
PceVdc::~PceVdc()
|
||||
{
|
||||
delete[] _vram;
|
||||
delete[] _spriteRam;
|
||||
delete[] _outBuffer[0];
|
||||
delete[] _outBuffer[1];
|
||||
}
|
||||
|
||||
PceVdcState& PceVdc::GetState()
|
||||
|
@ -57,16 +49,6 @@ PceVdcState& PceVdc::GetState()
|
|||
return _state;
|
||||
}
|
||||
|
||||
uint16_t* PceVdc::GetScreenBuffer()
|
||||
{
|
||||
return _currentOutBuffer;
|
||||
}
|
||||
|
||||
uint16_t* PceVdc::GetPreviousScreenBuffer()
|
||||
{
|
||||
return _currentOutBuffer == _outBuffer[0] ? _outBuffer[1] : _outBuffer[0];
|
||||
}
|
||||
|
||||
uint8_t PceVdc::GetClockDivider()
|
||||
{
|
||||
return _vce->GetClockDivider();
|
||||
|
@ -113,7 +95,9 @@ void PceVdc::Exec()
|
|||
ProcessEndOfScanline();
|
||||
}
|
||||
|
||||
_emu->ProcessPpuCycle<CpuType::Pce>();
|
||||
if(!_isVdc2) {
|
||||
_emu->ProcessPpuCycle<CpuType::Pce>();
|
||||
}
|
||||
}
|
||||
|
||||
void PceVdc::TriggerHdsIrqs()
|
||||
|
@ -123,7 +107,7 @@ void PceVdc::TriggerHdsIrqs()
|
|||
}
|
||||
if(_hasSpriteOverflow && _state.EnableOverflowIrq) {
|
||||
_state.SpriteOverflow = true;
|
||||
_console->GetMemoryManager()->SetIrqSource(PceIrqSource::Irq1);
|
||||
_vpc->SetIrq(this);
|
||||
}
|
||||
_hasSpriteOverflow = false;
|
||||
}
|
||||
|
@ -559,8 +543,8 @@ void PceVdc::ProcessSatbTransfer()
|
|||
|
||||
int i = _state.SatbTransferOffset;
|
||||
uint16_t value = ReadVram(_state.SatbBlockSrc + i);
|
||||
_emu->ProcessPpuWrite<CpuType::Pce>(i << 1, value & 0xFF, MemoryType::PceSpriteRam);
|
||||
_emu->ProcessPpuWrite<CpuType::Pce>((i << 1) + 1, value >> 8, MemoryType::PceSpriteRam);
|
||||
_emu->ProcessPpuWrite<CpuType::Pce>(i << 1, value & 0xFF, _spriteRamType);
|
||||
_emu->ProcessPpuWrite<CpuType::Pce>((i << 1) + 1, value >> 8, _spriteRamType);
|
||||
_spriteRam[i] = value;
|
||||
|
||||
_state.SatbTransferOffset++;
|
||||
|
@ -570,7 +554,7 @@ void PceVdc::ProcessSatbTransfer()
|
|||
|
||||
if(_state.VramSatbIrqEnabled) {
|
||||
_state.SatbTransferDone = true;
|
||||
_console->GetMemoryManager()->SetIrqSource(PceIrqSource::Irq1);
|
||||
_vpc->SetIrq(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -612,7 +596,7 @@ void PceVdc::ProcessVramDmaTransfer()
|
|||
_vramDmaRunning = false;
|
||||
if(_state.VramVramIrqEnabled) {
|
||||
_state.VramTransferDone = true;
|
||||
_console->GetMemoryManager()->SetIrqSource(PceIrqSource::Irq1);
|
||||
_vpc->SetIrq(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -660,7 +644,7 @@ void PceVdc::IncrementRcrCounter()
|
|||
//This triggers ~12 VDC cycles before the end of the visible part of the scanline
|
||||
if(_state.EnableScanlineIrq && _state.RcrCounter == (int)_state.RasterCompareRegister - 0x40) {
|
||||
_state.ScanlineDetected = true;
|
||||
_console->GetMemoryManager()->SetIrqSource(PceIrqSource::Irq1);
|
||||
_vpc->SetIrq(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -685,18 +669,9 @@ void PceVdc::ProcessEndOfScanline()
|
|||
_state.HClock = 0;
|
||||
_state.Scanline++;
|
||||
|
||||
if(_state.Scanline >= 14 && _state.Scanline < 256) {
|
||||
uint16_t row = _state.Scanline - 14;
|
||||
if(row == 0) {
|
||||
_currentOutBuffer = _currentOutBuffer == _outBuffer[0] ? _outBuffer[1] : _outBuffer[0];
|
||||
_currentClockDividers = _currentOutBuffer == _outBuffer[0] ? _rowVceClockDivider[0] : _rowVceClockDivider[1];
|
||||
}
|
||||
_currentClockDividers[row] = GetClockDivider();
|
||||
}
|
||||
|
||||
if(_state.Scanline == 256) {
|
||||
_state.FrameCount++;
|
||||
SendFrame();
|
||||
_vpc->SendFrame(this);
|
||||
} else if(_state.Scanline >= GetScanlineCount()) {
|
||||
//Update flags that were locked during burst mode
|
||||
_state.Scanline = 0;
|
||||
|
@ -705,9 +680,13 @@ void PceVdc::ProcessEndOfScanline()
|
|||
_state.BackgroundEnabled = _state.NextBackgroundEnabled;
|
||||
_state.SpritesEnabled = _state.NextSpritesEnabled;
|
||||
|
||||
_emu->ProcessEvent(EventType::StartFrame);
|
||||
if(!_isVdc2) {
|
||||
_emu->ProcessEvent(EventType::StartFrame);
|
||||
}
|
||||
}
|
||||
|
||||
_vpc->ProcessScanlineStart(this, _state.Scanline);
|
||||
|
||||
if(_needRcrIncrement) {
|
||||
IncrementRcrCounter();
|
||||
}
|
||||
|
@ -756,7 +735,7 @@ void PceVdc::ProcessEndOfVisibleFrame()
|
|||
|
||||
if(_state.EnableVerticalBlankIrq) {
|
||||
_state.VerticalBlank = true;
|
||||
_console->GetMemoryManager()->SetIrqSource(PceIrqSource::Irq1);
|
||||
_vpc->SetIrq(this);
|
||||
}
|
||||
|
||||
_needVertBlankIrq = false;
|
||||
|
@ -802,13 +781,13 @@ void PceVdc::DrawScanline()
|
|||
|
||||
if(inPicture && (_state.BackgroundEnabled || _state.SpritesEnabled)) {
|
||||
PcEngineConfig& cfg = _emu->GetSettings()->GetPcEngineConfig();
|
||||
bool bgEnabled = _state.BackgroundEnabled && !cfg.DisableBackground;
|
||||
bool sprEnabled = _state.SpritesEnabled && !cfg.DisableSprites;
|
||||
bool bgEnabled = _state.BackgroundEnabled && !(_isVdc2 ? cfg.DisableBackgroundVdc2 : cfg.DisableBackground);
|
||||
bool sprEnabled = _state.SpritesEnabled && !(_isVdc2 ? cfg.DisableSpritesVdc2 : cfg.DisableSprites);
|
||||
uint16_t grayscaleBit = _vce->IsGrayscale() ? 0x200 : 0;
|
||||
|
||||
for(; xStart < xMax; xStart++) {
|
||||
uint8_t bgColor = 0;
|
||||
uint16_t outColor = _vce->GetPalette(0);
|
||||
uint16_t outColor = PceVpc::TransparentPixelFlag | _vce->GetPalette(0);
|
||||
if(bgEnabled) {
|
||||
uint16_t screenX = (_state.HvLatch.BgScrollX & 0x07) + _screenOffsetX;
|
||||
uint16_t column = screenX >> 3;
|
||||
|
@ -835,11 +814,11 @@ void PceVdc::DrawScanline()
|
|||
//Note: don't trigger sprite 0 hit for sprites that are drawn because of the "remove sprite limit" option
|
||||
if(_state.EnableCollisionIrq && i < _drawSpriteCount) {
|
||||
_state.Sprite0Hit = true;
|
||||
_console->GetMemoryManager()->SetIrqSource(PceIrqSource::Irq1);
|
||||
_vpc->SetIrq(this);
|
||||
}
|
||||
} else {
|
||||
if(sprEnabled && (bgColor == 0 || _drawSprites[i].ForegroundPriority)) {
|
||||
outColor = _vce->GetPalette(256 + _drawSprites[i].Palette * 16 + sprColor);
|
||||
outColor = PceVpc::SpritePixelFlag | _vce->GetPalette(256 + _drawSprites[i].Palette * 16 + sprColor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -871,36 +850,18 @@ void PceVdc::DrawScanline()
|
|||
}
|
||||
|
||||
if(_state.HClock == 1365) {
|
||||
uint32_t offset = (_state.Scanline - 14) * PceConstants::MaxScreenWidth;
|
||||
memcpy(_currentOutBuffer + offset, _rowBuffer, PceConstants::ClockPerScanline / GetClockDivider() * sizeof(uint16_t));
|
||||
_vpc->ProcessScanlineEnd(this, _state.Scanline, _rowBuffer);
|
||||
}
|
||||
|
||||
_xStart = xStart;
|
||||
_lastDrawHClock = _state.HClock / GetClockDivider() * GetClockDivider();
|
||||
}
|
||||
|
||||
void PceVdc::SendFrame()
|
||||
{
|
||||
_emu->ProcessEvent(EventType::EndFrame);
|
||||
_emu->GetNotificationManager()->SendNotification(ConsoleNotificationType::PpuFrameDone, _currentOutBuffer);
|
||||
|
||||
bool forRewind = _emu->GetRewindManager()->IsRewinding();
|
||||
|
||||
RenderedFrame frame(_currentOutBuffer, 512, PceConstants::ScreenHeight * 2, 0.5, _state.FrameCount, _console->GetControlManager()->GetPortStates());
|
||||
frame.Data = _currentClockDividers;
|
||||
_emu->GetVideoDecoder()->UpdateFrame(frame, forRewind, forRewind);
|
||||
|
||||
_emu->ProcessEndOfFrame();
|
||||
|
||||
_console->GetControlManager()->UpdateInputState();
|
||||
_console->GetControlManager()->UpdateControlDevices();
|
||||
}
|
||||
|
||||
void PceVdc::ProcessVramRead()
|
||||
{
|
||||
_state.ReadBuffer = ReadVram(_state.MemAddrRead);
|
||||
_emu->ProcessPpuRead<CpuType::Pce>((_state.MemAddrRead << 1), (uint8_t)_state.ReadBuffer, MemoryType::PceVideoRam);
|
||||
_emu->ProcessPpuRead<CpuType::Pce>((_state.MemAddrRead << 1) + 1, (uint8_t)(_state.ReadBuffer >> 8), MemoryType::PceVideoRam);
|
||||
_emu->ProcessPpuRead<CpuType::Pce>((_state.MemAddrRead << 1), (uint8_t)_state.ReadBuffer, _vramType);
|
||||
_emu->ProcessPpuRead<CpuType::Pce>((_state.MemAddrRead << 1) + 1, (uint8_t)(_state.ReadBuffer >> 8), _vramType);
|
||||
_pendingMemoryRead = false;
|
||||
}
|
||||
|
||||
|
@ -908,8 +869,8 @@ void PceVdc::ProcessVramWrite()
|
|||
{
|
||||
if(_state.MemAddrWrite < 0x8000) {
|
||||
//Ignore writes to mirror at $8000+
|
||||
_emu->ProcessPpuWrite<CpuType::Pce>(_state.MemAddrWrite << 1, _state.VramData & 0xFF, MemoryType::PceVideoRam);
|
||||
_emu->ProcessPpuWrite<CpuType::Pce>((_state.MemAddrWrite << 1) + 1, _state.VramData, MemoryType::PceVideoRam);
|
||||
_emu->ProcessPpuWrite<CpuType::Pce>(_state.MemAddrWrite << 1, _state.VramData & 0xFF, _vramType);
|
||||
_emu->ProcessPpuWrite<CpuType::Pce>((_state.MemAddrWrite << 1) + 1, _state.VramData, _vramType);
|
||||
_vram[_state.MemAddrWrite] = _state.VramData;
|
||||
_state.MemAddrWrite += _state.VramAddrIncrement;
|
||||
}
|
||||
|
@ -958,7 +919,7 @@ uint8_t PceVdc::ReadRegister(uint16_t addr)
|
|||
_state.SpriteOverflow = false;
|
||||
_state.Sprite0Hit = false;
|
||||
|
||||
_console->GetMemoryManager()->ClearIrqSource(PceIrqSource::Irq1);
|
||||
_vpc->ClearIrq(this);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "Shared/Emulator.h"
|
||||
#include "MemoryType.h"
|
||||
#include "PCE/PceTypes.h"
|
||||
#include "PCE/PceConstants.h"
|
||||
|
||||
class PceConsole;
|
||||
class PceVce;
|
||||
class PceVpc;
|
||||
|
||||
enum class PceVdcModeH
|
||||
{
|
||||
|
@ -58,15 +60,10 @@ private:
|
|||
Emulator* _emu = nullptr;
|
||||
PceConsole* _console = nullptr;
|
||||
PceVce* _vce = nullptr;
|
||||
PceVpc* _vpc = nullptr;
|
||||
uint16_t* _vram = nullptr;
|
||||
uint16_t* _spriteRam = nullptr;
|
||||
|
||||
uint16_t* _outBuffer[2] = {};
|
||||
uint16_t* _currentOutBuffer = nullptr;
|
||||
|
||||
uint8_t _rowVceClockDivider[2][PceConstants::ScreenHeight] = {};
|
||||
uint8_t* _currentClockDividers = nullptr;
|
||||
|
||||
uint16_t _rowBuffer[PceConstants::MaxScreenWidth] = {};
|
||||
|
||||
uint16_t _vramOpenBus = 0;
|
||||
|
@ -109,6 +106,10 @@ private:
|
|||
PceVdcEvent _nextEvent = PceVdcEvent::None;
|
||||
uint16_t _nextEventCounter = 0;
|
||||
|
||||
bool _isVdc2 = false;
|
||||
MemoryType _vramType = MemoryType::PceVideoRam;
|
||||
MemoryType _spriteRamType = MemoryType::PceSpriteRam;
|
||||
|
||||
uint8_t _drawSpriteCount = 0;
|
||||
uint8_t _totalSpriteCount = 0;
|
||||
bool _rowHasSprite0 = false;
|
||||
|
@ -131,8 +132,6 @@ private:
|
|||
void ProcessVramWrite();
|
||||
__noinline void ProcessVramAccesses();
|
||||
|
||||
void SendFrame();
|
||||
|
||||
uint8_t GetClockDivider();
|
||||
uint16_t GetScanlineCount();
|
||||
uint16_t DotsToClocks(int dots);
|
||||
|
@ -172,14 +171,10 @@ private:
|
|||
bool IsVramAccessBlocked();
|
||||
|
||||
public:
|
||||
PceVdc(Emulator* emu, PceConsole* console, PceVce* vce);
|
||||
PceVdc(Emulator* emu, PceConsole* console, PceVpc* vpc, PceVce* vce, bool isVdc2);
|
||||
~PceVdc();
|
||||
|
||||
PceVdcState& GetState();
|
||||
uint16_t* GetScreenBuffer();
|
||||
uint16_t* GetPreviousScreenBuffer();
|
||||
uint8_t* GetRowClockDividers() { return _currentClockDividers; }
|
||||
uint8_t* GetPreviousRowClockDividers() { return _currentClockDividers == _rowVceClockDivider[0] ? _rowVceClockDivider[1] : _rowVceClockDivider[0]; }
|
||||
|
||||
uint16_t GetHClock() { return _state.HClock; }
|
||||
uint16_t GetScanline() { return _state.Scanline; }
|
||||
|
|
292
Core/PCE/PceVpc.cpp
Normal file
292
Core/PCE/PceVpc.cpp
Normal file
|
@ -0,0 +1,292 @@
|
|||
#include "stdafx.h"
|
||||
#include "PCE/PceVpc.h"
|
||||
#include "PCE/PceVdc.h"
|
||||
#include "PCE/PceVce.h"
|
||||
#include "PCE/PceMemoryManager.h"
|
||||
#include "PCE/PceControlManager.h"
|
||||
#include "PCE/PceConsole.h"
|
||||
#include "Shared/RewindManager.h"
|
||||
#include "Shared/Video/VideoDecoder.h"
|
||||
#include "Shared/NotificationManager.h"
|
||||
#include "EventType.h"
|
||||
|
||||
PceVpc::PceVpc(Emulator* emu, PceConsole* console, PceVce* vce)
|
||||
{
|
||||
_emu = emu;
|
||||
_console = console;
|
||||
_vce = vce;
|
||||
|
||||
_outBuffer[0] = new uint16_t[PceConstants::MaxScreenWidth * PceConstants::ScreenHeight];
|
||||
_outBuffer[1] = new uint16_t[PceConstants::MaxScreenWidth * PceConstants::ScreenHeight];
|
||||
_currentOutBuffer = _outBuffer[0];
|
||||
|
||||
memset(_outBuffer[0], 0, PceConstants::MaxScreenWidth * PceConstants::ScreenHeight * sizeof(uint16_t));
|
||||
memset(_outBuffer[1], 0, PceConstants::MaxScreenWidth * PceConstants::ScreenHeight * sizeof(uint16_t));
|
||||
}
|
||||
|
||||
PceVpc::~PceVpc()
|
||||
{
|
||||
delete[] _outBuffer[0];
|
||||
delete[] _outBuffer[1];
|
||||
}
|
||||
|
||||
void PceVpc::ConnectVdc(PceVdc* vdc1, PceVdc* vdc2)
|
||||
{
|
||||
_vdc1 = vdc1;
|
||||
_vdc2 = vdc2;
|
||||
|
||||
if(vdc2) {
|
||||
//Default power on values (SuperGrafx only)
|
||||
Write(0x08, 0x11);
|
||||
Write(0x09, 0x11);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t PceVpc::Read(uint16_t addr)
|
||||
{
|
||||
if(_vdc2) {
|
||||
//SuperGrafx enabled
|
||||
switch(addr & 0x1F) {
|
||||
case 0: case 1: case 2: case 3:
|
||||
case 4: case 5: case 6: case 7:
|
||||
return _vdc1->ReadRegister(addr);
|
||||
|
||||
case 0x08: return _state.Priority1;
|
||||
case 0x09: return _state.Priority2;
|
||||
|
||||
case 0x0A: return (_state.Window1 & 0xFF);
|
||||
case 0x0B: return (_state.Window1 >> 8);
|
||||
case 0x0C: return (_state.Window2 & 0xFF);
|
||||
case 0x0D: return (_state.Window2 >> 8);
|
||||
|
||||
case 0x0E: return 0;
|
||||
case 0x0F: return 0;
|
||||
|
||||
case 0x10: case 0x11: case 0x12: case 0x13:
|
||||
case 0x14: case 0x15: case 0x16: case 0x17:
|
||||
return _vdc2->ReadRegister(addr & 0x03);
|
||||
|
||||
default:
|
||||
//18-1F are unused
|
||||
return 0xFF;
|
||||
}
|
||||
} else {
|
||||
//Regular PC Engine with a single VDC
|
||||
return _vdc1->ReadRegister(addr);
|
||||
}
|
||||
}
|
||||
|
||||
void PceVpc::Write(uint16_t addr, uint8_t value)
|
||||
{
|
||||
if(_vdc2) {
|
||||
//SuperGrafx enabled
|
||||
switch(addr & 0x1F) {
|
||||
case 0: case 1: case 2: case 3:
|
||||
case 4: case 5: case 6: case 7:
|
||||
_vdc1->WriteRegister(addr, value);
|
||||
break;
|
||||
|
||||
case 0x08:
|
||||
SetPriorityConfig(PceVpcPixelWindow::Both, value & 0x0F);
|
||||
SetPriorityConfig(PceVpcPixelWindow::Window2, (value >> 4) & 0x0F);
|
||||
_state.Priority1 = value;
|
||||
break;
|
||||
|
||||
case 0x09:
|
||||
SetPriorityConfig(PceVpcPixelWindow::Window1, value & 0x0F);
|
||||
SetPriorityConfig(PceVpcPixelWindow::NoWindow, (value >> 4) & 0x0F);
|
||||
_state.Priority2 = value;
|
||||
break;
|
||||
|
||||
case 0x0A: _state.Window1 = (_state.Window1 & 0x300) | value; break;
|
||||
case 0x0B: _state.Window1 = (_state.Window1 & 0xFF) | ((value & 0x03) << 8); break;
|
||||
case 0x0C: _state.Window2 = (_state.Window2 & 0x300) | value; break;
|
||||
case 0x0D: _state.Window2 = (_state.Window2 & 0xFF) | ((value & 0x03) << 8); break;
|
||||
|
||||
case 0x0E: _state.StToVdc2Mode = (value & 0x01) != 0; break;
|
||||
|
||||
case 0x10: case 0x11: case 0x12: case 0x13:
|
||||
case 0x14: case 0x15: case 0x16: case 0x17:
|
||||
_vdc2->WriteRegister(addr & 0x03, value);
|
||||
break;
|
||||
|
||||
default:
|
||||
//0F, 18-1F are unused
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
//Regular PC Engine with a single VDC
|
||||
_vdc1->WriteRegister(addr, value);
|
||||
}
|
||||
}
|
||||
|
||||
void PceVpc::StVdcWrite(uint16_t addr, uint8_t value)
|
||||
{
|
||||
if(_state.StToVdc2Mode) {
|
||||
_vdc2->WriteRegister(addr, value);
|
||||
} else {
|
||||
_vdc1->WriteRegister(addr, value);
|
||||
}
|
||||
}
|
||||
|
||||
void PceVpc::Exec()
|
||||
{
|
||||
if(_vdc2) {
|
||||
_vdc2->Exec();
|
||||
}
|
||||
_vdc1->Exec();
|
||||
}
|
||||
|
||||
void PceVpc::DrawScanline()
|
||||
{
|
||||
if(_vdc2) {
|
||||
_vdc2->DrawScanline();
|
||||
}
|
||||
_vdc1->DrawScanline();
|
||||
}
|
||||
|
||||
void PceVpc::ProcessScanlineStart(PceVdc* vdc, uint16_t scanline)
|
||||
{
|
||||
if(vdc == _vdc2) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(scanline >= 14 && scanline < 256) {
|
||||
uint16_t row = scanline - 14;
|
||||
if(row == 0) {
|
||||
_currentOutBuffer = _currentOutBuffer == _outBuffer[0] ? _outBuffer[1] : _outBuffer[0];
|
||||
_currentClockDividers = _currentOutBuffer == _outBuffer[0] ? _rowVceClockDivider[0] : _rowVceClockDivider[1];
|
||||
}
|
||||
_currentClockDividers[row] = _vce->GetClockDivider();
|
||||
}
|
||||
}
|
||||
|
||||
void PceVpc::ProcessScanlineEnd(PceVdc* vdc, uint16_t scanline, uint16_t* rowBuffer)
|
||||
{
|
||||
if(vdc == _vdc2) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t offset = (scanline - 14) * PceConstants::MaxScreenWidth;
|
||||
if(_vdc2) {
|
||||
//Supergrafx mode, merge outputs
|
||||
uint16_t* rowBufferVdc2 = _vdc2->GetRowBuffer();
|
||||
|
||||
uint32_t pixelCount = PceConstants::ClockPerScanline / _vce->GetClockDivider();
|
||||
for(uint32_t i = 0; i < pixelCount; i++) {
|
||||
PceVpcPriorityMode prio = (PceVpcPriorityMode)((i < _state.Window1) | ((i < _state.Window2) << 1));
|
||||
PceVpcPriorityConfig& cfg = _state.WindowCfg[(int)prio];
|
||||
uint8_t enabledLayers = (uint8_t)cfg.Vdc1Enabled | ((uint8_t)cfg.Vdc2Enabled << 1);
|
||||
uint16_t color;
|
||||
switch(enabledLayers) {
|
||||
default:
|
||||
case 0: color = 0; break;
|
||||
case 1: color = rowBuffer[i]; break;
|
||||
case 2: color = rowBufferVdc2[i]; break;
|
||||
|
||||
case 3:
|
||||
{
|
||||
bool isSpriteVdc1 = (rowBuffer[i] & PceVpc::SpritePixelFlag) != 0;
|
||||
bool isSpriteVdc2 = (rowBufferVdc2[i] & PceVpc::SpritePixelFlag) != 0;
|
||||
bool isTransparentVdc1 = (rowBuffer[i] & PceVpc::TransparentPixelFlag) != 0;
|
||||
|
||||
switch(cfg.PriorityMode) {
|
||||
default:
|
||||
case PceVpcPriorityMode::Default:
|
||||
color = isTransparentVdc1 ? rowBufferVdc2[i] : rowBuffer[i];
|
||||
break;
|
||||
|
||||
case PceVpcPriorityMode::Vdc2SpritesAboveVdc1Bg:
|
||||
if(isTransparentVdc1 || (isSpriteVdc2 && !isSpriteVdc1)) {
|
||||
//VDC1 transparent, show VDC2, or
|
||||
//VDC2 is a sprite and VDC1 is not a sprite, show VDC2
|
||||
color = rowBufferVdc2[i];
|
||||
} else {
|
||||
color = rowBuffer[i];
|
||||
}
|
||||
break;
|
||||
|
||||
case PceVpcPriorityMode::Vdc1SpritesBelowVdc2Bg:
|
||||
if(isTransparentVdc1 || (isSpriteVdc1 && !isSpriteVdc2)) {
|
||||
//VDC1 transparent, show VDC2, or
|
||||
//VDC1 is a sprite, show VDC2
|
||||
color = rowBufferVdc2[i];
|
||||
} else {
|
||||
color = rowBuffer[i];
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_currentOutBuffer[offset + i] = color;
|
||||
}
|
||||
} else {
|
||||
//PC Engine, display VDC1's data
|
||||
memcpy(_currentOutBuffer + offset, rowBuffer, PceConstants::ClockPerScanline / _vce->GetClockDivider() * sizeof(uint16_t));
|
||||
}
|
||||
}
|
||||
|
||||
void PceVpc::SendFrame(PceVdc* vdc)
|
||||
{
|
||||
if(vdc == _vdc2) {
|
||||
return;
|
||||
}
|
||||
|
||||
_emu->ProcessEvent(EventType::EndFrame);
|
||||
_emu->GetNotificationManager()->SendNotification(ConsoleNotificationType::PpuFrameDone, _currentOutBuffer);
|
||||
|
||||
bool forRewind = _emu->GetRewindManager()->IsRewinding();
|
||||
|
||||
RenderedFrame frame(_currentOutBuffer, 512, PceConstants::ScreenHeight * 2, 0.5, _vdc1->GetState().FrameCount, _console->GetControlManager()->GetPortStates());
|
||||
frame.Data = _currentClockDividers;
|
||||
_emu->GetVideoDecoder()->UpdateFrame(frame, forRewind, forRewind);
|
||||
|
||||
_emu->ProcessEndOfFrame();
|
||||
|
||||
_console->GetControlManager()->UpdateInputState();
|
||||
_console->GetControlManager()->UpdateControlDevices();
|
||||
}
|
||||
|
||||
void PceVpc::UpdateIrqState()
|
||||
{
|
||||
if(_hasIrqVdc1 || _hasIrqVdc2) {
|
||||
_console->GetMemoryManager()->SetIrqSource(PceIrqSource::Irq1);
|
||||
} else {
|
||||
_console->GetMemoryManager()->ClearIrqSource(PceIrqSource::Irq1);
|
||||
}
|
||||
}
|
||||
|
||||
void PceVpc::SetIrq(PceVdc* vdc)
|
||||
{
|
||||
if(vdc == _vdc1) {
|
||||
_hasIrqVdc1 = true;
|
||||
} else {
|
||||
_hasIrqVdc2 = true;
|
||||
}
|
||||
UpdateIrqState();
|
||||
}
|
||||
|
||||
void PceVpc::ClearIrq(PceVdc* vdc)
|
||||
{
|
||||
if(vdc == _vdc1) {
|
||||
_hasIrqVdc1 = false;
|
||||
} else {
|
||||
_hasIrqVdc2 = false;
|
||||
}
|
||||
UpdateIrqState();
|
||||
}
|
||||
|
||||
void PceVpc::SetPriorityConfig(PceVpcPixelWindow wnd, uint8_t value)
|
||||
{
|
||||
PceVpcPriorityConfig& cfg = _state.WindowCfg[(int)wnd];
|
||||
cfg.Vdc1Enabled = (value & 0x01) != 0;
|
||||
cfg.Vdc2Enabled = (value & 0x02) != 0;
|
||||
switch((value >> 2) & 0x03) {
|
||||
case 0: cfg.PriorityMode = PceVpcPriorityMode::Default; break;
|
||||
case 1: cfg.PriorityMode = PceVpcPriorityMode::Vdc2SpritesAboveVdc1Bg; break;
|
||||
case 2: cfg.PriorityMode = PceVpcPriorityMode::Vdc1SpritesBelowVdc2Bg; break;
|
||||
case 3: cfg.PriorityMode = PceVpcPriorityMode::Default; break;
|
||||
}
|
||||
}
|
63
Core/PCE/PceVpc.h
Normal file
63
Core/PCE/PceVpc.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "PCE/PceTypes.h"
|
||||
#include "PCE/PceConstants.h"
|
||||
|
||||
class PceVdc;
|
||||
class PceVce;
|
||||
class PceConsole;
|
||||
class Emulator;
|
||||
|
||||
class PceVpc
|
||||
{
|
||||
public:
|
||||
static constexpr uint16_t SpritePixelFlag = 0x8000;
|
||||
static constexpr uint16_t TransparentPixelFlag = 0x4000;
|
||||
|
||||
private:
|
||||
PceVdc* _vdc1 = nullptr;
|
||||
PceVdc* _vdc2 = nullptr;
|
||||
PceVce* _vce = nullptr;
|
||||
Emulator* _emu = nullptr;
|
||||
PceConsole* _console = nullptr;
|
||||
bool _hasIrqVdc1 = false;
|
||||
bool _hasIrqVdc2 = false;
|
||||
|
||||
uint16_t* _outBuffer[2] = {};
|
||||
uint16_t* _currentOutBuffer = nullptr;
|
||||
|
||||
uint8_t _rowVceClockDivider[2][PceConstants::ScreenHeight] = {};
|
||||
uint8_t* _currentClockDividers = nullptr;
|
||||
|
||||
PceVpcState _state = {};
|
||||
|
||||
void SetPriorityConfig(PceVpcPixelWindow wnd, uint8_t value);
|
||||
void UpdateIrqState();
|
||||
|
||||
public:
|
||||
PceVpc(Emulator* emu, PceConsole* console, PceVce* vce);
|
||||
~PceVpc();
|
||||
|
||||
void ConnectVdc(PceVdc* vdc1, PceVdc* vdc2);
|
||||
|
||||
uint8_t Read(uint16_t addr);
|
||||
void Write(uint16_t addr, uint8_t value);
|
||||
|
||||
void StVdcWrite(uint16_t addr, uint8_t value);
|
||||
|
||||
void Exec();
|
||||
void DrawScanline();
|
||||
void ProcessScanlineStart(PceVdc* vdc, uint16_t scanline);
|
||||
void ProcessScanlineEnd(PceVdc* vdc, uint16_t scanline, uint16_t* rowBuffer);
|
||||
void SendFrame(PceVdc* vdc);
|
||||
|
||||
void SetIrq(PceVdc* vdc);
|
||||
void ClearIrq(PceVdc* vdc);
|
||||
|
||||
PceVpcState GetState() { return _state; }
|
||||
|
||||
uint16_t* GetScreenBuffer() { return _currentOutBuffer; }
|
||||
uint16_t* GetPreviousScreenBuffer() { return _currentOutBuffer == _outBuffer[0] ? _outBuffer[1] : _outBuffer[0]; }
|
||||
uint8_t* GetRowClockDividers() { return _currentClockDividers; }
|
||||
uint8_t* GetPreviousRowClockDividers() { return _currentClockDividers == _rowVceClockDivider[0] ? _rowVceClockDivider[1] : _rowVceClockDivider[0]; }
|
||||
};
|
|
@ -226,6 +226,7 @@ void SnesPpuTools::GetSpriteInfo(DebugSpriteInfo& sprite, uint16_t spriteIndex,
|
|||
sprite.Bpp = 4;
|
||||
sprite.Format = TileFormat::Bpp4;
|
||||
sprite.SpriteIndex = spriteIndex;
|
||||
sprite.UseExtendedVram = false;
|
||||
sprite.X = spriteX;
|
||||
sprite.Y = spriteY;
|
||||
sprite.RawX = sign | oamRam[addr];
|
||||
|
|
|
@ -403,7 +403,9 @@ struct PcEngineConfig
|
|||
|
||||
bool RemoveSpriteLimit = false;
|
||||
bool DisableSprites = false;
|
||||
bool DisableSpritesVdc2 = false;
|
||||
bool DisableBackground = false;
|
||||
bool DisableBackgroundVdc2 = false;
|
||||
|
||||
uint32_t Palette[512] = { };
|
||||
};
|
||||
|
|
|
@ -41,7 +41,9 @@ namespace Mesen.Config
|
|||
|
||||
[Reactive] public bool RemoveSpriteLimit { get; set; } = false;
|
||||
[Reactive] public bool DisableSprites { get; set; } = false;
|
||||
[Reactive] public bool DisableSpritesVdc2 { get; set; } = false;
|
||||
[Reactive] public bool DisableBackground { get; set; } = false;
|
||||
[Reactive] public bool DisableBackgroundVdc2 { get; set; } = false;
|
||||
|
||||
[Reactive] public UInt32[] Palette { get; set; } = PcEngineConfig.DefaultPalette.ToArray();
|
||||
|
||||
|
@ -73,7 +75,9 @@ namespace Mesen.Config
|
|||
|
||||
RemoveSpriteLimit = RemoveSpriteLimit,
|
||||
DisableBackground = DisableBackground,
|
||||
DisableBackgroundVdc2 = DisableBackgroundVdc2,
|
||||
DisableSprites = DisableSprites,
|
||||
DisableSpritesVdc2 = DisableSpritesVdc2,
|
||||
|
||||
Palette = Palette,
|
||||
});
|
||||
|
@ -150,7 +154,9 @@ namespace Mesen.Config
|
|||
|
||||
[MarshalAs(UnmanagedType.I1)] public bool RemoveSpriteLimit;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool DisableSprites;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool DisableSpritesVdc2;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool DisableBackground;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool DisableBackgroundVdc2;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
|
||||
public UInt32[] Palette;
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace Mesen.Debugger.StatusViews
|
|||
public override void UpdateUiState()
|
||||
{
|
||||
PceCpuState cpu = DebugApi.GetCpuState<PceCpuState>(CpuType.Pce);
|
||||
PceVdcState vdc = DebugApi.GetPpuState<PceVdcState>(CpuType.Pce);
|
||||
PceVideoState video = DebugApi.GetPpuState<PceVideoState>(CpuType.Pce);
|
||||
|
||||
RegA = cpu.A;
|
||||
RegX = cpu.X;
|
||||
|
@ -76,15 +76,14 @@ namespace Mesen.Debugger.StatusViews
|
|||
}
|
||||
StackPreview = sb.ToString();
|
||||
|
||||
Cycle = vdc.HClock;
|
||||
Scanline = vdc.Scanline;
|
||||
FrameCount = vdc.FrameCount;
|
||||
Cycle = video.Vdc.HClock;
|
||||
Scanline = video.Vdc.Scanline;
|
||||
FrameCount = video.Vdc.FrameCount;
|
||||
}
|
||||
|
||||
public override void UpdateConsoleState()
|
||||
{
|
||||
PceCpuState cpu = DebugApi.GetCpuState<PceCpuState>(CpuType.Pce);
|
||||
PceVdcState ppu = DebugApi.GetPpuState<PceVdcState>(CpuType.Pce);
|
||||
|
||||
cpu.A = RegA;
|
||||
cpu.X = RegX;
|
||||
|
@ -93,11 +92,7 @@ namespace Mesen.Debugger.StatusViews
|
|||
cpu.PC = RegPC;
|
||||
cpu.PS = RegPS;
|
||||
|
||||
ppu.HClock = Cycle;
|
||||
ppu.Scanline = Scanline;
|
||||
|
||||
DebugApi.SetCpuState(cpu, CpuType.Pce);
|
||||
DebugApi.SetPpuState(ppu, CpuType.Pce);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,5 +5,6 @@ namespace Mesen.Debugger.Utilities
|
|||
public interface ICpuTypeModel
|
||||
{
|
||||
CpuType CpuType { get; set; }
|
||||
void OnGameLoaded();
|
||||
}
|
||||
}
|
|
@ -94,6 +94,7 @@ namespace Mesen.Debugger.Utilities
|
|||
if(!romInfo.CpuTypes.Contains(model.CpuType)) {
|
||||
model.CpuType = romInfo.ConsoleType.GetMainCpuType();
|
||||
}
|
||||
model.OnGameLoaded();
|
||||
|
||||
cfg.UpdateMinMaxValues();
|
||||
|
||||
|
|
|
@ -88,7 +88,6 @@ namespace Mesen.Debugger.ViewModels
|
|||
},
|
||||
});
|
||||
|
||||
AddDisposable(this.WhenAnyValue(x => x.CpuType).Subscribe(_ => RefreshData()));
|
||||
AddDisposable(this.WhenAnyValue(x => x.Config.Zoom).Subscribe(x => BlockSize = Math.Max(16, 16 + (x - 1) * 4)));
|
||||
AddDisposable(this.WhenAnyValue(x => x.SelectedPalette).Subscribe(x => UpdatePreviewPanel()));
|
||||
|
||||
|
@ -179,5 +178,10 @@ namespace Mesen.Debugger.ViewModels
|
|||
return new DynamicTooltip() { Items = entries };
|
||||
}
|
||||
}
|
||||
|
||||
public void OnGameLoaded()
|
||||
{
|
||||
RefreshData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -144,11 +144,18 @@ namespace Mesen.Debugger.ViewModels
|
|||
};
|
||||
} else if(lastState is PceState pceState) {
|
||||
tabs = new List<RegisterViewerTab>() {
|
||||
GetPceCpuTab(ref pceState),
|
||||
GetPceVdcTab(ref pceState),
|
||||
GetPceVceTab(ref pceState),
|
||||
GetPcePsgTab(ref pceState)
|
||||
GetPceCpuTab(ref pceState)
|
||||
};
|
||||
|
||||
if(pceState.IsSuperGrafx) {
|
||||
tabs.Add(GetPceVdcTab(ref pceState.Video.Vdc, "1"));
|
||||
tabs.Add(GetPceVdcTab(ref pceState.Video.Vdc2, "2"));
|
||||
tabs.Add(GetPceVpcTab(ref pceState));
|
||||
} else {
|
||||
tabs.Add(GetPceVdcTab(ref pceState.Video.Vdc));
|
||||
}
|
||||
tabs.Add(GetPceVceTab(ref pceState));
|
||||
tabs.Add(GetPcePsgTab(ref pceState));
|
||||
}
|
||||
|
||||
if(Tabs.Count != tabs.Count) {
|
||||
|
@ -1136,7 +1143,7 @@ namespace Mesen.Debugger.ViewModels
|
|||
|
||||
private RegisterViewerTab GetPceVceTab(ref PceState state)
|
||||
{
|
||||
PceVceState vce = state.Vce;
|
||||
PceVceState vce = state.Video.Vce;
|
||||
|
||||
List<RegEntry> entries = new List<RegEntry>() {
|
||||
new RegEntry("$00.0-1", "CR - Clock Speed", vce.ClockDivider == 4 ? "5.37 MHz" : vce.ClockDivider == 3 ? "7.16 MHz" : "10.74 MHz"),
|
||||
|
@ -1151,10 +1158,47 @@ namespace Mesen.Debugger.ViewModels
|
|||
};
|
||||
}
|
||||
|
||||
private RegisterViewerTab GetPceVdcTab(ref PceState state)
|
||||
private RegisterViewerTab GetPceVpcTab(ref PceState state)
|
||||
{
|
||||
PceVdcState vdc = state.Vdc;
|
||||
PceVpcState vpc = state.Video.Vpc;
|
||||
|
||||
List<RegEntry> entries = new List<RegEntry>() {
|
||||
new RegEntry("$08.0-3", "Priority Config (Both windows)", null),
|
||||
new RegEntry("$08.0", "VDC1 Enabled", vpc.WindowCfg[3].Vdc1Enabled),
|
||||
new RegEntry("$08.1", "VDC2 Enabled", vpc.WindowCfg[3].Vdc2Enabled),
|
||||
new RegEntry("$08.2-3", "Priority Mode", (vpc.Priority1 >> 2) & 0x03),
|
||||
|
||||
new RegEntry("$08.4-7", "Priority Config (Window 2 only)", null),
|
||||
new RegEntry("$08.4", "VDC1 Enabled", vpc.WindowCfg[2].Vdc1Enabled),
|
||||
new RegEntry("$08.5", "VDC2 Enabled", vpc.WindowCfg[2].Vdc2Enabled),
|
||||
new RegEntry("$08.6-7", "Priority Mode", (vpc.Priority1 >> 6) & 0x03),
|
||||
|
||||
new RegEntry("$09.0-3", "Priority Config (Window 1 only)", null),
|
||||
new RegEntry("$09.0", "VDC1 Enabled", vpc.WindowCfg[1].Vdc1Enabled),
|
||||
new RegEntry("$09.1", "VDC2 Enabled", vpc.WindowCfg[1].Vdc2Enabled),
|
||||
new RegEntry("$09.2-3", "Priority Mode", (vpc.Priority2 >> 2) & 0x03),
|
||||
|
||||
new RegEntry("$09.4-7", "Priority Config (No window)", null),
|
||||
new RegEntry("$09.4", "VDC1 Enabled", vpc.WindowCfg[0].Vdc1Enabled),
|
||||
new RegEntry("$09.5", "VDC2 Enabled", vpc.WindowCfg[0].Vdc2Enabled),
|
||||
new RegEntry("$09.6-7", "Priority Mode", (vpc.Priority2 >> 6) & 0x03),
|
||||
|
||||
new RegEntry("$0A-0D", "Windows", null),
|
||||
new RegEntry("$0A-0B", "Window 1", vpc.Window1, Format.X16),
|
||||
new RegEntry("$0C-0D", "Window 2", vpc.Window2, Format.X16),
|
||||
|
||||
new RegEntry("$0E", "", null),
|
||||
new RegEntry("$0E", "STn writes to VDC2", vpc.StToVdc2Mode),
|
||||
};
|
||||
|
||||
return new RegisterViewerTab() {
|
||||
TabName = "VPC",
|
||||
Data = entries
|
||||
};
|
||||
}
|
||||
|
||||
private RegisterViewerTab GetPceVdcTab(ref PceVdcState vdc, string suffix = "")
|
||||
{
|
||||
List<RegEntry> entries = new List<RegEntry>() {
|
||||
new RegEntry("", "State", null),
|
||||
new RegEntry("", "HClock (H)", vdc.HClock, Format.X16),
|
||||
|
@ -1225,7 +1269,7 @@ namespace Mesen.Debugger.ViewModels
|
|||
};
|
||||
|
||||
return new RegisterViewerTab() {
|
||||
TabName = "VDC",
|
||||
TabName = "VDC" + suffix,
|
||||
Data = entries
|
||||
};
|
||||
}
|
||||
|
@ -1297,6 +1341,12 @@ namespace Mesen.Debugger.ViewModels
|
|||
Data = entries
|
||||
};
|
||||
}
|
||||
|
||||
public void OnGameLoaded()
|
||||
{
|
||||
UpdateRomInfo();
|
||||
RefreshData();
|
||||
}
|
||||
}
|
||||
|
||||
public class RegisterViewerTab : ReactiveObject
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace Mesen.Debugger.ViewModels
|
|||
|
||||
[Reactive] public bool HorizontalMirror { get; set; }
|
||||
[Reactive] public bool VerticalMirror { get; set; }
|
||||
[Reactive] public bool UseExtendedVram { get; set; }
|
||||
[Reactive] public NullableBoolean UseSecondTable { get; set; }
|
||||
|
||||
[Reactive] public DynamicBitmap? SpritePreview { get; set; }
|
||||
|
@ -57,6 +58,7 @@ namespace Mesen.Debugger.ViewModels
|
|||
TileAddress = sprite.TileAddress;
|
||||
PaletteAddress = sprite.PaletteAddress;
|
||||
UseSecondTable = sprite.UseSecondTable;
|
||||
UseExtendedVram = sprite.UseExtendedVram;
|
||||
|
||||
fixed(UInt32* p = sprite.SpritePreview) {
|
||||
if(SpritePreview == null || SpritePreview.PixelSize.Width != sprite.Width || SpritePreview.PixelSize.Height != sprite.Height) {
|
||||
|
|
|
@ -134,10 +134,6 @@ namespace Mesen.Debugger.ViewModels
|
|||
return;
|
||||
}
|
||||
|
||||
AddDisposable(this.WhenAnyValue(x => x.CpuType).Subscribe(_ => {
|
||||
RefreshData();
|
||||
}));
|
||||
|
||||
AddDisposable(this.WhenAnyValue(x => x.SelectedSprite).Subscribe(x => {
|
||||
UpdateSelectionPreview();
|
||||
if(x != null) {
|
||||
|
@ -166,7 +162,7 @@ namespace Mesen.Debugger.ViewModels
|
|||
OnClick = () => {
|
||||
SpritePreviewModel? sprite = GetSelectedSprite();
|
||||
if(sprite?.TileAddress >= 0) {
|
||||
MemoryToolsWindow.ShowInMemoryTools(CpuType.GetVramMemoryType(), sprite.TileAddress);
|
||||
MemoryToolsWindow.ShowInMemoryTools(CpuType.GetVramMemoryType(sprite.UseExtendedVram), sprite.TileAddress);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -182,7 +178,7 @@ namespace Mesen.Debugger.ViewModels
|
|||
if(sprite?.TileAddress >= 0 && _palette != null) {
|
||||
DebugPaletteInfo pal = _palette.Get();
|
||||
int paletteOffset = (int)(pal.BgColorCount / pal.ColorsPerPalette);
|
||||
TileViewerWindow.OpenAtTile(CpuType, CpuType.GetVramMemoryType(), sprite.TileAddress, sprite.Format, TileLayout.Normal, sprite.Palette + paletteOffset);
|
||||
TileViewerWindow.OpenAtTile(CpuType, CpuType.GetVramMemoryType(sprite.UseExtendedVram), sprite.TileAddress, sprite.Format, TileLayout.Normal, sprite.Palette + paletteOffset);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -345,16 +341,39 @@ namespace Mesen.Debugger.ViewModels
|
|||
InitGrid(sprites.Length);
|
||||
}
|
||||
|
||||
private byte[] GetExtendedRam(MemoryType baseType, MemoryType extType)
|
||||
{
|
||||
byte[] extRam = DebugApi.GetMemoryState(extType);
|
||||
if(extRam.Length > 0) {
|
||||
byte[] ram = DebugApi.GetMemoryState(baseType);
|
||||
int length = ram.Length;
|
||||
Array.Resize(ref ram, extRam.Length + length);
|
||||
Array.Copy(extRam, 0, ram, length, extRam.Length);
|
||||
return ram;
|
||||
} else {
|
||||
return DebugApi.GetMemoryState(baseType);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] GetVram()
|
||||
{
|
||||
return GetExtendedRam(CpuType.GetVramMemoryType(), CpuType.GetVramMemoryType(getExtendedRam: true));
|
||||
}
|
||||
|
||||
private byte[] GetSpriteRam()
|
||||
{
|
||||
return GetExtendedRam(CpuType.GetSpriteRamMemoryType(), CpuType.GetSpriteRamMemoryType(getExtendedRam: true));
|
||||
}
|
||||
|
||||
public void RefreshData()
|
||||
{
|
||||
_ppuState = DebugApi.GetPpuState(CpuType);
|
||||
_vram = DebugApi.GetMemoryState(CpuType.GetVramMemoryType());
|
||||
|
||||
MemoryType spriteMemType = CpuType.GetSpriteRamMemoryType();
|
||||
int spriteRamSize = DebugApi.GetMemorySize(spriteMemType);
|
||||
_vram = GetVram();
|
||||
|
||||
int spriteRamSize = DebugApi.GetMemorySize(CpuType.GetSpriteRamMemoryType()) + DebugApi.GetMemorySize(CpuType.GetSpriteRamMemoryType(getExtendedRam: true));
|
||||
if(Config.Source == SpriteViewerSource.SpriteRam) {
|
||||
_spriteRam = DebugApi.GetMemoryState(spriteMemType);
|
||||
_spriteRam = GetSpriteRam();
|
||||
} else {
|
||||
MemoryType cpuMemory = CpuType.ToMemoryType();
|
||||
_spriteRam = DebugApi.GetMemoryValues(cpuMemory, (uint)Config.SourceOffset, (uint)(Config.SourceOffset + spriteRamSize - 1));
|
||||
|
@ -472,5 +491,10 @@ namespace Mesen.Debugger.ViewModels
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void OnGameLoaded()
|
||||
{
|
||||
RefreshData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -135,11 +135,6 @@ namespace Mesen.Debugger.ViewModels
|
|||
|
||||
InitForCpuType();
|
||||
|
||||
AddDisposable(this.WhenAnyValue(x => x.CpuType).Subscribe(_ => {
|
||||
InitForCpuType();
|
||||
RefreshData();
|
||||
}));
|
||||
|
||||
AddDisposable(this.WhenAnyValue(x => x.Config.Format).Subscribe(x => {
|
||||
PaletteSelectionMode = GetBitsPerPixel(x) switch {
|
||||
2 => PaletteSelectionMode.FourColors,
|
||||
|
@ -252,10 +247,19 @@ namespace Mesen.Debugger.ViewModels
|
|||
}
|
||||
|
||||
case CpuType.Pce:
|
||||
return new() {
|
||||
new("BG", () => ApplyBgPreset(0)),
|
||||
new("Sprites", () => ApplySpritePreset(0)),
|
||||
};
|
||||
if(DebugApi.GetConsoleState<PceState>(ConsoleType.PcEngine).IsSuperGrafx) {
|
||||
return new() {
|
||||
new("BG1", () => ApplyBgPreset(0)),
|
||||
new("SPR1", () => ApplySpritePreset(0)),
|
||||
new("BG2", () => ApplyBgPreset(1)),
|
||||
new("SPR2", () => ApplySpritePreset(1)),
|
||||
};
|
||||
} else {
|
||||
return new() {
|
||||
new("BG", () => ApplyBgPreset(0)),
|
||||
new("Sprites", () => ApplySpritePreset(0)),
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Exception("Unsupported CPU type");
|
||||
|
@ -386,7 +390,7 @@ namespace Mesen.Debugger.ViewModels
|
|||
}
|
||||
|
||||
case CpuType.Pce: {
|
||||
Config.Source = MemoryType.PceVideoRam;
|
||||
Config.Source = layer == 0 ?MemoryType.PceVideoRam : MemoryType.PceVideoRamVdc2;
|
||||
Config.StartAddress = 0;
|
||||
Config.ColumnCount = 32;
|
||||
Config.RowCount = 64;
|
||||
|
@ -461,7 +465,7 @@ namespace Mesen.Debugger.ViewModels
|
|||
}
|
||||
|
||||
case CpuType.Pce: {
|
||||
Config.Source = MemoryType.PceVideoRam;
|
||||
Config.Source = layer == 0 ? MemoryType.PceVideoRam : MemoryType.PceVideoRamVdc2;
|
||||
Config.StartAddress = 0;
|
||||
Config.ColumnCount = 32;
|
||||
Config.RowCount = 64;
|
||||
|
@ -576,11 +580,6 @@ namespace Mesen.Debugger.ViewModels
|
|||
{
|
||||
_ppuState = DebugApi.GetPpuState(CpuType);
|
||||
|
||||
List<ConfigPreset> presets = GetConfigPresets();
|
||||
if(presets.Count != ConfigPresets.Count) {
|
||||
ConfigPresets = presets;
|
||||
}
|
||||
|
||||
PaletteColors = DebugApi.GetPaletteInfo(CpuType).GetRgbPalette();
|
||||
PaletteColumnCount = PaletteColors.Length > 16 ? 16 : 4;
|
||||
_sourceData = DebugApi.GetMemoryState(Config.Source);
|
||||
|
@ -692,6 +691,12 @@ namespace Mesen.Debugger.ViewModels
|
|||
_ => new PixelSize(8,8),
|
||||
};
|
||||
}
|
||||
|
||||
public void OnGameLoaded()
|
||||
{
|
||||
InitForCpuType();
|
||||
RefreshData();
|
||||
}
|
||||
}
|
||||
|
||||
public class ConfigPreset
|
||||
|
|
|
@ -54,6 +54,7 @@ namespace Mesen.Debugger.ViewModels
|
|||
private byte[]? _prevVram;
|
||||
private byte[] _vram = Array.Empty<byte>();
|
||||
private UInt32[] _palette = Array.Empty<UInt32>();
|
||||
private bool _refreshDataOnTabChange;
|
||||
|
||||
[Obsolete("For designer only")]
|
||||
public TilemapViewerViewModel() : this(CpuType.Snes, new PictureViewer(), null) { }
|
||||
|
@ -116,7 +117,7 @@ namespace Mesen.Debugger.ViewModels
|
|||
OnClick = () => {
|
||||
DebugTilemapTileInfo? tile = GetSelectedTileInfo();
|
||||
if(tile != null && tile.Value.TileMapAddress >= 0) {
|
||||
MemoryToolsWindow.ShowInMemoryTools(CpuType.GetVramMemoryType(), tile.Value.TileMapAddress);
|
||||
MemoryToolsWindow.ShowInMemoryTools(GetVramMemoryType(), tile.Value.TileMapAddress);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -126,7 +127,7 @@ namespace Mesen.Debugger.ViewModels
|
|||
OnClick = () => {
|
||||
DebugTilemapTileInfo? tile = GetSelectedTileInfo();
|
||||
if(tile != null && tile.Value.TileAddress >= 0) {
|
||||
TileViewerWindow.OpenAtTile(CpuType, CpuType.GetVramMemoryType(), tile.Value.TileAddress, _tilemapInfo.Format, TileLayout.Normal, tile.Value.PaletteIndex);
|
||||
TileViewerWindow.OpenAtTile(CpuType, GetVramMemoryType(), tile.Value.TileAddress, _tilemapInfo.Format, TileLayout.Normal, tile.Value.PaletteIndex);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -141,14 +142,14 @@ namespace Mesen.Debugger.ViewModels
|
|||
return;
|
||||
}
|
||||
|
||||
AddDisposable(this.WhenAnyValue(x => x.CpuType).Subscribe(_ => {
|
||||
InitForCpuType();
|
||||
IsNes = CpuType == CpuType.Nes;
|
||||
RefreshData();
|
||||
}));
|
||||
|
||||
AddDisposable(this.WhenAnyValue(x => x.Tabs).Subscribe(x => ShowTabs = x.Count > 1));
|
||||
AddDisposable(this.WhenAnyValue(x => x.SelectedTab).Subscribe(x => RefreshTab()));
|
||||
AddDisposable(this.WhenAnyValue(x => x.SelectedTab).Subscribe(x => {
|
||||
if(_refreshDataOnTabChange) {
|
||||
RefreshData();
|
||||
} else {
|
||||
RefreshTab();
|
||||
}
|
||||
}));
|
||||
AddDisposable(this.WhenAnyValue(x => x.SelectionRect).Subscribe(x => UpdatePreviewPanel()));
|
||||
AddDisposable(ReactiveHelper.RegisterRecursiveObserver(Config, Config_PropertyChanged));
|
||||
|
||||
|
@ -158,6 +159,7 @@ namespace Mesen.Debugger.ViewModels
|
|||
|
||||
private void InitForCpuType()
|
||||
{
|
||||
_refreshDataOnTabChange = false;
|
||||
switch(CpuType) {
|
||||
case CpuType.Snes:
|
||||
Tabs = new List<TilemapViewerTab>() {
|
||||
|
@ -169,12 +171,25 @@ namespace Mesen.Debugger.ViewModels
|
|||
break;
|
||||
|
||||
case CpuType.Nes:
|
||||
case CpuType.Pce:
|
||||
Tabs = new List<TilemapViewerTab>() {
|
||||
new() { Title = "", Layer = 0 }
|
||||
};
|
||||
break;
|
||||
|
||||
case CpuType.Pce:
|
||||
if(DebugApi.GetConsoleState<PceState>(ConsoleType.PcEngine).IsSuperGrafx) {
|
||||
_refreshDataOnTabChange = true;
|
||||
Tabs = new List<TilemapViewerTab>() {
|
||||
new() { Title = "VDC1", Layer = 0 },
|
||||
new() { Title = "VDC2", Layer = 1, VramMemoryType = MemoryType.PceVideoRamVdc2 }
|
||||
};
|
||||
} else {
|
||||
Tabs = new List<TilemapViewerTab>() {
|
||||
new() { Title = "", Layer = 0 }
|
||||
};
|
||||
}
|
||||
break;
|
||||
|
||||
case CpuType.Gameboy:
|
||||
Tabs = new List<TilemapViewerTab>() {
|
||||
new() { Title = "$9800", Layer = 0 },
|
||||
|
@ -239,12 +254,17 @@ namespace Mesen.Debugger.ViewModels
|
|||
};
|
||||
}
|
||||
|
||||
private MemoryType GetVramMemoryType()
|
||||
{
|
||||
return SelectedTab?.VramMemoryType ?? CpuType.GetVramMemoryType();
|
||||
}
|
||||
|
||||
public void RefreshData()
|
||||
{
|
||||
BaseState ppuState = DebugApi.GetPpuState(CpuType);
|
||||
_ppuState = ppuState;
|
||||
_prevVram = _vram;
|
||||
_vram = DebugApi.GetMemoryState(CpuType.GetVramMemoryType());
|
||||
_vram = DebugApi.GetMemoryState(GetVramMemoryType());
|
||||
_palette = DebugApi.GetPaletteInfo(CpuType).GetRgbPalette();
|
||||
|
||||
RefreshTab();
|
||||
|
@ -386,12 +406,20 @@ namespace Mesen.Debugger.ViewModels
|
|||
return new DynamicTooltip() { Items = entries };
|
||||
}
|
||||
}
|
||||
|
||||
public void OnGameLoaded()
|
||||
{
|
||||
InitForCpuType();
|
||||
IsNes = CpuType == CpuType.Nes;
|
||||
RefreshData();
|
||||
}
|
||||
}
|
||||
|
||||
public class TilemapViewerTab : ViewModelBase
|
||||
{
|
||||
[Reactive] public string Title { get; set; } = "";
|
||||
[Reactive] public int Layer { get; set; } = 0;
|
||||
[Reactive] public MemoryType? VramMemoryType { get; set; }
|
||||
[Reactive] public bool Enabled { get; set; } = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,11 +43,6 @@ namespace Mesen.Debugger.Windows
|
|||
|
||||
public void ProcessNotification(NotificationEventArgs e)
|
||||
{
|
||||
if(e.NotificationType == ConsoleNotificationType.GameLoaded) {
|
||||
_model.UpdateRomInfo();
|
||||
_model.RefreshData();
|
||||
}
|
||||
|
||||
ToolRefreshHelper.ProcessNotification(this, e, _model.RefreshTiming, _model, _model.RefreshData);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,24 +20,24 @@ namespace Mesen.Interop
|
|||
};
|
||||
}
|
||||
|
||||
public static MemoryType GetVramMemoryType(this CpuType cpuType)
|
||||
public static MemoryType GetVramMemoryType(this CpuType cpuType, bool getExtendedRam = false)
|
||||
{
|
||||
return cpuType switch {
|
||||
CpuType.Snes => MemoryType.SnesVideoRam,
|
||||
CpuType.Gameboy => MemoryType.GbVideoRam,
|
||||
CpuType.Nes => MemoryType.NesPpuMemory,
|
||||
CpuType.Pce => MemoryType.PceVideoRam,
|
||||
CpuType.Pce => getExtendedRam ? MemoryType.PceVideoRamVdc2 : MemoryType.PceVideoRam,
|
||||
_ => throw new Exception("Invalid CPU type"),
|
||||
};
|
||||
}
|
||||
|
||||
public static MemoryType GetSpriteRamMemoryType(this CpuType cpuType)
|
||||
public static MemoryType GetSpriteRamMemoryType(this CpuType cpuType, bool getExtendedRam = false)
|
||||
{
|
||||
return cpuType switch {
|
||||
CpuType.Snes => MemoryType.SnesSpriteRam,
|
||||
CpuType.Gameboy => MemoryType.GbSpriteRam,
|
||||
CpuType.Nes => MemoryType.NesSpriteRam,
|
||||
CpuType.Pce => MemoryType.PceSpriteRam,
|
||||
CpuType.Pce => getExtendedRam ? MemoryType.PceSpriteRamVdc2 : MemoryType.PceSpriteRam,
|
||||
_ => throw new Exception("Invalid CPU type"),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -110,7 +110,7 @@ namespace Mesen.Interop
|
|||
CpuType.Snes => GetPpuState<SnesPpuState>(cpuType),
|
||||
CpuType.Nes => GetPpuState<NesPpuState>(cpuType),
|
||||
CpuType.Gameboy => GetPpuState<GbPpuState>(cpuType),
|
||||
CpuType.Pce => GetPpuState<PceVdcState>(cpuType),
|
||||
CpuType.Pce => GetPpuState<PceVideoState>(cpuType),
|
||||
_ => throw new Exception("Unsupport cpu type")
|
||||
};
|
||||
}
|
||||
|
@ -442,7 +442,7 @@ namespace Mesen.Interop
|
|||
ConsoleType.Snes => state is SnesPpuState,
|
||||
ConsoleType.Nes => state is NesPpuState,
|
||||
ConsoleType.Gameboy => state is GbPpuState,
|
||||
ConsoleType.PcEngine => state is PceVdcState,
|
||||
ConsoleType.PcEngine => state is PceVideoState,
|
||||
_ => false
|
||||
};
|
||||
}
|
||||
|
@ -504,8 +504,10 @@ namespace Mesen.Interop
|
|||
PceCardRam,
|
||||
PceAdpcmRam,
|
||||
PceVideoRam,
|
||||
PcePaletteRam,
|
||||
PceVideoRamVdc2,
|
||||
PceSpriteRam,
|
||||
PceSpriteRamVdc2,
|
||||
PcePaletteRam,
|
||||
|
||||
Register
|
||||
}
|
||||
|
@ -870,6 +872,7 @@ namespace Mesen.Interop
|
|||
[MarshalAs(UnmanagedType.I1)] public bool HorizontalMirror;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool VerticalMirror;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool Visible;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool UseExtendedVram;
|
||||
public NullableBoolean UseSecondTable;
|
||||
|
||||
public fixed UInt32 SpritePreview[64*64];
|
||||
|
|
|
@ -1457,15 +1457,58 @@ namespace Mesen.Interop
|
|||
public byte NoiseFrequency;
|
||||
}
|
||||
|
||||
public enum PceVpcPriorityMode
|
||||
{
|
||||
Default = 0,
|
||||
Vdc1SpritesBelowVdc2Bg = 1,
|
||||
Vdc2SpritesAboveVdc1Bg = 2,
|
||||
}
|
||||
|
||||
public enum PceVpcPixelWindow
|
||||
{
|
||||
NoWindow,
|
||||
Window1,
|
||||
Window2,
|
||||
Both
|
||||
}
|
||||
|
||||
public struct PceVpcPriorityConfig
|
||||
{
|
||||
public PceVpcPriorityMode PriorityMode;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool Vdc1Enabled;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool Vdc2Enabled;
|
||||
}
|
||||
|
||||
public struct PceVpcState
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||
public PceVpcPriorityConfig[] WindowCfg;
|
||||
public byte Priority1;
|
||||
public byte Priority2;
|
||||
public UInt16 Window1;
|
||||
public UInt16 Window2;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool StToVdc2Mode;
|
||||
}
|
||||
|
||||
public struct PceVideoState : BaseState
|
||||
{
|
||||
public PceVdcState Vdc;
|
||||
public PceVceState Vce;
|
||||
public PceVpcState Vpc;
|
||||
public PceVdcState Vdc2;
|
||||
}
|
||||
|
||||
public struct PceState : BaseState
|
||||
{
|
||||
public PceCpuState Cpu;
|
||||
public PceVdcState Vdc;
|
||||
public PceVceState Vce;
|
||||
public PceVideoState Video;
|
||||
|
||||
public PceMemoryManager MemoryManager;
|
||||
public PcePsgState Psg;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
||||
public PcePsgChannelState[] PsgChannels;
|
||||
|
||||
[MarshalAs(UnmanagedType.I1)] public bool IsSuperGrafx;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,8 +74,10 @@ namespace Mesen.Interop
|
|||
case MemoryType.PceCardRam:
|
||||
case MemoryType.PceAdpcmRam:
|
||||
case MemoryType.PceVideoRam:
|
||||
case MemoryType.PceVideoRamVdc2:
|
||||
case MemoryType.PcePaletteRam:
|
||||
case MemoryType.PceSpriteRam:
|
||||
case MemoryType.PceSpriteRamVdc2:
|
||||
return CpuType.Pce;
|
||||
|
||||
default:
|
||||
|
@ -102,8 +104,10 @@ namespace Mesen.Interop
|
|||
case MemoryType.NesPaletteRam:
|
||||
|
||||
case MemoryType.PceVideoRam:
|
||||
case MemoryType.PceVideoRamVdc2:
|
||||
case MemoryType.PcePaletteRam:
|
||||
case MemoryType.PceSpriteRam:
|
||||
case MemoryType.PceSpriteRamVdc2:
|
||||
return true;
|
||||
|
||||
default:
|
||||
|
@ -271,8 +275,10 @@ namespace Mesen.Interop
|
|||
MemoryType.PceCardRam => "Card RAM",
|
||||
MemoryType.PceAdpcmRam => "ADPCM",
|
||||
MemoryType.PceVideoRam => "VRAM",
|
||||
MemoryType.PceVideoRamVdc2 => "VRAM2",
|
||||
MemoryType.PcePaletteRam => "PAL",
|
||||
MemoryType.PceSpriteRam=> "SPR",
|
||||
MemoryType.PceSpriteRam => "SPR",
|
||||
MemoryType.PceSpriteRamVdc2 => "SPR2",
|
||||
|
||||
MemoryType.Register => "REG",
|
||||
|
||||
|
|
|
@ -377,7 +377,9 @@
|
|||
<Control ID="lblMiscSettings">Miscellaneous Settings</Control>
|
||||
<Control ID="chkRemoveSpriteLimit">Remove sprite limit</Control>
|
||||
<Control ID="chkDisableBackground">Disable background</Control>
|
||||
<Control ID="chkDisableBackgroundVdc2">Disable background (VDC2 - SuperGrafx)</Control>
|
||||
<Control ID="chkDisableSprites">Disable sprites</Control>
|
||||
<Control ID="chkDisableSpritesVdc2">Disable sprites (VDC2 - SuperGrafx)</Control>
|
||||
|
||||
<Control ID="lblPalette">Palette</Control>
|
||||
</Form>
|
||||
|
@ -1891,9 +1893,11 @@
|
|||
<Value ID="PceCardRam">Card RAM</Value>
|
||||
<Value ID="PceAdpcmRam">ADPCM RAM</Value>
|
||||
<Value ID="PceVideoRam">Video RAM</Value>
|
||||
<Value ID="PceVideoRamVdc2">Video RAM (VDC2)</Value>
|
||||
<Value ID="PcePaletteRam">Palette RAM</Value>
|
||||
<Value ID="PceSpriteRam">Sprite RAM</Value>
|
||||
|
||||
<Value ID="PceSpriteRamVdc2">Sprite RAM (VDC2)</Value>
|
||||
|
||||
<Value ID="Register">Register</Value>
|
||||
</Enum>
|
||||
<Enum ID="GameboyModel">
|
||||
|
|
|
@ -82,7 +82,9 @@
|
|||
<c:OptionSection Header="{l:Translate lblMiscSettings}" Margin="0">
|
||||
<CheckBox IsChecked="{CompiledBinding Config.RemoveSpriteLimit}" Content="{l:Translate chkRemoveSpriteLimit}" />
|
||||
<c:CheckBoxWarning IsChecked="{CompiledBinding Config.DisableBackground}" Text="{l:Translate chkDisableBackground}" />
|
||||
<c:CheckBoxWarning IsChecked="{CompiledBinding Config.DisableSprites}" Text="{l:Translate chkDisableSprites}" />
|
||||
<c:CheckBoxWarning IsChecked="{CompiledBinding Config.DisableSprites}" Text="{l:Translate chkDisableSprites}" />
|
||||
<c:CheckBoxWarning IsChecked="{CompiledBinding Config.DisableBackgroundVdc2}" Text="{l:Translate chkDisableBackgroundVdc2}" />
|
||||
<c:CheckBoxWarning IsChecked="{CompiledBinding Config.DisableSpritesVdc2}" Text="{l:Translate chkDisableSpritesVdc2}" />
|
||||
</c:OptionSection>
|
||||
<c:OptionSection Header="{l:Translate lblPalette}">
|
||||
<c:PaletteConfig
|
||||
|
|
|
@ -40,6 +40,11 @@ uint32_t CRC32::GetCRC(uint8_t* buffer, std::streamoff length)
|
|||
return crc32_16bytes(buffer, length, 0);
|
||||
}
|
||||
|
||||
uint32_t CRC32::GetCRC(vector<uint8_t> data)
|
||||
{
|
||||
return crc32_16bytes(data.data(), (std::streamoff)data.size(), 0);
|
||||
}
|
||||
|
||||
uint32_t CRC32::GetCRC(string filename)
|
||||
{
|
||||
uint32_t crc = 0;
|
||||
|
|
|
@ -8,5 +8,6 @@ private:
|
|||
|
||||
public:
|
||||
static uint32_t GetCRC(uint8_t* buffer, std::streamoff length);
|
||||
static uint32_t GetCRC(vector<uint8_t> data);
|
||||
static uint32_t GetCRC(string filename);
|
||||
};
|
Loading…
Add table
Reference in a new issue