Merge pull request #2042 from giuse94/mc-docs

Documentation for memory card
This commit is contained in:
Kieron 2024-11-10 19:49:21 +00:00 committed by GitHub
commit 3f69ba75f3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 164 additions and 98 deletions

View File

@ -144,9 +144,9 @@ STATIC void jpegcam_unk1_80063704(char *buf, mem_card *pMemcard, int arg2, int a
for (index = 0; index < pMemcard->field_2_file_count; index++)
{
if (strncmp(pMemcard->field_4_blocks[index].field_0_name, memoryCardFileName, 13) == 0)
if (strncmp(pMemcard->field_4_files[index].field_0_name, memoryCardFileName, 13) == 0)
{
blocks_avail |= 1 << (pMemcard->field_4_blocks[index].field_0_name[18] - 64);
blocks_avail |= 1 << (pMemcard->field_4_files[index].field_0_name[18] - 64);
}
}

View File

@ -262,7 +262,7 @@ int saveFile_8004983C(struct mem_card *pMemcard)
memoryCardFileName[19] = 'A' + i;
for (file = 0; file < pMemcard->field_2_file_count; file++)
{
if (!strcmp(pMemcard->field_4_blocks[file].field_0_name, memoryCardFileName))
if (!strcmp(pMemcard->field_4_files[file].field_0_name, memoryCardFileName))
{
flags1 = 1;
}
@ -370,7 +370,7 @@ int loadFile_80049CE8(mem_card *pMemcard, int idx)
success = 0;
for (retries = 4; retries > 0; retries--)
{
memcard_read(pMemcard->field_0_card_idx, pMemcard->field_4_blocks[idx].field_0_name, 0, buf, MC_BLOCK_SIZE);
memcard_read(pMemcard->field_0_card_idx, pMemcard->field_4_files[idx].field_0_name, 0, buf, MC_BLOCK_SIZE);
while (memcard_get_status() > 0)
{
@ -675,7 +675,7 @@ loop_52:
goto loop_3;
}
if (memcard_delete(dword_800AB6FC, pMemcard->field_4_blocks[fidx].field_0_name) == 0)
if (memcard_delete(dword_800AB6FC, pMemcard->field_4_files[fidx].field_0_name) == 0)
{
init_file_mode_helper_helper_helper3_80049E94(0x45000003);
goto block_72;
@ -1137,7 +1137,7 @@ void menu_radio_do_file_mode_save_memcard_8004B0A0(MenuWork *work, char *pOt, SE
char saveid[16];
char discnum[16];
char newfile[32];
char freeblocks[32];
char freeBlocksText[32];
LINE_F2 *pLine;
SPRT *pSprt;
@ -1146,7 +1146,7 @@ void menu_radio_do_file_mode_save_memcard_8004B0A0(MenuWork *work, char *pOt, SE
DR_TPAGE *pTpage;
int sp88;
int blocks_req;
int freeBlocksCount;
int difficulty;
int sp8C;
int sp90;
@ -1421,7 +1421,7 @@ void menu_radio_do_file_mode_save_memcard_8004B0A0(MenuWork *work, char *pOt, SE
return;
}
blocks_req = mcd_last_file_800ABB68[dword_800AB6FC]->field_3_free_blocks;
freeBlocksCount = mcd_last_file_800ABB68[dword_800AB6FC]->field_3_free_blocks;
if (dword_800ABB74->max_num == 1)
{
@ -1440,8 +1440,8 @@ void menu_radio_do_file_mode_save_memcard_8004B0A0(MenuWork *work, char *pOt, SE
config.flags = 0x2;
config.colour = 0x66748956;
sprintf(freeblocks, "FREE: %d BLOCK%s", blocks_req, (blocks_req > 1) ? "S" : "");
_menu_number_draw_string2_80043220(prim, &config, freeblocks);
sprintf(freeBlocksText, "FREE: %d BLOCK%s", freeBlocksCount, (freeBlocksCount > 1) ? "S" : "");
_menu_number_draw_string2_80043220(prim, &config, freeBlocksText);
// Blinking effect.
if ((GV_Time % 32) > 10)
@ -1533,7 +1533,7 @@ int menu_radio_do_file_mode_helper12_8004BA80(MenuWork *work, mem_card *pMemcard
SELECT_INFO *info)
{
MENU_CURPOS *pIter;
mem_card_block *pBlock;
mem_card_file *pMcFile;
int i;
pIter = info->curpos;
@ -1543,12 +1543,12 @@ int menu_radio_do_file_mode_helper12_8004BA80(MenuWork *work, mem_card *pMemcard
for (i = 0; i < pMemcard->field_2_file_count; i++)
{
pBlock = &pMemcard->field_4_blocks[i];
printf("FILE %s\n", pBlock->field_0_name);
pMcFile = &pMemcard->field_4_files[i];
printf("FILE %s\n", pMcFile->field_0_name);
if (strncmp(pBlock->field_0_name, memoryCardFileName, 13) == 0)
if (strncmp(pMcFile->field_0_name, memoryCardFileName, 13) == 0)
{
menu_radio_do_file_mode_helper12_helper_8004B8FC(pIter->mes, pBlock->field_0_name);
menu_radio_do_file_mode_helper12_helper_8004B8FC(pIter->mes, pMcFile->field_0_name);
pIter->field_20 = i;
pIter++;
}

View File

@ -29,7 +29,7 @@ extern volatile long gMemCard_io_size_800B5648;
STATIC void memcard_hwcard_do_op(int op);
STATIC void memcard_swcard_do_op(int op);
STATIC int memcard_retry_helper(int state);
STATIC int dummy(int state);
STATIC void memcard_retry(int port);
static inline void memcard_access_wait(void)
@ -109,7 +109,24 @@ STATIC void memcard_set_sw_hw_card_fns(void)
gSwCard_do_op_800B52EC = memcard_swcard_do_op;
}
STATIC int memcard_easy_format_test(int hCard)
/**
* @brief Determines whether the memory card in the specified port is formatted.
*
* This function reads the first sector of the first block from the specified
* memory card. If the first two bytes are 'M' and 'C', then the card is deemed
* formatted, unformatted otherwise.
*
* @param port The port to check: 0 for port 1, 1 for port 2.
*
* @bug When passing 1 as argument, the function does not check port 2, but tries
* to access port B of MultiTap on port 1 instead, which results in an error.
*
* @return
* - 1 if the memory card is formatted.
* - 5 if the memory card is unformatted.
* - 2 if an error occurred.
*/
STATIC int memcard_easy_format_test(int port)
{
char buffer[128];
@ -118,7 +135,13 @@ STATIC int memcard_easy_format_test(int hCard)
memcard_access_wait();
_card_read(hCard, 0, buffer);
// BUG: the first parameter is the channel, not the port, so the correct
// value to pass is port * 16 + cardIndex. Therefore the function works
// correctly when port is 0, but when port is 1, it tries to access
// port B of MultiTap on port 1, which results in an error.
// However, this function is probably never executed by the game.
// See also the comment in memcard_init().
_card_read(port, 0, buffer);
do {
mts_wait_vbl(1);
@ -144,7 +167,20 @@ STATIC int memcard_easy_format_test(int hCard)
}
}
STATIC int memcard_loaddir(int port, int *pFreeBlockCount)
/**
* Gets information about all the files contained in a memory card.
*
* For each file in the memory card, this function fills
* gMemCards_800B52F8[port].field_4_files[i] fields by setting the file name
* and size, and mem_card_file::field_14 to 0 (unknown meaning).
*
* @param port The memory card port: 0 for port 1, 1 for port 2.
* @param pUsedBlocksCount When the function returns, contains the number of
* blocks that are in use in the memory card.
*
* @return The number of files contained in the memory card.
*/
STATIC int memcard_loaddir(int port, int *pUsedBlocksCount)
{
struct DIRENTRY dir;
char name[32];
@ -161,34 +197,46 @@ STATIC int memcard_loaddir(int port, int *pFreeBlockCount)
files = 0;
do {
memcpy(gMemCards_800B52F8[port].field_4_blocks[files].field_0_name, dir.name, sizeof(dir.name));
gMemCards_800B52F8[port].field_4_blocks[files].field_14 = 0;
gMemCards_800B52F8[port].field_4_blocks[files].field_18_size = dir.size;
memcpy(gMemCards_800B52F8[port].field_4_files[files].field_0_name, dir.name, sizeof(dir.name));
gMemCards_800B52F8[port].field_4_files[files].field_14 = 0;
gMemCards_800B52F8[port].field_4_files[files].field_18_size = dir.size;
blocks += (dir.size + 8191) / MC_BLOCK_SIZE;
files++;
}
while (nextfile(&dir));
printf("TOTAL %d FILES used %d block\n", files, blocks);
*pFreeBlockCount = blocks;
*pUsedBlocksCount = blocks;
return files;
}
printf("NO FILE\n");
*pFreeBlockCount = 0;
*pUsedBlocksCount = 0;
return 0;
}
STATIC void memcard_load_files(int idx)
/**
* Helper function for memcard_get_files().
*
* This function fills all gMemCards_800B52F8[port] fields by setting the card
* index, the number of files contained in the card, the number of free blocks,
* and mem_card::field_1_last_op to 1 (unknown meaning). It then calls
* memcard_loaddir() to fill the array mem_card::field_4_files.
*
* @param port The memory card port: 0 for port 1, 1 for port 2.
*/
STATIC void memcard_load_files(int port)
{
int freeBlockCount;
gMemCards_800B52F8[idx].field_0_card_idx = idx;
gMemCards_800B52F8[idx].field_1_last_op = 1;
gMemCards_800B52F8[idx].field_2_file_count = memcard_loaddir(idx, &freeBlockCount);
gMemCards_800B52F8[idx].field_3_free_blocks = 15 - freeBlockCount;
int pUsedBlocksCount;
gMemCards_800B52F8[port].field_0_card_idx = port;
gMemCards_800B52F8[port].field_1_last_op = 1;
gMemCards_800B52F8[port].field_2_file_count = memcard_loaddir(port, &pUsedBlocksCount);
gMemCards_800B52F8[port].field_3_free_blocks = 15 - pUsedBlocksCount;
}
STATIC int memcard_retry_helper(int state)
// Pure function whose return value is never used
// (as of the current decompilation status).
STATIC int dummy(int state)
{
switch (state)
{
@ -211,21 +259,6 @@ void memcard_reset_status(void)
gMemCards_800B52F8[1].field_1_last_op = 2;
}
static inline void memcard_wait(void)
{
printf("[R]");
while ((gHwCard_do_op_800B52E8 != memcard_hwcard_do_op) ||
(gSwCard_do_op_800B52EC != memcard_swcard_do_op))
{
printf("ACCESS WAIT..\n");
mts_wait_vbl(2);
}
gHwCardLastOp_800B52F4 = 0;
gSwCardLastOp_800B52F0 = 0;
}
int memcard_check(int port)
{
int chan;
@ -243,7 +276,7 @@ int memcard_check(int port)
while (1)
{
memcard_wait();
memcard_access_wait();
_card_info(chan);
if ((retries++) > 10)
@ -292,7 +325,7 @@ int memcard_check(int port)
}
loop_24:
memcard_wait();
memcard_access_wait();
_card_clear(chan);
do {
@ -304,7 +337,7 @@ int memcard_check(int port)
{
gMemCards_800B52F8[port].field_1_last_op = 4;
memcard_wait();
memcard_access_wait();
_card_load(chan);
do {
@ -346,7 +379,7 @@ exit:
void memcard_init(void)
{
int idx; // $s1
int port; // $s1
if (!gmem_card_system_inited_8009D524)
{
@ -386,7 +419,7 @@ void memcard_init(void)
ExitCriticalSection();
idx = 0;
port = 0;
InitCARD(0);
StartCARD();
@ -394,27 +427,30 @@ void memcard_init(void)
mts_set_vsync_task();
memcard_reset_status();
for (idx = 0; idx < 2; idx++)
for (port = 0; port < 2; port++)
{
if (!memcard_check(idx))
if (!memcard_check(port))
{
long v2 = memcard_easy_format_test(idx);
if (v2 == 5)
// I couldn't make the game enter this path without forcing it,
// but I think it is never executed because the function below
// is bugged with regard to port 2.
long memCardType = memcard_easy_format_test(port);
if (memCardType == 5) // Unformatted card.
{
gMemCards_800B52F8[idx].field_1_last_op = 5;
gMemCards_800B52F8[port].field_1_last_op = 5;
}
else if (v2 == 1)
else if (memCardType == 1) // Formatted card.
{
gMemCards_800B52F8[idx].field_1_last_op = 1;
gMemCards_800B52F8[port].field_1_last_op = 1;
}
else
else // Error.
{
gMemCards_800B52F8[idx].field_1_last_op = 2;
gMemCards_800B52F8[port].field_1_last_op = 2;
}
}
else
{
gMemCards_800B52F8[idx].field_1_last_op = 5;
gMemCards_800B52F8[port].field_1_last_op = 5;
}
}
}
@ -446,8 +482,9 @@ void memcard_retry(int port)
{
case 1:
case 4:
// Dead code path.
op = gMemCards_800B52F8[port].field_1_last_op;
memcard_retry_helper(op);
dummy(op);
return;
case 3:
@ -479,33 +516,55 @@ void memcard_retry(int port)
mts_wait_vbl(3);
}
memcard_retry_helper(op);
dummy(op);
}
mem_card *memcard_get_files(int idx)
/**
* Gets the number of files, their name and size, and the number of free blocks
* for the memory card in the specified port.
*
* This function calls other internal functions to fill all
* gMemCards_800B52F8[port] fields, but only if such card is in a suitable
* status to perform the operation, i.e., if its field_1_last_op
* is 1 or 4 (unknown meaning).
*
* @param port The memory card port: 0 for port 1, 1 for port 2.
*
* @return A pointer to gMemCards_800B52F8[port] containing the requested
* information if the operation was performed, otherwise 0.
*/
mem_card *memcard_get_files(int port)
{
mem_card *pCardBase = gMemCards_800B52F8;
mem_card *pCard = &pCardBase[idx];
mem_card *pCard = &pCardBase[port];
if (pCard->field_1_last_op == 1 || pCard->field_1_last_op == 4)
{
memcard_load_files(idx);
memcard_load_files(port);
pCard->field_1_last_op = 1;
return pCard;
}
return 0;
}
int memcard_delete(int idx, const char *filename)
/**
* Tries to delete the specified file from the memory card in the specified port.
*
* @param port The memory card port: 0 for port 1, 1 for port 2.
* @param filename The name of the file to delete.
*
* @return 1 if the file was deleted, 0 otherwise.
*/
int memcard_delete(int port, const char *filename)
{
char tmp[32];
mem_card *pCardBase = gMemCards_800B52F8;
mem_card *pCard = &pCardBase[idx];
mem_card *pCard = &pCardBase[port];
if (pCard->field_1_last_op == 1)
{
sprintf(tmp, "bu%02X:%s", 0x10 * idx, filename);
sprintf(tmp, "bu%02X:%s", 16 * port, filename);
if (erase(tmp))
{
printf("Deleted File %s", filename);
@ -555,13 +614,13 @@ STATIC void memcard_set_read_write(int fileSize)
#define ROUND_UP(val,rounding) (((val) + (rounding) - 1) / (rounding) * (rounding))
void memcard_write(int idx, const char *filename, int seekPos, char *pBuffer, int bufferSize)
void memcard_write(int port, const char *filename, int seekPos, char *pBuffer, int bufferSize)
{
int blocks = ROUND_UP(bufferSize, MC_BLOCK_SIZE) / MC_BLOCK_SIZE;
int hFile;
char name[32];
sprintf(name, "bu%02X:%s", idx * 16, filename);
sprintf(name, "bu%02X:%s", port * 16, filename);
hFile = open(name, (blocks << 16) | O_CREAT);
if (hFile < 0)
@ -590,12 +649,12 @@ void memcard_write(int idx, const char *filename, int seekPos, char *pBuffer, in
printf("WRITING FILE %s...\n", filename);
}
void memcard_read(int idx, const char *filename, int seekPos, char *pBuffer, int bufferSize)
void memcard_read(int port, const char *filename, int seekPos, char *pBuffer, int bufferSize)
{
char name[32];
int hFile;
sprintf(name, "bu%02x:%s", idx * 16, filename);
sprintf(name, "bu%02x:%s", port * 16, filename);
hFile = open(name, FREAD | FASYNC);
if (hFile < 0)
{
@ -620,21 +679,28 @@ int memcard_get_status(void)
return gMemCard_io_size_800B5648;
}
int memcard_format(int idx)
/**
* Tries to format the memory card in the specified port.
*
* @param port The memory card port: 0 for port 1, 1 for port 2.
*
* @return 1 if the memory card was formatted, 0 otherwise.
*/
int memcard_format(int port)
{
int retries;
char cardPath[32];
retries = 4;
sprintf(cardPath, "bu%02x:", idx * 16);
sprintf(cardPath, "bu%02x:", port * 16);
if (gMemCards_800B52F8[idx].field_1_last_op == 5)
if (gMemCards_800B52F8[port].field_1_last_op == 5)
{
retry:
if (format(cardPath) != 0)
{
printf("FORMATED %d\n", idx);
gMemCards_800B52F8[idx].field_1_last_op = 1;
printf("FORMATED %d\n", port);
gMemCards_800B52F8[port].field_1_last_op = 1;
return 1;
}
retries--;

View File

@ -4,14 +4,14 @@
// 8 KB
#define MC_BLOCK_SIZE 8192
typedef struct mem_card_block
typedef struct mem_card_file
{
char field_0_name[20];
char field_14;
char field_15;
unsigned short field_16;
int field_18_size;
} mem_card_block;
} mem_card_file;
typedef struct mem_card
{
@ -19,22 +19,22 @@ typedef struct mem_card
unsigned char field_1_last_op;
char field_2_file_count;
char field_3_free_blocks;
mem_card_block field_4_blocks[15];
mem_card_file field_4_files[15];
} mem_card;
typedef void (*TMemCardFunc)(int);
void memcard_reset_status(void);
int memcard_check(int idx);
int memcard_check(int port);
void memcard_init(void);
void memcard_exit(void);
void memcard_retry(int port);
mem_card *memcard_get_files(int idx);
int memcard_delete(int idx, const char *filename);
mem_card *memcard_get_files(int port);
int memcard_delete(int port, const char *filename);
void memcard_write(int idx, const char *filename, int seekPos, char *pBuffer, int bufferSize);
void memcard_read(int idx, const char *filename, int seekPos, char *pBuffer, int bufferSize);
void memcard_write(int port, const char *filename, int seekPos, char *pBuffer, int bufferSize);
void memcard_read(int port, const char *filename, int seekPos, char *pBuffer, int bufferSize);
int memcard_get_status(void);
int memcard_format(int idx);
int memcard_format(int port);
#endif // _MEMCARD_H_

View File

@ -579,7 +579,7 @@ int camera_800C6A40(MenuWork *work, mem_card *pMemcard, const char *param_3,
SELECT_INFO *info)
{
MENU_CURPOS *pIter;
mem_card_block *pBlock;
mem_card_file *pMcFile;
int i;
pIter = info->curpos;
@ -589,12 +589,12 @@ int camera_800C6A40(MenuWork *work, mem_card *pMemcard, const char *param_3,
for (i = 0; i < pMemcard->field_2_file_count; i++)
{
pBlock = &pMemcard->field_4_blocks[i];
printf((char *)camera_aFiles_800D0010, pBlock->field_0_name);
pMcFile = &pMemcard->field_4_files[i];
printf((char *)camera_aFiles_800D0010, pMcFile->field_0_name);
if (strncmp(pBlock->field_0_name, camera_dword_800C37F8, 13) == 0)
if (strncmp(pMcFile->field_0_name, camera_dword_800C37F8, 13) == 0)
{
camera_800C68BC(pIter->mes, pBlock->field_0_name);
camera_800C68BC(pIter->mes, pMcFile->field_0_name);
pIter->field_20 = i;
pIter++;
}

View File

@ -791,19 +791,19 @@ void title_open_800C5D30(OpenWork *work)
found = 0;
for (i = 0; i < card1.field_2_file_count; i++)
{
printf("name = %s\n", card1.field_4_blocks[i].field_0_name);
printf("name = %s\n", card1.field_4_files[i].field_0_name);
mismatch = 0;
for (j = 0; j < 12; j++)
{
if (card1.field_4_blocks[i].field_0_name[j] != name[j])
if (card1.field_4_files[i].field_0_name[j] != name[j])
{
mismatch = 1;
break;
}
}
if (mismatch == 0 && card1.field_4_blocks[i].field_0_name[12] == 'G')
if (mismatch == 0 && card1.field_4_files[i].field_0_name[12] == 'G')
{
found = 1;
}
@ -832,19 +832,19 @@ void title_open_800C5D30(OpenWork *work)
found = 0;
for (i = 0; i < card2.field_2_file_count; i++)
{
printf("name = %s\n", card2.field_4_blocks[i].field_0_name);
printf("name = %s\n", card2.field_4_files[i].field_0_name);
mismatch = 0;
for (j = 0; j < 12; j++)
{
if (card2.field_4_blocks[i].field_0_name[j] != name[j])
if (card2.field_4_files[i].field_0_name[j] != name[j])
{
mismatch = 1;
break;
}
}
if (mismatch == 0 && card2.field_4_blocks[i].field_0_name[12] == 'G')
if (mismatch == 0 && card2.field_4_files[i].field_0_name[12] == 'G')
{
found = 1;
}