From e137a3f9796d21ceee820c18772293abf696efd9 Mon Sep 17 00:00:00 2001 From: Sour Date: Wed, 18 May 2022 18:23:34 -0400 Subject: [PATCH] PCE: Arcade card support --- Core/Core.vcxproj | 3 + Core/Core.vcxproj.filters | 9 ++ Core/Debugger/DebugUtilities.h | 1 + Core/MemoryType.h | 1 + Core/PCE/IPceMapper.h | 9 ++ Core/PCE/PceArcadeCard.cpp | 208 ++++++++++++++++++++++++++ Core/PCE/PceArcadeCard.h | 32 ++++ Core/PCE/PceCdRom.cpp | 11 +- Core/PCE/PceMemoryManager.h | 30 ++-- Core/PCE/PceSf2RomMapper.cpp | 2 +- Core/PCE/PceSf2RomMapper.h | 5 +- Core/PCE/PceTypes.h | 31 ++++ NewUI/Interop/DebugApi.cs | 1 + NewUI/Interop/MemoryTypeExtensions.cs | 2 + NewUI/Localization/resources.en.xml | 3 +- 15 files changed, 330 insertions(+), 18 deletions(-) create mode 100644 Core/PCE/IPceMapper.h create mode 100644 Core/PCE/PceArcadeCard.cpp create mode 100644 Core/PCE/PceArcadeCard.h diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 26c19d0d..a65aa76e 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -19,6 +19,8 @@ + + @@ -456,6 +458,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index e415dab3..3d858970 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -1817,6 +1817,12 @@ PCE + + PCE + + + PCE + @@ -1898,6 +1904,9 @@ PCE + + PCE + diff --git a/Core/Debugger/DebugUtilities.h b/Core/Debugger/DebugUtilities.h index f455d7d1..580cd38a 100644 --- a/Core/Debugger/DebugUtilities.h +++ b/Core/Debugger/DebugUtilities.h @@ -109,6 +109,7 @@ public: case MemoryType::PceCdromRam: case MemoryType::PceCardRam: case MemoryType::PceAdpcmRam: + case MemoryType::PceArcadeCardRam: case MemoryType::PceVideoRam: case MemoryType::PceVideoRamVdc2: case MemoryType::PcePaletteRam: diff --git a/Core/MemoryType.h b/Core/MemoryType.h index 748768e6..e7502bb9 100644 --- a/Core/MemoryType.h +++ b/Core/MemoryType.h @@ -55,6 +55,7 @@ enum class MemoryType PceCdromRam, PceCardRam, PceAdpcmRam, + PceArcadeCardRam, PceVideoRam, PceVideoRamVdc2, PceSpriteRam, diff --git a/Core/PCE/IPceMapper.h b/Core/PCE/IPceMapper.h new file mode 100644 index 00000000..469019f6 --- /dev/null +++ b/Core/PCE/IPceMapper.h @@ -0,0 +1,9 @@ +#pragma once +#include "stdafx.h" + +class IPceMapper +{ +public: + virtual uint8_t Read(uint8_t bank, uint16_t addr, uint8_t value) { return value; } + virtual void Write(uint8_t bank, uint16_t addr, uint8_t value) {} +}; diff --git a/Core/PCE/PceArcadeCard.cpp b/Core/PCE/PceArcadeCard.cpp new file mode 100644 index 00000000..3b1fe8cd --- /dev/null +++ b/Core/PCE/PceArcadeCard.cpp @@ -0,0 +1,208 @@ +#include "stdafx.h" +#include "PCE/PceArcadeCard.h" +#include "Shared/EmuSettings.h" +#include "Shared/Emulator.h" + +PceArcadeCard::PceArcadeCard(Emulator* emu) +{ + _state = {}; + _ram = new uint8_t[PceArcadeCard::ArcadeRamMemSize]; + emu->GetSettings()->InitializeRam(_ram, PceArcadeCard::ArcadeRamMemSize); + emu->RegisterMemory(MemoryType::PceArcadeCardRam, _ram, PceArcadeCard::ArcadeRamMemSize); +} + +PceArcadeCard::~PceArcadeCard() +{ + delete[] _ram; +} + +uint32_t PceArcadeCard::GetAddress(PceArcadeCardPortConfig& port) +{ + uint32_t addr = port.BaseAddress; + if(port.AddOffset) { + addr += port.Offset; + if(port.SignedOffset) { + addr += 0xFF0000; + } + } + return addr & 0x1FFFFF; +} + +void PceArcadeCard::ProcessAutoInc(PceArcadeCardPortConfig& port) +{ + if(port.AutoIncrement) { + if(port.AddIncrementToBase) { + port.BaseAddress = (port.BaseAddress + port.IncValue) & 0xFFFFFF; + } else { + port.Offset += port.IncValue; + } + } +} + +void PceArcadeCard::AddOffsetToBase(PceArcadeCardPortConfig& port) +{ + uint32_t addr = port.BaseAddress + port.Offset; + if(port.SignedOffset) { + addr += 0xFF0000; + } + port.BaseAddress = addr & 0xFFFFFF; +} + +uint8_t PceArcadeCard::ReadPortValue(uint8_t portNumber) +{ + PceArcadeCardPortConfig& port = _state.Port[portNumber]; + uint32_t addr = GetAddress(port); + ProcessAutoInc(port); + return _ram[addr]; +} + +void PceArcadeCard::WritePortValue(uint8_t portNumber, uint8_t value) +{ + PceArcadeCardPortConfig& port = _state.Port[portNumber]; + uint32_t addr = GetAddress(port); + ProcessAutoInc(port); + _ram[addr] = value; +} + +uint8_t PceArcadeCard::ReadPortRegister(uint8_t portNumber, uint8_t reg) +{ + PceArcadeCardPortConfig& port = _state.Port[portNumber]; + switch(reg) { + case 0x00: + case 0x01: + return ReadPortValue(portNumber); + + case 0x02: return port.BaseAddress & 0xFF; + case 0x03: return (port.BaseAddress >> 8) & 0xFF; + case 0x04: return (port.BaseAddress >> 16) & 0xFF; + case 0x05: return port.Offset & 0xFF; + case 0x06: return (port.Offset >> 8) & 0xFF; + case 0x07: return port.IncValue & 0xFF; + case 0x08: return (port.IncValue >> 8) & 0xFF; + case 0x09: return port.Control; + case 0x0A: return 0; + default: return 0xFF; + } +} + +void PceArcadeCard::WritePortRegister(uint8_t portNumber, uint8_t reg, uint8_t value) +{ + PceArcadeCardPortConfig& port = _state.Port[portNumber]; + switch(reg) { + case 0x00: + case 0x01: + WritePortValue(portNumber, value); + break; + + case 0x02: port.BaseAddress = (port.BaseAddress & 0xFFFF00) | value; break; + case 0x03: port.BaseAddress = (port.BaseAddress & 0xFF00FF) | (value << 8); break; + case 0x04: port.BaseAddress = (port.BaseAddress & 0x00FFFF) | (value << 16); break; + + case 0x05: + port.Offset = (port.Offset & 0xFF00) | value; + if(port.AddOffsetTrigger == PceArcadePortOffsetTrigger::AddOnLowWrite) { + AddOffsetToBase(port); + } + break; + + case 0x06: + port.Offset = (port.Offset & 0x00FF) | (value << 8); + if(port.AddOffsetTrigger == PceArcadePortOffsetTrigger::AddOnHighWrite) { + AddOffsetToBase(port); + } + break; + + case 0x07: port.IncValue = (port.IncValue & 0xFF00) | value; break; + case 0x08: port.IncValue = (port.IncValue & 0x00FF) | (value << 8); break; + + case 0x09: + port.Control = value & 0x7F; //bit 7 is unused? + port.AutoIncrement = (value & 0x01) != 0; + port.AddOffset = (value & 0x02) != 0; + port.SignedIncrement = (value & 0x04) != 0; //not used? + port.SignedOffset = (value & 0x08) != 0; + port.AddIncrementToBase = (value & 0x10) != 0; + port.AddOffsetTrigger = (PceArcadePortOffsetTrigger)((value & 0x60) >> 5); + break; + + case 0x0A: + if(port.AddOffsetTrigger == PceArcadePortOffsetTrigger::AddOnReg0AWrite) { + AddOffsetToBase(port); + } + break; + } +} + +uint8_t PceArcadeCard::Read(uint8_t bank, uint16_t addr, uint8_t value) +{ + if(bank == 0xFF) { + addr &= 0x1FFF; + + if(addr >= 0x1A00 && addr <= 0x1A3F) { + return ReadPortRegister((addr & 0x30) >> 4, addr & 0x0F); + } else { + switch(addr) { + case 0x1AE0: return _state.ValueReg & 0xFF; + case 0x1AE1: return (_state.ValueReg >> 8) & 0xFF; + case 0x1AE2: return (_state.ValueReg >> 16) & 0xFF; + case 0x1AE3: return (_state.ValueReg >> 24) & 0xFF; + + case 0x1AE4: return _state.ShiftReg; + case 0x1AE5: return _state.RotateReg; + + //Arcade card version+signature + case 0x1AFE: return 0x10; + case 0x1AFF: return 0x51; + } + } + } else if(bank >= 0x40 && bank <= 0x43) { + return ReadPortValue(bank & 0x03); + } + + return value; +} + +void PceArcadeCard::Write(uint8_t bank, uint16_t addr, uint8_t value) +{ + if(bank == 0xFF) { + addr &= 0x1FFF; + + if(addr >= 0x1A00 && addr <= 0x1A3F) { + WritePortRegister((addr & 0x30) >> 4, addr & 0x0F, value); + } else { + switch(addr) { + case 0x1AE0: _state.ValueReg = (_state.ValueReg & 0xFFFFFF00) | value; break; + case 0x1AE1: _state.ValueReg = (_state.ValueReg & 0xFFFF00FF) | (value << 8); break; + case 0x1AE2: _state.ValueReg = (_state.ValueReg & 0xFF00FFFF) | (value << 16); break; + case 0x1AE3: _state.ValueReg = (_state.ValueReg & 0x00FFFFFF) | (value << 24); break; + + case 0x1AE4: + _state.ShiftReg = value; + if(value) { + if(value & 0x08) { + _state.ValueReg >>= ~(value & 0x07) + 1; + } else { + _state.ValueReg <<= (value & 0x07); + } + } + break; + + case 0x1AE5: + //untested + _state.RotateReg = value; + if(value) { + if(value & 0x08) { + uint8_t rotateRight = ~(value & 0x07) + 1; + _state.ValueReg = (_state.ValueReg >> rotateRight) | (_state.ValueReg << (32 - rotateRight)); + } else { + uint8_t rotateLeft = (value & 0x07); + _state.ValueReg = (_state.ValueReg << rotateLeft) | (_state.ValueReg >> (32 - rotateLeft)); + } + } + break; + } + } + } else if(bank >= 0x40 && bank <= 0x43) { + WritePortValue(bank & 0x03, value); + } +} diff --git a/Core/PCE/PceArcadeCard.h b/Core/PCE/PceArcadeCard.h new file mode 100644 index 00000000..76230c54 --- /dev/null +++ b/Core/PCE/PceArcadeCard.h @@ -0,0 +1,32 @@ +#pragma once +#include "stdafx.h" +#include "PCE/IPceMapper.h" +#include "PCE/PceTypes.h" + +class Emulator; + +class PceArcadeCard final : public IPceMapper +{ +private: + static constexpr int ArcadeRamMemSize = 0x200000; + + PceArcadeCardState _state; + uint8_t* _ram = nullptr; + + uint32_t GetAddress(PceArcadeCardPortConfig& port); + void ProcessAutoInc(PceArcadeCardPortConfig& port); + void AddOffsetToBase(PceArcadeCardPortConfig& port); + + uint8_t ReadPortValue(uint8_t portNumber); + void WritePortValue(uint8_t portNumber, uint8_t value); + + uint8_t ReadPortRegister(uint8_t portNumber, uint8_t reg); + void WritePortRegister(uint8_t portNumber, uint8_t reg, uint8_t value); + +public: + PceArcadeCard(Emulator* emu); + virtual ~PceArcadeCard(); + + uint8_t Read(uint8_t bank, uint16_t addr, uint8_t value) override; + void Write(uint8_t bank, uint16_t addr, uint8_t value) override; +}; diff --git a/Core/PCE/PceCdRom.cpp b/Core/PCE/PceCdRom.cpp index addea876..78f4f526 100644 --- a/Core/PCE/PceCdRom.cpp +++ b/Core/PCE/PceCdRom.cpp @@ -152,10 +152,13 @@ uint8_t PceCdRom::Read(uint16_t addr) case 0x0C: case 0x0D: case 0x0E: case 0x0F: return _adpcm.Read(addr); - case 0xC0: return 0x00; - case 0xC1: return 0xAA; - case 0xC2: return 0x55; - case 0xC3: return 0x03; + case 0xC0: case 0xC1: case 0xC2: case 0xC3: + if(_emu->GetSettings()->GetPcEngineConfig().CdRomType == PceCdRomType::CdRom) { + return 0xFF; + } else { + constexpr uint8_t superCdRomSignature[4] = { 0x00, 0xAA, 0x55, 0x03 }; + return superCdRomSignature[addr & 0x03]; + } default: LogDebug("Read unknown CDROM register: " + HexUtilities::ToHex(addr)); diff --git a/Core/PCE/PceMemoryManager.h b/Core/PCE/PceMemoryManager.h index ab694de7..fb517a55 100644 --- a/Core/PCE/PceMemoryManager.h +++ b/Core/PCE/PceMemoryManager.h @@ -7,6 +7,8 @@ #include "PCE/PceTimer.h" #include "PCE/PcePsg.h" #include "PCE/PceControlManager.h" +#include "PCE/IPceMapper.h" +#include "PCE/PceArcadeCard.h" #include "PCE/PceSf2RomMapper.h" #include "PCE/PceCdRom.h" #include "Debugger/DebugTypes.h" @@ -31,7 +33,7 @@ private: PcePsg* _psg = nullptr; PceControlManager* _controlManager = nullptr; PceCdRom* _cdrom = nullptr; - unique_ptr _mapper; + unique_ptr _mapper; unique_ptr _timer; PceMemoryManagerState _state = {}; @@ -103,14 +105,15 @@ public: if(_cdrom) { _cdromRamSize = 0x10000; _cdromRam = new uint8_t[_cdromRamSize]; - - _cardRamSize = 0x30000; - _cardRam = new uint8_t[_cardRamSize]; - _emu->GetSettings()->InitializeRam(_cdromRam, _cdromRamSize); - _emu->GetSettings()->InitializeRam(_cardRam, _cardRamSize); _emu->RegisterMemory(MemoryType::PceCdromRam, _cdromRam, _cdromRamSize); - _emu->RegisterMemory(MemoryType::PceCardRam, _cardRam, _cardRamSize); + + if(cfg.CdRomType == PceCdRomType::SuperCdRom || cfg.CdRomType == PceCdRomType::Arcade) { + _cardRamSize = 0x30000; + _cardRam = new uint8_t[_cardRamSize]; + _emu->GetSettings()->InitializeRam(_cardRam, _cardRamSize); + _emu->RegisterMemory(MemoryType::PceCardRam, _cardRam, _cardRamSize); + } } _emu->RegisterMemory(MemoryType::PcePrgRom, _prgRom, _prgRomSize); @@ -154,7 +157,9 @@ public: UpdateMappings(bankOffsets); } - if(_prgRomSize > 0x80 * 0x2000) { + if(_cdrom && cfg.CdRomType == PceCdRomType::Arcade) { + _mapper.reset(new PceArcadeCard(emu)); + } else if(_prgRomSize > 0x80 * 0x2000) { //For ROMs over 1MB, assume this is the SF2 board _mapper.reset(new PceSf2RomMapper(this)); } @@ -327,6 +332,11 @@ public: } else { value = ReadRegister(addr & 0x1FFF); } + + if(_mapper) { + value = _mapper->Read(bank, addr, value); + } + if(_cheatManager->HasCheats()) { _cheatManager->ApplyCheat((bank << 13) | (addr & 0x1FFF), value); } @@ -349,11 +359,11 @@ public: { _emu->ProcessMemoryWrite(addr, value, type); + uint8_t bank = _state.Mpr[(addr & 0xE000) >> 13]; if(_mapper) { - _mapper->Write(addr, value); + _mapper->Write(bank, addr, value); } - uint8_t bank = _state.Mpr[(addr & 0xE000) >> 13]; addr &= 0x1FFF; if(bank != 0xFF) { if(_writeBanks[bank]) { diff --git a/Core/PCE/PceSf2RomMapper.cpp b/Core/PCE/PceSf2RomMapper.cpp index 7ded9c80..44a401bf 100644 --- a/Core/PCE/PceSf2RomMapper.cpp +++ b/Core/PCE/PceSf2RomMapper.cpp @@ -7,7 +7,7 @@ PceSf2RomMapper::PceSf2RomMapper(PceMemoryManager* memoryManager) _memoryManager = memoryManager; } -void PceSf2RomMapper::Write(uint16_t addr, uint8_t value) +void PceSf2RomMapper::Write(uint8_t bank, uint16_t addr, uint8_t value) { if((addr & 0x1FFC) == 0x1FF0) { _selectedBank = addr & 0x03; diff --git a/Core/PCE/PceSf2RomMapper.h b/Core/PCE/PceSf2RomMapper.h index 08221fb7..a8e18de2 100644 --- a/Core/PCE/PceSf2RomMapper.h +++ b/Core/PCE/PceSf2RomMapper.h @@ -1,9 +1,10 @@ #pragma once #include "stdafx.h" +#include "PCE/IPceMapper.h" class PceMemoryManager; -class PceSf2RomMapper +class PceSf2RomMapper : public IPceMapper { private: uint8_t _selectedBank = 0; @@ -11,5 +12,5 @@ private: public: PceSf2RomMapper(PceMemoryManager* memoryManager); - void Write(uint16_t addr, uint8_t value); + void Write(uint8_t bank, uint16_t addr, uint8_t value) override; }; diff --git a/Core/PCE/PceTypes.h b/Core/PCE/PceTypes.h index 0a4557e0..772aa49d 100644 --- a/Core/PCE/PceTypes.h +++ b/Core/PCE/PceTypes.h @@ -252,6 +252,37 @@ struct PceVideoState : BaseState PceVdcState Vdc2; }; +enum class PceArcadePortOffsetTrigger +{ + None = 0, + AddOnLowWrite = 1, + AddOnHighWrite = 2, + AddOnReg0AWrite = 3, +}; + +struct PceArcadeCardPortConfig +{ + uint32_t BaseAddress; + uint16_t Offset; + uint16_t IncValue; + + uint8_t Control; + bool AutoIncrement; + bool AddOffset; + bool SignedIncrement; //unused? + bool SignedOffset; + bool AddIncrementToBase; + PceArcadePortOffsetTrigger AddOffsetTrigger; +}; + +struct PceArcadeCardState +{ + PceArcadeCardPortConfig Port[4]; + uint32_t ValueReg; + uint8_t ShiftReg; + uint8_t RotateReg; +}; + struct PceState { PceCpuState Cpu; diff --git a/NewUI/Interop/DebugApi.cs b/NewUI/Interop/DebugApi.cs index 49173646..b4cb2d26 100644 --- a/NewUI/Interop/DebugApi.cs +++ b/NewUI/Interop/DebugApi.cs @@ -503,6 +503,7 @@ namespace Mesen.Interop PceCdromRam, PceCardRam, PceAdpcmRam, + PceArcadeCardRam, PceVideoRam, PceVideoRamVdc2, PceSpriteRam, diff --git a/NewUI/Interop/MemoryTypeExtensions.cs b/NewUI/Interop/MemoryTypeExtensions.cs index 6a94e318..ac50af05 100644 --- a/NewUI/Interop/MemoryTypeExtensions.cs +++ b/NewUI/Interop/MemoryTypeExtensions.cs @@ -73,6 +73,7 @@ namespace Mesen.Interop case MemoryType.PceCdromRam: case MemoryType.PceCardRam: case MemoryType.PceAdpcmRam: + case MemoryType.PceArcadeCardRam: case MemoryType.PceVideoRam: case MemoryType.PceVideoRamVdc2: case MemoryType.PcePaletteRam: @@ -274,6 +275,7 @@ namespace Mesen.Interop MemoryType.PceCdromRam => "CDRAM", MemoryType.PceCardRam => "Card RAM", MemoryType.PceAdpcmRam => "ADPCM", + MemoryType.PceArcadeCardRam => "ARC", MemoryType.PceVideoRam => "VRAM", MemoryType.PceVideoRamVdc2 => "VRAM2", MemoryType.PcePaletteRam => "PAL", diff --git a/NewUI/Localization/resources.en.xml b/NewUI/Localization/resources.en.xml index 730780a9..36d5365f 100644 --- a/NewUI/Localization/resources.en.xml +++ b/NewUI/Localization/resources.en.xml @@ -1766,7 +1766,7 @@ CD-ROM² Super CD-ROM² - Arcade CD-ROM² + Arcade CD-ROM² (recommended) Random Values (Default) @@ -1892,6 +1892,7 @@ CD-ROM RAM Card RAM ADPCM RAM + Arcade Card RAM Video RAM Video RAM (VDC2) Palette RAM