mirror of
https://github.com/SourMesen/Mesen2.git
synced 2025-04-02 10:21:44 -04:00
275 lines
8 KiB
C++
275 lines
8 KiB
C++
#include "pch.h"
|
|
#include "PCE/CdRom/PceArcadeCard.h"
|
|
#include "PCE/PceConsole.h"
|
|
#include "Shared/EmuSettings.h"
|
|
#include "Shared/Emulator.h"
|
|
#include "Utilities/Serializer.h"
|
|
#include "Shared/MessageManager.h"
|
|
|
|
PceArcadeCard::PceArcadeCard(PceConsole* console, Emulator* emu)
|
|
{
|
|
_emu = emu;
|
|
_ram = new uint8_t[PceArcadeCard::ArcadeRamMemSize];
|
|
_isRamUsed = false;
|
|
console->InitializeRam(_ram, PceArcadeCard::ArcadeRamMemSize);
|
|
emu->RegisterMemory(MemoryType::PceArcadeCardRam, _ram, PceArcadeCard::ArcadeRamMemSize);
|
|
|
|
_mappedBanks[0x40] = true;
|
|
_mappedBanks[0x41] = true;
|
|
_mappedBanks[0x42] = true;
|
|
_mappedBanks[0x43] = true;
|
|
_mappedBanks[0xFF] = true;
|
|
}
|
|
|
|
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);
|
|
uint8_t value = _ram[addr];
|
|
_emu->ProcessMemoryAccess<CpuType::Pce, MemoryType::PceArcadeCardRam, MemoryOperationType::Read>(addr, value);
|
|
return value;
|
|
}
|
|
|
|
void PceArcadeCard::WritePortValue(uint8_t portNumber, uint8_t value)
|
|
{
|
|
PceArcadeCardPortConfig& port = _state.Port[portNumber];
|
|
uint32_t addr = GetAddress(port);
|
|
ProcessAutoInc(port);
|
|
_isRamUsed = true;
|
|
_emu->ProcessMemoryAccess<CpuType::Pce, MemoryType::PceArcadeCardRam, MemoryOperationType::Write>(addr, value);
|
|
_ram[addr] = value;
|
|
}
|
|
|
|
uint8_t PceArcadeCard::ReadPortRegister(uint8_t portNumber, uint8_t reg)
|
|
{
|
|
PceArcadeCardPortConfig& port = _state.Port[portNumber];
|
|
|
|
//LogDebug("[Arcade Card] Port register read: Port = " + std::to_string(portNumber) + " Reg = $" + HexUtilities::ToHex(reg));
|
|
|
|
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:
|
|
LogDebug("[Arcade Card] Unknown port register read: Port = " + std::to_string(portNumber) + " Reg = $" + HexUtilities::ToHex(reg));
|
|
return 0xFF;
|
|
}
|
|
}
|
|
|
|
void PceArcadeCard::WritePortRegister(uint8_t portNumber, uint8_t reg, uint8_t value)
|
|
{
|
|
PceArcadeCardPortConfig& port = _state.Port[portNumber];
|
|
|
|
//LogDebug("[Arcade Card] Port register write: Port = " + std::to_string(portNumber) + " Reg = $" + HexUtilities::ToHex(reg) + " = $" + HexUtilities::ToHex(value));
|
|
|
|
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;
|
|
|
|
default:
|
|
LogDebug("[Arcade Card] Unknown port register write: Port = " + std::to_string(portNumber) + " Reg = $" + HexUtilities::ToHex(reg) + " = $" + HexUtilities::ToHex(value));
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
uint8_t PceArcadeCard::Read(uint8_t bank, uint16_t addr, uint8_t value)
|
|
{
|
|
if(bank == 0xFF) {
|
|
addr &= 0x1FFF;
|
|
|
|
if(addr >= 0x1A00 && addr <= 0x1BFF) {
|
|
if(addr <= 0x1A7F) {
|
|
return ReadPortRegister((addr & 0x30) >> 4, addr & 0x0F);
|
|
} else {
|
|
//LogDebug("[Arcade Card] Register read: $" + HexUtilities::ToHex(addr));
|
|
|
|
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;
|
|
|
|
default:
|
|
LogDebug("[Arcade Card] Unknown register read: $" + HexUtilities::ToHex(addr));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} 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 <= 0x1BFF) {
|
|
if(addr <= 0x1A7F) {
|
|
WritePortRegister((addr & 0x30) >> 4, addr & 0x0F, value);
|
|
} else {
|
|
//LogDebug("[Arcade Card] Register write: $" + HexUtilities::ToHex(addr) + " = $" + HexUtilities::ToHex(value));
|
|
|
|
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;
|
|
|
|
default:
|
|
LogDebug("[Arcade Card] Unknown register write: $" + HexUtilities::ToHex(addr) + " = $" + HexUtilities::ToHex(value));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else if(bank >= 0x40 && bank <= 0x43) {
|
|
WritePortValue(bank & 0x03, value);
|
|
}
|
|
}
|
|
|
|
void PceArcadeCard::Serialize(Serializer& s)
|
|
{
|
|
SV(_isRamUsed);
|
|
if(_isRamUsed) {
|
|
SVArray(_ram, PceArcadeCard::ArcadeRamMemSize);
|
|
}
|
|
|
|
for(int i = 0; i < 4; i++) {
|
|
SVI(_state.Port[i].AddIncrementToBase);
|
|
SVI(_state.Port[i].AddOffset);
|
|
SVI(_state.Port[i].AddOffsetTrigger);
|
|
SVI(_state.Port[i].AutoIncrement);
|
|
SVI(_state.Port[i].BaseAddress);
|
|
SVI(_state.Port[i].Control);
|
|
SVI(_state.Port[i].IncValue);
|
|
SVI(_state.Port[i].Offset);
|
|
SVI(_state.Port[i].SignedIncrement);
|
|
SVI(_state.Port[i].SignedOffset);
|
|
}
|
|
SV(_state.RotateReg);
|
|
SV(_state.ShiftReg);
|
|
SV(_state.ValueReg);
|
|
}
|