duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

memory_card.cpp (12646B)


      1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
      2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
      3 
      4 #include "memory_card.h"
      5 #include "host.h"
      6 #include "system.h"
      7 
      8 #include "util/imgui_manager.h"
      9 #include "util/state_wrapper.h"
     10 
     11 #include "common/bitutils.h"
     12 #include "common/error.h"
     13 #include "common/file_system.h"
     14 #include "common/log.h"
     15 #include "common/path.h"
     16 #include "common/string_util.h"
     17 
     18 #include "IconsFontAwesome5.h"
     19 
     20 Log_SetChannel(MemoryCard);
     21 
     22 MemoryCard::MemoryCard()
     23   : m_save_event(
     24       "Memory Card Host Flush", GetSaveDelayInTicks(), GetSaveDelayInTicks(),
     25       [](void* param, TickCount ticks, TickCount ticks_late) { static_cast<MemoryCard*>(param)->SaveIfChanged(true); },
     26       this)
     27 {
     28   m_FLAG.no_write_yet = true;
     29 }
     30 
     31 MemoryCard::~MemoryCard()
     32 {
     33   SaveIfChanged(false);
     34 }
     35 
     36 TickCount MemoryCard::GetSaveDelayInTicks()
     37 {
     38   return System::GetTicksPerSecond() * SAVE_DELAY_IN_SECONDS;
     39 }
     40 
     41 void MemoryCard::Reset()
     42 {
     43   ResetTransferState();
     44   SaveIfChanged(true);
     45   m_FLAG.no_write_yet = true;
     46 }
     47 
     48 bool MemoryCard::DoState(StateWrapper& sw)
     49 {
     50   if (sw.IsReading())
     51     SaveIfChanged(true);
     52 
     53   sw.Do(&m_state);
     54   sw.Do(&m_FLAG.bits);
     55   sw.Do(&m_address);
     56   sw.Do(&m_sector_offset);
     57   sw.Do(&m_checksum);
     58   sw.Do(&m_last_byte);
     59   sw.Do(&m_data);
     60   sw.Do(&m_changed);
     61 
     62   return !sw.HasError();
     63 }
     64 
     65 void MemoryCard::CopyState(const MemoryCard* src)
     66 {
     67   DebugAssert(m_data == src->m_data);
     68 
     69   m_state = src->m_state;
     70   m_FLAG.bits = src->m_FLAG.bits;
     71   m_address = src->m_address;
     72   m_sector_offset = src->m_sector_offset;
     73   m_checksum = src->m_checksum;
     74   m_last_byte = src->m_last_byte;
     75   m_changed = src->m_changed;
     76 }
     77 
     78 void MemoryCard::ResetTransferState()
     79 {
     80   m_state = State::Idle;
     81   m_address = 0;
     82   m_sector_offset = 0;
     83   m_checksum = 0;
     84   m_last_byte = 0;
     85 }
     86 
     87 bool MemoryCard::Transfer(const u8 data_in, u8* data_out)
     88 {
     89   bool ack = false;
     90 #ifdef _DEBUG
     91   const State old_state = m_state;
     92 #endif
     93 
     94   switch (m_state)
     95   {
     96 
     97 #define FIXED_REPLY_STATE(state, reply, ack_value, next_state)                                                         \
     98   case state:                                                                                                          \
     99   {                                                                                                                    \
    100     *data_out = reply;                                                                                                 \
    101     ack = ack_value;                                                                                                   \
    102     m_state = next_state;                                                                                              \
    103   }                                                                                                                    \
    104   break;
    105 
    106 #define ADDRESS_STATE_MSB(state, next_state)                                                                           \
    107   case state:                                                                                                          \
    108   {                                                                                                                    \
    109     *data_out = 0x00;                                                                                                  \
    110     ack = true;                                                                                                        \
    111     m_address = ((m_address & u16(0x00FF)) | (ZeroExtend16(data_in) << 8)) & 0x3FF;                                    \
    112     m_state = next_state;                                                                                              \
    113   }                                                                                                                    \
    114   break;
    115 
    116 #define ADDRESS_STATE_LSB(state, next_state)                                                                           \
    117   case state:                                                                                                          \
    118   {                                                                                                                    \
    119     *data_out = m_last_byte;                                                                                           \
    120     ack = true;                                                                                                        \
    121     m_address = ((m_address & u16(0xFF00)) | ZeroExtend16(data_in)) & 0x3FF;                                           \
    122     m_sector_offset = 0;                                                                                               \
    123     m_state = next_state;                                                                                              \
    124   }                                                                                                                    \
    125   break;
    126 
    127     // read state
    128 
    129     FIXED_REPLY_STATE(State::ReadCardID1, 0x5A, true, State::ReadCardID2);
    130     FIXED_REPLY_STATE(State::ReadCardID2, 0x5D, true, State::ReadAddressMSB);
    131     ADDRESS_STATE_MSB(State::ReadAddressMSB, State::ReadAddressLSB);
    132     ADDRESS_STATE_LSB(State::ReadAddressLSB, State::ReadACK1);
    133     FIXED_REPLY_STATE(State::ReadACK1, 0x5C, true, State::ReadACK2);
    134     FIXED_REPLY_STATE(State::ReadACK2, 0x5D, true, State::ReadConfirmAddressMSB);
    135     FIXED_REPLY_STATE(State::ReadConfirmAddressMSB, Truncate8(m_address >> 8), true, State::ReadConfirmAddressLSB);
    136     FIXED_REPLY_STATE(State::ReadConfirmAddressLSB, Truncate8(m_address), true, State::ReadData);
    137 
    138     case State::ReadData:
    139     {
    140       const u8 bits = m_data[ZeroExtend32(m_address) * MemoryCardImage::FRAME_SIZE + m_sector_offset];
    141       if (m_sector_offset == 0)
    142       {
    143         DEV_LOG("Reading memory card sector {}", m_address);
    144         m_checksum = Truncate8(m_address >> 8) ^ Truncate8(m_address) ^ bits;
    145       }
    146       else
    147       {
    148         m_checksum ^= bits;
    149       }
    150 
    151       *data_out = bits;
    152       ack = true;
    153 
    154       m_sector_offset++;
    155       if (m_sector_offset == MemoryCardImage::FRAME_SIZE)
    156       {
    157         m_state = State::ReadChecksum;
    158         m_sector_offset = 0;
    159       }
    160     }
    161     break;
    162 
    163       FIXED_REPLY_STATE(State::ReadChecksum, m_checksum, true, State::ReadEnd);
    164       FIXED_REPLY_STATE(State::ReadEnd, 0x47, true, State::Idle);
    165 
    166       // write state
    167 
    168       FIXED_REPLY_STATE(State::WriteCardID1, 0x5A, true, State::WriteCardID2);
    169       FIXED_REPLY_STATE(State::WriteCardID2, 0x5D, true, State::WriteAddressMSB);
    170       ADDRESS_STATE_MSB(State::WriteAddressMSB, State::WriteAddressLSB);
    171       ADDRESS_STATE_LSB(State::WriteAddressLSB, State::WriteData);
    172 
    173     case State::WriteData:
    174     {
    175       if (m_sector_offset == 0)
    176       {
    177         INFO_LOG("Writing memory card sector {}", m_address);
    178         m_checksum = Truncate8(m_address >> 8) ^ Truncate8(m_address) ^ data_in;
    179         m_FLAG.no_write_yet = false;
    180       }
    181       else
    182       {
    183         m_checksum ^= data_in;
    184       }
    185 
    186       const u32 offset = ZeroExtend32(m_address) * MemoryCardImage::FRAME_SIZE + m_sector_offset;
    187       m_changed |= (m_data[offset] != data_in);
    188       m_data[offset] = data_in;
    189 
    190       *data_out = m_last_byte;
    191       ack = true;
    192 
    193       m_sector_offset++;
    194       if (m_sector_offset == MemoryCardImage::FRAME_SIZE)
    195       {
    196         m_state = State::WriteChecksum;
    197         m_sector_offset = 0;
    198         if (m_changed)
    199           QueueFileSave();
    200       }
    201     }
    202     break;
    203 
    204       FIXED_REPLY_STATE(State::WriteChecksum, m_checksum, true, State::WriteACK1);
    205       FIXED_REPLY_STATE(State::WriteACK1, 0x5C, true, State::WriteACK2);
    206       FIXED_REPLY_STATE(State::WriteACK2, 0x5D, true, State::WriteEnd);
    207       FIXED_REPLY_STATE(State::WriteEnd, 0x47, false, State::Idle);
    208 
    209       // TODO: This really needs a proper buffer system...
    210       FIXED_REPLY_STATE(State::GetIDCardID1, 0x5A, true, State::GetIDCardID2);
    211       FIXED_REPLY_STATE(State::GetIDCardID2, 0x5D, true, State::GetIDACK1);
    212       FIXED_REPLY_STATE(State::GetIDACK1, 0x5C, true, State::GetIDACK2);
    213       FIXED_REPLY_STATE(State::GetIDACK2, 0x5D, true, State::GetID1);
    214       FIXED_REPLY_STATE(State::GetID1, 0x04, true, State::GetID2);
    215       FIXED_REPLY_STATE(State::GetID2, 0x00, true, State::GetID3);
    216       FIXED_REPLY_STATE(State::GetID3, 0x00, true, State::GetID4);
    217       FIXED_REPLY_STATE(State::GetID4, 0x80, true, State::Command);
    218 
    219       // new command
    220     case State::Idle:
    221     {
    222       // select device
    223       if (data_in == 0x81)
    224       {
    225         *data_out = 0xFF;
    226         ack = true;
    227         m_state = State::Command;
    228       }
    229     }
    230     break;
    231 
    232     case State::Command:
    233     {
    234       switch (data_in)
    235       {
    236         case 0x52: // read data
    237         {
    238           *data_out = m_FLAG.bits;
    239           ack = true;
    240           m_state = State::ReadCardID1;
    241         }
    242         break;
    243 
    244         case 0x57: // write data
    245         {
    246           *data_out = m_FLAG.bits;
    247           ack = true;
    248           m_state = State::WriteCardID1;
    249         }
    250         break;
    251 
    252         case 0x53: // get id
    253         {
    254           *data_out = m_FLAG.bits;
    255           ack = true;
    256           m_state = State::GetIDCardID1;
    257         }
    258         break;
    259 
    260         default:
    261           [[unlikely]]
    262           {
    263             ERROR_LOG("Invalid command 0x{:02X}", data_in);
    264             *data_out = m_FLAG.bits;
    265             ack = false;
    266             m_state = State::Idle;
    267           }
    268       }
    269     }
    270     break;
    271 
    272     default:
    273       UnreachableCode();
    274       break;
    275   }
    276 
    277   DEBUG_LOG("Transfer, old_state={}, new_state={}, data_in=0x{:02X}, data_out=0x{:02X}, ack={}",
    278             static_cast<u32>(old_state), static_cast<u32>(m_state), data_in, *data_out, ack ? "true" : "false");
    279   m_last_byte = data_in;
    280   return ack;
    281 }
    282 
    283 bool MemoryCard::IsOrWasRecentlyWriting() const
    284 {
    285   return (m_state == State::WriteData || m_save_event.IsActive());
    286 }
    287 
    288 std::unique_ptr<MemoryCard> MemoryCard::Create()
    289 {
    290   std::unique_ptr<MemoryCard> mc = std::make_unique<MemoryCard>();
    291   mc->Format();
    292   return mc;
    293 }
    294 
    295 std::unique_ptr<MemoryCard> MemoryCard::Open(std::string_view filename)
    296 {
    297   std::unique_ptr<MemoryCard> mc = std::make_unique<MemoryCard>();
    298   mc->m_filename = filename;
    299 
    300   Error error;
    301   if (!FileSystem::FileExists(mc->m_filename.c_str())) [[unlikely]]
    302   {
    303     Host::AddIconOSDMessage(fmt::format("memory_card_{}", filename), ICON_FA_SD_CARD,
    304                             fmt::format(TRANSLATE_FS("OSDMessage", "Memory card '{}' does not exist, creating."),
    305                                         Path::GetFileName(filename), Host::OSD_INFO_DURATION));
    306     mc->Format();
    307     mc->SaveIfChanged(true);
    308   }
    309   else if (!MemoryCardImage::LoadFromFile(&mc->m_data, mc->m_filename.c_str(), &error)) [[unlikely]]
    310   {
    311     Host::AddIconOSDMessage(fmt::format("memory_card_{}", filename), ICON_FA_SD_CARD,
    312                             fmt::format(TRANSLATE_FS("OSDMessage", "Memory card '{}' could not be read: {}"),
    313                                         Path::GetFileName(filename), Host::OSD_INFO_DURATION));
    314     mc->Format();
    315   }
    316 
    317   return mc;
    318 }
    319 
    320 void MemoryCard::Format()
    321 {
    322   MemoryCardImage::Format(&m_data);
    323   m_changed = true;
    324 }
    325 
    326 bool MemoryCard::SaveIfChanged(bool display_osd_message)
    327 {
    328   m_save_event.Deactivate();
    329 
    330   if (!m_changed)
    331     return true;
    332 
    333   m_changed = false;
    334 
    335   if (m_filename.empty())
    336     return false;
    337 
    338   std::string osd_key;
    339   std::string display_name;
    340   if (display_osd_message)
    341   {
    342     osd_key = fmt::format("memory_card_save_{}", m_filename);
    343     display_name = FileSystem::GetDisplayNameFromPath(m_filename);
    344   }
    345 
    346   INFO_LOG("Saving memory card to {}...", Path::GetFileTitle(m_filename));
    347 
    348   Error error;
    349   if (!MemoryCardImage::SaveToFile(m_data, m_filename.c_str(), &error))
    350   {
    351     if (display_osd_message)
    352     {
    353       Host::AddIconOSDMessage(std::move(osd_key), ICON_FA_SD_CARD,
    354                               fmt::format(TRANSLATE_FS("OSDMessage", "Failed to save memory card to '{}': {}"),
    355                                           Path::GetFileName(display_name), error.GetDescription()),
    356                               Host::OSD_ERROR_DURATION);
    357     }
    358 
    359     return false;
    360   }
    361 
    362   if (display_osd_message)
    363   {
    364     Host::AddIconOSDMessage(
    365       std::move(osd_key), ICON_FA_SD_CARD,
    366       fmt::format(TRANSLATE_FS("OSDMessage", "Saved memory card to '{}'."), Path::GetFileName(display_name)),
    367       Host::OSD_QUICK_DURATION);
    368   }
    369 
    370   return true;
    371 }
    372 
    373 void MemoryCard::QueueFileSave()
    374 {
    375   // skip if the event is already pending, or we don't have a backing file
    376   if (m_save_event.IsActive() || m_filename.empty())
    377     return;
    378 
    379   // save in one second, that should be long enough for everything to finish writing
    380   m_save_event.Schedule(GetSaveDelayInTicks());
    381 }