Add support for homebrew-specific special header flag

Nintendo 64 homebrew community is standardizing on a convention to
declare the save memory type as a header flag. This convention has been
first introduced by EverDrive 64 as a way to handle games not present
in their DB, but it's been since adopted by libdragon as well.

With this commit, cen64 will automatically configure the correct savetype
for homebrew ROMs using the special header flag.

I've also added support for a 1Mbit SRAM savetype. This was never used
in commercial games but it is available with EverDrive64 and is one of
the possible configuration options. It costs nothing to support it and
may help development of homebrew games that decide to use that savetype.
This commit is contained in:
Giovanni Bajo 2022-03-19 22:53:05 +01:00 committed by Simon Eriksson
parent 5431cd25b3
commit 71903c63fa
4 changed files with 37 additions and 0 deletions

View file

@ -158,6 +158,14 @@ int cen64_main(int argc, const char **argv) {
printf("Warning: cart saves to 768kbit SRAM, but different size specified (see -sram768k)\n");
}
break;
case CART_DB_SAVE_TYPE_SRAM_1MBIT:
if (options.sram_path == NULL) {
printf("Warning: cart saves to 1mbit SRAM, but none specified (see -sram1m)\n");
open_save_file(NULL, 0x20000, &sram, NULL);
} else if (options.sram_size != 0x20000) {
printf("Warning: cart saves to 1mbit SRAM, but different size specified (see -sram1m)\n");
}
break;
}
}

View file

@ -200,6 +200,9 @@ static const struct cart_db_entry cart_db_table[] = {
{"NZS", "EJP", CART_DB_SAVE_TYPE_FLASH_1MBIT, "Legend of Zelda: Majora's Mask"},
};
static struct cart_db_entry homebrew_entry =
{"ED", "EJP", CART_DB_SAVE_TYPE_NONE, "Homebrew ROM with header in EverDrive / Libdragon format"};
static int cart_db_table_sorter(const void *a, const void *b) {
const struct cart_db_entry *entry_a = (const struct cart_db_entry *) a;
const struct cart_db_entry *entry_b = (const struct cart_db_entry *) b;
@ -218,6 +221,19 @@ const struct cart_db_entry *cart_db_get_entry(const uint8_t *rom) {
return cart_db_table + i;
}
if (rom_id[1] == 'E' && rom_id[2] == 'D') {
uint8_t config = rom[0x3f];
switch (config >> 4) {
case 1: homebrew_entry.save_type = CART_DB_SAVE_TYPE_EEPROM_4KBIT; break;
case 2: homebrew_entry.save_type = CART_DB_SAVE_TYPE_EEPROM_16KBIT; break;
case 3: homebrew_entry.save_type = CART_DB_SAVE_TYPE_SRAM_256KBIT; break;
case 4: homebrew_entry.save_type = CART_DB_SAVE_TYPE_SRAM_768KBIT; break;
case 5: homebrew_entry.save_type = CART_DB_SAVE_TYPE_FLASH_1MBIT; break;
case 6: homebrew_entry.save_type = CART_DB_SAVE_TYPE_SRAM_1MBIT; break;
}
return &homebrew_entry;
}
return NULL;
}

View file

@ -12,11 +12,13 @@
#define __device_cart_db_h__
enum cart_db_save_type {
CART_DB_SAVE_TYPE_NONE,
CART_DB_SAVE_TYPE_EEPROM_4KBIT,
CART_DB_SAVE_TYPE_EEPROM_16KBIT,
CART_DB_SAVE_TYPE_FLASH_1MBIT,
CART_DB_SAVE_TYPE_SRAM_256KBIT,
CART_DB_SAVE_TYPE_SRAM_768KBIT,
CART_DB_SAVE_TYPE_SRAM_1MBIT,
};
struct cart_db_entry {

View file

@ -139,6 +139,16 @@ int parse_options(struct cen64_options *options, int argc, const char *argv[]) {
options->sram_size = 0x18000;
}
else if (!strcmp(argv[i], "-sram1m")) {
if ((i + 1) >= (argc - 1)) {
printf("-sram1m requires a path to the save file.\n\n");
return 1;
}
options->sram_path = argv[++i];
options->sram_size = 0x20000;
}
else if (!strcmp(argv[i], "-flash")) {
if ((i + 1) >= (argc - 1)) {
printf("-flash requires a path to the save file.\n\n");
@ -294,6 +304,7 @@ void print_command_line_usage(const char *invokation_string) {
" -sram <path> : Path to 256 kbit SRAM save (alias of -sram256k).\n"
" -sram256k <path> : Path to 256 kbit SRAM save.\n"
" -sram768k <path> : Path to 768 kbit SRAM save.\n"
" -sram1m <path> : Path to 1 mbit SRAM save.\n"
" -flash <path> : Path to FlashRAM save.\n"
" For mempak see controller options.\n"