Mesen2/Core/GBA/GbaControlManager.cpp
Sour 7f0831a542 GBA/SMS/WS: Fixed broken lag counter
Also make counter reset to 0 when game is reset on all consoles
2024-12-26 12:01:19 +09:00

156 lines
No EOL
4.1 KiB
C++

#include "pch.h"
#include "GBA/GbaControlManager.h"
#include "GBA/GbaMemoryManager.h"
#include "GBA/Input/GbaController.h"
#include "Shared/Emulator.h"
#include "Shared/EmuSettings.h"
#include "Utilities/BitUtilities.h"
GbaControlManager::GbaControlManager(Emulator* emu, GbaConsole* console) : BaseControlManager(emu, CpuType::Gba)
{
_console = console;
}
void GbaControlManager::Init(GbaMemoryManager* memoryManager)
{
_memoryManager = memoryManager;
}
GbaControlManagerState& GbaControlManager::GetState()
{
return _state;
}
void GbaControlManager::UpdateInputState()
{
BaseControlManager::UpdateInputState();
_state.ActiveKeys = (ReadController(0) | (ReadController(1) << 8));
CheckForIrq();
}
shared_ptr<BaseControlDevice> GbaControlManager::CreateControllerDevice(ControllerType type, uint8_t port)
{
shared_ptr<BaseControlDevice> device;
GbaConfig& cfg = _emu->GetSettings()->GetGbaConfig();
switch(type) {
default:
case ControllerType::None: break;
case ControllerType::GbaController: device.reset(new GbaController(_emu, port, cfg.Controller.Keys)); break;
}
return device;
}
void GbaControlManager::UpdateControlDevices()
{
GbaConfig cfg = _emu->GetSettings()->GetGbaConfig();
if(_emu->GetSettings()->IsEqual(_prevConfig, cfg) && _controlDevices.size() > 0) {
//Do nothing if configuration is unchanged
return;
}
auto lock = _deviceLock.AcquireSafe();
ClearDevices();
shared_ptr<BaseControlDevice> device(CreateControllerDevice(ControllerType::GbaController, 0));
if(device) {
RegisterControlDevice(device);
}
}
uint8_t GbaControlManager::ReadController(uint32_t addr)
{
for(shared_ptr<BaseControlDevice>& controller : _controlDevices) {
if(controller->GetPort() == 0 && controller->GetControllerType() == ControllerType::GbaController) {
if(addr & 0x01) {
//TODOGBA other bits are 0 or 1?
return (
(controller->IsPressed(GbaController::R) ? 0 : (1 << 0)) |
(controller->IsPressed(GbaController::L) ? 0 : (1 << 1))
);
} else {
return (
(controller->IsPressed(GbaController::A) ? 0 : (1 << 0)) |
(controller->IsPressed(GbaController::B) ? 0 : (1 << 1)) |
(controller->IsPressed(GbaController::Select) ? 0 : (1 << 2)) |
(controller->IsPressed(GbaController::Start) ? 0 : (1 << 3)) |
(controller->IsPressed(GbaController::Right) ? 0 : (1 << 4)) |
(controller->IsPressed(GbaController::Left) ? 0 : (1 << 5)) |
(controller->IsPressed(GbaController::Up) ? 0 : (1 << 6)) |
(controller->IsPressed(GbaController::Down) ? 0 : (1 << 7))
);
}
}
}
return 0xFF;
}
uint8_t GbaControlManager::ReadInputPort(uint32_t addr)
{
if(addr & 0x02) {
if(addr & 0x01) {
return BitUtilities::GetBits<0>(_state.KeyControl);
} else {
return BitUtilities::GetBits<8>(_state.KeyControl);
}
} else {
SetInputReadFlag();
return (addr & 0x01) ? (_state.ActiveKeys >> 8) : (uint8_t)_state.ActiveKeys;
}
}
bool GbaControlManager::CheckInputCondition()
{
uint16_t activeKeys = _state.ActiveKeys ^ 0x3FF;
if(_state.KeyControl & 0x8000) {
//AND mode
if((activeKeys & 0x3FF) == (_state.KeyControl & 0x3FF)) {
return true;
}
} else {
//OR mode
if(activeKeys & _state.KeyControl & 0x3FF) {
return true;
}
}
return false;
}
void GbaControlManager::CheckForIrq()
{
if(_state.KeyControl & 0x4000) {
if(CheckInputCondition()) {
_memoryManager->SetIrqSource(GbaIrqSource::Keypad);
}
}
}
void GbaControlManager::WriteInputPort(GbaAccessModeVal mode, uint32_t addr, uint8_t value)
{
if(addr & 0x01) {
BitUtilities::SetBits<8>(_state.KeyControl, value);
} else {
BitUtilities::SetBits<0>(_state.KeyControl, value);
}
bool updateIrq = (addr & 0x03) == 0x03 || (mode & GbaAccessMode::Byte) || ((mode & GbaAccessMode::HalfWord) && (addr & 0x01));
if(updateIrq) {
//Only check for irq updates after the write operation is done (otherwise this could trigger an unexpected IRQ)
CheckForIrq();
}
}
void GbaControlManager::Serialize(Serializer& s)
{
BaseControlManager::Serialize(s);
SV(_state.KeyControl);
SV(_state.ActiveKeys);
for(uint8_t i = 0; i < _controlDevices.size(); i++) {
SVI(_controlDevices[i]);
}
}