PCE: Arcade card support

This commit is contained in:
Sour 2022-05-18 18:23:34 -04:00
parent 0a6a8e92b2
commit e137a3f979
15 changed files with 330 additions and 18 deletions

View file

@ -19,6 +19,8 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="PCE\IPceMapper.h" />
<ClInclude Include="PCE\PceArcadeCard.h" />
<ClInclude Include="PCE\PceVpc.h" />
<ClInclude Include="PCE\Input\PceAvenuePad6.h" />
<ClInclude Include="PCE\Input\PceTurboTap.h" />
@ -456,6 +458,7 @@
<ClCompile Include="PCE\Debugger\PceVdcTools.cpp" />
<ClCompile Include="PCE\Debugger\PceTraceLogger.cpp" />
<ClCompile Include="PCE\PceAdpcm.cpp" />
<ClCompile Include="PCE\PceArcadeCard.cpp" />
<ClCompile Include="PCE\PceCdAudioPlayer.cpp" />
<ClCompile Include="PCE\PceCdRom.cpp" />
<ClCompile Include="PCE\PceConsole.cpp" />

View file

@ -1817,6 +1817,12 @@
<ClInclude Include="PCE\PceVpc.h">
<Filter>PCE</Filter>
</ClInclude>
<ClInclude Include="PCE\IPceMapper.h">
<Filter>PCE</Filter>
</ClInclude>
<ClInclude Include="PCE\PceArcadeCard.h">
<Filter>PCE</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Shared\Video\RotateFilter.cpp">
@ -1898,6 +1904,9 @@
<Filter>PCE</Filter>
</ClCompile>
<ClCompile Include="PCE\PceVpc.cpp" />
<ClCompile Include="PCE\PceArcadeCard.cpp">
<Filter>PCE</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="PCE">

View file

@ -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:

View file

@ -55,6 +55,7 @@ enum class MemoryType
PceCdromRam,
PceCardRam,
PceAdpcmRam,
PceArcadeCardRam,
PceVideoRam,
PceVideoRamVdc2,
PceSpriteRam,

9
Core/PCE/IPceMapper.h Normal file
View file

@ -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) {}
};

208
Core/PCE/PceArcadeCard.cpp Normal file
View file

@ -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);
}
}

32
Core/PCE/PceArcadeCard.h Normal file
View file

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

View file

@ -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));

View file

@ -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<PceSf2RomMapper> _mapper;
unique_ptr<IPceMapper> _mapper;
unique_ptr<PceTimer> _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<CpuType::Pce>()) {
_cheatManager->ApplyCheat<CpuType::Pce>((bank << 13) | (addr & 0x1FFF), value);
}
@ -349,11 +359,11 @@ public:
{
_emu->ProcessMemoryWrite<CpuType::Pce>(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]) {

View file

@ -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;

View file

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

View file

@ -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;

View file

@ -503,6 +503,7 @@ namespace Mesen.Interop
PceCdromRam,
PceCardRam,
PceAdpcmRam,
PceArcadeCardRam,
PceVideoRam,
PceVideoRamVdc2,
PceSpriteRam,

View file

@ -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",

View file

@ -1766,7 +1766,7 @@
<Enum ID="PceCdRomType">
<Value ID="CdRom">CD-ROM²</Value>
<Value ID="SuperCdRom">Super CD-ROM²</Value>
<Value ID="Arcade">Arcade CD-ROM²</Value>
<Value ID="Arcade">Arcade CD-ROM² (recommended)</Value>
</Enum>
<Enum ID="RamState">
<Value ID="Random">Random Values (Default)</Value>
@ -1892,6 +1892,7 @@
<Value ID="PceCdromRam">CD-ROM RAM</Value>
<Value ID="PceCardRam">Card RAM</Value>
<Value ID="PceAdpcmRam">ADPCM RAM</Value>
<Value ID="PceArcadeCardRam">Arcade Card RAM</Value>
<Value ID="PceVideoRam">Video RAM</Value>
<Value ID="PceVideoRamVdc2">Video RAM (VDC2)</Value>
<Value ID="PcePaletteRam">Palette RAM</Value>