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)
|
||||
{
|
||||
Settings settings;
|
||||
settings.memory_card_a_filename = "memory_card_a.mcd";
|
||||
|
||||
m_system = std::make_unique<System>(this, settings);
|
||||
if (!m_system->Initialize())
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -32,4 +32,7 @@ struct Settings
|
|||
} debugging;
|
||||
|
||||
// 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 "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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */,
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue