Pad: Set up memory cards via settings

This commit is contained in:
Connor McLaughlin 2019-10-27 16:45:23 +10:00
parent 739ada4721
commit 0092cb1016
10 changed files with 149 additions and 18 deletions

View File

@ -12,6 +12,7 @@ HostInterface::~HostInterface() = default;
bool HostInterface::InitializeSystem(const char* filename, const char* exp1_filename)
{
Settings settings;
settings.memory_card_a_filename = "memory_card_a.mcd";
m_system = std::make_unique<System>(this, settings);
if (!m_system->Initialize())

View File

@ -1,12 +1,17 @@
#include "memory_card.h"
#include "YBaseLib/AutoReleasePtr.h"
#include "YBaseLib/ByteStream.h"
#include "YBaseLib/FileSystem.h"
#include "YBaseLib/Log.h"
#include "common/state_wrapper.h"
#include "host_interface.h"
#include "system.h"
#include <cstdio>
Log_SetChannel(MemoryCard);
MemoryCard::MemoryCard()
MemoryCard::MemoryCard(System* system) : m_system(system)
{
m_FLAG.no_write_yet = true;
Format();
}
MemoryCard::~MemoryCard() = default;
@ -24,6 +29,7 @@ bool MemoryCard::DoState(StateWrapper& sw)
sw.Do(&m_checksum);
sw.Do(&m_last_byte);
sw.Do(&m_data);
sw.Do(&m_changed);
return !sw.HasError();
}
@ -35,6 +41,7 @@ void MemoryCard::ResetTransferState()
m_sector_offset = 0;
m_checksum = 0;
m_last_byte = 0;
m_changed = false;
}
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_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;
ack = true;
@ -143,6 +155,11 @@ bool MemoryCard::Transfer(const u8 data_in, u8* data_out)
{
m_state = State::WriteChecksum;
m_sector_offset = 0;
if (m_changed)
{
m_changed = false;
SaveToFile();
}
}
}
break;
@ -213,9 +230,24 @@ bool MemoryCard::Transfer(const u8 data_in, u8* data_out)
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)
@ -285,3 +317,46 @@ u8* MemoryCard::GetSectorPtr(u32 sector)
Assert(sector < NUM_SECTORS);
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;
}

View File

@ -1,8 +1,12 @@
#pragma once
#include "common/bitfield.h"
#include "pad_device.h"
#include <memory>
#include <array>
#include <memory>
#include <string>
#include <string_view>
class System;
class MemoryCard final : public PadDevice
{
@ -14,10 +18,11 @@ public:
NUM_SECTORS = DATA_SIZE / SECTOR_SIZE
};
MemoryCard();
MemoryCard(System* system);
~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;
bool DoState(StateWrapper& sw) override;
@ -70,11 +75,19 @@ private:
u8* GetSectorPtr(u32 sector);
bool LoadFromFile();
bool SaveToFile();
System* m_system;
State m_state = State::Idle;
u16 m_address = 0;
u8 m_sector_offset = 0;
u8 m_checksum = 0;
u8 m_last_byte = 0;
bool m_changed = false;
std::array<u8, DATA_SIZE> m_data{};
std::string m_filename;
};

View File

@ -1,7 +1,9 @@
#include "pad.h"
#include "YBaseLib/Log.h"
#include "common/state_wrapper.h"
#include "host_interface.h"
#include "interrupt_controller.h"
#include "memory_card.h"
#include "pad_device.h"
#include "system.h"
Log_SetChannel(Pad);
@ -46,6 +48,28 @@ bool Pad::DoState(StateWrapper& sw)
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 (!sw.DoMarker("MemoryCard") || !m_memory_cards[i]->DoState(sw))

View File

@ -10,6 +10,7 @@ class StateWrapper;
class System;
class InterruptController;
class PadDevice;
class MemoryCard;
class Pad
{
@ -24,8 +25,8 @@ public:
PadDevice* GetController(u32 slot) { return m_controllers[slot].get(); }
void SetController(u32 slot, std::shared_ptr<PadDevice> dev) { m_controllers[slot] = dev; }
PadDevice* GetMemoryCard(u32 slot) { return m_memory_cards[slot].get(); }
void SetMemoryCard(u32 slot, std::shared_ptr<PadDevice> dev) { m_memory_cards[slot] = dev; }
MemoryCard* GetMemoryCard(u32 slot) { return m_memory_cards[slot].get(); }
void SetMemoryCard(u32 slot, std::shared_ptr<MemoryCard> dev) { m_memory_cards[slot] = dev; }
u32 ReadRegister(u32 offset);
void WriteRegister(u32 offset, u32 value);
@ -118,5 +119,5 @@ private:
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_memory_cards;
std::array<std::shared_ptr<MemoryCard>, NUM_SLOTS> m_memory_cards;
};

View File

@ -32,4 +32,7 @@ struct Settings
} debugging;
// TODO: Controllers, memory cards, etc.
std::string memory_card_a_filename;
std::string memory_card_b_filename;
};

View File

@ -9,6 +9,7 @@
#include "gpu.h"
#include "interrupt_controller.h"
#include "mdec.h"
#include "memory_card.h"
#include "pad.h"
#include "pad_device.h"
#include "spu.h"
@ -98,6 +99,8 @@ bool System::Initialize()
if (!m_mdec->Initialize(this, m_dma.get()))
return false;
UpdateMemoryCards();
return true;
}
@ -361,9 +364,24 @@ void System::SetController(u32 slot, std::shared_ptr<PadDevice> 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

View File

@ -71,7 +71,7 @@ public:
void StallCPU(TickCount ticks);
void SetController(u32 slot, std::shared_ptr<PadDevice> dev);
void SetMemoryCard(u32 slot, std::shared_ptr<PadDevice> dev);
void UpdateMemoryCards();
bool HasMedia() const;
bool InsertMedia(const char* path);

View File

@ -271,9 +271,6 @@ void SDLInterface::ConnectDevices()
{
m_controller = DigitalController::Create();
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 */,

View File

@ -111,7 +111,6 @@ private:
std::map<int, SDL_GameController*> m_sdl_controllers;
std::shared_ptr<DigitalController> m_controller;
std::shared_ptr<MemoryCard> m_memory_card;
float m_vps = 0.0f;
float m_fps = 0.0f;