GCMemcard: The update counters are interpreted as signed values for the newer-than comparison.

This commit is contained in:
Admiral H. Curtiss 2019-08-14 23:50:43 +02:00
parent 8fc2f0ff2d
commit 7d4cabea07
2 changed files with 7 additions and 5 deletions

View File

@ -249,8 +249,11 @@ std::pair<GCMemcardErrorCode, std::optional<GCMemcard>> GCMemcard::Open(std::str
error_code |= bat_block_1_error_code; error_code |= bat_block_1_error_code;
// select the in-use Dir and BAT blocks based on update counter // select the in-use Dir and BAT blocks based on update counter
// TODO: Is there a special case for wraparound after 65535 block updates, or is it assumed that
// the hardware fails long before that anyway? // These are compared as signed values by the GC BIOS. There is no protection against overflow, so
// if one block is MAX_VAL and the other is MIN_VAL it still picks the MAX_VAL one as the active
// one, even if that results in a corrupted memory card.
// TODO: We could try to be smarter about this to rescue seemingly-corrupted cards.
if (card.m_directory_blocks[0].m_update_counter >= card.m_directory_blocks[1].m_update_counter) if (card.m_directory_blocks[0].m_update_counter >= card.m_directory_blocks[1].m_update_counter)
card.m_active_directory = 0; card.m_active_directory = 0;

View File

@ -311,8 +311,7 @@ struct Directory
std::array<u8, 0x3a> m_padding; std::array<u8, 0x3a> m_padding;
// 2 bytes at 0x1ffa: Update Counter // 2 bytes at 0x1ffa: Update Counter
// TODO: What happens if this overflows? Is there a special case for preferring 0 over max value? Common::BigEndianValue<s16> m_update_counter;
Common::BigEndianValue<u16> m_update_counter;
// 2 bytes at 0x1ffc: Additive Checksum // 2 bytes at 0x1ffc: Additive Checksum
u16 m_checksum; u16 m_checksum;
@ -343,7 +342,7 @@ struct BlockAlloc
u16 m_checksum_inv; u16 m_checksum_inv;
// 2 bytes at 0x0004: Update Counter // 2 bytes at 0x0004: Update Counter
Common::BigEndianValue<u16> m_update_counter; Common::BigEndianValue<s16> m_update_counter;
// 2 bytes at 0x0006: Free Blocks // 2 bytes at 0x0006: Free Blocks
Common::BigEndianValue<u16> m_free_blocks; Common::BigEndianValue<u16> m_free_blocks;