N64: Just some cleanup. Made code simpler. Added some comments where needed.

This commit is contained in:
Rikard Bengtsson
2023-10-06 08:57:57 +02:00
parent d53a998eac
commit 1fc9c37c07

View File

@@ -13,15 +13,15 @@
static constexpr uint64_t FNV_PRIME = 0x100000001b3;
static constexpr uint64_t FNV_OFFSET_BASIS = 0xcbf29ce484222325;
static constexpr uint8_t CARTID_LENGTH = 6;
static constexpr auto CARTID_PREFIX = "ID:";
static constexpr uint64_t fnv_hash(const char *s, uint64_t h = FNV_OFFSET_BASIS)
{
static constexpr uint64_t fnv_hash(const char *s, uint64_t h = FNV_OFFSET_BASIS) {
if (s) while (uint8_t a = *(s++)) h = (h ^ a) * FNV_PRIME;
return h;
}
enum class MemoryType
{
enum class MemoryType {
NONE = 0,
EEPROM_512,
EEPROM_2k,
@@ -30,9 +30,9 @@ enum class MemoryType
FLASH_128k
};
enum class CIC
{
CIC_NUS_6101 = 0,
enum class CIC {
UNKNOWN = -1,
CIC_NUS_6101,
CIC_NUS_6102,
CIC_NUS_7101,
CIC_NUS_7102,
@@ -48,90 +48,174 @@ enum class CIC
CIC_NUS_DDUS
};
enum class SystemType
{
NTSC = 0,
enum class SystemType {
UNKNOWN = -1,
NTSC,
PAL
};
enum class RomFormat
{
enum class RomFormat {
UNKNOWN = 0,
BIG_ENDIAN,
BYTE_SWAPPED,
LITTLE_ENDIAN,
};
enum class AutoDetect
{
enum class AutoDetect {
ON = 0,
OFF = 1,
};
static RomFormat detectRomFormat(const uint8_t* data)
{
static RomFormat detectRomFormat(const uint8_t* data) {
// data should be aligned
const uint32_t val = *(uint32_t*)data;
// the following checks assume we're on a little-endian platform
// for each check, the first value is for regular roms, the 2nd is for 64DD images
if (val == 0x40123780 || val == 0x40072780) return RomFormat::BIG_ENDIAN;
if (val == 0x12408037 || val == 0x07408027) return RomFormat::BYTE_SWAPPED;
if (val == 0x80371240 || val == 0x80270740) return RomFormat::LITTLE_ENDIAN;
// third is a malformed magic word used in homebrew (mostly pointless)
if (val == UINT32_C(0x40123780) || val == UINT32_C(0x40072780) || val == UINT32_C(0x41123780)) return RomFormat::BIG_ENDIAN;
if (val == UINT32_C(0x12408037) || val == UINT32_C(0x07408027) || val == UINT32_C(0x12418037)) return RomFormat::BYTE_SWAPPED;
if (val == UINT32_C(0x80371240) || val == UINT32_C(0x80270740) || val == UINT32_C(0x80371241)) return RomFormat::LITTLE_ENDIAN;
return RomFormat::UNKNOWN;
}
static void normalizeData(uint8_t* data, size_t size, RomFormat format)
{
switch(format)
{
static void normalizeData(uint8_t* data, size_t size, RomFormat format) {
switch(format) {
case RomFormat::BYTE_SWAPPED:
for (size_t i = 0; i < size; i += 2)
{
auto c0 = data[0];
auto c1 = data[1];
data[0] = c1;
data[1] = c0;
data += 2;
}
break;
for (size_t i = 0; i < size; i += 2) {
auto c0 = data[0];
auto c1 = data[1];
data[0] = c1;
data[1] = c0;
data += 2;
}
break;
case RomFormat::LITTLE_ENDIAN:
for (size_t i = 0; i < size; i += 4)
{
auto c0 = data[0];
auto c1 = data[1];
auto c2 = data[2];
auto c3 = data[3];
data[0] = c3;
data[1] = c2;
data[2] = c1;
data[3] = c0;
data += 4;
}
break;
for (size_t i = 0; i < size; i += 4) {
auto c0 = data[0];
auto c1 = data[1];
auto c2 = data[2];
auto c3 = data[3];
data[0] = c3;
data[1] = c2;
data[2] = c1;
data[3] = c0;
data += 4;
}
break;
default:
{
// nothing to do
}
break;
}
}
static void normalizeString(char* s)
{
static void normalizeString(char* s) {
// change the string to lower-case
while (*s) { *s = tolower(*s); ++s; }
}
static bool detect_rom_settings_in_db(const char* lookup_hash, const char* db_file_name)
{
// return true if cic and system region is detected
static bool parse_and_apply_db_tags(char* tags) {
MemoryType save_type = MemoryType::NONE;
SystemType system_type = SystemType::UNKNOWN;
CIC cic = CIC::UNKNOWN;
bool cpak = false;
bool rpak = false;
bool tpak = false;
bool rtc = false;
const char separator[] = "|";
for (char* tag = strtok(tags, separator); tag; tag = strtok(nullptr, separator)) {
printf("Tag: %s\n", tag);
normalizeString(tag);
switch (fnv_hash(tag)) {
case fnv_hash("eeprom512"): save_type = MemoryType::EEPROM_512; break;
case fnv_hash("eeprom2k"): save_type = MemoryType::EEPROM_2k; break;
case fnv_hash("sram32k"): save_type = MemoryType::SRAM_32k; break;
case fnv_hash("sram96k"): save_type = MemoryType::SRAM_96k; break;
case fnv_hash("flash128k"): save_type = MemoryType::FLASH_128k; break;
case fnv_hash("ntsc"): system_type = SystemType::NTSC; break;
case fnv_hash("pal"): system_type = SystemType::PAL; break;
case fnv_hash("cpak"): cpak = true; break;
case fnv_hash("rpak"): rpak = true; break;
case fnv_hash("tpak"): tpak = true; break;
case fnv_hash("rtc"): rtc = true; break;
case fnv_hash("cic6101"): cic = CIC::CIC_NUS_6101; break;
case fnv_hash("cic6102"): cic = CIC::CIC_NUS_6102; break;
case fnv_hash("cic6103"): cic = CIC::CIC_NUS_6103; break;
case fnv_hash("cic6105"): cic = CIC::CIC_NUS_6105; break;
case fnv_hash("cic6106"): cic = CIC::CIC_NUS_6106; break;
case fnv_hash("cic7101"): cic = CIC::CIC_NUS_7101; break;
case fnv_hash("cic7102"): cic = CIC::CIC_NUS_7102; break;
case fnv_hash("cic7103"): cic = CIC::CIC_NUS_7103; break;
case fnv_hash("cic7105"): cic = CIC::CIC_NUS_7105; break;
case fnv_hash("cic7106"): cic = CIC::CIC_NUS_7106; break;
case fnv_hash("cic8303"): cic = CIC::CIC_NUS_8303; break;
case fnv_hash("cic8401"): cic = CIC::CIC_NUS_8401; break;
case fnv_hash("cic5167"): cic = CIC::CIC_NUS_5167; break;
case fnv_hash("cicDDUS"): cic = CIC::CIC_NUS_DDUS; break;
default: printf("Unknown tag: %s\n", tag); break;
}
}
printf("System: %d, Save Type: %d, CIC: %d, CPak: %d, RPak: %d, TPak %d, RTC: %d\n", (int)system_type, (int)save_type, (int)cic, cpak, rpak, tpak, rtc);
const auto auto_detect = (AutoDetect)user_io_status_get("[64]");
if (auto_detect == AutoDetect::ON) {
printf("Auto-detect is on, updating OSD settings\n");
if (system_type != SystemType::UNKNOWN) user_io_status_set("[80:79]", (uint32_t)system_type);
if (cic != CIC::UNKNOWN) user_io_status_set("[68:65]", (uint32_t)cic);
user_io_status_set("[71]", (uint32_t)cpak);
user_io_status_set("[72]", (uint32_t)rpak);
user_io_status_set("[73]", (uint32_t)tpak);
user_io_status_set("[74]", (uint32_t)rtc);
user_io_status_set("[77:75]", (uint32_t)save_type);
}
else {
printf("Auto-detect is off, not updating OSD settings\n");
}
return (auto_detect != AutoDetect::ON) || (system_type != SystemType::UNKNOWN && cic != CIC::UNKNOWN);
}
bool md5_matches(const char* line, const char* md5) {
for (auto i = 0; i < 32; i++) {
if (line[i] == '\0' || md5[i] != tolower(line[i]))
return false;
}
return true;
}
bool cart_id_matches(const char* line, const char* cart_id) {
// A valid ID line should start with "ID:"
if (strncmp(line, CARTID_PREFIX, strlen(CARTID_PREFIX)) != 0)
return false;
// Skip the line if it doesn't match our cart_id, '_' = don't care
auto lp = (char*)line + strlen(CARTID_PREFIX);
for (auto i = 0; i < CARTID_LENGTH; i++, lp++) {
if (*lp != '_' && *lp != cart_id[i])
return false; // character didn't match
if (*lp == ' ') // early termination
return true;
}
return true;
}
static uint8_t detect_rom_settings_in_db(const char* lookup_hash, const char* db_file_name) {
fileTextReader reader = {};
char file_path[1024];
sprintf(file_path, "%s/%s", HomeDir(), db_file_name);
if (!FileOpenTextReader(&reader, file_path))
{
if (!FileOpenTextReader(&reader, file_path)) {
printf("Failed to open N64 data file %s\n", file_path);
return false;
}
@@ -139,90 +223,56 @@ static bool detect_rom_settings_in_db(const char* lookup_hash, const char* db_fi
char tags[128];
const char* line;
while ((line = FileReadLine(&reader)))
{
// skip the line if it doesn't start with our hash
if (strncmp(lookup_hash, line, 32) != 0)
while ((line = FileReadLine(&reader))) {
// Skip the line if it doesn't start with our hash
if (!md5_matches(line, lookup_hash))
continue;
if (sscanf(line, "%*s %s", tags) != 1)
{
printf("No tags found.\n");
continue;
}
printf("Found ROM entry: %s\n", line);
MemoryType save_type = MemoryType::NONE;
SystemType system_type = SystemType::NTSC;
CIC cic = CIC::CIC_NUS_6102;
bool cpak = false;
bool rpak = false;
bool tpak = false;
bool rtc = false;
const char separator[] = "|";
for (char* tag = strtok(tags, separator); tag; tag = strtok(nullptr, separator))
{
printf("Tag: %s\n", tag);
normalizeString(tag);
switch (fnv_hash(tag))
{
case fnv_hash("eeprom512"): save_type = MemoryType::EEPROM_512; break;
case fnv_hash("eeprom2k"): save_type = MemoryType::EEPROM_2k; break;
case fnv_hash("sram32k"): save_type = MemoryType::SRAM_32k; break;
case fnv_hash("sram96k"): save_type = MemoryType::SRAM_96k; break;
case fnv_hash("flash128k"): save_type = MemoryType::FLASH_128k; break;
case fnv_hash("ntsc"): system_type = SystemType::NTSC; break;
case fnv_hash("pal"): system_type = SystemType::PAL; break;
case fnv_hash("cpak"): cpak = true; break;
case fnv_hash("rpak"): rpak = true; break;
case fnv_hash("tpak"): tpak = true; break;
case fnv_hash("rtc"): rtc = true; break;
case fnv_hash("cic6101"): cic = CIC::CIC_NUS_6101; break;
case fnv_hash("cic6102"): cic = CIC::CIC_NUS_6102; break;
case fnv_hash("cic6103"): cic = CIC::CIC_NUS_6103; break;
case fnv_hash("cic6105"): cic = CIC::CIC_NUS_6105; break;
case fnv_hash("cic6106"): cic = CIC::CIC_NUS_6106; break;
case fnv_hash("cic7101"): cic = CIC::CIC_NUS_7101; break;
case fnv_hash("cic7102"): cic = CIC::CIC_NUS_7102; break;
case fnv_hash("cic7103"): cic = CIC::CIC_NUS_7103; break;
case fnv_hash("cic7105"): cic = CIC::CIC_NUS_7105; break;
case fnv_hash("cic7106"): cic = CIC::CIC_NUS_7106; break;
case fnv_hash("cic8303"): cic = CIC::CIC_NUS_8303; break;
case fnv_hash("cic8401"): cic = CIC::CIC_NUS_8401; break;
case fnv_hash("cic5167"): cic = CIC::CIC_NUS_5167; break;
case fnv_hash("cicDDUS"): cic = CIC::CIC_NUS_DDUS; break;
default: printf("Unknown tag: %s\n", tag);
}
}
printf("System: %d, Save Type: %d, CIC: %d, CPak: %d, RPak: %d, TPak %d, RTC: %d\n", (int)system_type, (int)save_type, (int)cic, cpak, rpak, tpak, rtc);
const auto auto_detect = (AutoDetect)user_io_status_get("[64]");
if (auto_detect == AutoDetect::ON)
{
printf("Auto-detect is on, updating OSD settings\n");
user_io_status_set("[80:79]", (uint32_t)system_type);
user_io_status_set("[68:65]", (uint32_t)cic);
user_io_status_set("[71]", (uint32_t)cpak);
user_io_status_set("[72]", (uint32_t)rpak);
user_io_status_set("[73]", (uint32_t)tpak);
user_io_status_set("[74]", (uint32_t)rtc);
user_io_status_set("[77:75]", (uint32_t)save_type);
}
else
{
printf("Auto-detect is off, not updating OSD settings\n");
if (sscanf(line, "%*s %s", tags) != 1) {
printf("No tags found.\n");
return 2;
}
return true;
// 2 = System region and/or CIC wasn't in DB, will need detection
return parse_and_apply_db_tags(tags) ? 3 : 2;
}
return false;
return 0;
}
static uint8_t detect_rom_settings_in_db_with_cartid(const char* cart_id, const char* db_file_name) {
fileTextReader reader = {};
char file_path[1024];
sprintf(file_path, "%s/%s", HomeDir(), db_file_name);
if (!FileOpenTextReader(&reader, file_path)) {
printf("Failed to open N64 data file %s\n", file_path);
return false;
}
char tags[128];
const char* line;
while ((line = FileReadLine(&reader))) {
// Skip the line if it doesn't start with our ID
if (!cart_id_matches(line, cart_id))
continue;
printf("Found ROM entry: %s\n", line);
if (sscanf(line, "%*s %s", tags) != 1) {
printf("No tags found.\n");
return 2;
}
// 2 = System region and/or CIC wasn't in DB, will need detection
return parse_and_apply_db_tags(tags) ? 3 : 2;
}
return 0;
}
static const char* DB_FILE_NAMES[] =
@@ -231,77 +281,91 @@ static const char* DB_FILE_NAMES[] =
"N64-database_user.txt",
};
static bool detect_rom_settings_in_dbs(const char* lookup_hash)
{
for (const char* db_file_name: DB_FILE_NAMES)
{
if (detect_rom_settings_in_db(lookup_hash, db_file_name))
return true;
static uint8_t detect_rom_settings_in_dbs_with_md5(const char* lookup) {
for (const char* db_file_name : DB_FILE_NAMES) {
const auto detected = detect_rom_settings_in_db(lookup, db_file_name);
if (detected != 0) return detected;
}
return false;
return 0;
}
static bool detect_rom_settings_from_first_chunk(char region_code, uint64_t crc)
{
SystemType system_type;
static uint8_t detect_rom_settings_in_dbs_with_cartid(const char* lookup) {
if (strlen(lookup) < CARTID_LENGTH)
return 0;
for (auto i = 0; i < CARTID_LENGTH; i++) {
if ((lookup[i] >= '0' && lookup[i] <= '9') || (lookup[i] >= 'A' && lookup[i] <= 'Z'))
continue;
return 0;
}
for (const char* db_file_name : DB_FILE_NAMES) {
const auto detected = detect_rom_settings_in_db_with_cartid(lookup, db_file_name);
if (detected != 0) return detected;
}
return 0;
}
static bool detect_rom_settings_from_first_chunk(char region_code, uint64_t crc) {
SystemType system_type = SystemType::NTSC;
CIC cic;
bool is_known_cic = true;
const auto auto_detect = (AutoDetect)user_io_status_get("[64]");
if (auto_detect != AutoDetect::ON)
{
if ((AutoDetect)user_io_status_get("[64]") != AutoDetect::ON) {
printf("Auto-detect is off, not updating OSD settings\n");
return true;
}
switch (region_code)
{
case 'D': //Germany
case 'F': //France
case 'H': //Netherlands (Dutch)
case 'I': //Italy
case 'L': //Gateway 64
case 'P': //Europe
case 'S': //Spain
case 'U': //Australia
case 'W': //Scandinavia
case 'X': //Europe
case 'Y': //Europe
switch (region_code) {
case 'D': // Germany
case 'F': // France
case 'H': // Netherlands (Dutch)
case 'I': // Italy
case 'L': // Gateway 64
case 'P': // Europe
case 'S': // Spain
case 'U': // Australia
case 'W': // Scandinavia
case 'X': // Europe
case 'Y': // Europe
system_type = SystemType::PAL; break;
default:
system_type = SystemType::NTSC; break;
}
// the following checks assume we're on a little-endian platform
switch (crc)
{
switch (crc) {
default:
printf("Unknown CIC, uses default\n");
is_known_cic = false;
// fall through
case UINT64_C(0x000000a316adc55a):
case UINT64_C(0x000000039c981107): // hcs64's CIC-6102 IPL3 replacement
case UINT64_C(0x000000a30dacd530): // Unknown. Used in SM64 hacks
case UINT64_C(0x000000d2828281b0): // Unknown. Used in some homebrew
case UINT64_C(0x0000009acc31e644): // Unknown. Used in some betas and homebrew. Dev boot code?
cic = system_type == SystemType::NTSC
cic = system_type == SystemType::NTSC
? CIC::CIC_NUS_6102
: CIC::CIC_NUS_7101; break;
case UINT64_C(0x000000a405397b05): cic = CIC::CIC_NUS_7102; system_type = SystemType::PAL; break;
case UINT64_C(0x000000a0f26f62fe): cic = CIC::CIC_NUS_6101; system_type = SystemType::NTSC; break;
case UINT64_C(0x000000a405397b05): system_type = SystemType::PAL; cic = CIC::CIC_NUS_7102; break;
case UINT64_C(0x000000a0f26f62fe): system_type = SystemType::NTSC; cic = CIC::CIC_NUS_6101; break;
case UINT64_C(0x000000a9229d7c45):
cic = system_type == SystemType::NTSC
cic = system_type == SystemType::NTSC
? CIC::CIC_NUS_6103
: CIC::CIC_NUS_7103; break;
case UINT64_C(0x000000f8b860ed00):
cic = system_type == SystemType::NTSC
cic = system_type == SystemType::NTSC
? CIC::CIC_NUS_6105
: CIC::CIC_NUS_7105; break;
case UINT64_C(0x000000ba5ba4b8cd):
cic = system_type == SystemType::NTSC
cic = system_type == SystemType::NTSC
? CIC::CIC_NUS_6106
: CIC::CIC_NUS_7106; break;
case UINT64_C(0x0000012daafc8aab): cic = CIC::CIC_NUS_5167; break;
case UINT64_C(0x000000a9df4b39e1): cic = CIC::CIC_NUS_8303; break;
case UINT64_C(0x000000aa764e39e1): cic = CIC::CIC_NUS_8401; break;
case UINT64_C(0x000000abb0b739e1): cic = CIC::CIC_NUS_DDUS; break;
default: return false;
}
printf("System: %d, CIC: %d\n", (int)system_type, (int)cic);
@@ -310,22 +374,17 @@ static bool detect_rom_settings_from_first_chunk(char region_code, uint64_t crc)
user_io_status_set("[80:79]", (uint32_t)system_type);
user_io_status_set("[68:65]", (uint32_t)cic);
return true;
return is_known_cic;
}
static void md5_to_hex(uint8_t* in, char* out)
{
char *p = out;
for (int i = 0; i < 16; i++)
{
sprintf(p, "%02x", in[i]);
p += 2;
static void md5_to_hex(uint8_t* in, char* out) {
for (auto i = 0; i < 16; i++) {
sprintf(out, "%02x", in[i]);
out += 2;
}
*p = '\0';
}
int n64_rom_tx(const char* name, unsigned char index)
{
int n64_rom_tx(const char* name, unsigned char index) {
static uint8_t buf[4096];
fileTYPE f = {};
@@ -349,16 +408,20 @@ int n64_rom_tx(const char* name, unsigned char index)
process_ss(name);
bool is_first_chunk = true;
bool rom_found_in_db = false;
bool cic_detected = false;
RomFormat rom_format = RomFormat::UNKNOWN;
// 0 = Nothing detected
// 1 = System region and CIC detected
// 2 = Found some ROM info in DB (Save type etc.), but System region and CIC has not been determined
// 3 = Has detected everything, System type, CIC, Save type etc.
uint8_t rom_settings_detected = 0;
RomFormat rom_format;
MD5Context ctx;
MD5Init(&ctx);
uint8_t md5[16];
char md5_hex[40];
uint64_t ipl3_crc = 0;
char region_code = '\0';
uint64_t bootcode_sum = 0;
char cart_id[8];
while (bytes2send)
{
@@ -367,14 +430,15 @@ int n64_rom_tx(const char* name, unsigned char index)
FileReadAdv(&f, buf, chunk);
// perform sanity checks and detect ROM format
if (is_first_chunk)
{
if (chunk < 4096)
{
if (is_first_chunk) {
if (chunk < 4096) {
printf("Failed to load ROM: must be at least 4096 bytes\n");
return 0;
}
rom_format = detectRomFormat(buf);
if (rom_format == RomFormat::UNKNOWN)
printf("Unknown ROM format\n");
}
// normalize data to big-endian format
@@ -382,9 +446,8 @@ int n64_rom_tx(const char* name, unsigned char index)
MD5Update(&ctx, buf, chunk);
if (is_first_chunk)
{
// try to detect ROM settings based on header MD5 hash
if (is_first_chunk) {
// Try to detect ROM settings based on header MD5 hash
// For calculating the MD5 hash of the header, we need to make a
// copy of the context before calling MD5Final, otherwise the file
@@ -395,13 +458,28 @@ int n64_rom_tx(const char* name, unsigned char index)
md5_to_hex(md5, md5_hex);
printf("Header MD5: %s\n", md5_hex);
rom_found_in_db = detect_rom_settings_in_dbs(md5_hex);
if (!rom_found_in_db)
{
rom_settings_detected = detect_rom_settings_in_dbs_with_md5(md5_hex);
if (rom_settings_detected == 0)
printf("No ROM information found for header hash: %s\n", md5_hex);
for (size_t i = 0x40 / sizeof(uint32_t); i < 0x1000 / sizeof(uint32_t); i++) ipl3_crc += ((uint32_t*)buf)[i];
region_code = buf[0x3e];
// Calculate boot ROM checksum
for (uint32_t i = 0x40 / sizeof(uint32_t); i < 0x1000 / sizeof(uint32_t); i++) {
bootcode_sum += ((uint32_t*)buf)[i];
}
/* The first byte (starting at 0x3b) indicates the type of ROM
* 'N' = cart
* 'D' = 64DD disk
* 'C' = cartridge part of expandable game
* 'E' = 64DD expansion for cart
* 'Z' = Aleck64 cart
* The second and third byte form a 2-letter ID for the game
* The fourth byte indicates the region and language for the game
* The fifth byte indicates the revision of the game */
strncpy(cart_id, (char*)(buf + 0x3b), 4);
sprintf((char*)(cart_id + 4), "%02X", buf[0x3f]);
printf("Cartridge ID: %s\n", cart_id);
}
user_io_file_tx_data(buf, chunk);
@@ -415,38 +493,44 @@ int n64_rom_tx(const char* name, unsigned char index)
md5_to_hex(md5, md5_hex);
printf("File MD5: %s\n", md5_hex);
// Try to detect ROM settings from file MD5 if they are not available yet
if (!rom_found_in_db)
{
rom_found_in_db = detect_rom_settings_in_dbs(md5_hex);
if (!rom_found_in_db) printf("No ROM information found for file hash: %s\n", md5_hex);
}
// Try to detect ROM settings from full file MD5 if they're are not detected yet
if (rom_settings_detected == 0)
rom_settings_detected = detect_rom_settings_in_dbs_with_md5(md5_hex);
// Try detect (partial) ROM settings by analyzing the ROM itself. (region, cic and save type)
// Fallback for missing db entries.
if (!rom_found_in_db)
{
cic_detected = detect_rom_settings_from_first_chunk(region_code, ipl3_crc);
if (!cic_detected) printf("Unknown CIC type: %016" PRIX64 "\n", ipl3_crc);
// Try to detect ROM settings by cart ID if they're are not detected yet
if (rom_settings_detected == 0) {
printf("No ROM information found for file hash: %s\n", md5_hex);
rom_settings_detected = detect_rom_settings_in_dbs_with_cartid(cart_id);
if (rom_settings_detected == 0)
printf("No ROM information found for cart ID: %s\n", cart_id);
// Try detect (partial) ROM settings by analyzing the ROM itself. (System region and CIC)
if ((rom_settings_detected == 0 || rom_settings_detected == 2) &&
detect_rom_settings_from_first_chunk(cart_id[3], bootcode_sum)) {
rom_settings_detected |= 1;
}
}
// Complement info found in DB with System region and CIC
else if (rom_settings_detected == 2 &&
detect_rom_settings_from_first_chunk(cart_id[3], bootcode_sum)) {
rom_settings_detected = 3;
}
printf("Done.\n");
FileClose(&f);
// mount save state
// Mount save state
char file_path[1024];
FileGenerateSavePath(name, file_path);
user_io_file_mount(file_path, 0, 1);
// signal end of transmission
// Signal end of transmission
user_io_set_download(0);
ProgressMessage(0, 0, 0, 0);
if (!rom_found_in_db)
{
if (!cic_detected) Info("auto-detect failed");
else Info("use database if save is needed");
}
if (rom_settings_detected == 0 || rom_settings_detected == 2)
Info("Auto-detect failed:\nUnknown CIC type.");
else if (rom_settings_detected == 1)
Info("Auto-detect failed:\nROM missing from database,\nyou might not be able to save.", 5000);
return 1;
}