N64 improvements, save files (#859)
N64 improvements. Split N64 save files into eep, sra, fla, mpk and tpk files. Add "wide" tag detection to database, auto-switches to widescreen if found. Prioritize N64-database_user.txt, so that people can override games already in the regular database file. Honor order that rpak, cpak and tpak are written in database, for p1 controller.
This commit is contained in:
@@ -814,7 +814,7 @@ int FileCanWrite(const char *name)
|
||||
return ((st.st_mode & S_IWUSR) != 0);
|
||||
}
|
||||
|
||||
static void create_path(const char *base_dir, const char* sub_dir)
|
||||
void create_path(const char *base_dir, const char* sub_dir)
|
||||
{
|
||||
make_fullpath(base_dir);
|
||||
mkdir(full_path, S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
|
||||
@@ -148,4 +148,6 @@ const char* FileReadLine(fileTextReader *reader);
|
||||
#define CIFS_DIR "cifs"
|
||||
#define DOCS_DIR "docs"
|
||||
|
||||
void create_path(const char *base_dir, const char* sub_dir);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "n64.h"
|
||||
#include "n64_cpak_header.h"
|
||||
#include "../../menu.h"
|
||||
#include "../../user_io.h"
|
||||
|
||||
@@ -9,8 +10,8 @@
|
||||
|
||||
#include "lib/md5/md5.h"
|
||||
|
||||
static constexpr size_t CARTID_LENGTH = 6; // Ex: NSME00
|
||||
static constexpr size_t MD5_LENGTH = 16;
|
||||
static constexpr auto CARTID_LENGTH = 6U; // Ex: NSME00
|
||||
static constexpr auto MD5_LENGTH = 16U;
|
||||
static constexpr auto CARTID_PREFIX = "ID:";
|
||||
static constexpr auto AR_TYPE_OPT = "[48:47]";
|
||||
static constexpr auto AUTODETECT_OPT = "[64]";
|
||||
@@ -29,7 +30,7 @@ static constexpr const char *const CONTROLLER_OPTS[] = { "[51:49]", "[54:52]", "
|
||||
static constexpr uint64_t FNV_PRIME = 0x100000001b3;
|
||||
static constexpr uint64_t FNV_OFFSET_BASIS = 0xcbf29ce484222325;
|
||||
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 >= 'A' && a <= 'Z' ? a += ('a' - 'A') : a)) * FNV_PRIME;
|
||||
if (s) while (uint8_t a = *(s++)) h = (h ^ ((a >= 'A') && (a <= 'Z') ? a + ('a' - 'A') : a)) * FNV_PRIME;
|
||||
return h;
|
||||
}
|
||||
|
||||
@@ -70,7 +71,7 @@ enum class SystemType : uint32_t {
|
||||
UNKNOWN = ~0U
|
||||
};
|
||||
|
||||
enum class RomFormat : uint32_t {
|
||||
enum class DataFormat : uint32_t {
|
||||
BIG_ENDIAN = 0,
|
||||
BYTE_SWAPPED,
|
||||
LITTLE_ENDIAN,
|
||||
@@ -92,14 +93,26 @@ enum class AutoDetect : uint32_t {
|
||||
OFF
|
||||
};
|
||||
|
||||
enum class AspectRatio : uint32_t {
|
||||
ORIGINAL = 0,
|
||||
FULL,
|
||||
CUSTOM_1,
|
||||
CUSTOM_2,
|
||||
UNKNOWN = ~0U
|
||||
};
|
||||
|
||||
static AspectRatio old_ar = AspectRatio::UNKNOWN;
|
||||
|
||||
static const char* stringify(MemoryType v) {
|
||||
switch (v) {
|
||||
default: return "(none)";
|
||||
case MemoryType::EEPROM_512: return "4K EEPROM";
|
||||
case MemoryType::EEPROM_2k: return "16K EEPROM";
|
||||
case MemoryType::SRAM_32k: return "256K SRAM";
|
||||
case MemoryType::SRAM_96k: return "768K SRAM";
|
||||
case MemoryType::FLASH_128k: return "Flash RAM";
|
||||
case MemoryType::CPAK: return "CPAK DATA";
|
||||
case MemoryType::TPAK: return "TPAK DATA";
|
||||
default: return "(none)";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,7 +164,7 @@ static const char* stringify(bool v) {
|
||||
: "No";
|
||||
}
|
||||
|
||||
static RomFormat detectRomFormat(const uint8_t *data) {
|
||||
static DataFormat detectRomFormat(const uint8_t *data) {
|
||||
// Data should be aligned
|
||||
const uint32_t val = *(uint32_t *)data;
|
||||
|
||||
@@ -162,15 +175,15 @@ static RomFormat detectRomFormat(const uint8_t *data) {
|
||||
case UINT32_C(0x40123780):
|
||||
case UINT32_C(0x40072780):
|
||||
case UINT32_C(0x41123780):
|
||||
return RomFormat::BIG_ENDIAN;
|
||||
return DataFormat::BIG_ENDIAN;
|
||||
case UINT32_C(0x12408037):
|
||||
case UINT32_C(0x07408027):
|
||||
case UINT32_C(0x12418037):
|
||||
return RomFormat::BYTE_SWAPPED;
|
||||
return DataFormat::BYTE_SWAPPED;
|
||||
case UINT32_C(0x80371240):
|
||||
case UINT32_C(0x80270740):
|
||||
case UINT32_C(0x80371241):
|
||||
return RomFormat::LITTLE_ENDIAN;
|
||||
return DataFormat::LITTLE_ENDIAN;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -178,22 +191,21 @@ static RomFormat detectRomFormat(const uint8_t *data) {
|
||||
// Endianness could not be determined, use just first byte.
|
||||
switch (val & 0xff) {
|
||||
case 0x80:
|
||||
return RomFormat::BIG_ENDIAN;
|
||||
return DataFormat::BIG_ENDIAN;
|
||||
case 0x37:
|
||||
case 0x27:
|
||||
return RomFormat::BYTE_SWAPPED;
|
||||
return DataFormat::BYTE_SWAPPED;
|
||||
case 0x40:
|
||||
case 0x41:
|
||||
return RomFormat::LITTLE_ENDIAN;
|
||||
return DataFormat::LITTLE_ENDIAN;
|
||||
default:
|
||||
return RomFormat::UNKNOWN;
|
||||
return DataFormat::UNKNOWN;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void normalizeData(uint8_t* data, size_t size, RomFormat format) {
|
||||
static void normalizeData(uint8_t* data, size_t size, DataFormat format) {
|
||||
switch (format) {
|
||||
case RomFormat::BYTE_SWAPPED:
|
||||
case DataFormat::BYTE_SWAPPED:
|
||||
size &= ~1U;
|
||||
for (size_t i = 0; i < size; i += 2) {
|
||||
auto c0 = data[0];
|
||||
@@ -203,7 +215,7 @@ static void normalizeData(uint8_t* data, size_t size, RomFormat format) {
|
||||
data += 2;
|
||||
}
|
||||
break;
|
||||
case RomFormat::LITTLE_ENDIAN:
|
||||
case DataFormat::LITTLE_ENDIAN:
|
||||
size &= ~3U;
|
||||
for (size_t i = 0; i < size; i += 4) {
|
||||
auto c0 = data[0];
|
||||
@@ -223,25 +235,154 @@ static void normalizeData(uint8_t* data, size_t size, RomFormat format) {
|
||||
}
|
||||
}
|
||||
|
||||
static MemoryType get_save_type() {
|
||||
auto tmp = (MemoryType)user_io_status_get(SAVE_TYPE_OPT);
|
||||
return (get_save_size(tmp) ? tmp : MemoryType::NONE);
|
||||
static MemoryType get_cart_save_type() {
|
||||
auto v = (MemoryType)user_io_status_get(SAVE_TYPE_OPT);
|
||||
return (get_save_size(v) ? v : MemoryType::NONE);
|
||||
}
|
||||
|
||||
static void set_save_type(MemoryType v) {
|
||||
user_io_status_set(SAVE_TYPE_OPT,
|
||||
static void set_cart_save_type(MemoryType v) {
|
||||
user_io_status_set(SAVE_TYPE_OPT,
|
||||
(uint32_t)(get_save_size(v) ? v : MemoryType::NONE));
|
||||
}
|
||||
|
||||
static uint32_t get_save_file_offset(unsigned char idx) {
|
||||
uint32_t offset = 0;
|
||||
MemoryType save_type = get_cart_save_type();
|
||||
|
||||
if (idx && (save_type != MemoryType::NONE)) {
|
||||
offset += get_save_size(save_type);
|
||||
idx--;
|
||||
}
|
||||
|
||||
if (idx && (bool)user_io_status_get(TPAK_OPT)) {
|
||||
offset += get_save_size(MemoryType::TPAK);
|
||||
idx--;
|
||||
}
|
||||
|
||||
offset += get_save_size(MemoryType::CPAK) * idx;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static char full_path[1024];
|
||||
|
||||
static size_t create_file(const char* filename, const uint8_t* data, size_t sz) {
|
||||
sprintf(full_path, "%s/%s", getRootDir(), filename);
|
||||
printf("Open file %s\n", full_path);
|
||||
FILE* fp = fopen(full_path, "w");
|
||||
if (!fp) {
|
||||
return 0;
|
||||
}
|
||||
sz = fwrite(data, sizeof(uint8_t), sz, fp);
|
||||
printf("Wrote %u bytes\n", sz);
|
||||
fclose(fp);
|
||||
return sz;
|
||||
}
|
||||
|
||||
static size_t read_file(const char* filename, uint8_t* data, uint32_t offset, size_t sz) {
|
||||
sprintf(full_path, "%s/%s", getRootDir(), filename);
|
||||
printf("Open file %s\n", full_path);
|
||||
FILE* fp = fopen(full_path, "r");
|
||||
if (!fp) {
|
||||
return 0;
|
||||
}
|
||||
fseek(fp, 0L, SEEK_END);
|
||||
size_t fs = ftell(fp);
|
||||
printf("File is %u bytes\n", fs);
|
||||
if (offset > fs) {
|
||||
return 0;
|
||||
}
|
||||
if (offset + sz > fs) {
|
||||
sz = fs - offset;
|
||||
}
|
||||
fseek(fp, offset, SEEK_SET);
|
||||
printf("Reading %u to %u\n", offset, offset + sz);
|
||||
sz = fread(data, sizeof(uint8_t), sz, fp);
|
||||
printf("Read %u bytes\n", sz);
|
||||
fclose(fp);
|
||||
return sz;
|
||||
}
|
||||
|
||||
static uint8_t mounted_save_files;
|
||||
static uint8_t save_file_buf[0x20000]; // Largest save size
|
||||
|
||||
struct SaveFile {
|
||||
int idx = -1;
|
||||
MemoryType type;
|
||||
|
||||
const char* get_path() {
|
||||
if (idx < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
auto file = get_image(idx);
|
||||
if (!file) {
|
||||
return nullptr;
|
||||
}
|
||||
return file->name;
|
||||
}
|
||||
|
||||
size_t get_size() {
|
||||
return get_save_size(type);
|
||||
}
|
||||
|
||||
void mount(const char* path) {
|
||||
idx = mounted_save_files++;
|
||||
user_io_file_mount(path, idx, 1);
|
||||
}
|
||||
|
||||
// Return "true" if created
|
||||
bool create_if_missing(const char* path, const char* old_path) {
|
||||
if (FileExists(path, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto sz = get_size();
|
||||
memset(save_file_buf, 0, sz);
|
||||
bool found_old_data = false;
|
||||
|
||||
if (sz && FileExists(old_path, 0)) {
|
||||
uint32_t off = get_save_file_offset((idx < 0) ? mounted_save_files : idx);
|
||||
if (read_file(old_path, save_file_buf, off, sz)) {
|
||||
printf("Found old save data (%s), converting to %s.\n", old_path, stringify(type));
|
||||
found_old_data = true;
|
||||
if ((type == MemoryType::CPAK) || (type == MemoryType::TPAK)) {
|
||||
normalizeData(save_file_buf, sz, DataFormat::LITTLE_ENDIAN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_old_data && (type == MemoryType::CPAK)) {
|
||||
memcpy(save_file_buf, cpak_header[((idx < 0) ? mounted_save_files : idx) % (sizeof(cpak_header) / sizeof(*cpak_header))], sizeof(*cpak_header));
|
||||
}
|
||||
|
||||
if (!create_file(path, save_file_buf, sz)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("Created file: %s (%u bytes)\n", path, sz);
|
||||
return true;
|
||||
}
|
||||
|
||||
SaveFile(MemoryType type) {
|
||||
this->type = type;
|
||||
}
|
||||
|
||||
SaveFile() {
|
||||
this->type = MemoryType::NONE;
|
||||
}
|
||||
};
|
||||
|
||||
static SaveFile save_files[8]{};
|
||||
|
||||
static bool is_auto() {
|
||||
return (AutoDetect)user_io_status_get(AUTODETECT_OPT) == AutoDetect::ON;
|
||||
}
|
||||
|
||||
static int8_t hex_to_dec(const char x) {
|
||||
if (x >= '0' && x <= '9') return x - '0';
|
||||
if (x >= 'A' && x <= 'F') return x - 'A' + 10;
|
||||
if (x >= 'a' && x <= 'f') return x - 'a' + 10;
|
||||
return -1;
|
||||
static uint8_t hex_to_dec(const char x) {
|
||||
if (x >= '0' && x <= '9') return (x - '0');
|
||||
if (x >= 'A' && x <= 'F') return (x - 'A') + 10;
|
||||
if (x >= 'a' && x <= 'f') return (x - 'a') + 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void trim(char* out, size_t len, const char* str)
|
||||
@@ -279,11 +420,7 @@ static void trim(char* out, size_t len, const char* str)
|
||||
out[out_size] = '\0';
|
||||
|
||||
// Obfuscate illegal characters
|
||||
for (size_t i = 0; i < out_size; i++) {
|
||||
if (out[i] == '\0') {
|
||||
break;
|
||||
}
|
||||
// Valid characters
|
||||
for (size_t i = 0; (i < out_size) && out[i]; i++) {
|
||||
if ((out[i] >= 0x20) && (out[i] < 0xa0)) {
|
||||
continue;
|
||||
}
|
||||
@@ -306,37 +443,39 @@ static bool parse_and_apply_db_tags(char *tags) {
|
||||
bool rtc = false;
|
||||
bool wide = false;
|
||||
|
||||
PadType prefered_pad = PadType::N64_PAD;
|
||||
|
||||
for (auto tag = strtok(tags, separator); tag; tag = strtok(nullptr, separator)) {
|
||||
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("noepak"): no_epak = true; 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("ntsc"): ntsc: system_type = SystemType::NTSC; break;
|
||||
case fnv_hash("pal"): pal: system_type = SystemType::PAL; break;
|
||||
case fnv_hash("wide"): wide = true; break;
|
||||
case fnv_hash("cic6101"): cic_type = CIC::CIC_NUS_6101; goto ntsc;
|
||||
case fnv_hash("cic6102"): cic_type = CIC::CIC_NUS_6102; goto ntsc;
|
||||
case fnv_hash("cic6103"): cic_type = CIC::CIC_NUS_6103; goto ntsc;
|
||||
case fnv_hash("cic6105"): cic_type = CIC::CIC_NUS_6105; goto ntsc;
|
||||
case fnv_hash("cic6106"): cic_type = CIC::CIC_NUS_6106; goto ntsc;
|
||||
case fnv_hash("cic7101"): cic_type = CIC::CIC_NUS_7101; goto pal;
|
||||
case fnv_hash("cic7102"): cic_type = CIC::CIC_NUS_7102; goto pal;
|
||||
case fnv_hash("cic7103"): cic_type = CIC::CIC_NUS_7103; goto pal;
|
||||
case fnv_hash("cic7105"): cic_type = CIC::CIC_NUS_7105; goto pal;
|
||||
case fnv_hash("cic7106"): cic_type = CIC::CIC_NUS_7106; goto pal;
|
||||
case fnv_hash("cic8303"): cic_type = CIC::CIC_NUS_8303; break;
|
||||
case fnv_hash("cic8401"): cic_type = CIC::CIC_NUS_8401; break;
|
||||
case fnv_hash("cic5167"): cic_type = CIC::CIC_NUS_5167; break;
|
||||
case fnv_hash("cicddus"): cic_type = CIC::CIC_NUS_DDUS; break;
|
||||
case fnv_hash("cic5101"): cic_type = CIC::CIC_NUS_5101; break;
|
||||
default: printf("Unknown tag: [%s] (skipping)\n", tag); break;
|
||||
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("noepak"): no_epak = true; break;
|
||||
case fnv_hash("cpak"): cpak = true; if (prefered_pad == PadType::N64_PAD) prefered_pad = PadType::N64_PAD_WITH_CPAK; break;
|
||||
case fnv_hash("rpak"): rpak = true; if (prefered_pad == PadType::N64_PAD) prefered_pad = PadType::N64_PAD_WITH_RPAK; break;
|
||||
case fnv_hash("tpak"): tpak = true; if (prefered_pad == PadType::N64_PAD) prefered_pad = PadType::N64_PAD_WITH_TPAK; break;
|
||||
case fnv_hash("rtc"): rtc = true; break;
|
||||
case fnv_hash("ntsc"): ntsc: system_type = SystemType::NTSC; break;
|
||||
case fnv_hash("pal"): pal: system_type = SystemType::PAL; break;
|
||||
case fnv_hash("wide"): wide = true; break;
|
||||
case fnv_hash("cic6101"): cic_type = CIC::CIC_NUS_6101; goto ntsc;
|
||||
case fnv_hash("cic6102"): cic_type = CIC::CIC_NUS_6102; goto ntsc;
|
||||
case fnv_hash("cic6103"): cic_type = CIC::CIC_NUS_6103; goto ntsc;
|
||||
case fnv_hash("cic6105"): cic_type = CIC::CIC_NUS_6105; goto ntsc;
|
||||
case fnv_hash("cic6106"): cic_type = CIC::CIC_NUS_6106; goto ntsc;
|
||||
case fnv_hash("cic7101"): cic_type = CIC::CIC_NUS_7101; goto pal;
|
||||
case fnv_hash("cic7102"): cic_type = CIC::CIC_NUS_7102; goto pal;
|
||||
case fnv_hash("cic7103"): cic_type = CIC::CIC_NUS_7103; goto pal;
|
||||
case fnv_hash("cic7105"): cic_type = CIC::CIC_NUS_7105; goto pal;
|
||||
case fnv_hash("cic7106"): cic_type = CIC::CIC_NUS_7106; goto pal;
|
||||
case fnv_hash("cic8303"): cic_type = CIC::CIC_NUS_8303; break;
|
||||
case fnv_hash("cic8401"): cic_type = CIC::CIC_NUS_8401; break;
|
||||
case fnv_hash("cic5167"): cic_type = CIC::CIC_NUS_5167; break;
|
||||
case fnv_hash("cicddus"): cic_type = CIC::CIC_NUS_DDUS; break;
|
||||
case fnv_hash("cic5101"): cic_type = CIC::CIC_NUS_5101; break;
|
||||
default: printf("Unknown tag: [%s] (skipping)\n", tag); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,17 +508,23 @@ static bool parse_and_apply_db_tags(char *tags) {
|
||||
user_io_status_set(RPAK_OPT, (uint32_t)rpak);
|
||||
user_io_status_set(TPAK_OPT, (uint32_t)tpak);
|
||||
user_io_status_set(RTC_OPT, (uint32_t)rtc);
|
||||
set_save_type(save_type);
|
||||
set_cart_save_type(save_type);
|
||||
|
||||
if ((PadType)user_io_status_get(CONTROLLER_OPTS[0]) != PadType::SNAC) {
|
||||
user_io_status_set(CONTROLLER_OPTS[0], (uint32_t)(
|
||||
tpak ? PadType::N64_PAD_WITH_TPAK :
|
||||
cpak ? PadType::N64_PAD_WITH_CPAK :
|
||||
rpak ? PadType::N64_PAD_WITH_RPAK :
|
||||
PadType::N64_PAD));
|
||||
user_io_status_set(CONTROLLER_OPTS[0], (uint32_t)prefered_pad);
|
||||
}
|
||||
|
||||
if (wide) user_io_status_set(AR_TYPE_OPT, 1);
|
||||
auto current_ar = (AspectRatio)user_io_status_get(AR_TYPE_OPT);
|
||||
if (wide) {
|
||||
if (current_ar != AspectRatio::FULL) {
|
||||
old_ar = current_ar;
|
||||
}
|
||||
user_io_status_set(AR_TYPE_OPT, (uint32_t)AspectRatio::FULL);
|
||||
}
|
||||
else if ((current_ar == AspectRatio::FULL) && (old_ar != AspectRatio::UNKNOWN)) {
|
||||
user_io_status_set(AR_TYPE_OPT, (uint32_t)old_ar);
|
||||
old_ar = AspectRatio::UNKNOWN;
|
||||
}
|
||||
|
||||
return (system_type != SystemType::UNKNOWN && cic_type != CIC::UNKNOWN);
|
||||
}
|
||||
@@ -396,7 +541,7 @@ static bool md5_matches(const char* line, const char* md5) {
|
||||
}
|
||||
|
||||
// Returns numbers of matching characters if match, otherwize 0
|
||||
static size_t cart_id_matches(const char* line, const char* cart_id) {
|
||||
static size_t cart_id_is_match(const char* line, const char* cart_id) {
|
||||
const auto prefix_len = strlen(CARTID_PREFIX);
|
||||
|
||||
// A valid ID line should start with "ID:"
|
||||
@@ -407,12 +552,12 @@ static size_t cart_id_matches(const char* line, const char* cart_id) {
|
||||
// Skip the line if it doesn't match our cart_id, '_' = don't care
|
||||
const char* lp = line + prefix_len;
|
||||
for (size_t i = 0; i < CARTID_LENGTH && *lp; i++, lp++) {
|
||||
if (*lp != '_' && *lp != cart_id[i]) {
|
||||
return 0; // Character didn't match pattern
|
||||
if (i && isspace(*lp)) {
|
||||
return i; // Early termination
|
||||
}
|
||||
|
||||
if (isspace(*lp)) {
|
||||
return i; // Early termination
|
||||
if (*lp != '_' && *lp != cart_id[i]) {
|
||||
return 0; // Character didn't match pattern
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,7 +612,7 @@ static uint8_t detect_rom_settings_in_db_with_cartid(const char* cart_id, const
|
||||
|
||||
while (const char* line = FileReadLine(&reader)) {
|
||||
// Skip lines that doesn't start with our ID
|
||||
if (!(i = cart_id_matches(line, cart_id))) continue;
|
||||
if (!(i = cart_id_is_match(line, cart_id))) continue;
|
||||
|
||||
auto s = line + strlen(CARTID_PREFIX) + i;
|
||||
auto tags = new char[strlen(s) + 1];
|
||||
@@ -486,26 +631,26 @@ static uint8_t detect_rom_settings_in_db_with_cartid(const char* cart_id, const
|
||||
}
|
||||
|
||||
static const char* DB_FILE_NAMES[] = {
|
||||
"N64-database.txt",
|
||||
"N64-database_user.txt",
|
||||
"N64-database.txt"
|
||||
};
|
||||
|
||||
static uint8_t detect_rom_settings_in_dbs_with_md5(const char* lookup_hash) {
|
||||
for (const char* db_file_name : DB_FILE_NAMES) {
|
||||
const auto detected = detect_rom_settings_in_db(lookup_hash, db_file_name);
|
||||
if (detected) {
|
||||
return detected;
|
||||
uint8_t detected = 0;
|
||||
for (auto i = 0U; i < (sizeof(DB_FILE_NAMES) / sizeof(*DB_FILE_NAMES)); i++) {
|
||||
if ((detected = detect_rom_settings_in_db(lookup_hash, DB_FILE_NAMES[i]))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return detected;
|
||||
}
|
||||
|
||||
static uint8_t detect_rom_settings_in_dbs_with_cartid(const char* lookup_id) {
|
||||
// Check if all characters in the lookup are valid
|
||||
for (size_t i = 0; i < CARTID_LENGTH; i++) {
|
||||
auto c = lookup_id[i];
|
||||
if (isupper(c) || isdigit(c)) {
|
||||
if (isalnum(c)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -513,18 +658,19 @@ static uint8_t detect_rom_settings_in_dbs_with_cartid(const char* lookup_id) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (const char* db_file_name : DB_FILE_NAMES) {
|
||||
const auto detected = detect_rom_settings_in_db_with_cartid(lookup_id, db_file_name);
|
||||
if (detected) {
|
||||
return detected;
|
||||
uint8_t detected = 0;
|
||||
for (auto i = 0U; i < (sizeof(DB_FILE_NAMES) / sizeof(*DB_FILE_NAMES)); i++) {
|
||||
if ((detected = detect_rom_settings_in_db_with_cartid(lookup_id, DB_FILE_NAMES[i]))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return detected;
|
||||
}
|
||||
|
||||
// "Advanced" Homebrew ROM Header https://n64brew.dev/wiki/ROM_Header
|
||||
static bool detect_homebrew_header(const uint8_t* controller_settings, const char* cart_id) {
|
||||
if (!(cart_id[1] == 'E' && cart_id[2] == 'D')) {
|
||||
if ((cart_id[1] != 'E') || (cart_id[2] != 'D')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -535,10 +681,33 @@ static bool detect_homebrew_header(const uint8_t* controller_settings, const cha
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (hex_to_dec(cart_id[4])) {
|
||||
case 1:
|
||||
set_cart_save_type(MemoryType::EEPROM_512);
|
||||
break;
|
||||
case 2:
|
||||
set_cart_save_type(MemoryType::EEPROM_2k);
|
||||
break;
|
||||
case 3:
|
||||
set_cart_save_type(MemoryType::SRAM_32k);
|
||||
break;
|
||||
case 4:
|
||||
set_cart_save_type(MemoryType::SRAM_96k);
|
||||
break;
|
||||
case 5:
|
||||
set_cart_save_type(MemoryType::FLASH_128k);
|
||||
break;
|
||||
//case 6:
|
||||
// set_cart_save_type(MemoryType::SRAM_128k);
|
||||
// break;
|
||||
default:
|
||||
set_cart_save_type(MemoryType::NONE);
|
||||
break;
|
||||
}
|
||||
|
||||
printf("Auto-detect is ON, updating OSD settings\n");
|
||||
|
||||
set_save_type((MemoryType)hex_to_dec(cart_id[4]));
|
||||
user_io_status_set(RTC_OPT, (uint32_t)(hex_to_dec(cart_id[5]) & 1));
|
||||
user_io_status_set(RTC_OPT, (uint32_t)(hex_to_dec(cart_id[5]) & 1)); // RTC
|
||||
|
||||
user_io_status_set(RPAK_OPT, (uint32_t)(
|
||||
(controller_settings[0]) == 0x01 ||
|
||||
@@ -558,7 +727,7 @@ static bool detect_homebrew_header(const uint8_t* controller_settings, const cha
|
||||
(controller_settings[2] == 0x03) ||
|
||||
(controller_settings[3] == 0x03) ? 1 : 0)); // Transfer Pak
|
||||
|
||||
uint32_t c_idx = 0;
|
||||
size_t c_idx = 0;
|
||||
for (auto c_opt : CONTROLLER_OPTS) {
|
||||
if (controller_settings[c_idx] && ((PadType)user_io_status_get(c_opt) != PadType::SNAC)) {
|
||||
if (controller_settings[c_idx] < 0x80) {
|
||||
@@ -584,17 +753,18 @@ static bool detect_rom_settings_from_first_chunk(const char region_code, const u
|
||||
bool is_known_cic = 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
|
||||
case 'D': // Germany
|
||||
case 'F': // France
|
||||
case 'H': // Netherlands
|
||||
case 'I': // Italy
|
||||
case 'L': // Gateway 64 (PAL)
|
||||
case 'P': // Europe
|
||||
case 'S': // Spain
|
||||
case 'U': // Australia
|
||||
case 'W': // Scandinavia
|
||||
case 'X': // Europe
|
||||
case 'Y': // Europe
|
||||
case 'Z': // Europe
|
||||
system_type = SystemType::PAL; break;
|
||||
default:
|
||||
system_type = SystemType::NTSC; break;
|
||||
@@ -604,7 +774,6 @@ static bool detect_rom_settings_from_first_chunk(const char region_code, const u
|
||||
size_t n = 2;
|
||||
|
||||
if (n) do {
|
||||
// The following checks assume we're on a little-endian platform
|
||||
switch (*signatures) {
|
||||
default:
|
||||
if (--n) {
|
||||
@@ -615,40 +784,41 @@ static bool detect_rom_settings_from_first_chunk(const char region_code, const u
|
||||
printf("Unknown CIC (Signature: 0x%016llx), uses default.\n", *signatures);
|
||||
is_known_cic = false;
|
||||
// Fall through
|
||||
case UINT64_C(0x000000a316adc55a):
|
||||
case UINT64_C(0x000000a316adc55a): // CIC-6102/7101 IPL3
|
||||
case UINT64_C(0x000000a30dacd530): // NOP:ed out CRC check
|
||||
case UINT64_C(0x000000039c981107): // hcs64's CIC-6102 IPL3 replacement
|
||||
case UINT64_C(0x000000d2828281b0): // Unknown. Used in some homebrew
|
||||
case UINT64_C(0x0000009acc31e644): // Unknown. Used in some betas and homebrew. Dev boot code?
|
||||
case UINT64_C(0x0000009474732e6b): // iQue hacks
|
||||
case UINT64_C(0x000000d2be3c4486): // Xeno Crisis custom IPL3
|
||||
case UINT64_C(0x0000009acc31e644): // HW1 IPL3 (Turok E3 prototype)
|
||||
case UINT64_C(0x0000009474732e6b): // IPL3 re-assembled with the GNU assembler (iQue)
|
||||
cic = (system_type != SystemType::PAL) ? CIC::CIC_NUS_6102 : CIC::CIC_NUS_7101; break;
|
||||
case UINT64_C(0x000000a405397b05):
|
||||
case UINT64_C(0x000000a405397b05): // CIC-7102 IPL3
|
||||
case UINT64_C(0x000000a3fc388adb): // NOP:ed out CRC check
|
||||
system_type = SystemType::PAL; cic = CIC::CIC_NUS_7102; break;
|
||||
case UINT64_C(0x000000a0f26f62fe):
|
||||
case UINT64_C(0x000000a0f26f62fe): // CIC-6101 IPL3
|
||||
case UINT64_C(0x000000a0e96e72d4): // NOP:ed out CRC check
|
||||
system_type = SystemType::NTSC; cic = CIC::CIC_NUS_6101; break;
|
||||
case UINT64_C(0x000000a9229d7c45):
|
||||
case UINT64_C(0x000000a9229d7c45): // CIC-x103 IPL3
|
||||
case UINT64_C(0x000000a9199c8c1b): // NOP:ed out CRC check
|
||||
case UINT64_C(0x000000271316d406): // iQue hacks
|
||||
cic = (system_type == SystemType::NTSC) ? CIC::CIC_NUS_6103 : CIC::CIC_NUS_7103; break;
|
||||
case UINT64_C(0x000000f8b860ed00):
|
||||
case UINT64_C(0x000000271316d406): // All zeros bar font (iQue Paper Mario)
|
||||
cic = (system_type != SystemType::PAL) ? CIC::CIC_NUS_6103 : CIC::CIC_NUS_7103; break;
|
||||
case UINT64_C(0x000000f8b860ed00): // CIC-x105 IPL3
|
||||
case UINT64_C(0x000000f8af5ffcd6): // NOP:ed out CRC check
|
||||
cic = (system_type == SystemType::NTSC) ? CIC::CIC_NUS_6105 : CIC::CIC_NUS_7105; break;
|
||||
case UINT64_C(0x000000ba5ba4b8cd):
|
||||
cic = (system_type == SystemType::NTSC) ? CIC::CIC_NUS_6106 : CIC::CIC_NUS_7106; break;
|
||||
cic = (system_type != SystemType::PAL) ? CIC::CIC_NUS_6105 : CIC::CIC_NUS_7105; break;
|
||||
case UINT64_C(0x000000ba5ba4b8cd): // CIC-x106 IPL3
|
||||
cic = (system_type != SystemType::PAL) ? 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;
|
||||
case UINT64_C(0x00000081ce470326):
|
||||
case UINT64_C(0x00000081ce470326): // CIC-5101 IPL3
|
||||
case UINT64_C(0x000000827a47195a): // Kuru Kuru Fever
|
||||
case UINT64_C(0x00000082551e4848): // Tower & Shaft
|
||||
cic = CIC::CIC_NUS_5101; break;
|
||||
}
|
||||
} while (cic == CIC::UNKNOWN);
|
||||
|
||||
printf("System: %s, CIC: %s\n", stringify(system_type), stringify(cic));
|
||||
printf("Region: %s, CIC: CIC-NUS-%s\n", stringify(system_type), stringify(cic));
|
||||
|
||||
if (!is_auto()) {
|
||||
printf("Auto-detect is OFF, not updating OSD settings\n");
|
||||
@@ -671,8 +841,7 @@ static void md5_to_hex(uint8_t* md5, char* out) {
|
||||
}
|
||||
}
|
||||
|
||||
static void calc_bootcode_checksums(uint64_t bootcode_sums[2], const uint8_t* buf)
|
||||
{
|
||||
static void calc_bootcode_checksums(uint64_t bootcode_sums[2], const uint8_t* buf) {
|
||||
size_t i;
|
||||
uint64_t sum = 0;
|
||||
|
||||
@@ -691,6 +860,189 @@ static void calc_bootcode_checksums(uint64_t bootcode_sums[2], const uint8_t* bu
|
||||
bootcode_sums[0] = sum;
|
||||
}
|
||||
|
||||
// Mount Save File. Return "true" if save file was created
|
||||
static bool mount_save_file(const char *name, MemoryType type, const char *old_path) {
|
||||
char save_path[1024];
|
||||
create_path(SAVE_DIR, CoreName);
|
||||
sprintf(save_path, "%s/%s/", SAVE_DIR, CoreName);
|
||||
char* fname = save_path + strlen(save_path);
|
||||
|
||||
const char* p = strrchr(name, '/');
|
||||
if (p) {
|
||||
strcat(fname, p + 1);
|
||||
}
|
||||
else {
|
||||
strcat(fname, name);
|
||||
}
|
||||
|
||||
char ext[16];
|
||||
|
||||
switch (type) {
|
||||
case MemoryType::EEPROM_512:
|
||||
case MemoryType::EEPROM_2k:
|
||||
strcpy(ext, ".eep");
|
||||
break;
|
||||
case MemoryType::SRAM_32k:
|
||||
case MemoryType::SRAM_96k:
|
||||
strcpy(ext, ".sra");
|
||||
break;
|
||||
case MemoryType::FLASH_128k:
|
||||
strcpy(ext, ".fla");
|
||||
break;
|
||||
case MemoryType::CPAK:
|
||||
case MemoryType::TPAK:
|
||||
sprintf(ext, "_%u%s",
|
||||
(mounted_save_files + ((get_cart_save_type() == MemoryType::NONE) ? 1 : 0)),
|
||||
((type == MemoryType::CPAK) ? ".cpk" : ".tpk"));
|
||||
break;
|
||||
default:
|
||||
strcpy(ext, ".sav");
|
||||
break;
|
||||
}
|
||||
|
||||
char* e = strrchr(fname, '.');
|
||||
if (e) {
|
||||
strcpy(e, ext);
|
||||
}
|
||||
else {
|
||||
strcat(fname, ext);
|
||||
}
|
||||
|
||||
auto save_file = new SaveFile(type);
|
||||
auto is_new = save_file->create_if_missing(save_path, old_path);
|
||||
save_file->mount(save_path);
|
||||
save_files[save_file->idx] = *save_file;
|
||||
return is_new;
|
||||
}
|
||||
|
||||
static void get_old_save_path(char* save_path, const char *name) {
|
||||
constexpr auto ext = ".sav";
|
||||
|
||||
create_path(SAVE_DIR, CoreName);
|
||||
sprintf(save_path, "%s/%s/", SAVE_DIR, CoreName);
|
||||
char* fname = save_path + strlen(save_path);
|
||||
|
||||
const char* p = strrchr(name, '/');
|
||||
if (p) {
|
||||
strcat(fname, p + 1);
|
||||
}
|
||||
else {
|
||||
strcat(fname, name);
|
||||
}
|
||||
|
||||
char* e = strrchr(fname, '.');
|
||||
if (e) {
|
||||
strcpy(e, ext);
|
||||
}
|
||||
else {
|
||||
strcat(fname, ext);
|
||||
}
|
||||
}
|
||||
|
||||
void n64_load_savedata(uint64_t lba, int ack, uint64_t &buffer_lba, uint8_t* buffer, uint32_t buffer_size, uint32_t blksz, uint32_t sz) {
|
||||
int fio_size = user_io_get_width();
|
||||
buffer_lba = -1;
|
||||
int done = 0;
|
||||
int invalid = 0;
|
||||
|
||||
unsigned char file_idx = 0;
|
||||
int64_t pos = lba * blksz;
|
||||
while (pos >= get_save_file_offset(file_idx + 1)) {
|
||||
file_idx++;
|
||||
if (file_idx >= mounted_save_files) {
|
||||
invalid = 1;
|
||||
buffer_lba = lba;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!invalid) {
|
||||
fileTYPE* file = get_image(file_idx);
|
||||
pos -= get_save_file_offset(file_idx);
|
||||
|
||||
if (file->size)
|
||||
{
|
||||
diskled_on();
|
||||
if (FileSeek(file, pos, SEEK_SET) && FileReadAdv(file, buffer, buffer_size)) {
|
||||
// printf("Loaded save data, %u bytes from %s (%lld)\n", sz, file->name, pos);
|
||||
done = 1;
|
||||
buffer_lba = lba;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Even after error we have to provide the block to the core
|
||||
//Give an empty block.
|
||||
if (!done || invalid) {
|
||||
memset(buffer, 0, buffer_size);
|
||||
}
|
||||
else if ((save_files[file_idx].type == MemoryType::CPAK) || (save_files[file_idx].type == MemoryType::TPAK)) {
|
||||
normalizeData(buffer, sz, DataFormat::LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
// data is now stored in buffer. send it to fpga
|
||||
EnableIO();
|
||||
spi_w(UIO_SECTOR_RD | ack);
|
||||
spi_block_write(buffer, fio_size, sz);
|
||||
DisableIO();
|
||||
}
|
||||
|
||||
void n64_save_savedata(uint64_t lba, int ack, uint64_t& buffer_lba, uint8_t* buffer, uint32_t blksz, uint32_t sz) {
|
||||
menu_process_save();
|
||||
|
||||
int fio_size = user_io_get_width();
|
||||
buffer_lba = -1;
|
||||
|
||||
unsigned char file_idx = 0;
|
||||
int64_t pos = lba * blksz;
|
||||
int invalid = 0;
|
||||
|
||||
while (pos >= get_save_file_offset(file_idx + 1)) {
|
||||
file_idx++;
|
||||
if (file_idx >= mounted_save_files) {
|
||||
invalid = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch sector data from FPGA ...
|
||||
EnableIO();
|
||||
spi_w(UIO_SECTOR_WR | ack);
|
||||
spi_block_read(buffer, fio_size, sz);
|
||||
DisableIO();
|
||||
|
||||
if (invalid) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto file = get_image(file_idx);
|
||||
pos -= get_save_file_offset(file_idx);
|
||||
|
||||
if (sz) {
|
||||
diskled_on();
|
||||
if (FileSeek(file, pos, SEEK_SET)) {
|
||||
if ((save_files[file_idx].type == MemoryType::CPAK) || (save_files[file_idx].type == MemoryType::TPAK)) {
|
||||
normalizeData(buffer, sz, DataFormat::LITTLE_ENDIAN);
|
||||
}
|
||||
if (!FileWriteAdv(file, buffer, sz)) {
|
||||
printf("Failed to write save data! (%u bytes to %s at %lld)\n", sz, file->name, pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void unmount_all_save_files()
|
||||
{
|
||||
fileTYPE *file;
|
||||
for (auto i = 0U; i < (sizeof(save_files) / sizeof(SaveFile)); i++) {
|
||||
if ((file = get_image(i)) && file->opened()) {
|
||||
FileClose(file);
|
||||
}
|
||||
save_files[i] = {};
|
||||
}
|
||||
mounted_save_files = 0;
|
||||
}
|
||||
|
||||
int n64_rom_tx(const char *name, unsigned char idx) {
|
||||
static uint8_t buf[4096];
|
||||
fileTYPE f;
|
||||
@@ -709,7 +1061,7 @@ int n64_rom_tx(const char *name, unsigned char idx) {
|
||||
user_io_set_download(1);
|
||||
|
||||
const int use_progress = 1;
|
||||
if (use_progress) ProgressMessage();
|
||||
if (use_progress) ProgressMessage(0, 0, 0, 0);
|
||||
|
||||
if ((idx & 0x3f) == 2) {
|
||||
// Handle non-N64 files (GameBoy)
|
||||
@@ -736,12 +1088,14 @@ int n64_rom_tx(const char *name, unsigned char idx) {
|
||||
// save state processing
|
||||
process_ss(name);
|
||||
|
||||
unmount_all_save_files();
|
||||
|
||||
/* 0 = Nothing detected
|
||||
1 = System region and CIC detected
|
||||
2 = Found some ROM info in DB (Save type etc.), but System region and/or CIC has not been determined
|
||||
3 = Has detected everything, System type, CIC, Save type etc. */
|
||||
uint8_t rom_settings_detected = 0;
|
||||
RomFormat rom_format;
|
||||
DataFormat rom_format;
|
||||
uint8_t md5[MD5_LENGTH];
|
||||
char md5_hex[MD5_LENGTH * 2 + 1];
|
||||
uint64_t bootcode_sums[2] = { };
|
||||
@@ -763,6 +1117,10 @@ int n64_rom_tx(const char *name, unsigned char idx) {
|
||||
if (chunk < 4096) {
|
||||
printf("Failed to load ROM: must be at least 4096 bytes\n");
|
||||
Info("Invalid ROM!");
|
||||
|
||||
// Signal end of transmission
|
||||
user_io_set_download(0);
|
||||
ProgressMessage(0, 0, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -795,9 +1153,9 @@ int n64_rom_tx(const char *name, unsigned char idx) {
|
||||
calc_bootcode_checksums(bootcode_sums, buf);
|
||||
|
||||
/* The first byte (starting at 0x3b) indicates the type of ROM
|
||||
'N' = cartridge
|
||||
'N' = Cartridge
|
||||
'D' = 64DD disk
|
||||
'C' = cartridge part of expandable game
|
||||
'C' = Cartridge part of expandable game
|
||||
'E' = 64DD expansion for cart
|
||||
'Z' = Aleck64 cart
|
||||
The 2nd and 3rd byte form a 2-letter ID for the game
|
||||
@@ -830,8 +1188,6 @@ int n64_rom_tx(const char *name, unsigned char idx) {
|
||||
is_first_chunk = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
MD5Final(md5, &ctx);
|
||||
md5_to_hex(md5, md5_hex);
|
||||
printf("File MD5: %s\n", md5_hex);
|
||||
@@ -846,7 +1202,6 @@ int n64_rom_tx(const char *name, unsigned char idx) {
|
||||
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) {
|
||||
// "Advanced" Homebrew ROM Header https://n64brew.dev/wiki/ROM_Header
|
||||
if (detect_homebrew_header(controller_settings, cart_id)) {
|
||||
rom_settings_detected = 2;
|
||||
}
|
||||
@@ -854,14 +1209,16 @@ int n64_rom_tx(const char *name, unsigned char idx) {
|
||||
printf("No ROM information found for Cart ID: %s\n", cart_id);
|
||||
if (is_auto()) {
|
||||
// Defaulting misc. System Settings
|
||||
// auto is_wide = user_io_status_get(AR_OPT) == 1;
|
||||
// if (is_wide) user_io_status_set(AR_TYPE_OPT, 0); // Resetting Aspect Ratio to Original
|
||||
if (old_ar != AspectRatio::UNKNOWN) {
|
||||
user_io_status_set(AR_TYPE_OPT, (uint32_t)old_ar); // Resetting Aspect Ratio to Original
|
||||
old_ar = AspectRatio::UNKNOWN;
|
||||
}
|
||||
user_io_status_set(NO_EPAK_OPT, 0); // Enable Expansion Pak
|
||||
user_io_status_set(CPAK_OPT, 1); // Enable Controller Pak (?)
|
||||
user_io_status_set(CPAK_OPT, 0); // Disable Controller Pak
|
||||
user_io_status_set(RPAK_OPT, 0); // Disable Rumble Pak
|
||||
user_io_status_set(TPAK_OPT, 0); // Disable Transfer Pak
|
||||
user_io_status_set(RTC_OPT, 0); // Disable RTC
|
||||
set_save_type(MemoryType::EEPROM_512); // Use the most common save type (?)
|
||||
set_cart_save_type(MemoryType::NONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -881,16 +1238,43 @@ int n64_rom_tx(const char *name, unsigned char idx) {
|
||||
printf("Done.\n");
|
||||
FileClose(&f);
|
||||
|
||||
// Mount save state
|
||||
char file_path[1024];
|
||||
FileGenerateSavePath(name, file_path);
|
||||
user_io_file_mount(file_path, 0, 1);
|
||||
auto save_type = get_cart_save_type();
|
||||
char old_save_path[1024];
|
||||
get_old_save_path(old_save_path, name);
|
||||
bool do_reset = false;
|
||||
|
||||
if (save_type != MemoryType::NONE) {
|
||||
do_reset |= mount_save_file(name, save_type, old_save_path);
|
||||
}
|
||||
|
||||
auto use_cpak = (bool)user_io_status_get(CPAK_OPT);
|
||||
auto use_tpak = (bool)user_io_status_get(TPAK_OPT);
|
||||
|
||||
// First controller can be either tpak or cpak. Tpak is prioritized.
|
||||
if (use_tpak || use_cpak) {
|
||||
do_reset |= mount_save_file(name,
|
||||
(use_tpak ? MemoryType::TPAK : MemoryType::CPAK),
|
||||
old_save_path);
|
||||
}
|
||||
|
||||
if (use_cpak) {
|
||||
do_reset |= mount_save_file(name, MemoryType::CPAK, old_save_path);
|
||||
do_reset |= mount_save_file(name, MemoryType::CPAK, old_save_path);
|
||||
do_reset |= mount_save_file(name, MemoryType::CPAK, old_save_path);
|
||||
}
|
||||
|
||||
// Signal end of transmission
|
||||
user_io_set_download(0);
|
||||
|
||||
ProgressMessage(0, 0, 0, 0);
|
||||
|
||||
// reset if new save files were
|
||||
if (do_reset) {
|
||||
user_io_status_set("[0]", 1);
|
||||
usleep(100000);
|
||||
user_io_status_set("[0]", 0);
|
||||
}
|
||||
|
||||
if (!is_auto()) {
|
||||
return 1;
|
||||
}
|
||||
@@ -900,8 +1284,8 @@ int n64_rom_tx(const char *name, unsigned char idx) {
|
||||
|
||||
char info[256];
|
||||
size_t len = sprintf(info, "Auto-detect:");
|
||||
if (strlen(cart_id) && ((cart_id[1] != 'E') || (cart_id[2] != 'D'))) len += sprintf(info + len, "\n[%.4s] v.%u.%u", cart_id, hex_to_dec(cart_id[4]) + 1, hex_to_dec(cart_id[5]));
|
||||
if (strlen(internal_name)) len += sprintf(info + len, "\n\"%s\"", internal_name);
|
||||
if (*cart_id && ((cart_id[1] != 'E') || (cart_id[2] != 'D'))) len += sprintf(info + len, "\n[%.4s] v.%u.%u", cart_id, hex_to_dec(cart_id[4]) + 1, hex_to_dec(cart_id[5]));
|
||||
if (*internal_name) len += sprintf(info + len, "\n\"%s\"", internal_name);
|
||||
if ((rom_settings_detected & 1) == 0) {
|
||||
len += sprintf(info + len, "\nUnknown Region/CIC");
|
||||
}
|
||||
@@ -917,24 +1301,21 @@ int n64_rom_tx(const char *name, unsigned char idx) {
|
||||
Info(info, 4000);
|
||||
}
|
||||
else {
|
||||
auto save_type = get_save_type();
|
||||
auto no_epak = (bool)user_io_status_get(NO_EPAK_OPT);
|
||||
auto tpak = (bool)user_io_status_get(TPAK_OPT);
|
||||
auto cpak = (bool)user_io_status_get(CPAK_OPT);
|
||||
auto rpak = (bool)user_io_status_get(RPAK_OPT);
|
||||
auto tpak = (bool)user_io_status_get(TPAK_OPT);
|
||||
auto rtc = (bool)user_io_status_get(RTC_OPT);
|
||||
|
||||
if (save_type != MemoryType::NONE) len += sprintf(info + len, "\nSave Type: %s", stringify(save_type));
|
||||
if (tpak) len += sprintf(info + len, "\nTransfer Pak \x96");
|
||||
if (cpak) len += sprintf(info + len, "\nController Pak \x96");
|
||||
if (rpak) len += sprintf(info + len, "\nRumble Pak \x96");
|
||||
if (tpak) len += sprintf(info + len, "\nTransfer Pak \x96");
|
||||
if (rtc) len += sprintf(info + len, "\nRTC \x96");
|
||||
if (no_epak) sprintf(info + len, "\nDisable Expansion Pak \x96");
|
||||
if (no_epak) sprintf(info + len, "\nDisable Exp. Pak \x96");
|
||||
|
||||
Info(info, 6000);
|
||||
}
|
||||
|
||||
printf("%s\n", info);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
#define N64_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "../../file_io.h"
|
||||
|
||||
int n64_rom_tx(const char* name, unsigned char index);
|
||||
void n64_load_savedata(uint64_t lba, int ack, uint64_t& buffer_lba, uint8_t* buffer, uint32_t buffer_size, uint32_t blksz, uint32_t sz);
|
||||
void n64_save_savedata(uint64_t lba, int ack, uint64_t& buffer_lba, uint8_t* buffer, uint32_t blksz, uint32_t sz);
|
||||
|
||||
#endif
|
||||
194
support/n64/n64_cpak_header.h
Normal file
194
support/n64/n64_cpak_header.h
Normal file
@@ -0,0 +1,194 @@
|
||||
|
||||
static const uint8_t cpak_header[4][768] = { {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0xc2, 0x1e, 0x03, 0x11, 0x8a, 0x6a, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x50, 0xa8, 0xaf, 0x4a,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0xc2, 0x1e, 0x03, 0x11, 0x8a, 0x6a, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x50, 0xa8, 0xaf, 0x4a,
|
||||
0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0xc2, 0x1e, 0x03, 0x11, 0x8a, 0x6a, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x50, 0xa8, 0xaf, 0x4a,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0xc2, 0x1e, 0x03, 0x11, 0x8a, 0x6a, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x50, 0xa8, 0xaf, 0x4a,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03 }, {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x1a, 0x00, 0x00, 0x00, 0x02, 0xaa, 0x23, 0x00, 0x7b, 0x3c, 0x56, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0xe8, 0x11, 0x17, 0xe1,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x1a, 0x00, 0x00, 0x00, 0x02, 0xaa, 0x23, 0x00, 0x7b, 0x3c, 0x56, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0xe8, 0x11, 0x17, 0xe1,
|
||||
0x00, 0x1a, 0x00, 0x00, 0x00, 0x02, 0xaa, 0x23, 0x00, 0x7b, 0x3c, 0x56, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0xe8, 0x11, 0x17, 0xe1,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x1a, 0x00, 0x00, 0x00, 0x02, 0xaa, 0x23, 0x00, 0x7b, 0x3c, 0x56, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0xe8, 0x11, 0x17, 0xe1,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03 }, {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x26, 0x00, 0x00, 0x00, 0x01, 0x5e, 0xd9, 0x04, 0x95, 0x99, 0xfe, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0xfe, 0x94, 0x01, 0x5e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x26, 0x00, 0x00, 0x00, 0x01, 0x5e, 0xd9, 0x04, 0x95, 0x99, 0xfe, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0xfe, 0x94, 0x01, 0x5e,
|
||||
0x00, 0x26, 0x00, 0x00, 0x00, 0x01, 0x5e, 0xd9, 0x04, 0x95, 0x99, 0xfe, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0xfe, 0x94, 0x01, 0x5e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x26, 0x00, 0x00, 0x00, 0x01, 0x5e, 0xd9, 0x04, 0x95, 0x99, 0xfe, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0xfe, 0x94, 0x01, 0x5e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03 }, {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x1f, 0x00, 0x00, 0x00, 0x04, 0xf6, 0x56, 0x04, 0x06, 0x30, 0xc4, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x2c, 0x44, 0xd3, 0xae,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x1f, 0x00, 0x00, 0x00, 0x04, 0xf6, 0x56, 0x04, 0x06, 0x30, 0xc4, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x2c, 0x44, 0xd3, 0xae,
|
||||
0x00, 0x1f, 0x00, 0x00, 0x00, 0x04, 0xf6, 0x56, 0x04, 0x06, 0x30, 0xc4, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x2c, 0x44, 0xd3, 0xae,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x1f, 0x00, 0x00, 0x00, 0x04, 0xf6, 0x56, 0x04, 0x06, 0x30, 0xc4, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x2c, 0x44, 0xd3, 0xae,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03 } };
|
||||
@@ -3,81 +3,82 @@
|
||||
#include <math.h>
|
||||
#include "../../user_io.h"
|
||||
|
||||
#define N64_MAX_DIAG 69
|
||||
#define N64_MAX_DIST sqrt(N64_MAX_DIAG * N64_MAX_DIAG * 2)
|
||||
#define N64_MAX_CARDINAL 85
|
||||
#define OUTER_DEADZONE 2.0f
|
||||
#define WEDGE_BOUNDARY (N64_MAX_CARDINAL - 69.0f) / 69.0f
|
||||
static constexpr int MAX_DIAG = 69;
|
||||
static constexpr int MAX_CARDINAL = 85;
|
||||
static constexpr float OUTER_DEADZONE = 2.0f;
|
||||
static constexpr float WEDGE_BOUNDARY = (float)(MAX_CARDINAL - MAX_DIAG) / MAX_DIAG;
|
||||
static constexpr float MAX_DIST = hypotf(MAX_DIAG, MAX_DIAG);
|
||||
|
||||
|
||||
|
||||
void stick_swap(int num, int stick, int *num2, int *stick2)
|
||||
void stick_swap(int num, int stick, int* num2, int* stick2)
|
||||
{
|
||||
int get=user_io_status_get("TV",1);
|
||||
int p2=get%2;
|
||||
int p3=get&2;
|
||||
int swap=get&4;
|
||||
if(swap) //reverse sticks
|
||||
{
|
||||
stick=1-stick;
|
||||
int get = user_io_status_get("TV", 1);
|
||||
int p2 = get & 1;
|
||||
int p3 = get & 2;
|
||||
int swap = get & 4;
|
||||
|
||||
//reverse sticks
|
||||
if (swap) {
|
||||
stick = stick ? 0 : 1;
|
||||
}
|
||||
if(p3) //p1 right stick -> p3
|
||||
{
|
||||
if (stick && num<2)
|
||||
{
|
||||
num+=2;
|
||||
stick=0;
|
||||
|
||||
//p1 right stick -> p3
|
||||
if (p3) {
|
||||
if (stick && (num < 2)) {
|
||||
num += 2;
|
||||
stick = 0;
|
||||
}
|
||||
else if(!stick && 2<num && num<5) //swap sticks to minimize conflict
|
||||
{
|
||||
num-=2;
|
||||
stick=1;
|
||||
//swap sticks to minimize conflict
|
||||
else if (!stick && (2 < num) && (num < 5)) {
|
||||
num -= 2;
|
||||
stick = 1;
|
||||
}
|
||||
}
|
||||
if(p2) //p1 right stick -> p2
|
||||
{
|
||||
if (stick && ( (num==0) | (num==2)))
|
||||
{
|
||||
|
||||
//p1 right stick -> p2
|
||||
if (p2) {
|
||||
if (stick && ((num == 0) || (num == 2))) {
|
||||
num++;
|
||||
stick=0;
|
||||
stick = 0;
|
||||
}
|
||||
else if(!stick && num%2==1)
|
||||
{
|
||||
else if (!stick && (num % 2 == 1)) {
|
||||
num--;
|
||||
stick=1;
|
||||
stick = 1;
|
||||
}
|
||||
}
|
||||
*num2=num;
|
||||
*stick2=stick;
|
||||
|
||||
*num2 = num;
|
||||
*stick2 = stick;
|
||||
}
|
||||
|
||||
void n64_joy_emu(int x, int y, int* x2, int* y2, int max_cardinal, float max_range)
|
||||
{
|
||||
void n64_joy_emu(const int x, const int y, int* x2, int* y2, int max_cardinal, float max_range) {
|
||||
// Move to top right quadrant to standardize solutions
|
||||
const int x_flip = x < 0 ? -1 : 1;
|
||||
const int y_flip = y < 0 ? -1 : 1;
|
||||
const int abs_x = x * x_flip;
|
||||
const int abs_y = y * y_flip;
|
||||
const float abs_x = x * x_flip;
|
||||
const float abs_y = y * y_flip;
|
||||
|
||||
// Either reduce range to radius 97.5807358037f ((69,69) diagonal of original controller)
|
||||
// Either reduce range to radius 97.5807358037f ((69, 69) diagonal of original controller)
|
||||
// or reduce cardinals to 85, whichever is less aggressive (smaller reduction in scaling)
|
||||
// (subtracts 2 from each to allow for minor outer deadzone)
|
||||
// assumes the max range is at least 85 (max cardinal of original controller)
|
||||
if (max_cardinal < N64_MAX_CARDINAL) max_cardinal = N64_MAX_CARDINAL;
|
||||
if (max_range < N64_MAX_DIST) max_range = N64_MAX_DIST;
|
||||
float scale_cardinal = N64_MAX_CARDINAL / (max_cardinal - OUTER_DEADZONE);
|
||||
float scale_range = N64_MAX_DIST / (max_range - OUTER_DEADZONE);
|
||||
float scale = scale_cardinal > scale_range ? scale_cardinal : scale_range;
|
||||
float scaled_x = abs_x * scale;
|
||||
float scaled_y = abs_y * scale;
|
||||
if (max_cardinal < MAX_CARDINAL) max_cardinal = MAX_CARDINAL;
|
||||
if (max_range < MAX_DIST) max_range = MAX_DIST;
|
||||
|
||||
const float scale_cardinal = MAX_CARDINAL / (max_cardinal - OUTER_DEADZONE);
|
||||
const float scale_range = MAX_DIST / (max_range - OUTER_DEADZONE);
|
||||
const float scale = scale_cardinal > scale_range ? scale_cardinal : scale_range;
|
||||
const float scaled_x = abs_x * scale;
|
||||
const float scaled_y = abs_y * scale;
|
||||
|
||||
// Move to octagon's lower wedge in top right quadrant to further standardize solution
|
||||
float scaled_max;
|
||||
float scaled_min;
|
||||
|
||||
if (abs_x > abs_y) {
|
||||
scaled_max = scaled_x;
|
||||
scaled_min = scaled_y;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
scaled_max = scaled_y;
|
||||
scaled_min = scaled_x;
|
||||
}
|
||||
@@ -85,28 +86,23 @@ void n64_joy_emu(int x, int y, int* x2, int* y2, int max_cardinal, float max_ran
|
||||
// Clamp scaled_min and scaled_max
|
||||
// Note: wedge boundary is given by x = 85 - y * ((85 - 69) / 69)
|
||||
// If x + y * (16 / 69) > 85, coordinates exceed boundary and need clamped
|
||||
float boundary = scaled_max + scaled_min * WEDGE_BOUNDARY;
|
||||
if (boundary > N64_MAX_CARDINAL) {
|
||||
const float boundary = scaled_max + scaled_min * WEDGE_BOUNDARY;
|
||||
if (boundary > MAX_CARDINAL) {
|
||||
// We know target value is on:
|
||||
// 1) Boundary line: x = 85 - y * (16 / 69)
|
||||
// 2) Observed slope line: y = (scaled_max / scaled_min) * x
|
||||
// Solving system of equations yields:
|
||||
scaled_min = N64_MAX_CARDINAL * scaled_min / boundary;
|
||||
scaled_max = N64_MAX_CARDINAL - scaled_min * WEDGE_BOUNDARY; // Boundary line
|
||||
scaled_min = MAX_CARDINAL * scaled_min / boundary;
|
||||
scaled_max = MAX_CARDINAL - scaled_min * WEDGE_BOUNDARY; // Boundary line
|
||||
}
|
||||
|
||||
// Move back from wedge to actual coordinates
|
||||
if (abs_x > abs_y) {
|
||||
*x2 = x_flip * scaled_max;
|
||||
*y2 = y_flip * scaled_min;
|
||||
} else {
|
||||
*x2 = x_flip * scaled_min;
|
||||
*y2 = y_flip * scaled_max;
|
||||
*x2 = nearbyintf(scaled_max * x_flip);
|
||||
*y2 = nearbyintf(scaled_min * y_flip);
|
||||
}
|
||||
else {
|
||||
*x2 = nearbyintf(scaled_min * x_flip);
|
||||
*y2 = nearbyintf(scaled_max * y_flip);
|
||||
}
|
||||
}
|
||||
|
||||
#undef N64_MAX_DIAG
|
||||
#undef N64_MAX_DIST
|
||||
#undef N64_MAX_CARDINAL
|
||||
#undef OUTER_DEADZONE
|
||||
#undef WEDGE_BOUNDARY
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
void stick_swap(int num, int stick, int *num2, int *stick2);
|
||||
void n64_joy_emu(int x, int y, int* x2, int* y2, int max_cardinal, float max_range);
|
||||
void n64_joy_emu(const int x, const int y, int* x2, int* y2, int max_cardinal, float max_range);
|
||||
|
||||
31
user_io.cpp
31
user_io.cpp
@@ -96,6 +96,11 @@ const char *get_image_name(int i)
|
||||
return p;
|
||||
}
|
||||
|
||||
fileTYPE *get_image(int i)
|
||||
{
|
||||
return &sd_image[i];
|
||||
}
|
||||
|
||||
static uint32_t uart_mode;
|
||||
uint32_t user_io_get_uart_mode()
|
||||
{
|
||||
@@ -1050,7 +1055,7 @@ const char* get_rbf_path()
|
||||
return core_path;
|
||||
}
|
||||
|
||||
void MakeFile(const char * filename, const char * data)
|
||||
void MakeFile(const char *filename, const char *data)
|
||||
{
|
||||
FILE * file;
|
||||
file = fopen(filename, "w");
|
||||
@@ -1230,14 +1235,14 @@ uint16_t sdram_sz(int sz)
|
||||
{
|
||||
*par++ = 0x12;
|
||||
*par++ = 0x57;
|
||||
*par++ = (uint8_t)(sz>>8);
|
||||
*par++ = (uint8_t)(sz >> 8);
|
||||
*par++ = (uint8_t)sz;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((par[0] == 0x12) && (par[1] == 0x57))
|
||||
{
|
||||
res = 0x8000 | (par[2]<<8) | par[3];
|
||||
res = 0x8000 | (par[2] << 8) | par[3];
|
||||
if(res & 0x4000) printf("*** Debug phase: %d\n", (res & 0x100) ? (res & 0xFF) : -(res & 0xFF));
|
||||
else printf("*** Found SDRAM config: %d\n", res & 7);
|
||||
}
|
||||
@@ -1651,7 +1656,7 @@ void user_io_l_analog_joystick(unsigned char joystick, char valueX, char valueY)
|
||||
if (core_type == CORE_TYPE_8BIT)
|
||||
{
|
||||
spi_uio_cmd8_cont(UIO_ASTICK, joy);
|
||||
if(io_ver) spi_w((valueY<<8) | (uint8_t)(valueX));
|
||||
if(io_ver) spi_w((valueY << 8) | (uint8_t)(valueX));
|
||||
else
|
||||
{
|
||||
spi8(valueX);
|
||||
@@ -1687,7 +1692,7 @@ void user_io_digital_joystick(unsigned char joystick, uint32_t map, int newdir)
|
||||
|
||||
spi_uio_cmd_cont((joy < 2) ? (UIO_JOYSTICK0 + joy) : (UIO_JOYSTICK2 + joy - 2));
|
||||
spi_w(map);
|
||||
if(use32) spi_w(map>>16);
|
||||
if(use32) spi_w(map >> 16);
|
||||
DisableIO();
|
||||
|
||||
if (!is_minimig() && joy_transl == 1 && newdir)
|
||||
@@ -2095,12 +2100,12 @@ int user_io_file_mount(const char *name, unsigned char index, char pre, int pre_
|
||||
else
|
||||
{
|
||||
spi32_b(size);
|
||||
spi32_b(size>>32);
|
||||
spi32_b(size >> 32);
|
||||
}
|
||||
DisableIO();
|
||||
|
||||
// notify core of possible sd image change
|
||||
spi_uio_cmd8(UIO_SET_SDSTAT, (1<< index) | (writable ? 0 : 0x80));
|
||||
spi_uio_cmd8(UIO_SET_SDSTAT, (1 << index) | (writable ? 0 : 0x80));
|
||||
return ret ? 1 : 0;
|
||||
}
|
||||
|
||||
@@ -3051,9 +3056,13 @@ void user_io_poll()
|
||||
else if (op & 1) c64_readGCR(disk, lba, blks-1);
|
||||
else break;
|
||||
}
|
||||
else if (op == 2 && is_n64() && use_save)
|
||||
{
|
||||
n64_save_savedata(lba, ack, buffer_lba[disk], buffer[disk], blksz, sz);
|
||||
}
|
||||
else if (op == 2)
|
||||
{
|
||||
//printf("SD WR %d on %d\n", lba, disk);
|
||||
//printf("SD WR %llu on %d\n", lba, disk);
|
||||
|
||||
if (use_save) menu_process_save();
|
||||
|
||||
@@ -3101,6 +3110,10 @@ void user_io_poll()
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((op & 1) && is_n64() && use_save)
|
||||
{
|
||||
n64_load_savedata(lba, ack, buffer_lba[disk], buffer[disk], sizeof(*buffer), blksz, sz);
|
||||
}
|
||||
else if (op & 1)
|
||||
{
|
||||
uint32_t buf_n = sizeof(buffer[0]) / blksz;
|
||||
@@ -3109,7 +3122,7 @@ void user_io_poll()
|
||||
int done = 0;
|
||||
uint32_t offset;
|
||||
|
||||
if ((buffer_lba[disk] == (uint64_t)-1) || lba < buffer_lba[disk] || (lba + blks - buffer_lba[disk]) > buf_n)
|
||||
if ((buffer_lba[disk] == -1LLU) || lba < buffer_lba[disk] || (lba + blks - buffer_lba[disk]) > buf_n)
|
||||
{
|
||||
buffer_lba[disk] = -1;
|
||||
if (blksz == 2352 && is_psx())
|
||||
|
||||
Reference in New Issue
Block a user