Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SIO0 overhaul #1673

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
362 changes: 333 additions & 29 deletions src/core/memorycard.cc

Large diffs are not rendered by default.

158 changes: 129 additions & 29 deletions src/core/memorycard.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,22 @@

#include <stdint.h>

#include "core/psxemulator.h"
#include "core/sstate.h"

namespace PCSX {
class SIO;
class Memorycards;

/// <summary>
/// Implements a memory card for SIO
/// </summary>
class MemoryCard {
public:
MemoryCard() : m_sio(nullptr) { memset(m_mcdData, 0, c_cardSize); }
MemoryCard(SIO *parent) : m_sio(parent) { memset(m_mcdData, 0, c_cardSize); }
MemoryCard(uint8_t device_index) : m_deviceIndex(device_index){}

// Hardware events
void acknowledge();

void deselect() {
memset(&m_tempBuffer, 0, c_sectorSize);
m_currentCommand = Commands::None;
Expand All @@ -41,21 +45,16 @@ class MemoryCard {
m_sector = 0;
m_spdr = Responses::IdleHighZ;
}
void reset() {
deselect();
m_directoryFlag = Flags::DirectoryUnread;
}

void setPocketstationEnabled(bool enabled) { m_pocketstationEnabled = enabled; };

// File system / data manipulation
void commit(const PCSX::u8string path) {
if (!m_savedToDisk) {
saveMcd(path);
}
}
void createMcd(PCSX::u8string mcd);
bool dataChanged() { return !m_savedToDisk; }
void disablePocketstation() { m_pocketstationEnabled = false; };
void enablePocketstation() { m_pocketstationEnabled = true; };
void commit();
char *getMcdData() { return m_mcdData; }
void loadMcd(PCSX::u8string mcd);
void saveMcd(PCSX::u8string mcd, const char *data, uint32_t adr, size_t size);
void saveMcd(PCSX::u8string mcd) { saveMcd(mcd, m_mcdData, 0, c_cardSize); }

private:
enum Commands : uint8_t {
Expand Down Expand Up @@ -97,21 +96,21 @@ class MemoryCard {
friend class SIO;
friend SaveStates::SaveState SaveStates::constructSaveState();

static constexpr size_t c_sectorSize = 8 * 16;
static constexpr size_t c_blockSize = 8192;
static constexpr size_t c_cardSize = 1024 * c_sectorSize;
static constexpr size_t c_sectorSize = 8 * 16; // 80h bytes per sector/frame
static constexpr size_t c_blockSize = c_sectorSize * 64; // 40h sectors per block
static constexpr size_t c_cardSize = c_blockSize * 16; // 16 blocks per frame(directory+15 saves);

// State machine / handlers
uint8_t transceive(uint8_t value);
uint8_t tickReadCommand(uint8_t value);
uint8_t tickWriteCommand(uint8_t value);
uint8_t tickPS_GetDirIndex(uint8_t value); // 5Ah
uint8_t tickPS_GetVersion(uint8_t value); // 58h
uint8_t tickPS_PrepFileExec(uint8_t value); // 59h
uint8_t tickPS_ExecCustom(uint8_t value); // 5Dh

char m_mcdData[c_cardSize];
uint8_t m_tempBuffer[c_sectorSize];
uint8_t transceive(uint8_t value, bool *ack); // *
uint8_t tickReadCommand(uint8_t value, bool *ack); // 52h
uint8_t tickWriteCommand(uint8_t value, bool *ack); // 57h
uint8_t tickPS_GetDirIndex(uint8_t value, bool *ack); // 5Ah
uint8_t tickPS_GetVersion(uint8_t value, bool *ack); // 58h
uint8_t tickPS_PrepFileExec(uint8_t value, bool *ack); // 59h
uint8_t tickPS_ExecCustom(uint8_t value, bool *ack); // 5Dh

char m_mcdData[c_cardSize] = {0};
uint8_t m_tempBuffer[c_blockSize] = {0};
bool m_savedToDisk = false;

uint8_t m_checksumIn = 0, m_checksumOut = 0;
Expand All @@ -128,7 +127,108 @@ class MemoryCard {
bool m_pocketstationEnabled = false;
uint16_t m_directoryIndex = 0;

SIO *m_sio;
SIO *m_sio = nullptr;
uint8_t m_deviceIndex = 0;
};

/// <summary>
/// Helper functions for MemoryCard class, gui, and filesystem
/// </summary>
class MemoryCards {
public:
void deselect() {
m_memoryCard[0].deselect();
m_memoryCard[1].deselect();
}

void reset() {
m_memoryCard[0].reset();
m_memoryCard[1].reset();
}

struct McdBlock {
McdBlock() { reset(); }
int mcd;
int number;
std::string titleAscii;
std::string titleSjis;
std::string titleUtf8;
std::string id;
std::string name;
uint32_t fileSize;
uint32_t iconCount;
uint16_t icon[16 * 16 * 3];
uint32_t allocState;
int16_t nextBlock;
void reset() {
mcd = 0;
number = 0;
titleAscii.clear();
titleSjis.clear();
titleUtf8.clear();
id.clear();
name.clear();
fileSize = 0;
iconCount = 0;
memset(icon, 0, sizeof(icon));
allocState = 0;
nextBlock = -1;
}
bool isErased() const { return (allocState & 0xa0) == 0xa0; }
bool isChained() const { return (allocState & ~1) == 0x52; }
};

static constexpr size_t c_sectorSize = 8 * 16; // 80h bytes per sector/frame
static constexpr size_t c_blockSize = c_sectorSize * 64; // 40h sectors per block
static constexpr size_t c_cardSize = c_blockSize * 16; // 16 blocks per frame(directory+15 saves)

bool copyMcdFile(McdBlock block);
void eraseMcdFile(const McdBlock &block);
void eraseMcdFile(int mcd, int block) {
McdBlock info;
getMcdBlockInfo(mcd, block, info);
eraseMcdFile(info);
}
int findFirstFree(int mcd);
unsigned getFreeSpace(int mcd);
unsigned getFileBlockCount(McdBlock block);
void getMcdBlockInfo(int mcd, int block, McdBlock &info);
char *getMcdData(int mcd);
char *getMcdData(const McdBlock &block) { return getMcdData(block.mcd); }

// File operations
void createMcd(PCSX::u8string mcd);
void loadMcds(const CommandLine::args &args);
bool saveMcd(int card_index);

bool loadMcd(PCSX::u8string mcd, char *data);
bool saveMcd(PCSX::u8string mcd, const char *data, uint32_t adr, size_t size);

static constexpr int otherMcd(int mcd) {
if ((mcd != 0) && (mcd != 1)) throw std::runtime_error("Bad memory card number");
if (mcd == 0) return 1;
return 0;
}

PCSX::u8string getMcdPath(int index) {
std::filesystem::path *paths[] = {&PCSX::g_emulator->settings.get<PCSX::Emulator::SettingMcd1>().value,
&PCSX::g_emulator->settings.get<PCSX::Emulator::SettingMcd2>().value};

PCSX::u8string thepath = paths[index]->u8string();
return thepath;
}
bool isCardInserted(int index) {
bool *const inserted_lut[] = {&PCSX::g_emulator->settings.get<PCSX::Emulator::SettingMcd1Inserted>().value,
&PCSX::g_emulator->settings.get<PCSX::Emulator::SettingMcd2Inserted>().value};

return *inserted_lut[index];
}

static constexpr int otherMcd(const McdBlock &block) { return otherMcd(block.mcd); }
void resetCard(int index);
void setPocketstationEnabled(int index, bool enabled);

MemoryCard m_memoryCard[2] = {MemoryCard(0), MemoryCard(1)};
};

} // namespace PCSX
75 changes: 64 additions & 11 deletions src/core/pad.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/***************************************************************************

Check notice on line 1 in src/core/pad.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

ℹ Getting worse: Lines of Code in a Single File

The lines of code increases from 1050 to 1085, improve code health by reducing it to 1000. The number of Lines of Code in a single file. More Lines of Code lowers the code health.

Check notice on line 1 in src/core/pad.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

✅ Getting better: Overall Code Complexity

The mean cyclomatic complexity decreases from 9.58 to 9.53, threshold = 4. This file has many conditional statements (e.g. if, for, while) across its implementation, leading to lower code health. Avoid adding more conditionals.
* Copyright (C) 2019 PCSX-Redux authors *
* *
* This program is free software; you can redistribute it and/or modify *
Expand Down Expand Up @@ -45,8 +45,6 @@
PadsImpl();
void init() override;
void shutdown() override;
uint8_t startPoll(Port port) override;
uint8_t poll(uint8_t value, Port port, uint32_t& padState) override;

json getCfg() override;
void setCfg(const json& j) override;
Expand All @@ -63,10 +61,18 @@
if (pad > m_pads.size()) {
return false;
} else {
return m_pads[pad - 1].isControllerConnected();
return m_pads[pad].isControllerConnected();
}
}

void deselect() {
for (int i = 0; i < m_pads.size(); i++) {
m_pads[i].deselect();
}
}

uint8_t transceive(int index, uint8_t value, bool* ack) override { return m_pads[index].transceive(value, ack); }

private:
PCSX::EventBus::Listener m_listener;
// This is a list of all of the valid GLFW gamepad IDs that we have found querying GLFW.
Expand Down Expand Up @@ -168,6 +174,12 @@
bool isControllerButtonPressed(int button, GLFWgamepadstate* state);
bool isControllerConnected() { return m_settings.get<SettingConnected>(); }

void deselect() {
m_bufferIndex = 0;
m_padState = Pads::PAD_STATE_IDLE;
}
uint8_t transceive(uint8_t value, bool* ack);

json getCfg();
void setCfg(const json& j);
void setDefaults(bool firstController);
Expand Down Expand Up @@ -199,6 +211,13 @@
uint8_t m_stdpar[8] = {0x41, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
uint8_t m_mousepar[6] = {0x12, 0x5a, 0xff, 0xff, 0xff, 0xff};
uint8_t m_analogpar[8] = {0x73, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};

static constexpr size_t c_padBufferSize = 0x1010;

uint8_t m_buffer[c_padBufferSize];
uint32_t m_bufferIndex = 0;
uint32_t m_maxBufferIndex = 0;
uint32_t m_padState = Pads::PAD_STATE_IDLE;
};

std::array<Pad, 2> m_pads;
Expand Down Expand Up @@ -678,15 +697,49 @@
pad.buttonStatus = result ^ 0xffff; // Controls are inverted, so 0 = pressed
}

uint8_t PadsImpl::startPoll(Port port) {
int index = magic_enum::enum_integer(port);
m_pads[index].getButtons();
return m_pads[index].startPoll();
}
uint8_t PadsImpl::Pad::transceive(uint8_t value, bool* ack) {
uint8_t data_out = 0xff;

switch (m_padState) {
case Pads::PAD_STATE_IDLE: // start pad
getButtons();
m_buffer[0] = startPoll();
m_maxBufferIndex = 2;
m_bufferIndex = 0;
m_padState = Pads::PAD_STATE_READ_COMMAND;
break;

case Pads::PAD_STATE_READ_COMMAND:
m_padState = Pads::PAD_STATE_READ_DATA;
m_bufferIndex = 1;
m_buffer[m_bufferIndex] = poll(value, m_padState);

if (!(m_buffer[m_bufferIndex] & 0x0f)) {
m_maxBufferIndex = 2 + 32;
} else {
m_maxBufferIndex = 2 + (m_buffer[m_bufferIndex] & 0x0f) * 2;
}

break;

case Pads::PAD_STATE_READ_DATA:
m_bufferIndex++;
m_buffer[m_bufferIndex] = poll(value, m_padState);

if (m_bufferIndex == m_maxBufferIndex) {
m_padState = Pads::PAD_STATE_BAD_COMMAND;
}
break;
}

data_out = m_buffer[m_bufferIndex];

if (m_padState == Pads::PAD_STATE_BAD_COMMAND) {
} else {
*ack = true;
}

uint8_t PadsImpl::poll(uint8_t value, Port port, uint32_t& padState) {
int index = magic_enum::enum_integer(port);
return m_pads[index].poll(value, padState);
return data_out;
}

uint8_t PadsImpl::Pad::poll(uint8_t value, uint32_t& padState) {
Expand Down
12 changes: 10 additions & 2 deletions src/core/pad.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,25 @@ using json = nlohmann::json;
namespace PCSX {

class GUI;
class SIO;

class Pads {
public:
enum class Port { Port1 = 0, Port2 };

virtual ~Pads() = default;

class InputDevice {
virtual void* getPadState() = 0;
virtual bool isButtonPressed(int button) = 0;
virtual void updateInput() = 0;
};

virtual void init() = 0;
virtual void shutdown() = 0;
virtual uint8_t startPoll(Port port) = 0;
virtual uint8_t poll(uint8_t value, Port port, uint32_t& padState) = 0;

virtual void deselect() = 0;
virtual uint8_t transceive(int index, uint8_t value, bool* ack) = 0;

virtual json getCfg() = 0;
virtual void setCfg(const json& j) = 0;
Expand Down
1 change: 1 addition & 0 deletions src/core/psxemulator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ PCSX::Emulator::Emulator()
m_lua(new PCSX::Lua()),
m_mdec(new PCSX::MDEC()),
m_mem(new PCSX::Memory()),
m_memoryCards(new PCSX::MemoryCards()),
m_pads(PCSX::Pads::factory()),
m_pioCart(new PCSX::PIOCart),
m_sio(new PCSX::SIO()),
Expand Down
2 changes: 2 additions & 0 deletions src/core/psxemulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ class HW;
class Lua;
class MDEC;
class Memory;
class MemoryCards;
class Pads;
class R3000Acpu;
class SIO;
Expand Down Expand Up @@ -248,6 +249,7 @@ class Emulator {
std::unique_ptr<Lua> m_lua;
std::unique_ptr<MDEC> m_mdec;
std::unique_ptr<Memory> m_mem;
std::unique_ptr<MemoryCards> m_memoryCards;
std::unique_ptr<Pads> m_pads;
std::unique_ptr<PIOCart> m_pioCart;
std::unique_ptr<R3000Acpu> m_cpu;
Expand Down
Loading
Loading