Core: Added SNES controller support
This commit is contained in:
parent
aaf147b53b
commit
b806b3d96e
21 changed files with 1008 additions and 45 deletions
279
Core/BaseControlDevice.cpp
Normal file
279
Core/BaseControlDevice.cpp
Normal file
|
@ -0,0 +1,279 @@
|
|||
#include "stdafx.h"
|
||||
#include "BaseControlDevice.h"
|
||||
#include "KeyManager.h"
|
||||
#include "../Utilities/StringUtilities.h"
|
||||
#include "Console.h"
|
||||
//#include "EmulationSettings.h"
|
||||
|
||||
BaseControlDevice::BaseControlDevice(shared_ptr<Console> console, uint8_t port, KeyMappingSet keyMappingSet)
|
||||
{
|
||||
_console = console;
|
||||
_port = port;
|
||||
_strobe = false;
|
||||
_keyMappings = keyMappingSet.GetKeyMappingArray();
|
||||
}
|
||||
|
||||
BaseControlDevice::~BaseControlDevice()
|
||||
{
|
||||
}
|
||||
|
||||
uint8_t BaseControlDevice::GetPort()
|
||||
{
|
||||
return _port;
|
||||
}
|
||||
|
||||
void BaseControlDevice::SetStateFromInput()
|
||||
{
|
||||
ClearState();
|
||||
InternalSetStateFromInput();
|
||||
}
|
||||
|
||||
void BaseControlDevice::InternalSetStateFromInput()
|
||||
{
|
||||
}
|
||||
|
||||
//TODO
|
||||
/*
|
||||
void BaseControlDevice::StreamState(bool saving)
|
||||
{
|
||||
auto lock = _stateLock.AcquireSafe();
|
||||
VectorInfo<uint8_t> state{ &_state.State };
|
||||
Stream(_strobe, state);
|
||||
}
|
||||
*/
|
||||
|
||||
bool BaseControlDevice::IsCurrentPort(uint16_t addr)
|
||||
{
|
||||
return _port == (addr - 0x4016);
|
||||
}
|
||||
|
||||
bool BaseControlDevice::IsExpansionDevice()
|
||||
{
|
||||
return _port == BaseControlDevice::ExpDevicePort;
|
||||
}
|
||||
|
||||
void BaseControlDevice::StrobeProcessRead()
|
||||
{
|
||||
if(_strobe) {
|
||||
RefreshStateBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
void BaseControlDevice::StrobeProcessWrite(uint8_t value)
|
||||
{
|
||||
bool prevStrobe = _strobe;
|
||||
_strobe = (value & 0x01) == 0x01;
|
||||
|
||||
if(prevStrobe && !_strobe) {
|
||||
RefreshStateBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
void BaseControlDevice::ClearState()
|
||||
{
|
||||
auto lock = _stateLock.AcquireSafe();
|
||||
_state = ControlDeviceState();
|
||||
}
|
||||
|
||||
ControlDeviceState BaseControlDevice::GetRawState()
|
||||
{
|
||||
auto lock = _stateLock.AcquireSafe();
|
||||
return _state;
|
||||
}
|
||||
|
||||
void BaseControlDevice::SetRawState(ControlDeviceState state)
|
||||
{
|
||||
auto lock = _stateLock.AcquireSafe();
|
||||
_state = state;
|
||||
}
|
||||
|
||||
void BaseControlDevice::SetTextState(string textState)
|
||||
{
|
||||
auto lock = _stateLock.AcquireSafe();
|
||||
ClearState();
|
||||
|
||||
if(IsRawString()) {
|
||||
_state.State.insert(_state.State.end(), textState.begin(), textState.end());
|
||||
} else {
|
||||
if(HasCoordinates()) {
|
||||
vector<string> data = StringUtilities::Split(textState, ' ');
|
||||
if(data.size() >= 3) {
|
||||
MousePosition pos;
|
||||
try {
|
||||
pos.X = (int16_t)std::stol(data[0]);
|
||||
pos.Y = (int16_t)std::stol(data[1]);
|
||||
} catch(std::exception ex) {
|
||||
pos.X = -1;
|
||||
pos.Y = -1;
|
||||
}
|
||||
SetCoordinates(pos);
|
||||
textState = data[2];
|
||||
}
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for(char c : textState) {
|
||||
if(c != '.') {
|
||||
SetBit(i);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string BaseControlDevice::GetTextState()
|
||||
{
|
||||
auto lock = _stateLock.AcquireSafe();
|
||||
if(IsRawString()) {
|
||||
return string((char*)_state.State.data(), _state.State.size());
|
||||
} else {
|
||||
string keyNames = GetKeyNames();
|
||||
string output = "";
|
||||
|
||||
if(HasCoordinates()) {
|
||||
MousePosition pos = GetCoordinates();
|
||||
output += std::to_string(pos.X) + " " + std::to_string(pos.Y) + " ";
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < keyNames.size(); i++) {
|
||||
output += IsPressed((uint8_t)i) ? keyNames[i] : '.';
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
void BaseControlDevice::EnsureCapacity(int32_t minBitCount)
|
||||
{
|
||||
auto lock = _stateLock.AcquireSafe();
|
||||
uint32_t minByteCount = minBitCount / 8 + 1 + (HasCoordinates() ? 32 : 0);
|
||||
int32_t gap = minByteCount - (int32_t)_state.State.size();
|
||||
|
||||
if(gap > 0) {
|
||||
_state.State.insert(_state.State.end(), gap, 0);
|
||||
}
|
||||
}
|
||||
|
||||
bool BaseControlDevice::HasCoordinates()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BaseControlDevice::IsRawString()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t BaseControlDevice::GetByteIndex(uint8_t bit)
|
||||
{
|
||||
return bit / 8 + (HasCoordinates() ? 4 : 0);
|
||||
}
|
||||
|
||||
bool BaseControlDevice::IsPressed(uint8_t bit)
|
||||
{
|
||||
auto lock = _stateLock.AcquireSafe();
|
||||
EnsureCapacity(bit);
|
||||
uint8_t bitMask = 1 << (bit % 8);
|
||||
return (_state.State[GetByteIndex(bit)] & bitMask) != 0;
|
||||
}
|
||||
|
||||
void BaseControlDevice::SetBitValue(uint8_t bit, bool set)
|
||||
{
|
||||
if(set) {
|
||||
SetBit(bit);
|
||||
} else {
|
||||
ClearBit(bit);
|
||||
}
|
||||
}
|
||||
|
||||
void BaseControlDevice::SetBit(uint8_t bit)
|
||||
{
|
||||
auto lock = _stateLock.AcquireSafe();
|
||||
EnsureCapacity(bit);
|
||||
uint8_t bitMask = 1 << (bit % 8);
|
||||
_state.State[GetByteIndex(bit)] |= bitMask;
|
||||
}
|
||||
|
||||
void BaseControlDevice::ClearBit(uint8_t bit)
|
||||
{
|
||||
auto lock = _stateLock.AcquireSafe();
|
||||
EnsureCapacity(bit);
|
||||
uint8_t bitMask = 1 << (bit % 8);
|
||||
_state.State[GetByteIndex(bit)] &= ~bitMask;
|
||||
}
|
||||
|
||||
void BaseControlDevice::InvertBit(uint8_t bit)
|
||||
{
|
||||
if(IsPressed(bit)) {
|
||||
ClearBit(bit);
|
||||
} else {
|
||||
SetBit(bit);
|
||||
}
|
||||
}
|
||||
|
||||
void BaseControlDevice::SetPressedState(uint8_t bit, uint32_t keyCode)
|
||||
{
|
||||
if(KeyManager::IsKeyPressed(keyCode)) {
|
||||
SetBit(bit);
|
||||
}
|
||||
}
|
||||
|
||||
void BaseControlDevice::SetPressedState(uint8_t bit, bool enabled)
|
||||
{
|
||||
if(enabled) {
|
||||
SetBit(bit);
|
||||
}
|
||||
}
|
||||
|
||||
void BaseControlDevice::SetCoordinates(MousePosition pos)
|
||||
{
|
||||
auto lock = _stateLock.AcquireSafe();
|
||||
EnsureCapacity(-1);
|
||||
|
||||
_state.State[0] = pos.X & 0xFF;
|
||||
_state.State[1] = (pos.X >> 8) & 0xFF;
|
||||
_state.State[2] = pos.Y & 0xFF;
|
||||
_state.State[3] = (pos.Y >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
MousePosition BaseControlDevice::GetCoordinates()
|
||||
{
|
||||
auto lock = _stateLock.AcquireSafe();
|
||||
EnsureCapacity(-1);
|
||||
|
||||
MousePosition pos;
|
||||
pos.X = _state.State[0] | (_state.State[1] << 8);
|
||||
pos.Y = _state.State[2] | (_state.State[3] << 8);
|
||||
return pos;
|
||||
}
|
||||
|
||||
void BaseControlDevice::SetMovement(MouseMovement mov)
|
||||
{
|
||||
MouseMovement prev = GetMovement();
|
||||
mov.dx += prev.dx;
|
||||
mov.dy += prev.dy;
|
||||
SetCoordinates({ mov.dx, mov.dy });
|
||||
}
|
||||
|
||||
MouseMovement BaseControlDevice::GetMovement()
|
||||
{
|
||||
MousePosition pos = GetCoordinates();
|
||||
SetCoordinates({ 0, 0 });
|
||||
return { pos.X, pos.Y };
|
||||
}
|
||||
|
||||
void BaseControlDevice::SwapButtons(shared_ptr<BaseControlDevice> state1, uint8_t button1, shared_ptr<BaseControlDevice> state2, uint8_t button2)
|
||||
{
|
||||
bool pressed1 = state1->IsPressed(button1);
|
||||
bool pressed2 = state2->IsPressed(button2);
|
||||
|
||||
state1->ClearBit(button1);
|
||||
state2->ClearBit(button2);
|
||||
|
||||
if(pressed1) {
|
||||
state2->SetBit(button2);
|
||||
}
|
||||
if(pressed2) {
|
||||
state1->SetBit(button1);
|
||||
}
|
||||
}
|
83
Core/BaseControlDevice.h
Normal file
83
Core/BaseControlDevice.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "ControlDeviceState.h"
|
||||
#include "SettingTypes.h"
|
||||
#include "IKeyManager.h"
|
||||
#include "../Utilities/SimpleLock.h"
|
||||
|
||||
class Console;
|
||||
|
||||
class BaseControlDevice
|
||||
{
|
||||
private:
|
||||
ControlDeviceState _state;
|
||||
|
||||
protected:
|
||||
shared_ptr<Console> _console;
|
||||
vector<KeyMapping> _keyMappings;
|
||||
bool _strobe;
|
||||
uint8_t _port;
|
||||
SimpleLock _stateLock;
|
||||
|
||||
virtual void RefreshStateBuffer() { }
|
||||
|
||||
//TODO
|
||||
//virtual void StreamState(bool saving);
|
||||
|
||||
void EnsureCapacity(int32_t minBitCount);
|
||||
uint32_t GetByteIndex(uint8_t bit);
|
||||
virtual bool HasCoordinates();
|
||||
virtual bool IsRawString();
|
||||
|
||||
bool IsCurrentPort(uint16_t addr);
|
||||
bool IsExpansionDevice();
|
||||
void StrobeProcessRead();
|
||||
void StrobeProcessWrite(uint8_t value);
|
||||
|
||||
virtual string GetKeyNames() { return ""; }
|
||||
|
||||
void SetPressedState(uint8_t bit, uint32_t keyCode);
|
||||
void SetPressedState(uint8_t bit, bool enabled);
|
||||
|
||||
void SetCoordinates(MousePosition pos);
|
||||
|
||||
void SetMovement(MouseMovement mov);
|
||||
MouseMovement GetMovement();
|
||||
|
||||
virtual void InternalSetStateFromInput();
|
||||
|
||||
public:
|
||||
static constexpr uint8_t ExpDevicePort = 4;
|
||||
static constexpr uint8_t ConsoleInputPort = 5;
|
||||
static constexpr uint8_t MapperInputPort = 6;
|
||||
static constexpr uint8_t ExpDevicePort2 = 7;
|
||||
static constexpr uint8_t PortCount = ExpDevicePort2 + 1;
|
||||
|
||||
BaseControlDevice(shared_ptr<Console> console, uint8_t port, KeyMappingSet keyMappingSet = KeyMappingSet());
|
||||
virtual ~BaseControlDevice();
|
||||
|
||||
uint8_t GetPort();
|
||||
|
||||
bool IsPressed(uint8_t bit);
|
||||
MousePosition GetCoordinates();
|
||||
|
||||
void ClearState();
|
||||
void SetBit(uint8_t bit);
|
||||
void ClearBit(uint8_t bit);
|
||||
void InvertBit(uint8_t bit);
|
||||
void SetBitValue(uint8_t bit, bool set);
|
||||
|
||||
void SetTextState(string state);
|
||||
string GetTextState();
|
||||
|
||||
void SetStateFromInput();
|
||||
virtual void OnAfterSetState() { }
|
||||
|
||||
void SetRawState(ControlDeviceState state);
|
||||
ControlDeviceState GetRawState();
|
||||
|
||||
virtual uint8_t ReadRam(uint16_t addr) = 0;
|
||||
virtual void WriteRam(uint16_t addr, uint8_t value) = 0;
|
||||
|
||||
void static SwapButtons(shared_ptr<BaseControlDevice> state1, uint8_t button1, shared_ptr<BaseControlDevice> state2, uint8_t button2);
|
||||
};
|
|
@ -120,7 +120,7 @@ void BaseRenderer::ShowFpsCounter(int lineNumber)
|
|||
if(_fpsTimer.GetElapsedMS() > 1000) {
|
||||
//Update fps every sec
|
||||
shared_ptr<Ppu> ppu = _console->GetPpu();
|
||||
uint32_t frameCount = ppu ? ppu->GetState().FrameCount : 0;
|
||||
uint32_t frameCount = ppu ? ppu->GetFrameCount() : 0;
|
||||
if(_lastFrameCount > frameCount) {
|
||||
_currentFPS = 0;
|
||||
} else {
|
||||
|
@ -167,7 +167,7 @@ void BaseRenderer::ShowFrameCounter(int lineNumber)
|
|||
int yPos = 13 + 24 * lineNumber;
|
||||
shared_ptr<Ppu> ppu = _console->GetPpu();
|
||||
|
||||
string frameCounter = MessageManager::Localize("Frame") + ": " + std::to_string(ppu ? ppu->GetState().FrameCount : 0);
|
||||
string frameCounter = MessageManager::Localize("Frame") + ": " + std::to_string(ppu ? ppu->GetFrameCount() : 0);
|
||||
DrawString(frameCounter, _screenWidth - 146, yPos, 250, 235, 215);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "Ppu.h"
|
||||
#include "Spc.h"
|
||||
#include "InternalRegisters.h"
|
||||
#include "ControlManager.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "Debugger.h"
|
||||
#include "NotificationManager.h"
|
||||
|
@ -52,12 +53,6 @@ void Console::Run()
|
|||
while(!_stopFlag) {
|
||||
_cpu->Exec();
|
||||
}
|
||||
|
||||
//Timer timer;
|
||||
/*std::cout << "Time: " << std::to_string(timer.GetElapsedMS()) << std::endl;
|
||||
std::cout << "OP Count: " << std::to_string(_cpu->opCount) << std::endl;
|
||||
std::cout << "OP/sec: " << std::to_string(_cpu->opCount * 1000 / timer.GetElapsedMS()) << std::endl;
|
||||
while(true);*/
|
||||
}
|
||||
|
||||
void Console::Stop()
|
||||
|
@ -76,6 +71,7 @@ void Console::Stop()
|
|||
_spc.reset();
|
||||
_cart.reset();
|
||||
_internalRegisters.reset();
|
||||
_controlManager.reset();
|
||||
_memoryManager.reset();
|
||||
}
|
||||
|
||||
|
@ -86,10 +82,11 @@ void Console::LoadRom(VirtualFile romFile, VirtualFile patchFile)
|
|||
shared_ptr<BaseCartridge> cart = BaseCartridge::CreateCartridge(romFile, patchFile);
|
||||
if(cart) {
|
||||
MessageManager::ClearLog();
|
||||
_internalRegisters.reset(new InternalRegisters());
|
||||
_internalRegisters.reset(new InternalRegisters(shared_from_this()));
|
||||
_ppu.reset(new Ppu(shared_from_this()));
|
||||
_spc.reset(new Spc(shared_from_this()));
|
||||
_cart = cart;
|
||||
_controlManager.reset(new ControlManager(shared_from_this()));
|
||||
_memoryManager.reset(new MemoryManager());
|
||||
_memoryManager->Initialize(shared_from_this());
|
||||
|
||||
|
@ -159,6 +156,11 @@ shared_ptr<InternalRegisters> Console::GetInternalRegisters()
|
|||
return _internalRegisters;
|
||||
}
|
||||
|
||||
shared_ptr<ControlManager> Console::GetControlManager()
|
||||
{
|
||||
return _controlManager;
|
||||
}
|
||||
|
||||
shared_ptr<Debugger> Console::GetDebugger(bool autoStart)
|
||||
{
|
||||
shared_ptr<Debugger> debugger = _debugger;
|
||||
|
|
|
@ -9,6 +9,7 @@ class Spc;
|
|||
class BaseCartridge;
|
||||
class MemoryManager;
|
||||
class InternalRegisters;
|
||||
class ControlManager;
|
||||
class Debugger;
|
||||
class DebugHud;
|
||||
class SoundMixer;
|
||||
|
@ -26,6 +27,7 @@ private:
|
|||
shared_ptr<MemoryManager> _memoryManager;
|
||||
shared_ptr<BaseCartridge> _cart;
|
||||
shared_ptr<InternalRegisters> _internalRegisters;
|
||||
shared_ptr<ControlManager> _controlManager;
|
||||
|
||||
shared_ptr<Debugger> _debugger;
|
||||
|
||||
|
@ -61,6 +63,7 @@ public:
|
|||
shared_ptr<BaseCartridge> GetCartridge();
|
||||
shared_ptr<MemoryManager> GetMemoryManager();
|
||||
shared_ptr<InternalRegisters> GetInternalRegisters();
|
||||
shared_ptr<ControlManager> GetControlManager();
|
||||
shared_ptr<Debugger> GetDebugger(bool autoStart = true);
|
||||
|
||||
bool IsRunning();
|
||||
|
|
13
Core/ControlDeviceState.h
Normal file
13
Core/ControlDeviceState.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include <cstring>
|
||||
|
||||
struct ControlDeviceState
|
||||
{
|
||||
vector<uint8_t> State;
|
||||
|
||||
bool operator!=(ControlDeviceState &other)
|
||||
{
|
||||
return State.size() != other.State.size() || memcmp(State.data(), other.State.data(), State.size()) != 0;
|
||||
}
|
||||
};
|
219
Core/ControlManager.cpp
Normal file
219
Core/ControlManager.cpp
Normal file
|
@ -0,0 +1,219 @@
|
|||
#include "stdafx.h"
|
||||
#include "ControlManager.h"
|
||||
#include "Console.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "KeyManager.h"
|
||||
#include "IKeyManager.h"
|
||||
#include "IInputProvider.h"
|
||||
#include "IInputRecorder.h"
|
||||
#include "SnesController.h"
|
||||
|
||||
ControlManager::ControlManager(shared_ptr<Console> console)
|
||||
{
|
||||
_console = console;
|
||||
_pollCounter = 0;
|
||||
|
||||
UpdateControlDevices();
|
||||
}
|
||||
|
||||
ControlManager::~ControlManager()
|
||||
{
|
||||
}
|
||||
|
||||
void ControlManager::RegisterInputProvider(IInputProvider* provider)
|
||||
{
|
||||
auto lock = _deviceLock.AcquireSafe();
|
||||
_inputProviders.push_back(provider);
|
||||
}
|
||||
|
||||
void ControlManager::UnregisterInputProvider(IInputProvider* provider)
|
||||
{
|
||||
auto lock = _deviceLock.AcquireSafe();
|
||||
vector<IInputProvider*> &vec = _inputProviders;
|
||||
vec.erase(std::remove(vec.begin(), vec.end(), provider), vec.end());
|
||||
}
|
||||
|
||||
void ControlManager::RegisterInputRecorder(IInputRecorder* provider)
|
||||
{
|
||||
auto lock = _deviceLock.AcquireSafe();
|
||||
_inputRecorders.push_back(provider);
|
||||
}
|
||||
|
||||
void ControlManager::UnregisterInputRecorder(IInputRecorder* provider)
|
||||
{
|
||||
auto lock = _deviceLock.AcquireSafe();
|
||||
vector<IInputRecorder*> &vec = _inputRecorders;
|
||||
vec.erase(std::remove(vec.begin(), vec.end(), provider), vec.end());
|
||||
}
|
||||
|
||||
vector<ControlDeviceState> ControlManager::GetPortStates()
|
||||
{
|
||||
auto lock = _deviceLock.AcquireSafe();
|
||||
|
||||
vector<ControlDeviceState> states;
|
||||
for(int i = 0; i < 4; i++) {
|
||||
shared_ptr<BaseControlDevice> device = GetControlDevice(i);
|
||||
if(device) {
|
||||
states.push_back(device->GetRawState());
|
||||
} else {
|
||||
states.push_back(ControlDeviceState());
|
||||
}
|
||||
}
|
||||
return states;
|
||||
}
|
||||
|
||||
shared_ptr<BaseControlDevice> ControlManager::GetControlDevice(uint8_t port)
|
||||
{
|
||||
auto lock = _deviceLock.AcquireSafe();
|
||||
|
||||
auto result = std::find_if(_controlDevices.begin(), _controlDevices.end(), [port](const shared_ptr<BaseControlDevice> control) { return control->GetPort() == port; });
|
||||
if(result != _controlDevices.end()) {
|
||||
return *result;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
vector<shared_ptr<BaseControlDevice>> ControlManager::GetControlDevices()
|
||||
{
|
||||
return _controlDevices;
|
||||
}
|
||||
|
||||
void ControlManager::RegisterControlDevice(shared_ptr<BaseControlDevice> controlDevice)
|
||||
{
|
||||
_controlDevices.push_back(controlDevice);
|
||||
}
|
||||
|
||||
ControllerType ControlManager::GetControllerType(uint8_t port)
|
||||
{
|
||||
return ControllerType::SnesController;
|
||||
//TODO _console->GetSettings()->GetControllerType(port);
|
||||
}
|
||||
|
||||
shared_ptr<BaseControlDevice> ControlManager::CreateControllerDevice(ControllerType type, uint8_t port, shared_ptr<Console> console)
|
||||
{
|
||||
shared_ptr<BaseControlDevice> device;
|
||||
|
||||
KeyMappingSet keyMappings = {};
|
||||
if(port == 0) {
|
||||
keyMappings.Mapping1.Up = KeyManager::GetKeyCode("Pad1 Up");
|
||||
keyMappings.Mapping1.Down = KeyManager::GetKeyCode("Pad1 Down");
|
||||
keyMappings.Mapping1.Left = KeyManager::GetKeyCode("Pad1 Left");
|
||||
keyMappings.Mapping1.Right = KeyManager::GetKeyCode("Pad1 Right");
|
||||
keyMappings.Mapping1.A = KeyManager::GetKeyCode("Pad1 B");
|
||||
keyMappings.Mapping1.B = KeyManager::GetKeyCode("Pad1 A");
|
||||
keyMappings.Mapping1.X = KeyManager::GetKeyCode("Pad1 Y");
|
||||
keyMappings.Mapping1.Y = KeyManager::GetKeyCode("Pad1 X");
|
||||
keyMappings.Mapping1.L = KeyManager::GetKeyCode("Pad1 L1");
|
||||
keyMappings.Mapping1.R = KeyManager::GetKeyCode("Pad1 R1");
|
||||
keyMappings.Mapping1.Select = KeyManager::GetKeyCode("Pad1 Back");
|
||||
keyMappings.Mapping1.Start = KeyManager::GetKeyCode("Pad1 Start");
|
||||
|
||||
keyMappings.Mapping2.Up = KeyManager::GetKeyCode("Up Arrow");
|
||||
keyMappings.Mapping2.Down = KeyManager::GetKeyCode("Down Arrow");
|
||||
keyMappings.Mapping2.Left = KeyManager::GetKeyCode("Left Arrow");
|
||||
keyMappings.Mapping2.Right = KeyManager::GetKeyCode("Right Arrow");
|
||||
keyMappings.Mapping2.A = KeyManager::GetKeyCode("Z");
|
||||
keyMappings.Mapping2.B = KeyManager::GetKeyCode("X");
|
||||
keyMappings.Mapping2.X = KeyManager::GetKeyCode("S");
|
||||
keyMappings.Mapping2.Y = KeyManager::GetKeyCode("A");
|
||||
keyMappings.Mapping2.L = KeyManager::GetKeyCode("Q");
|
||||
keyMappings.Mapping2.R = KeyManager::GetKeyCode("W");
|
||||
keyMappings.Mapping2.Select = KeyManager::GetKeyCode("E");
|
||||
keyMappings.Mapping2.Start = KeyManager::GetKeyCode("D");
|
||||
}
|
||||
|
||||
switch(type) {
|
||||
case ControllerType::None: break;
|
||||
case ControllerType::SnesController: device.reset(new SnesController(console, port, keyMappings)); break;
|
||||
}
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
void ControlManager::UpdateControlDevices()
|
||||
{
|
||||
auto lock = _deviceLock.AcquireSafe();
|
||||
_controlDevices.clear();
|
||||
|
||||
for(int i = 0; i < 4; i++) {
|
||||
shared_ptr<BaseControlDevice> device = CreateControllerDevice(GetControllerType(i), i, _console);
|
||||
if(device) {
|
||||
RegisterControlDevice(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ControlManager::GetOpenBusMask(uint8_t port)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ControlManager::UpdateInputState()
|
||||
{
|
||||
KeyManager::RefreshKeyState();
|
||||
|
||||
//auto lock = _deviceLock.AcquireSafe();
|
||||
|
||||
string log = "";
|
||||
for(shared_ptr<BaseControlDevice> &device : _controlDevices) {
|
||||
device->ClearState();
|
||||
|
||||
bool inputSet = false;
|
||||
for(size_t i = 0; i < _inputProviders.size(); i++) {
|
||||
IInputProvider* provider = _inputProviders[i];
|
||||
if(provider->SetInput(device.get())) {
|
||||
inputSet = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!inputSet) {
|
||||
device->SetStateFromInput();
|
||||
}
|
||||
|
||||
device->OnAfterSetState();
|
||||
//log += "|" + device->GetTextState();
|
||||
}
|
||||
|
||||
//TODO
|
||||
/*
|
||||
shared_ptr<Debugger> debugger = _console->GetDebugger(false);
|
||||
if(debugger) {
|
||||
debugger->ProcessEvent(EventType::InputPolled);
|
||||
}*/
|
||||
|
||||
for(IInputRecorder* recorder : _inputRecorders) {
|
||||
recorder->RecordInput(_controlDevices);
|
||||
}
|
||||
|
||||
//MessageManager::Log(log);
|
||||
|
||||
_pollCounter++;
|
||||
}
|
||||
|
||||
uint32_t ControlManager::GetPollCounter()
|
||||
{
|
||||
return ControlManager::_pollCounter;
|
||||
}
|
||||
|
||||
void ControlManager::SetPollCounter(uint32_t value)
|
||||
{
|
||||
_pollCounter = value;
|
||||
}
|
||||
|
||||
uint8_t ControlManager::Read(uint16_t addr)
|
||||
{
|
||||
uint8_t value = 0; //TODO _console->GetMemoryManager()->GetOpenBus(GetOpenBusMask(addr - 0x4016));
|
||||
for(shared_ptr<BaseControlDevice> &device : _controlDevices) {
|
||||
value |= device->ReadRam(addr);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void ControlManager::Write(uint16_t addr, uint8_t value)
|
||||
{
|
||||
for(shared_ptr<BaseControlDevice> &device : _controlDevices) {
|
||||
device->WriteRam(addr, value);
|
||||
}
|
||||
}
|
60
Core/ControlManager.h
Normal file
60
Core/ControlManager.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
#pragma once
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "../Utilities/SimpleLock.h"
|
||||
#include "IMemoryHandler.h"
|
||||
|
||||
class BaseControlDevice;
|
||||
class IInputRecorder;
|
||||
class IInputProvider;
|
||||
class Console;
|
||||
struct ControlDeviceState;
|
||||
enum class ControllerType;
|
||||
enum class ExpansionPortDevice;
|
||||
|
||||
class ControlManager
|
||||
{
|
||||
private:
|
||||
vector<IInputRecorder*> _inputRecorders;
|
||||
vector<IInputProvider*> _inputProviders;
|
||||
|
||||
//Static so that power cycle does not reset its value
|
||||
uint32_t _pollCounter;
|
||||
|
||||
protected:
|
||||
shared_ptr<Console> _console;
|
||||
SimpleLock _deviceLock;
|
||||
vector<shared_ptr<BaseControlDevice>> _controlDevices;
|
||||
shared_ptr<BaseControlDevice> _systemActionManager;
|
||||
|
||||
void RegisterControlDevice(shared_ptr<BaseControlDevice> controlDevice);
|
||||
|
||||
ControllerType GetControllerType(uint8_t port);
|
||||
uint8_t GetOpenBusMask(uint8_t port);
|
||||
|
||||
public:
|
||||
ControlManager(shared_ptr<Console> console);
|
||||
~ControlManager();
|
||||
|
||||
void UpdateControlDevices();
|
||||
void UpdateInputState();
|
||||
|
||||
uint32_t GetPollCounter();
|
||||
void SetPollCounter(uint32_t value);
|
||||
|
||||
void RegisterInputProvider(IInputProvider* provider);
|
||||
void UnregisterInputProvider(IInputProvider* provider);
|
||||
|
||||
void RegisterInputRecorder(IInputRecorder* recorder);
|
||||
void UnregisterInputRecorder(IInputRecorder* recorder);
|
||||
|
||||
vector<ControlDeviceState> GetPortStates();
|
||||
|
||||
shared_ptr<BaseControlDevice> GetControlDevice(uint8_t port);
|
||||
vector<shared_ptr<BaseControlDevice>> GetControlDevices();
|
||||
|
||||
static shared_ptr<BaseControlDevice> CreateControllerDevice(ControllerType type, uint8_t port, shared_ptr<Console> console);
|
||||
|
||||
uint8_t Read(uint16_t addr);
|
||||
void Write(uint16_t addr, uint8_t value);
|
||||
};
|
|
@ -44,6 +44,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="BaseCartridge.h" />
|
||||
<ClInclude Include="BaseControlDevice.h" />
|
||||
<ClInclude Include="BaseRenderer.h" />
|
||||
<ClInclude Include="BaseSoundManager.h" />
|
||||
<ClInclude Include="BaseVideoFilter.h" />
|
||||
|
@ -52,6 +53,8 @@
|
|||
<ClInclude Include="blargg_endian.h" />
|
||||
<ClInclude Include="blargg_source.h" />
|
||||
<ClInclude Include="Console.h" />
|
||||
<ClInclude Include="ControlDeviceState.h" />
|
||||
<ClInclude Include="ControlManager.h" />
|
||||
<ClInclude Include="Cpu.h" />
|
||||
<ClInclude Include="CpuTypes.h" />
|
||||
<ClInclude Include="Debugger.h" />
|
||||
|
@ -86,6 +89,7 @@
|
|||
<ClInclude Include="RamHandler.h" />
|
||||
<ClInclude Include="RomHandler.h" />
|
||||
<ClInclude Include="SettingTypes.h" />
|
||||
<ClInclude Include="SnesController.h" />
|
||||
<ClInclude Include="SNES_SPC.h" />
|
||||
<ClInclude Include="SoundMixer.h" />
|
||||
<ClInclude Include="Spc.h" />
|
||||
|
@ -99,10 +103,12 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="BaseCartridge.cpp" />
|
||||
<ClCompile Include="BaseControlDevice.cpp" />
|
||||
<ClCompile Include="BaseRenderer.cpp" />
|
||||
<ClCompile Include="BaseSoundManager.cpp" />
|
||||
<ClCompile Include="BaseVideoFilter.cpp" />
|
||||
<ClCompile Include="Console.cpp" />
|
||||
<ClCompile Include="ControlManager.cpp" />
|
||||
<ClCompile Include="Cpu.cpp" />
|
||||
<ClCompile Include="Cpu.Instructions.cpp" />
|
||||
<ClCompile Include="Debugger.cpp" />
|
||||
|
|
|
@ -158,6 +158,18 @@
|
|||
<ClInclude Include="InternalRegisters.h">
|
||||
<Filter>SNES</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="BaseControlDevice.h">
|
||||
<Filter>SNES\Input</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SnesController.h">
|
||||
<Filter>SNES\Input</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ControlDeviceState.h">
|
||||
<Filter>SNES\Input</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ControlManager.h">
|
||||
<Filter>SNES\Input</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp" />
|
||||
|
@ -245,6 +257,12 @@
|
|||
<ClCompile Include="InternalRegisters.cpp">
|
||||
<Filter>SNES</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="BaseControlDevice.cpp">
|
||||
<Filter>SNES\Input</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ControlManager.cpp">
|
||||
<Filter>SNES\Input</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="SNES">
|
||||
|
@ -268,5 +286,8 @@
|
|||
<Filter Include="SNES\SPC">
|
||||
<UniqueIdentifier>{e0e6a67b-620e-4fe4-9846-26a6c80ca6b6}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="SNES\Input">
|
||||
<UniqueIdentifier>{3a9ea5fe-e818-4e65-bd50-cb9591de3e0d}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -1,17 +1,90 @@
|
|||
#include "stdafx.h"
|
||||
#include "InternalRegisters.h"
|
||||
#include "Console.h"
|
||||
#include "Cpu.h"
|
||||
#include "Ppu.h"
|
||||
#include "ControlManager.h"
|
||||
#include "MessageManager.h"
|
||||
#include "../Utilities/HexUtilities.h"
|
||||
|
||||
InternalRegisters::InternalRegisters(shared_ptr<Console> console)
|
||||
{
|
||||
_console = console;
|
||||
}
|
||||
|
||||
void InternalRegisters::ProcessAutoJoypadRead()
|
||||
{
|
||||
if(!_enableAutoJoypadRead) {
|
||||
return;
|
||||
}
|
||||
|
||||
shared_ptr<ControlManager> controlManager = _console->GetControlManager();
|
||||
|
||||
controlManager->Write(0x4016, 1);
|
||||
controlManager->Write(0x4016, 0);
|
||||
|
||||
for(int i = 0; i < 4; i++) {
|
||||
_controllerData[i] = 0;
|
||||
}
|
||||
|
||||
for(int i = 0; i < 16; i++) {
|
||||
uint8_t port1 = controlManager->Read(0x4016);
|
||||
uint8_t port2 = controlManager->Read(0x4017);
|
||||
|
||||
_controllerData[0] <<= 1;
|
||||
_controllerData[1] <<= 1;
|
||||
_controllerData[2] <<= 1;
|
||||
_controllerData[3] <<= 1;
|
||||
|
||||
_controllerData[0] |= (port1 & 0x01);
|
||||
_controllerData[1] |= (port2 & 0x01);
|
||||
_controllerData[2] |= (port1 & 0x02) >> 1;
|
||||
_controllerData[3] |= (port2 & 0x02) >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
void InternalRegisters::SetNmiFlag(bool nmiFlag)
|
||||
{
|
||||
_nmiFlag = nmiFlag;
|
||||
}
|
||||
|
||||
uint8_t InternalRegisters::Read(uint16_t addr)
|
||||
{
|
||||
switch(addr) {
|
||||
case 0x4210: {
|
||||
//open bus implementation here is needed to pass CPUPHL test
|
||||
uint8_t value = (_nmiFlag ? 0x80 : 0) | ((addr >> 8) & 0x70);
|
||||
_nmiFlag = false;
|
||||
return value;
|
||||
}
|
||||
|
||||
case 0x4211: {
|
||||
uint8_t value = (_console->GetCpu()->CheckIrqSource(IrqSource::Ppu) ? 0x80 : 0) | ((addr >> 8) & 0x7F);
|
||||
_console->GetCpu()->ClearIrqSource(IrqSource::Ppu);
|
||||
return value;
|
||||
}
|
||||
|
||||
case 0x4212: {
|
||||
PpuState state = _console->GetPpu()->GetState();
|
||||
return (
|
||||
(state.Scanline >= 225 ? 0x80 : 0) |
|
||||
((state.Cycle >= 0x121 || state.Cycle <= 0x15) ? 0x40 : 0) |
|
||||
((_enableAutoJoypadRead && state.Scanline >= 225 && state.Scanline <= 227) ? 0x01 : 0) //Auto joypad read in progress
|
||||
);
|
||||
}
|
||||
|
||||
case 0x4214: return (uint8_t)_divResult;
|
||||
case 0x4215: return (uint8_t)(_divResult >> 8);
|
||||
|
||||
case 0x4216: return (uint8_t)_multOrRemainderResult;
|
||||
case 0x4217: return (uint8_t)(_multOrRemainderResult >> 8);
|
||||
|
||||
case 0x4218: case 0x421A: case 0x421C: case 0x421E:
|
||||
return (uint8_t)_controllerData[((addr & 0x0E) - 8) >> 1];
|
||||
|
||||
case 0x4219: case 0x421B: case 0x421D: case 0x421F:
|
||||
return (uint8_t)(_controllerData[((addr & 0x0E) - 8) >> 1] >> 8);
|
||||
|
||||
default:
|
||||
MessageManager::DisplayMessage("Debug", "Unimplemented register read: " + HexUtilities::ToHex(addr));
|
||||
return 0;
|
||||
|
@ -26,8 +99,7 @@ void InternalRegisters::Write(uint16_t addr, uint8_t value)
|
|||
_enableVerticalIrq = (value & 0x20) != 0;
|
||||
_enableHorizontalIrq = (value & 0x10) != 0;
|
||||
|
||||
//TODO
|
||||
//_autoJoypadRead = (value & 0x01) != 0;
|
||||
_enableAutoJoypadRead = (value & 0x01) != 0;
|
||||
break;
|
||||
|
||||
case 0x4202: _multOperand1 = value; break;
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
|
||||
class Console;
|
||||
|
||||
class InternalRegisters
|
||||
{
|
||||
private:
|
||||
shared_ptr<Console> _console;
|
||||
|
||||
uint8_t _multOperand1 = 0;
|
||||
uint8_t _multOperand2 = 0;
|
||||
uint16_t _multOrRemainderResult = 0;
|
||||
|
@ -12,19 +16,29 @@ private:
|
|||
uint8_t _divisor = 0;
|
||||
uint16_t _divResult = 0;
|
||||
|
||||
bool _enableAutoJoypadRead = false;
|
||||
|
||||
bool _nmiFlag = false;
|
||||
bool _enableNmi = false;
|
||||
bool _enableHorizontalIrq = false;
|
||||
bool _enableVerticalIrq = false;
|
||||
uint16_t _horizontalTimer = 0x1FF;
|
||||
uint16_t _verticalTimer = 0x1FF;
|
||||
|
||||
uint16_t _controllerData[4];
|
||||
|
||||
public:
|
||||
InternalRegisters(shared_ptr<Console> console);
|
||||
|
||||
void ProcessAutoJoypadRead();
|
||||
void SetNmiFlag(bool nmiFlag);
|
||||
|
||||
bool IsVerticalIrqEnabled() { return _enableVerticalIrq; }
|
||||
bool IsHorizontalIrqEnabled() { return _enableHorizontalIrq; }
|
||||
bool IsNmiEnabled() { return _enableNmi; }
|
||||
uint16_t GetHorizontalTimer() { return _horizontalTimer; }
|
||||
uint16_t GetVerticalTimer() { return _verticalTimer; }
|
||||
|
||||
|
||||
uint8_t Read(uint16_t addr);
|
||||
void Write(uint16_t addr, uint8_t value);
|
||||
};
|
|
@ -23,10 +23,9 @@ void KeyManager::RefreshKeyState()
|
|||
|
||||
bool KeyManager::IsKeyPressed(uint32_t keyCode)
|
||||
{
|
||||
//TODO
|
||||
/*if(_keyManager != nullptr) {
|
||||
return _settings->InputEnabled() && _keyManager->IsKeyPressed(keyCode);
|
||||
}*/
|
||||
if(_keyManager != nullptr) {
|
||||
return _keyManager->IsKeyPressed(keyCode);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "RamHandler.h"
|
||||
#include "DmaController.h"
|
||||
#include "BaseCartridge.h"
|
||||
#include "ControlManager.h"
|
||||
#include "InternalRegisters.h"
|
||||
#include "IMemoryHandler.h"
|
||||
#include "MessageManager.h"
|
||||
|
@ -18,16 +19,18 @@ private:
|
|||
Spc *_spc;
|
||||
DmaController *_dmaController;
|
||||
InternalRegisters *_regs;
|
||||
ControlManager *_controlManager;
|
||||
uint8_t *_workRam;
|
||||
uint32_t _wramPosition;
|
||||
|
||||
public:
|
||||
CpuRegisterHandler(Ppu *ppu, Spc *spc, DmaController *dmaController, InternalRegisters *regs, uint8_t *workRam)
|
||||
CpuRegisterHandler(Ppu *ppu, Spc *spc, DmaController *dmaController, InternalRegisters *regs, ControlManager *controlManager, uint8_t *workRam)
|
||||
{
|
||||
_ppu = ppu;
|
||||
_spc = spc;
|
||||
_regs = regs;
|
||||
_dmaController = dmaController;
|
||||
_controlManager = controlManager;
|
||||
|
||||
_workRam = workRam;
|
||||
_wramPosition = 0;
|
||||
|
@ -38,6 +41,8 @@ public:
|
|||
addr &= 0xFFFF;
|
||||
if(addr >= 0x2140 && addr <= 0x217F) {
|
||||
return _spc->Read(addr & 0x03);
|
||||
} else if(addr == 0x4016 || addr == 0x4017) {
|
||||
return _controlManager->Read(addr);
|
||||
} else if(addr < 0x4200) {
|
||||
return _ppu->Read(addr);
|
||||
} else {
|
||||
|
@ -61,6 +66,8 @@ public:
|
|||
case 0x2182: _wramPosition = (_wramPosition & 0x100FF) | (value << 8); break;
|
||||
case 0x2183: _wramPosition = (_wramPosition & 0xFFFF) | ((value & 0x01) << 16); break;
|
||||
}
|
||||
} else if(addr == 0x4016) {
|
||||
return _controlManager->Write(addr, value);
|
||||
} else if(addr == 0x420B || addr == 0x420C || addr >= 0x4300) {
|
||||
_dmaController->Write(addr, value);
|
||||
} else if(addr < 0x4200) {
|
||||
|
@ -104,7 +111,7 @@ public:
|
|||
_workRam = new uint8_t[MemoryManager::WorkRamSize];
|
||||
|
||||
_dmaController.reset(new DmaController(console->GetMemoryManager().get()));
|
||||
_cpuRegisterHandler.reset(new CpuRegisterHandler(_ppu.get(), console->GetSpc().get(), _dmaController.get(), console->GetInternalRegisters().get(), _workRam));
|
||||
_cpuRegisterHandler.reset(new CpuRegisterHandler(_ppu.get(), console->GetSpc().get(), _dmaController.get(), console->GetInternalRegisters().get(), console->GetControlManager().get(), _workRam));
|
||||
|
||||
memset(_handlers, 0, sizeof(_handlers));
|
||||
//memset(_workRam, 0, 128 * 1024);
|
||||
|
|
57
Core/Ppu.cpp
57
Core/Ppu.cpp
|
@ -5,6 +5,7 @@
|
|||
#include "Cpu.h"
|
||||
#include "Spc.h"
|
||||
#include "InternalRegisters.h"
|
||||
#include "ControlManager.h"
|
||||
#include "VideoDecoder.h"
|
||||
#include "NotificationManager.h"
|
||||
|
||||
|
@ -41,6 +42,11 @@ Ppu::~Ppu()
|
|||
delete[] _outputBuffers[1];
|
||||
}
|
||||
|
||||
uint32_t Ppu::GetFrameCount()
|
||||
{
|
||||
return _frameCount;
|
||||
}
|
||||
|
||||
PpuState Ppu::GetState()
|
||||
{
|
||||
return {
|
||||
|
@ -57,17 +63,19 @@ void Ppu::Exec()
|
|||
_scanline++;
|
||||
|
||||
if(_scanline == 225) {
|
||||
_frameCount++;
|
||||
_console->GetSpc()->ProcessEndFrame();
|
||||
_nmiFlag = true;
|
||||
_console->GetControlManager()->UpdateInputState();
|
||||
_regs->ProcessAutoJoypadRead();
|
||||
_regs->SetNmiFlag(true);
|
||||
SendFrame();
|
||||
|
||||
if(_regs->IsNmiEnabled()) {
|
||||
_console->GetCpu()->SetNmiFlag();
|
||||
}
|
||||
} else if(_scanline == 261) {
|
||||
_nmiFlag = false;
|
||||
_regs->SetNmiFlag(false);
|
||||
_scanline = 0;
|
||||
_frameCount++;
|
||||
}
|
||||
|
||||
if(_regs->IsVerticalIrqEnabled() && !_regs->IsHorizontalIrqEnabled() && _scanline == _regs->GetVerticalTimer()) {
|
||||
|
@ -175,25 +183,6 @@ uint8_t* Ppu::GetSpriteRam()
|
|||
uint8_t Ppu::Read(uint16_t addr)
|
||||
{
|
||||
switch(addr) {
|
||||
case 0x4210: {
|
||||
//open bus implementation here is needed to pass CPUPHL test
|
||||
uint8_t value = (_nmiFlag ? 0x80 : 0) | ((addr >> 8) & 0x70);
|
||||
_nmiFlag = false;
|
||||
return value;
|
||||
}
|
||||
|
||||
case 0x4211: {
|
||||
uint8_t value = (_console->GetCpu()->CheckIrqSource(IrqSource::Ppu) ? 0x80 : 0) | ((addr >> 8) & 0x7F);
|
||||
_console->GetCpu()->ClearIrqSource(IrqSource::Ppu);
|
||||
return value;
|
||||
}
|
||||
|
||||
case 0x4212:
|
||||
return (
|
||||
(_scanline >= 225 ? 0x80 : 0) |
|
||||
((_cycle >= 0x121 || _cycle <= 0x15) ? 0x40 : 0)
|
||||
);
|
||||
|
||||
default:
|
||||
MessageManager::DisplayMessage("Debug", "Unimplemented register read: " + HexUtilities::ToHex(addr));
|
||||
break;
|
||||
|
@ -205,6 +194,30 @@ uint8_t Ppu::Read(uint16_t addr)
|
|||
void Ppu::Write(uint32_t addr, uint8_t value)
|
||||
{
|
||||
switch(addr) {
|
||||
case 0x2101:
|
||||
//TODO
|
||||
//_spriteMode = (value & 0xE0) >> 5;
|
||||
//_spriteBaseAddress = (value & 0x07) << 13;
|
||||
//_spriteAddressOffset = (value & 0x18) << 9;
|
||||
break;
|
||||
|
||||
case 0x2102:
|
||||
//TODO
|
||||
//_oamAddress = (value << 1);
|
||||
break;
|
||||
|
||||
case 0x2103:
|
||||
//TODO
|
||||
//_oamTableSelect = value & 0x01;
|
||||
//_enableOamPriority = (value & 0x80) != 0;
|
||||
break;
|
||||
|
||||
case 0x2104:
|
||||
//TODO
|
||||
//_oam[_oamAddress] = value;
|
||||
//_oamAddress++;
|
||||
break;
|
||||
|
||||
case 0x2105:
|
||||
_bgMode = value & 0x07;
|
||||
|
||||
|
|
|
@ -23,8 +23,6 @@ private:
|
|||
uint8_t _bgMode = 0;
|
||||
LayerConfig _layerConfig[4];
|
||||
|
||||
bool _nmiFlag = false;
|
||||
|
||||
uint8_t *_vram;
|
||||
uint16_t _vramAddress;
|
||||
uint8_t _vramIncrementValue;
|
||||
|
@ -45,6 +43,7 @@ public:
|
|||
Ppu(shared_ptr<Console> console);
|
||||
~Ppu();
|
||||
|
||||
uint32_t GetFrameCount();
|
||||
PpuState GetState();
|
||||
|
||||
void Exec();
|
||||
|
|
|
@ -127,3 +127,80 @@ struct ScreenSize
|
|||
int32_t Height;
|
||||
double Scale;
|
||||
};
|
||||
|
||||
struct KeyMapping
|
||||
{
|
||||
uint32_t A = 0;
|
||||
uint32_t B = 0;
|
||||
uint32_t X = 0;
|
||||
uint32_t Y = 0;
|
||||
uint32_t L = 0;
|
||||
uint32_t R = 0;
|
||||
uint32_t Up = 0;
|
||||
uint32_t Down = 0;
|
||||
uint32_t Left = 0;
|
||||
uint32_t Right = 0;
|
||||
uint32_t Start = 0;
|
||||
uint32_t Select = 0;
|
||||
|
||||
uint32_t TurboA = 0;
|
||||
uint32_t TurboB = 0;
|
||||
uint32_t TurboX = 0;
|
||||
uint32_t TurboY = 0;
|
||||
uint32_t TurboL = 0;
|
||||
uint32_t TurboR = 0;
|
||||
uint32_t TurboSelect = 0;
|
||||
uint32_t TurboStart = 0;
|
||||
|
||||
bool HasKeySet()
|
||||
{
|
||||
if(A || B || X || Y || L || R || Up || Down || Left || Right || Start || Select || TurboA || TurboB || TurboX || TurboY || TurboL || TurboR || TurboStart || TurboSelect) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
bool HasKeyBinding(uint32_t* buttons, uint32_t count)
|
||||
{
|
||||
for(uint32_t i = 0; i < count; i++) {
|
||||
if(buttons[i] != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct KeyMappingSet
|
||||
{
|
||||
KeyMapping Mapping1;
|
||||
KeyMapping Mapping2;
|
||||
KeyMapping Mapping3;
|
||||
KeyMapping Mapping4;
|
||||
uint32_t TurboSpeed = 0;
|
||||
|
||||
vector<KeyMapping> GetKeyMappingArray()
|
||||
{
|
||||
vector<KeyMapping> keyMappings;
|
||||
if(Mapping1.HasKeySet()) {
|
||||
keyMappings.push_back(Mapping1);
|
||||
}
|
||||
if(Mapping2.HasKeySet()) {
|
||||
keyMappings.push_back(Mapping2);
|
||||
}
|
||||
if(Mapping3.HasKeySet()) {
|
||||
keyMappings.push_back(Mapping3);
|
||||
}
|
||||
if(Mapping4.HasKeySet()) {
|
||||
keyMappings.push_back(Mapping4);
|
||||
}
|
||||
return keyMappings;
|
||||
}
|
||||
};
|
||||
|
||||
enum class ControllerType
|
||||
{
|
||||
None = 0,
|
||||
SnesController = 1
|
||||
};
|
98
Core/SnesController.h
Normal file
98
Core/SnesController.h
Normal file
|
@ -0,0 +1,98 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "BaseControlDevice.h"
|
||||
|
||||
class SnesController : public BaseControlDevice
|
||||
{
|
||||
private:
|
||||
uint32_t _stateBuffer = 0;
|
||||
|
||||
protected:
|
||||
enum Buttons { A = 0, B, Select, Start, Up, Down, Left, Right, Y, X, L, R };
|
||||
|
||||
string GetKeyNames() override
|
||||
{
|
||||
return "ABSTUDLRYXLR";
|
||||
}
|
||||
|
||||
void InternalSetStateFromInput() override
|
||||
{
|
||||
for(KeyMapping keyMapping : _keyMappings) {
|
||||
SetPressedState(Buttons::A, keyMapping.A);
|
||||
SetPressedState(Buttons::B, keyMapping.B);
|
||||
SetPressedState(Buttons::Start, keyMapping.Start);
|
||||
SetPressedState(Buttons::Select, keyMapping.Select);
|
||||
SetPressedState(Buttons::Up, keyMapping.Up);
|
||||
SetPressedState(Buttons::Down, keyMapping.Down);
|
||||
SetPressedState(Buttons::Left, keyMapping.Left);
|
||||
SetPressedState(Buttons::Right, keyMapping.Right);
|
||||
SetPressedState(Buttons::X, keyMapping.X);
|
||||
SetPressedState(Buttons::Y, keyMapping.Y);
|
||||
SetPressedState(Buttons::L, keyMapping.L);
|
||||
SetPressedState(Buttons::R, keyMapping.R);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t ToByte()
|
||||
{
|
||||
//"A Super NES controller returns a 16-bit report in a similar order: B, Y, Select, Start, Up, Down, Left, Right, A, X, L, R, then four 0 bits."
|
||||
|
||||
return
|
||||
(uint8_t)IsPressed(Buttons::B) |
|
||||
((uint8_t)IsPressed(Buttons::Y) << 1) |
|
||||
((uint8_t)IsPressed(Buttons::Select) << 2) |
|
||||
((uint8_t)IsPressed(Buttons::Start) << 3) |
|
||||
((uint8_t)IsPressed(Buttons::Up) << 4) |
|
||||
((uint8_t)IsPressed(Buttons::Down) << 5) |
|
||||
((uint8_t)IsPressed(Buttons::Left) << 6) |
|
||||
((uint8_t)IsPressed(Buttons::Right) << 7) |
|
||||
((uint8_t)IsPressed(Buttons::A) << 8) |
|
||||
((uint8_t)IsPressed(Buttons::X) << 9) |
|
||||
((uint8_t)IsPressed(Buttons::L) << 10) |
|
||||
((uint8_t)IsPressed(Buttons::R) << 11);
|
||||
}
|
||||
|
||||
//TODO
|
||||
/*
|
||||
void StreamState(bool saving) override
|
||||
{
|
||||
BaseControlDevice::StreamState(saving);
|
||||
Stream(_stateBuffer);
|
||||
}*/
|
||||
|
||||
void RefreshStateBuffer() override
|
||||
{
|
||||
_stateBuffer = (uint32_t)ToByte();
|
||||
}
|
||||
|
||||
public:
|
||||
SnesController(shared_ptr<Console> console, uint8_t port, KeyMappingSet keyMappings) : BaseControlDevice(console, port, keyMappings)
|
||||
{
|
||||
}
|
||||
|
||||
uint8_t ReadRam(uint16_t addr) override
|
||||
{
|
||||
uint8_t output = 0;
|
||||
|
||||
if(IsCurrentPort(addr)) {
|
||||
if(_port >= 2) {
|
||||
output = (_stateBuffer & 0x01) << 1; //P3/P4 are reported in bit 2
|
||||
} else {
|
||||
output = _stateBuffer & 0x01;
|
||||
}
|
||||
_stateBuffer >>= 1;
|
||||
|
||||
//"All subsequent reads will return D=1 on an authentic controller but may return D=0 on third party controllers."
|
||||
_stateBuffer |= 0x8000;
|
||||
|
||||
StrobeProcessRead();
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void WriteRam(uint16_t addr, uint8_t value) override
|
||||
{
|
||||
StrobeProcessWrite(value);
|
||||
}
|
||||
};
|
|
@ -3,7 +3,6 @@
|
|||
#include "SNES_SPC.h"
|
||||
#include "Console.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "Ppu.h"
|
||||
#include "SoundMixer.h"
|
||||
#include "../Utilities/VirtualFile.h"
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "PpuTypes.h"
|
||||
|
||||
class Console;
|
||||
struct SNES_SPC;
|
||||
|
|
|
@ -13,7 +13,7 @@ using System.Windows.Forms;
|
|||
|
||||
namespace Mesen.GUI.Forms
|
||||
{
|
||||
public partial class frmMain : BaseForm
|
||||
public partial class frmMain : BaseInputForm
|
||||
{
|
||||
private NotificationListener _notifListener;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue