mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2025-01-18 06:25:37 +00:00
Pad: Set up memory cards via settings
This commit is contained in:
parent
739ada4721
commit
0092cb1016
|
@ -12,6 +12,7 @@ HostInterface::~HostInterface() = default;
|
||||||
bool HostInterface::InitializeSystem(const char* filename, const char* exp1_filename)
|
bool HostInterface::InitializeSystem(const char* filename, const char* exp1_filename)
|
||||||
{
|
{
|
||||||
Settings settings;
|
Settings settings;
|
||||||
|
settings.memory_card_a_filename = "memory_card_a.mcd";
|
||||||
|
|
||||||
m_system = std::make_unique<System>(this, settings);
|
m_system = std::make_unique<System>(this, settings);
|
||||||
if (!m_system->Initialize())
|
if (!m_system->Initialize())
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
#include "memory_card.h"
|
#include "memory_card.h"
|
||||||
|
#include "YBaseLib/AutoReleasePtr.h"
|
||||||
|
#include "YBaseLib/ByteStream.h"
|
||||||
|
#include "YBaseLib/FileSystem.h"
|
||||||
#include "YBaseLib/Log.h"
|
#include "YBaseLib/Log.h"
|
||||||
#include "common/state_wrapper.h"
|
#include "common/state_wrapper.h"
|
||||||
|
#include "host_interface.h"
|
||||||
|
#include "system.h"
|
||||||
|
#include <cstdio>
|
||||||
Log_SetChannel(MemoryCard);
|
Log_SetChannel(MemoryCard);
|
||||||
|
|
||||||
MemoryCard::MemoryCard()
|
MemoryCard::MemoryCard(System* system) : m_system(system)
|
||||||
{
|
{
|
||||||
m_FLAG.no_write_yet = true;
|
m_FLAG.no_write_yet = true;
|
||||||
Format();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryCard::~MemoryCard() = default;
|
MemoryCard::~MemoryCard() = default;
|
||||||
|
@ -24,6 +29,7 @@ bool MemoryCard::DoState(StateWrapper& sw)
|
||||||
sw.Do(&m_checksum);
|
sw.Do(&m_checksum);
|
||||||
sw.Do(&m_last_byte);
|
sw.Do(&m_last_byte);
|
||||||
sw.Do(&m_data);
|
sw.Do(&m_data);
|
||||||
|
sw.Do(&m_changed);
|
||||||
|
|
||||||
return !sw.HasError();
|
return !sw.HasError();
|
||||||
}
|
}
|
||||||
|
@ -35,6 +41,7 @@ void MemoryCard::ResetTransferState()
|
||||||
m_sector_offset = 0;
|
m_sector_offset = 0;
|
||||||
m_checksum = 0;
|
m_checksum = 0;
|
||||||
m_last_byte = 0;
|
m_last_byte = 0;
|
||||||
|
m_changed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MemoryCard::Transfer(const u8 data_in, u8* data_out)
|
bool MemoryCard::Transfer(const u8 data_in, u8* data_out)
|
||||||
|
@ -134,7 +141,12 @@ bool MemoryCard::Transfer(const u8 data_in, u8* data_out)
|
||||||
m_checksum ^= data_in;
|
m_checksum ^= data_in;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_data[ZeroExtend32(m_address) * SECTOR_SIZE + m_sector_offset] = data_in;
|
const u32 offset = ZeroExtend32(m_address) * SECTOR_SIZE + m_sector_offset;
|
||||||
|
if (m_data[offset] != data_in)
|
||||||
|
m_changed = true;
|
||||||
|
|
||||||
|
m_data[offset] = data_in;
|
||||||
|
|
||||||
*data_out = m_last_byte;
|
*data_out = m_last_byte;
|
||||||
ack = true;
|
ack = true;
|
||||||
|
|
||||||
|
@ -143,6 +155,11 @@ bool MemoryCard::Transfer(const u8 data_in, u8* data_out)
|
||||||
{
|
{
|
||||||
m_state = State::WriteChecksum;
|
m_state = State::WriteChecksum;
|
||||||
m_sector_offset = 0;
|
m_sector_offset = 0;
|
||||||
|
if (m_changed)
|
||||||
|
{
|
||||||
|
m_changed = false;
|
||||||
|
SaveToFile();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -213,9 +230,24 @@ bool MemoryCard::Transfer(const u8 data_in, u8* data_out)
|
||||||
return ack;
|
return ack;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<MemoryCard> MemoryCard::Create()
|
std::shared_ptr<MemoryCard> MemoryCard::Create(System* system)
|
||||||
{
|
{
|
||||||
return std::make_shared<MemoryCard>();
|
auto mc = std::make_shared<MemoryCard>(system);
|
||||||
|
mc->Format();
|
||||||
|
return mc;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<MemoryCard> MemoryCard::Open(System* system, std::string_view filename)
|
||||||
|
{
|
||||||
|
auto mc = std::make_shared<MemoryCard>(system);
|
||||||
|
mc->m_filename = filename;
|
||||||
|
if (!mc->LoadFromFile())
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Memory card at '%s' could not be read, formatting.");
|
||||||
|
mc->Format();
|
||||||
|
}
|
||||||
|
|
||||||
|
return mc;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 MemoryCard::ChecksumFrame(const u8* fptr)
|
u8 MemoryCard::ChecksumFrame(const u8* fptr)
|
||||||
|
@ -285,3 +317,46 @@ u8* MemoryCard::GetSectorPtr(u32 sector)
|
||||||
Assert(sector < NUM_SECTORS);
|
Assert(sector < NUM_SECTORS);
|
||||||
return &m_data[sector * SECTOR_SIZE];
|
return &m_data[sector * SECTOR_SIZE];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MemoryCard::LoadFromFile()
|
||||||
|
{
|
||||||
|
AutoReleasePtr<ByteStream> stream =
|
||||||
|
FileSystem::OpenFile(m_filename.c_str(), BYTESTREAM_OPEN_READ | BYTESTREAM_OPEN_STREAMED);
|
||||||
|
if (!stream)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const size_t num_read = stream->Read(m_data.data(), SECTOR_SIZE * NUM_SECTORS);
|
||||||
|
if (num_read != (SECTOR_SIZE * NUM_SECTORS))
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Only read %zu of %u sectors from '%s'", num_read / SECTOR_SIZE, NUM_SECTORS, m_filename.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MemoryCard::SaveToFile()
|
||||||
|
{
|
||||||
|
if (m_filename.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
AutoReleasePtr<ByteStream> stream =
|
||||||
|
FileSystem::OpenFile(m_filename.c_str(), BYTESTREAM_OPEN_CREATE | BYTESTREAM_OPEN_TRUNCATE | BYTESTREAM_OPEN_WRITE |
|
||||||
|
BYTESTREAM_OPEN_ATOMIC_UPDATE | BYTESTREAM_OPEN_STREAMED);
|
||||||
|
if (!stream)
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Failed to open '%s' for writing.", m_filename.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stream->Write2(m_data.data(), SECTOR_SIZE * NUM_SECTORS) || !stream->Commit())
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Failed to write sectors to '%s'", m_filename.c_str());
|
||||||
|
stream->Discard();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log_InfoPrintf("Saved memory card to '%s'", m_filename.c_str());
|
||||||
|
m_system->GetHostInterface()->AddOSDMessage(SmallString::FromFormat("Saved memory card to '%s'", m_filename.c_str()));
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -1,8 +1,12 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "common/bitfield.h"
|
#include "common/bitfield.h"
|
||||||
#include "pad_device.h"
|
#include "pad_device.h"
|
||||||
#include <memory>
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
class System;
|
||||||
|
|
||||||
class MemoryCard final : public PadDevice
|
class MemoryCard final : public PadDevice
|
||||||
{
|
{
|
||||||
|
@ -14,10 +18,11 @@ public:
|
||||||
NUM_SECTORS = DATA_SIZE / SECTOR_SIZE
|
NUM_SECTORS = DATA_SIZE / SECTOR_SIZE
|
||||||
};
|
};
|
||||||
|
|
||||||
MemoryCard();
|
MemoryCard(System* system);
|
||||||
~MemoryCard() override;
|
~MemoryCard() override;
|
||||||
|
|
||||||
static std::shared_ptr<MemoryCard> Create();
|
static std::shared_ptr<MemoryCard> Create(System* system);
|
||||||
|
static std::shared_ptr<MemoryCard> Open(System* system, std::string_view filename);
|
||||||
|
|
||||||
void Reset() override;
|
void Reset() override;
|
||||||
bool DoState(StateWrapper& sw) override;
|
bool DoState(StateWrapper& sw) override;
|
||||||
|
@ -70,11 +75,19 @@ private:
|
||||||
|
|
||||||
u8* GetSectorPtr(u32 sector);
|
u8* GetSectorPtr(u32 sector);
|
||||||
|
|
||||||
|
bool LoadFromFile();
|
||||||
|
bool SaveToFile();
|
||||||
|
|
||||||
|
System* m_system;
|
||||||
|
|
||||||
State m_state = State::Idle;
|
State m_state = State::Idle;
|
||||||
u16 m_address = 0;
|
u16 m_address = 0;
|
||||||
u8 m_sector_offset = 0;
|
u8 m_sector_offset = 0;
|
||||||
u8 m_checksum = 0;
|
u8 m_checksum = 0;
|
||||||
u8 m_last_byte = 0;
|
u8 m_last_byte = 0;
|
||||||
|
bool m_changed = false;
|
||||||
|
|
||||||
std::array<u8, DATA_SIZE> m_data{};
|
std::array<u8, DATA_SIZE> m_data{};
|
||||||
|
|
||||||
|
std::string m_filename;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
#include "pad.h"
|
#include "pad.h"
|
||||||
#include "YBaseLib/Log.h"
|
#include "YBaseLib/Log.h"
|
||||||
#include "common/state_wrapper.h"
|
#include "common/state_wrapper.h"
|
||||||
|
#include "host_interface.h"
|
||||||
#include "interrupt_controller.h"
|
#include "interrupt_controller.h"
|
||||||
|
#include "memory_card.h"
|
||||||
#include "pad_device.h"
|
#include "pad_device.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
Log_SetChannel(Pad);
|
Log_SetChannel(Pad);
|
||||||
|
@ -46,6 +48,28 @@ bool Pad::DoState(StateWrapper& sw)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool card_present = static_cast<bool>(m_memory_cards[i]);
|
||||||
|
sw.Do(&card_present);
|
||||||
|
|
||||||
|
if (card_present && !m_memory_cards[i])
|
||||||
|
{
|
||||||
|
const TinyString message = TinyString::FromFormat(
|
||||||
|
"Memory card %c present in save state but not in system. Creating temporary card.", 'A' + i);
|
||||||
|
m_system->GetHostInterface()->AddOSDMessage(message);
|
||||||
|
Log_WarningPrint(message);
|
||||||
|
|
||||||
|
m_memory_cards[i] = MemoryCard::Create(m_system);
|
||||||
|
}
|
||||||
|
else if (!card_present && m_memory_cards[i])
|
||||||
|
{
|
||||||
|
const TinyString message =
|
||||||
|
TinyString::FromFormat("Memory card %u present system but not save state. Removing card.", 'A' + i);
|
||||||
|
m_system->GetHostInterface()->AddOSDMessage(message);
|
||||||
|
Log_WarningPrint(message);
|
||||||
|
|
||||||
|
m_memory_cards[i].reset();
|
||||||
|
}
|
||||||
|
|
||||||
if (m_memory_cards[i])
|
if (m_memory_cards[i])
|
||||||
{
|
{
|
||||||
if (!sw.DoMarker("MemoryCard") || !m_memory_cards[i]->DoState(sw))
|
if (!sw.DoMarker("MemoryCard") || !m_memory_cards[i]->DoState(sw))
|
||||||
|
|
|
@ -10,6 +10,7 @@ class StateWrapper;
|
||||||
class System;
|
class System;
|
||||||
class InterruptController;
|
class InterruptController;
|
||||||
class PadDevice;
|
class PadDevice;
|
||||||
|
class MemoryCard;
|
||||||
|
|
||||||
class Pad
|
class Pad
|
||||||
{
|
{
|
||||||
|
@ -24,8 +25,8 @@ public:
|
||||||
PadDevice* GetController(u32 slot) { return m_controllers[slot].get(); }
|
PadDevice* GetController(u32 slot) { return m_controllers[slot].get(); }
|
||||||
void SetController(u32 slot, std::shared_ptr<PadDevice> dev) { m_controllers[slot] = dev; }
|
void SetController(u32 slot, std::shared_ptr<PadDevice> dev) { m_controllers[slot] = dev; }
|
||||||
|
|
||||||
PadDevice* GetMemoryCard(u32 slot) { return m_memory_cards[slot].get(); }
|
MemoryCard* GetMemoryCard(u32 slot) { return m_memory_cards[slot].get(); }
|
||||||
void SetMemoryCard(u32 slot, std::shared_ptr<PadDevice> dev) { m_memory_cards[slot] = dev; }
|
void SetMemoryCard(u32 slot, std::shared_ptr<MemoryCard> dev) { m_memory_cards[slot] = dev; }
|
||||||
|
|
||||||
u32 ReadRegister(u32 offset);
|
u32 ReadRegister(u32 offset);
|
||||||
void WriteRegister(u32 offset, u32 value);
|
void WriteRegister(u32 offset, u32 value);
|
||||||
|
@ -118,5 +119,5 @@ private:
|
||||||
InlineFIFOQueue<u8, 2> m_TX_FIFO;
|
InlineFIFOQueue<u8, 2> m_TX_FIFO;
|
||||||
|
|
||||||
std::array<std::shared_ptr<PadDevice>, NUM_SLOTS> m_controllers;
|
std::array<std::shared_ptr<PadDevice>, NUM_SLOTS> m_controllers;
|
||||||
std::array<std::shared_ptr<PadDevice>, NUM_SLOTS> m_memory_cards;
|
std::array<std::shared_ptr<MemoryCard>, NUM_SLOTS> m_memory_cards;
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,4 +32,7 @@ struct Settings
|
||||||
} debugging;
|
} debugging;
|
||||||
|
|
||||||
// TODO: Controllers, memory cards, etc.
|
// TODO: Controllers, memory cards, etc.
|
||||||
|
|
||||||
|
std::string memory_card_a_filename;
|
||||||
|
std::string memory_card_b_filename;
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "gpu.h"
|
#include "gpu.h"
|
||||||
#include "interrupt_controller.h"
|
#include "interrupt_controller.h"
|
||||||
#include "mdec.h"
|
#include "mdec.h"
|
||||||
|
#include "memory_card.h"
|
||||||
#include "pad.h"
|
#include "pad.h"
|
||||||
#include "pad_device.h"
|
#include "pad_device.h"
|
||||||
#include "spu.h"
|
#include "spu.h"
|
||||||
|
@ -98,6 +99,8 @@ bool System::Initialize()
|
||||||
if (!m_mdec->Initialize(this, m_dma.get()))
|
if (!m_mdec->Initialize(this, m_dma.get()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
UpdateMemoryCards();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,9 +364,24 @@ void System::SetController(u32 slot, std::shared_ptr<PadDevice> dev)
|
||||||
m_pad->SetController(slot, std::move(dev));
|
m_pad->SetController(slot, std::move(dev));
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::SetMemoryCard(u32 slot, std::shared_ptr<PadDevice> dev)
|
void System::UpdateMemoryCards()
|
||||||
{
|
{
|
||||||
m_pad->SetMemoryCard(slot, std::move(dev));
|
m_pad->SetMemoryCard(0, nullptr);
|
||||||
|
m_pad->SetMemoryCard(1, nullptr);
|
||||||
|
|
||||||
|
if (!m_settings.memory_card_a_filename.empty())
|
||||||
|
{
|
||||||
|
std::shared_ptr<MemoryCard> card = MemoryCard::Open(this, m_settings.memory_card_a_filename);
|
||||||
|
if (card)
|
||||||
|
m_pad->SetMemoryCard(0, std::move(card));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_settings.memory_card_b_filename.empty())
|
||||||
|
{
|
||||||
|
std::shared_ptr<MemoryCard> card = MemoryCard::Open(this, m_settings.memory_card_b_filename);
|
||||||
|
if (card)
|
||||||
|
m_pad->SetMemoryCard(1, std::move(card));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool System::HasMedia() const
|
bool System::HasMedia() const
|
||||||
|
|
|
@ -71,7 +71,7 @@ public:
|
||||||
void StallCPU(TickCount ticks);
|
void StallCPU(TickCount ticks);
|
||||||
|
|
||||||
void SetController(u32 slot, std::shared_ptr<PadDevice> dev);
|
void SetController(u32 slot, std::shared_ptr<PadDevice> dev);
|
||||||
void SetMemoryCard(u32 slot, std::shared_ptr<PadDevice> dev);
|
void UpdateMemoryCards();
|
||||||
|
|
||||||
bool HasMedia() const;
|
bool HasMedia() const;
|
||||||
bool InsertMedia(const char* path);
|
bool InsertMedia(const char* path);
|
||||||
|
|
|
@ -271,9 +271,6 @@ void SDLInterface::ConnectDevices()
|
||||||
{
|
{
|
||||||
m_controller = DigitalController::Create();
|
m_controller = DigitalController::Create();
|
||||||
m_system->SetController(0, m_controller);
|
m_system->SetController(0, m_controller);
|
||||||
|
|
||||||
m_memory_card = MemoryCard::Create();
|
|
||||||
m_system->SetMemoryCard(0, m_memory_card);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<SDLInterface> SDLInterface::Create(const char* filename /* = nullptr */,
|
std::unique_ptr<SDLInterface> SDLInterface::Create(const char* filename /* = nullptr */,
|
||||||
|
|
|
@ -111,7 +111,6 @@ private:
|
||||||
std::map<int, SDL_GameController*> m_sdl_controllers;
|
std::map<int, SDL_GameController*> m_sdl_controllers;
|
||||||
|
|
||||||
std::shared_ptr<DigitalController> m_controller;
|
std::shared_ptr<DigitalController> m_controller;
|
||||||
std::shared_ptr<MemoryCard> m_memory_card;
|
|
||||||
|
|
||||||
float m_vps = 0.0f;
|
float m_vps = 0.0f;
|
||||||
float m_fps = 0.0f;
|
float m_fps = 0.0f;
|
||||||
|
|
Loading…
Reference in a new issue