mirror of
https://github.com/SourMesen/Mesen2.git
synced 2025-04-02 10:21:44 -04:00
196 lines
4.9 KiB
C++
196 lines
4.9 KiB
C++
#include "pch.h"
|
|
#include "SMS/SmsControlManager.h"
|
|
#include "SMS/SmsConsole.h"
|
|
#include "SMS/SmsVdp.h"
|
|
#include "SMS/Input/SmsController.h"
|
|
#include "SMS/Input/SmsLightPhaser.h"
|
|
#include "SMS/Input/ColecoVisionController.h"
|
|
#include "Shared/Emulator.h"
|
|
#include "Shared/EmuSettings.h"
|
|
#include "Shared/KeyManager.h"
|
|
|
|
SmsControlManager::SmsControlManager(Emulator* emu, SmsConsole* console, SmsVdp* vdp) : BaseControlManager(emu, CpuType::Sms)
|
|
{
|
|
_emu = emu;
|
|
_console = console;
|
|
_vdp = vdp;
|
|
|
|
//"[Port $3F] defaults to an input-only state (ie. with all the low bits set) on startup."
|
|
_state.ControlPort = 0x0F;
|
|
}
|
|
|
|
shared_ptr<BaseControlDevice> SmsControlManager::CreateControllerDevice(ControllerType type, uint8_t port)
|
|
{
|
|
shared_ptr<BaseControlDevice> device;
|
|
|
|
bool isCv = _console->GetModel() == SmsModel::ColecoVision;
|
|
|
|
KeyMappingSet keys;
|
|
switch(port) {
|
|
default:
|
|
case 0: keys = isCv ? _emu->GetSettings()->GetCvConfig().Port1.Keys : _emu->GetSettings()->GetSmsConfig().Port1.Keys; break;
|
|
case 1: keys = isCv ? _emu->GetSettings()->GetCvConfig().Port2.Keys : _emu->GetSettings()->GetSmsConfig().Port2.Keys; break;
|
|
}
|
|
|
|
switch(type) {
|
|
default:
|
|
case ControllerType::None: break;
|
|
case ControllerType::SmsController: device.reset(new SmsController(_emu, port, keys)); break;
|
|
case ControllerType::SmsLightPhaser: device.reset(new SmsLightPhaser(_console, port, keys)); break;
|
|
case ControllerType::ColecoVisionController: device.reset(new ColecoVisionController(_emu, port, keys)); break;
|
|
}
|
|
|
|
return device;
|
|
}
|
|
|
|
void SmsControlManager::UpdateControlDevices()
|
|
{
|
|
SmsConfig& cfg = _emu->GetSettings()->GetSmsConfig();
|
|
CvConfig& cvCfg = _emu->GetSettings()->GetCvConfig();
|
|
if(_emu->GetSettings()->IsEqual(_prevConfig, cfg) && _emu->GetSettings()->IsEqual(_prevCvConfig, cvCfg) && _controlDevices.size() > 0) {
|
|
//Do nothing if configuration is unchanged
|
|
return;
|
|
}
|
|
|
|
auto lock = _deviceLock.AcquireSafe();
|
|
|
|
ClearDevices();
|
|
|
|
bool isCv = _console->GetModel() == SmsModel::ColecoVision;
|
|
for(int i = 0; i < 2; i++) {
|
|
shared_ptr<BaseControlDevice> device;
|
|
if(isCv) {
|
|
device = CreateControllerDevice(i == 0 ? cvCfg.Port1.Type : cvCfg.Port2.Type, i);
|
|
} else {
|
|
device = CreateControllerDevice(i == 0 ? cfg.Port1.Type : cfg.Port2.Type, i);
|
|
}
|
|
if(device) {
|
|
RegisterControlDevice(device);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool SmsControlManager::IsPausePressed()
|
|
{
|
|
shared_ptr<BaseControlDevice> device = GetControlDevice(0);
|
|
return device && device->IsPressed(SmsController::Buttons::Pause);
|
|
}
|
|
|
|
uint8_t SmsControlManager::InternalReadPort(uint8_t port)
|
|
{
|
|
uint8_t value = 0xFF;
|
|
for(shared_ptr<BaseControlDevice>& device : _controlDevices) {
|
|
if(device->IsConnected()) {
|
|
value &= device->ReadRam(port);
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
|
|
uint8_t SmsControlManager::ReadPort(uint8_t port)
|
|
{
|
|
SetInputReadFlag();
|
|
|
|
if(_console->GetModel() == SmsModel::ColecoVision) {
|
|
return ReadColecoVisionPort(port);
|
|
}
|
|
|
|
uint8_t value = InternalReadPort(port);
|
|
|
|
//Set TR/TH based on the $3F config
|
|
if(port == 0) {
|
|
value &= ~0x20;
|
|
value |= GetTr(false) ? 0x20 : 0;
|
|
} else {
|
|
value &= ~0xC8;
|
|
//TODOSMS add UI option for japan vs overseas model
|
|
value |= GetTh(true) ? 0x80 : 0;
|
|
value |= GetTh(false) ? 0x40 : 0;
|
|
value |= GetTr(true) ? 0x08 : 0;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
bool SmsControlManager::GetTh(bool portB)
|
|
{
|
|
if(portB) {
|
|
if(_state.ControlPort & 0x08) {
|
|
return (InternalReadPort(1) & 0x80) != 0;
|
|
} else {
|
|
return (_state.ControlPort & 0x80) != 0;
|
|
}
|
|
} else {
|
|
if(_state.ControlPort & 0x02) {
|
|
return (InternalReadPort(1) & 0x40) != 0;
|
|
} else {
|
|
return (_state.ControlPort & 0x20) != 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool SmsControlManager::GetTr(bool portB)
|
|
{
|
|
if(portB) {
|
|
if(_state.ControlPort & 0x04) {
|
|
return (InternalReadPort(1) & 0x08) != 0;
|
|
} else {
|
|
return (_state.ControlPort & 0x40) != 0;
|
|
}
|
|
} else {
|
|
if(_state.ControlPort & 0x01) {
|
|
return (InternalReadPort(0) & 0x20) != 0;
|
|
} else {
|
|
return (_state.ControlPort & 0x10) != 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SmsControlManager::WriteControlPort(uint8_t value)
|
|
{
|
|
if(_console->GetModel() == SmsModel::ColecoVision) {
|
|
WriteColecoVisionPort(value);
|
|
} else {
|
|
uint8_t thA = GetTh(false);
|
|
uint8_t thB = GetTh(true);
|
|
_state.ControlPort = value;
|
|
uint8_t newThA = GetTh(false);
|
|
uint8_t newThB = GetTh(true);
|
|
if((!thA && newThA) || (!thB && newThB)) {
|
|
_vdp->LatchHorizontalCounter();
|
|
}
|
|
}
|
|
}
|
|
|
|
uint8_t SmsControlManager::ReadColecoVisionPort(uint8_t port)
|
|
{
|
|
for(shared_ptr<BaseControlDevice>& device : _controlDevices) {
|
|
if(device->IsConnected() && device->GetPort() == port) {
|
|
return device->ReadRam(port);
|
|
}
|
|
}
|
|
return 0xFF;
|
|
}
|
|
|
|
void SmsControlManager::WriteColecoVisionPort(uint8_t value)
|
|
{
|
|
for(shared_ptr<BaseControlDevice>& device : _controlDevices) {
|
|
if(device->IsConnected()) {
|
|
device->WriteRam(0, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SmsControlManager::Serialize(Serializer& s)
|
|
{
|
|
BaseControlManager::Serialize(s);
|
|
SV(_state.ControlPort);
|
|
|
|
if(!s.IsSaving()) {
|
|
UpdateControlDevices();
|
|
}
|
|
|
|
for(uint8_t i = 0; i < _controlDevices.size(); i++) {
|
|
SVI(_controlDevices[i]);
|
|
}
|
|
}
|