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

[WIP] SD card adapter support #12680

Draft
wants to merge 40 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
c6c8126
Create EXI_DeviceSD
Pokechu22 Aug 16, 2020
a68f4f2
Dummy EXI_DeviceSD
Pokechu22 Aug 17, 2020
1afc1de
HLE kprintf
Pokechu22 Aug 18, 2020
452740e
Add SetCS - amend dummy
Pokechu22 Aug 18, 2020
32b10ac
Advance reading
Pokechu22 Aug 18, 2020
f0798d1
EXI_DeviceDummy: Log ImmReadWrite
Pokechu22 Aug 21, 2020
0d677e6
HACK to select SD - this will need to be tidied
Pokechu22 Aug 22, 2020
0b05085
Adjust SD getid thing
Pokechu22 Aug 22, 2020
b88811d
Basic command detection
Pokechu22 Aug 22, 2020
e641198
Reply -- make it to the next part at least
Pokechu22 Aug 22, 2020
5300bde
Implement CMD8
Pokechu22 Aug 22, 2020
ce85b22
CMD9 and CMD10 - early version
Pokechu22 Aug 23, 2020
b66b241
Hardcode data for CMD9 and CMD10
Pokechu22 Aug 23, 2020
4a13f84
Implement last few commands, enough to get it detected by libogc (tho…
Pokechu22 Aug 23, 2020
582dd35
Implement STOP_TRANSMISSION and APP_CMD SD_SEND_OP_COND
Pokechu22 Aug 23, 2020
8474bdc
Use correct CRC16s
Pokechu22 Aug 23, 2020
fe91623
Restructure code; start implementing read/write commands
Pokechu22 Aug 24, 2020
f057491
Add Common::HashCrc16 and Common::HashCrc7
Pokechu22 Aug 24, 2020
1faab59
Remove hardcoded CRCs; validate incoming CRC7
Pokechu22 Aug 24, 2020
fe3227d
WriteBlock -> WriteSingleBlock
Pokechu22 Aug 24, 2020
749da1e
Initial implementation of reads and writes
Pokechu22 Aug 25, 2020
9646fd3
Fix CRC handling
Pokechu22 Aug 25, 2020
0b89a5f
Implement SendStatus
Pokechu22 Aug 25, 2020
d30d3cc
Fix multi-block reads
Pokechu22 Aug 25, 2020
89f77a1
More work on multi-block reads; not fully functional
Pokechu22 Aug 26, 2020
0c0ad48
Undo some test stuff
Pokechu22 Aug 27, 2020
f41d68f
Implement ReadOCR
Pokechu22 Aug 28, 2020
98c1826
WIP fix block reads
Pokechu22 Aug 28, 2020
302b64d
Actually functional block read
Pokechu22 Aug 28, 2020
3d32c6b
NOTE: EXI_DeviceMemoryCard could still use some cleanup
Pokechu22 Aug 31, 2020
e372ebf
Allow configuring SP2
Pokechu22 Aug 31, 2020
fb0b86d
Partially implement configuring the SD card path
Pokechu22 Sep 4, 2020
dae01cc
Fix SD Media Launcher
Pokechu22 Sep 5, 2020
0766f1c
More documentation references
Pokechu22 Sep 5, 2020
6b7444c
Handle GoIdleState and SendInterfaceCond exceptions
Pokechu22 Sep 7, 2020
0a08247
Re-add ConfigManager.h include
Pokechu22 Sep 11, 2020
cbe5811
Print the file SD data is being read from
Pokechu22 Sep 13, 2020
b5a6fc1
Call SetCS for all devices
Pokechu22 Sep 13, 2020
d22f42a
Only return SD device when CS is 0
Pokechu22 Sep 13, 2020
d1bf525
Eliminate hacky setup states
Pokechu22 Sep 16, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions Source/Core/Common/Hash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -446,4 +446,48 @@ u32 ComputeCRC32(std::string_view data)
{
return ComputeCRC32(reinterpret_cast<const u8*>(data.data()), data.size());
}

u8 HashCrc7(const u8* ptr, size_t length)
{
// Used for SD cards
constexpr u8 CRC_POLYNOMIAL = 0x09;

u8 result = 0;
for (size_t i = 0; i < length; i++)
{
// TODO: Cache in a table
result ^= ptr[i];
for (auto bit = 0; bit < 8; bit++)
{
if (result & 0x80)
result = (result << 1) ^ (CRC_POLYNOMIAL << 1);
else
result = result << 1;
}
}

return result >> 1;
}

u16 HashCrc16(const u8* ptr, size_t length)
{
// Specifically CRC-16-CCITT, used for SD cards
constexpr u16 CRC_POLYNOMIAL = 0x1021;

u16 result = 0;
for (size_t i = 0; i < length; i++)
{
// TODO: Cache in a table
result ^= (ptr[i] << 8);
for (auto bit = 0; bit < 8; bit++)
{
if (result & 0x8000)
result = (result << 1) ^ CRC_POLYNOMIAL;
else
result = result << 1;
}
}

return result;
}
} // namespace Common
16 changes: 16 additions & 0 deletions Source/Core/Common/Hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#pragma once

#include <array>
#include <cstddef>
#include <string_view>

Expand All @@ -21,4 +22,19 @@ u32 StartCRC32();
u32 UpdateCRC32(u32 crc, const u8* data, size_t len);
u32 ComputeCRC32(const u8* data, size_t len);
u32 ComputeCRC32(std::string_view data);

// For SD card emulation
u8 HashCrc7(const u8* ptr, size_t length);
u16 HashCrc16(const u8* ptr, size_t length);

template <size_t N>
u8 HashCrc7(const std::array<u8, N>& data)
{
return HashCrc7(data.data(), N);
}
template <size_t N>
u16 HashCrc16(const std::array<u8, N>& data)
{
return HashCrc16(data.data(), N);
}
} // namespace Common
2 changes: 2 additions & 0 deletions Source/Core/Core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ add_library(core
HW/EXI/EXI_DeviceMic.h
HW/EXI/EXI_DeviceModem.cpp
HW/EXI/EXI_DeviceModem.h
HW/EXI/EXI_DeviceSD.cpp
HW/EXI/EXI_DeviceSD.h
HW/EXI/EXI.cpp
HW/EXI/EXI.h
HW/GBAPad.cpp
Expand Down
18 changes: 18 additions & 0 deletions Source/Core/Core/Config/MainSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,29 @@ const Info<std::string>& GetInfoForGCIPathOverride(ExpansionInterface::Slot slot

const Info<int> MAIN_MEMORY_CARD_SIZE{{System::Main, "Core", "MemoryCardSize"}, -1};

const Info<std::string> MAIN_SLOT_A_SD_CARD_PATH{{System::Main, "Core", "SlotASDCardPath"}, ""};
const Info<std::string> MAIN_SLOT_B_SD_CARD_PATH{{System::Main, "Core", "SlotBSDCardPath"}, ""};
const Info<std::string> MAIN_SP2_SD_CARD_PATH{{System::Main, "Core", "SP2SDCardPath"}, ""};
const Info<std::string>& GetInfoForSDCardPath(ExpansionInterface::Slot slot)
{
ASSERT(slot != ExpansionInterface::Slot::SP1);
static constexpr Common::EnumMap<const Info<std::string>*, ExpansionInterface::MAX_SLOT> infos{
&MAIN_SLOT_A_SD_CARD_PATH,
&MAIN_SLOT_B_SD_CARD_PATH,
nullptr,
&MAIN_SP2_SD_CARD_PATH,
};
return *infos[slot];
}

const Info<ExpansionInterface::EXIDeviceType> MAIN_SLOT_A{
{System::Main, "Core", "SlotA"}, ExpansionInterface::EXIDeviceType::MemoryCardFolder};
const Info<ExpansionInterface::EXIDeviceType> MAIN_SLOT_B{{System::Main, "Core", "SlotB"},
ExpansionInterface::EXIDeviceType::None};
const Info<ExpansionInterface::EXIDeviceType> MAIN_SERIAL_PORT_1{
{System::Main, "Core", "SerialPort1"}, ExpansionInterface::EXIDeviceType::None};
const Info<ExpansionInterface::EXIDeviceType> MAIN_SERIAL_PORT_2{
{System::Main, "Core", "SerialPort2"}, ExpansionInterface::EXIDeviceType::None};

const Info<ExpansionInterface::EXIDeviceType>& GetInfoForEXIDevice(ExpansionInterface::Slot slot)
{
Expand All @@ -126,6 +143,7 @@ const Info<ExpansionInterface::EXIDeviceType>& GetInfoForEXIDevice(ExpansionInte
&MAIN_SLOT_A,
&MAIN_SLOT_B,
&MAIN_SERIAL_PORT_1,
&MAIN_SERIAL_PORT_2,
};
return *infos[slot];
}
Expand Down
5 changes: 5 additions & 0 deletions Source/Core/Core/Config/MainSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,14 @@ extern const Info<std::string> MAIN_GCI_FOLDER_A_PATH_OVERRIDE;
extern const Info<std::string> MAIN_GCI_FOLDER_B_PATH_OVERRIDE;
const Info<std::string>& GetInfoForGCIPathOverride(ExpansionInterface::Slot slot);
extern const Info<int> MAIN_MEMORY_CARD_SIZE;
extern const Info<std::string> MAIN_SLOT_A_SD_CARD_PATH;
extern const Info<std::string> MAIN_SLOT_B_SD_CARD_PATH;
extern const Info<std::string> MAIN_SP2_SD_CARD_PATH;
const Info<std::string>& GetInfoForSDCardPath(ExpansionInterface::Slot slot);
extern const Info<ExpansionInterface::EXIDeviceType> MAIN_SLOT_A;
extern const Info<ExpansionInterface::EXIDeviceType> MAIN_SLOT_B;
extern const Info<ExpansionInterface::EXIDeviceType> MAIN_SERIAL_PORT_1;
extern const Info<ExpansionInterface::EXIDeviceType> MAIN_SERIAL_PORT_2;
const Info<ExpansionInterface::EXIDeviceType>& GetInfoForEXIDevice(ExpansionInterface::Slot slot);
extern const Info<std::string> MAIN_BBA_MAC;
extern const Info<std::string> MAIN_BBA_XLINK_IP;
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/HLE/HLE.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ namespace HLE
static std::map<u32, u32> s_hooked_addresses;

// clang-format off
constexpr std::array<Hook, 23> os_patches{{
constexpr std::array<Hook, 24> os_patches{{
// Placeholder, os_patches[0] is the "non-existent function" index
{"FAKE_TO_SKIP_0", HLE_Misc::UnimplementedFunction, HookType::Replace, HookFlag::Generic},

Expand Down
7 changes: 6 additions & 1 deletion Source/Core/Core/HW/EXI/EXI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ u8 SlotToEXIChannel(Slot slot)
return 1;
case Slot::SP1:
return 0;
case Slot::SP2:
return 2;
default:
PanicAlertFmt("Unhandled slot {}", slot);
return 0;
Expand All @@ -92,6 +94,8 @@ u8 SlotToEXIDevice(Slot slot)
return 0;
case Slot::SP1:
return 2;
case Slot::SP2:
return 0;
default:
PanicAlertFmt("Unhandled slot {}", slot);
return 0;
Expand Down Expand Up @@ -143,7 +147,8 @@ void ExpansionInterfaceManager::Init(const Sram* override_sram)
m_channels[0]->AddDevice(EXIDeviceType::MaskROM, 1);
m_channels[SlotToEXIChannel(Slot::SP1)]->AddDevice(Config::Get(Config::MAIN_SERIAL_PORT_1),
SlotToEXIDevice(Slot::SP1));
m_channels[2]->AddDevice(EXIDeviceType::AD16, 0);
m_channels[SlotToEXIChannel(Slot::SP2)]->AddDevice(Config::Get(Config::MAIN_SERIAL_PORT_2),
SlotToEXIDevice(Slot::SP2));

m_event_type_change_device = core_timing.RegisterEvent("ChangeEXIDevice", ChangeDeviceCallback);
m_event_type_update_interrupts =
Expand Down
7 changes: 4 additions & 3 deletions Source/Core/Core/HW/EXI/EXI.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,12 @@ enum class Slot : int
A,
B,
SP1,
SP2,
};
// Note: using auto here results in a false warning on GCC
// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80351
constexpr std::initializer_list<Slot> SLOTS = {Slot::A, Slot::B, Slot::SP1};
constexpr auto MAX_SLOT = Slot::SP1;
constexpr std::initializer_list<Slot> SLOTS = {Slot::A, Slot::B, Slot::SP1, Slot::SP2};
constexpr auto MAX_SLOT = Slot::SP2;
constexpr std::initializer_list<Slot> MEMCARD_SLOTS = {Slot::A, Slot::B};
constexpr auto MAX_MEMCARD_SLOT = Slot::B;
constexpr bool IsMemcardSlot(Slot slot)
Expand Down Expand Up @@ -106,5 +107,5 @@ class ExpansionInterfaceManager
template <>
struct fmt::formatter<ExpansionInterface::Slot> : EnumFormatter<ExpansionInterface::MAX_SLOT>
{
constexpr formatter() : EnumFormatter({"Slot A", "Slot B", "Serial Port 1"}) {}
constexpr formatter() : EnumFormatter({"Slot A", "Slot B", "Serial Port 1", "Serial Port 2"}) {}
};
17 changes: 14 additions & 3 deletions Source/Core/Core/HW/EXI/EXI_Channel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,16 @@ void CEXIChannel::RegisterMMIO(MMIO::Mapping* mmio, u32 base)
if (m_channel_id == 0)
m_status.ROMDIS = new_status.ROMDIS;

IEXIDevice* device = GetDevice(m_status.CHIP_SELECT ^ new_status.CHIP_SELECT);
for (int device = 0; device < NUM_DEVICES; device++)
{
if (m_devices[device])
{
bool was_selected = m_status.CHIP_SELECT & (1 << device);
bool is_selected = new_status.CHIP_SELECT & (1 << device);
m_devices[device]->SetCS(new_status.CHIP_SELECT, was_selected, is_selected);
}
}
m_status.CHIP_SELECT = new_status.CHIP_SELECT;
if (device != nullptr)
device->SetCS(m_status.CHIP_SELECT);

system.GetExpansionInterface().UpdateInterrupts();
}));
Expand Down Expand Up @@ -224,6 +230,11 @@ IEXIDevice* CEXIChannel::GetDevice(const u8 chip_select)
{
switch (chip_select)
{
case 0: // SD responds when the CS signal is 0, instead of 1.
if (m_devices[0] && m_devices[0]->m_device_type == EXIDeviceType::SD)
return m_devices[0].get();
else
return nullptr;
case 1:
return m_devices[0].get();
case 2:
Expand Down
7 changes: 6 additions & 1 deletion Source/Core/Core/HW/EXI/EXI_Device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "Core/HW/EXI/EXI_DeviceMemoryCard.h"
#include "Core/HW/EXI/EXI_DeviceMic.h"
#include "Core/HW/EXI/EXI_DeviceModem.h"
#include "Core/HW/EXI/EXI_DeviceSD.h"
#include "Core/HW/Memmap.h"
#include "Core/System.h"

Expand Down Expand Up @@ -82,7 +83,7 @@ bool IEXIDevice::IsPresent() const
return false;
}

void IEXIDevice::SetCS(int cs)
void IEXIDevice::SetCS(u32 cs, bool was_selected, bool is_selected)
{
}

Expand Down Expand Up @@ -162,6 +163,10 @@ std::unique_ptr<IEXIDevice> EXIDevice_Create(Core::System& system, const EXIDevi
result = std::make_unique<CEXIAgp>(system, slot);
break;

case EXIDeviceType::SD:
result = std::make_unique<CEXISD>(system, channel_num);
break;

case EXIDeviceType::AMBaseboard:
case EXIDeviceType::None:
default:
Expand Down
6 changes: 4 additions & 2 deletions Source/Core/Core/HW/EXI/EXI_Device.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ enum class EXIDeviceType : int
EthernetTapServer,
EthernetBuiltIn,
ModemTapServer,
SD,
None = 0xFF
};

Expand All @@ -62,7 +63,7 @@ class IEXIDevice

virtual bool UseDelayedTransferCompletion() const;
virtual bool IsPresent() const;
virtual void SetCS(int cs);
virtual void SetCS(u32 cs, bool was_selected, bool is_selected);
virtual void DoState(PointerWrap& p);

// Is generating interrupt ?
Expand All @@ -88,7 +89,7 @@ std::unique_ptr<IEXIDevice> EXIDevice_Create(Core::System& system, EXIDeviceType

template <>
struct fmt::formatter<ExpansionInterface::EXIDeviceType>
: EnumFormatter<ExpansionInterface::EXIDeviceType::ModemTapServer>
: EnumFormatter<ExpansionInterface::EXIDeviceType::SD>
{
static constexpr array_type names = {
_trans("Dummy"),
Expand All @@ -106,6 +107,7 @@ struct fmt::formatter<ExpansionInterface::EXIDeviceType>
_trans("Broadband Adapter (tapserver)"),
_trans("Broadband Adapter (HLE)"),
_trans("Modem Adapter (tapserver)"),
_trans("SD Adapter"),
};

constexpr formatter() : EnumFormatter(names) {}
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/HW/EXI/EXI_DeviceAD16.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ CEXIAD16::CEXIAD16(Core::System& system) : IEXIDevice(system)
{
}

void CEXIAD16::SetCS(int cs)
void CEXIAD16::SetCS(u32 cs, bool was_selected, bool is_selected)
{
if (cs)
if (!was_selected && is_selected)
m_position = 0;
}

Expand Down
3 changes: 2 additions & 1 deletion Source/Core/Core/HW/EXI/EXI_DeviceAD16.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ class CEXIAD16 : public IEXIDevice
{
public:
explicit CEXIAD16(Core::System& system);
void SetCS(int cs) override;

void SetCS(u32 cs, bool was_selected, bool is_selected) override;
bool IsPresent() const override;
void DoState(PointerWrap& p) override;

Expand Down
5 changes: 5 additions & 0 deletions Source/Core/Core/HW/EXI/EXI_DeviceDummy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ u32 CEXIDummy::ImmRead(u32 size)
return 0;
}

void CEXIDummy::ImmReadWrite(u32& data, u32 size)
{
INFO_LOG_FMT(EXPANSIONINTERFACE, "EXI Dummy {} ImmReadWrite {}", m_name, data);
}

void CEXIDummy::DMAWrite(u32 address, u32 size)
{
INFO_LOG_FMT(EXPANSIONINTERFACE, "EXI DUMMY {} DMAWrite: {:08x} bytes, from {:08x} to device",
Expand Down
1 change: 1 addition & 0 deletions Source/Core/Core/HW/EXI/EXI_DeviceDummy.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class CEXIDummy final : public IEXIDevice

void ImmWrite(u32 data, u32 size) override;
u32 ImmRead(u32 size) override;
void ImmReadWrite(u32& data, u32 size) override;

void DMAWrite(u32 address, u32 size) override;
void DMARead(u32 address, u32 size) override;
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/HW/EXI/EXI_DeviceEthernet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ CEXIETHERNET::~CEXIETHERNET()
m_network_interface->Deactivate();
}

void CEXIETHERNET::SetCS(int cs)
void CEXIETHERNET::SetCS(u32 cs, bool was_selected, bool is_selected)
{
if (cs)
if (!was_selected && is_selected)
{
// Invalidate the previous transfer
transfer.valid = false;
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/HW/EXI/EXI_DeviceEthernet.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ class CEXIETHERNET : public IEXIDevice
public:
CEXIETHERNET(Core::System& system, BBADeviceType type);
virtual ~CEXIETHERNET();
void SetCS(int cs) override;
void SetCS(u32 cs, bool was_selected, bool is_selected) override;
bool IsPresent() const override;
bool IsInterruptSet() override;
void ImmWrite(u32 data, u32 size) override;
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,9 @@ void CEXIIPL::LoadFontFile(const std::string& filename, u32 offset)
m_fonts_loaded = true;
}

void CEXIIPL::SetCS(int cs)
void CEXIIPL::SetCS(u32 cs, bool was_selected, bool is_selected)
{
if (cs)
if (!was_selected && is_selected)
{
m_command_bytes_received = 0;
m_cursor = 0;
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/HW/EXI/EXI_DeviceIPL.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class CEXIIPL : public IEXIDevice
explicit CEXIIPL(Core::System& system);
~CEXIIPL() override;

void SetCS(int cs) override;
void SetCS(u32 cs, bool was_selected, bool is_selected) override;
bool IsPresent() const override;
void DoState(PointerWrap& p) override;

Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/HW/EXI/EXI_DeviceMemoryCard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,9 +276,9 @@ void CEXIMemoryCard::CmdDoneLater(u64 cycles)
core_timing.ScheduleEvent(cycles, s_et_cmd_done[m_card_slot], static_cast<u64>(m_card_slot));
}

void CEXIMemoryCard::SetCS(int cs)
void CEXIMemoryCard::SetCS(u32 cs, bool was_selected, bool is_selected)
{
if (cs) // not-selected to selected
if (!was_selected && is_selected)
{
m_position = 0;
}
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/HW/EXI/EXI_DeviceMemoryCard.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class CEXIMemoryCard : public IEXIDevice
CEXIMemoryCard(Core::System& system, Slot slot, bool gci_folder,
const Memcard::HeaderData& header_data);
~CEXIMemoryCard() override;
void SetCS(int cs) override;
void SetCS(u32 cs, bool was_selected, bool is_selected) override;
bool IsInterruptSet() override;
bool UseDelayedTransferCompletion() const override;
bool IsPresent() const override;
Expand Down
Loading