#include "../copyright" #include #ifdef HAVE_STRINGS_H #include #endif #include #ifdef __linux #include #endif #include "snes9x.h" #include "memmap.h" #include "cpuexec.h" #include "ppu.h" #include "display.h" #include "cheats.h" #include "apu.h" #include "sa1.h" #include "dsp1.h" #include "srtc.h" #include "sdd1.h" #include "spc7110.h" #include "seta.h" #ifdef __W32_HEAP #include #endif #include "fxemu.h" extern struct FxInit_s SuperFX; #ifndef SET_UI_COLOR #define SET_UI_COLOR(r,g,b) ; #endif //you would think everyone would have these //since they're so useful. #ifndef max #define max(a,b) (((a) > (b)) ? (a) : (b)) #endif #ifndef min #define min(a,b) (((a) < (b)) ? (a) : (b)) #endif static int retry_count = 0; static uint8_t bytes0x2000 [0x2000]; int is_bsx(unsigned char*); int bs_name(unsigned char*); static int check_char(unsigned c) { if ((c & 0x80) == 0) return 0; if ((c - 0x20) & 0x40) return 1; return 0; } void S9xDeinterleaveType2(bool reset); uint32_t caCRC32(uint8_t* array, uint32_t size, uint32_t crc32); extern char* rom_filename; const uint32_t crc32Table[256] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; void S9xDeinterleaveType1(int TotalFileSize, uint8_t* base) { if (Settings.DisplayColor == 0xffff) { Settings.DisplayColor = BUILD_PIXEL(0, 31, 0); SET_UI_COLOR(0, 255, 0); } int i; int nblocks = TotalFileSize >> 16; uint8_t blocks [256]; for (i = 0; i < nblocks; i++) { blocks [i * 2] = i + nblocks; blocks [i * 2 + 1] = i; } // DS2 DMA notes: base may or may not be 32-byte aligned uint8_t* tmp = (uint8_t*) malloc(0x8000); if (tmp) { for (i = 0; i < nblocks * 2; i++) { int j; for (j = i; j < nblocks * 2; j++) { if (blocks [j] == i) { // memmove converted: Different mallocs [Neb] memcpy(tmp, &base [blocks [j] * 0x8000], 0x8000); // memmove converted: Different addresses, or identical for blocks[i] == blocks[j] [Neb] // DS2 DMA notes: Don't do DMA at all if blocks[i] == blocks[j] memcpy(&base [blocks [j] * 0x8000], &base [blocks [i] * 0x8000], 0x8000); // memmove converted: Different mallocs [Neb] memcpy(&base [blocks [i] * 0x8000], tmp, 0x8000); uint8_t b = blocks [j]; blocks [j] = blocks [i]; blocks [i] = b; break; } } } free((char*) tmp); } } void S9xDeinterleaveGD24(int TotalFileSize, uint8_t* base) { if (TotalFileSize != 0x300000) return; if (Settings.DisplayColor == 0xffff) { Settings.DisplayColor = BUILD_PIXEL(0, 31, 31); SET_UI_COLOR(0, 255, 255); } // DS2 DMA notes: base may or may not be 32-byte aligned uint8_t* tmp = (uint8_t*) malloc(0x80000); if (tmp) { // memmove converted: Different mallocs [Neb] memcpy(tmp, &base[0x180000], 0x80000); // memmove converted: Different addresses [Neb] memcpy(&base[0x180000], &base[0x200000], 0x80000); // memmove converted: Different addresses [Neb] memcpy(&base[0x200000], &base[0x280000], 0x80000); // memmove converted: Different mallocs [Neb] memcpy(&base[0x280000], tmp, 0x80000); free((char*) tmp); S9xDeinterleaveType1(TotalFileSize, base); } } static bool AllASCII(uint8_t* b, int size) { int i; for (i = 0; i < size; i++) { if (b[i] < 32 || b[i] > 126) return (false); } return (true); } static int ScoreHiROM(bool skip_header, int32_t romoff) { int score = 0; int o = skip_header ? 0xff00 + 0x200 : 0xff00; o += romoff; if (Memory.ROM [o + 0xd5] & 0x1) score += 2; //Mode23 is SA-1 if (Memory.ROM [o + 0xd5] == 0x23) score -= 2; if (Memory.ROM [o + 0xd4] == 0x20) score += 2; if ((Memory.ROM [o + 0xdc] + (Memory.ROM [o + 0xdd] << 8) + Memory.ROM [o + 0xde] + (Memory.ROM [o + 0xdf] << 8)) == 0xffff) { score += 2; if (0 != (Memory.ROM [o + 0xde] + (Memory.ROM [o + 0xdf] << 8))) score++; } if (Memory.ROM [o + 0xda] == 0x33) score += 2; if ((Memory.ROM [o + 0xd5] & 0xf) < 4) score += 2; if (!(Memory.ROM [o + 0xfd] & 0x80)) score -= 6; if ((Memory.ROM [o + 0xfc] | (Memory.ROM [o + 0xfd] << 8)) > 0xFFB0) score -= 2; //reduced after looking at a scan by Cowering if (Memory.CalculatedSize > 1024 * 1024 * 3) score += 4; if ((1 << (Memory.ROM [o + 0xd7] - 7)) > 48) score -= 1; if (!AllASCII(&Memory.ROM [o + 0xb0], 6)) score -= 1; if (!AllASCII(&Memory.ROM [o + 0xc0], ROM_NAME_LEN - 1)) score -= 1; return (score); } static int ScoreLoROM(bool skip_header, int32_t romoff) { int score = 0; int o = skip_header ? 0x7f00 + 0x200 : 0x7f00; o += romoff; if (!(Memory.ROM [o + 0xd5] & 0x1)) score += 3; //Mode23 is SA-1 if (Memory.ROM [o + 0xd5] == 0x23) score += 2; if ((Memory.ROM [o + 0xdc] + (Memory.ROM [o + 0xdd] << 8) + Memory.ROM [o + 0xde] + (Memory.ROM [o + 0xdf] << 8)) == 0xffff) { score += 2; if (0 != (Memory.ROM [o + 0xde] + (Memory.ROM [o + 0xdf] << 8))) score++; } if (Memory.ROM [o + 0xda] == 0x33) score += 2; if ((Memory.ROM [o + 0xd5] & 0xf) < 4) score += 2; if (Memory.CalculatedSize <= 1024 * 1024 * 16) score += 2; if (!(Memory.ROM [o + 0xfd] & 0x80)) score -= 6; if ((Memory.ROM [o + 0xfc] | (Memory.ROM [o + 0xfd] << 8)) > 0xFFB0) score -= 2;//reduced per Cowering suggestion if ((1 << (Memory.ROM [o + 0xd7] - 7)) > 48) score -= 1; if (!AllASCII(&Memory.ROM [o + 0xb0], 6)) score -= 1; if (!AllASCII(&Memory.ROM [o + 0xc0], ROM_NAME_LEN - 1)) score -= 1; return (score); } static char* Safe(const char* s) { static char* safe; static int safe_len = 0; if (s == NULL) { if (safe != NULL) { free((char*)safe); safe = NULL; } return NULL; } int len = strlen(s); if (!safe || len + 1 > safe_len) { if (safe) free((char*) safe); safe = (char*) malloc(safe_len = len + 1); } int i; for (i = 0; i < len; i++) { if (s [i] >= 32 && s [i] < 127) safe [i] = s[i]; else safe [i] = '?'; } safe [len] = 0; return (safe); } /**********************************************************************************************/ /* S9xInitMemory() */ /* This function allocates and zeroes all the memory needed by the emulator */ /**********************************************************************************************/ bool S9xInitMemory() { // DS2 DMA notes: These would do well to be allocated with 32 extra bytes // so they can be 32-byte aligned. [Neb] Memory.RAM = (uint8_t*) malloc(0x20000); Memory.SRAM = (uint8_t*) malloc(0x20000); Memory.VRAM = (uint8_t*) malloc(0x10000); #ifdef DS2_DMA ROM = (uint8_t*) AlignedMalloc(MAX_ROM_SIZE + 0x200 + 0x8000, 32, &PtrAdj.ROM); #else Memory.ROM = (uint8_t*) malloc(MAX_ROM_SIZE + 0x200 + 0x8000); #endif memset(Memory.RAM, 0, 0x20000); memset(Memory.SRAM, 0, 0x20000); memset(Memory.VRAM, 0, 0x10000); // Don't bother memsetting ROM, we will load a game anyway. [Neb] Memory.BSRAM = (uint8_t*) malloc(0x80000); memset(Memory.BSRAM, 0, 0x80000); Memory.FillRAM = NULL; IPPU.TileCache [TILE_2BIT] = (uint8_t*) malloc(MAX_2BIT_TILES * 128); IPPU.TileCache [TILE_4BIT] = (uint8_t*) malloc(MAX_4BIT_TILES * 128); IPPU.TileCache [TILE_8BIT] = (uint8_t*) malloc(MAX_8BIT_TILES * 128); IPPU.TileCached [TILE_2BIT] = (uint8_t*) malloc(MAX_2BIT_TILES); IPPU.TileCached [TILE_4BIT] = (uint8_t*) malloc(MAX_4BIT_TILES); IPPU.TileCached [TILE_8BIT] = (uint8_t*) malloc(MAX_8BIT_TILES); if (!Memory.RAM || !Memory.SRAM || !Memory.VRAM || !Memory.ROM || !Memory.BSRAM || !IPPU.TileCache [TILE_2BIT] || !IPPU.TileCache [TILE_4BIT] || !IPPU.TileCache [TILE_8BIT] || !IPPU.TileCached [TILE_2BIT] || !IPPU.TileCached [TILE_4BIT] || !IPPU.TileCached [TILE_8BIT]) { S9xDeinitMemory(); return (false); } // FillRAM uses first 32K of ROM image area, otherwise space just // wasted. Might be read by the SuperFX code. Memory.FillRAM = Memory.ROM; // Add 0x8000 to ROM image pointer to stop SuperFX code accessing // unallocated memory (can cause crash on some ports). Memory.ROM += 0x8000; // still 32-byte aligned Memory.C4RAM = Memory.ROM + 0x400000 + 8192 * 8; // still 32-byte aligned Memory.ROM = Memory.ROM; Memory.SRAM = Memory.SRAM; SuperFX.pvRegisters = &Memory.FillRAM [0x3000]; SuperFX.nRamBanks = 2; // Most only use 1. 1=64KB, 2=128KB=1024Mb SuperFX.pvRam = Memory.SRAM; SuperFX.nRomBanks = (2 * 1024 * 1024) / (32 * 1024); SuperFX.pvRom = (uint8_t*) Memory.ROM; memset(IPPU.TileCache [TILE_2BIT], 0, MAX_2BIT_TILES * 128); memset(IPPU.TileCache [TILE_4BIT], 0, MAX_4BIT_TILES * 128); memset(IPPU.TileCache [TILE_8BIT], 0, MAX_8BIT_TILES * 128); memset(IPPU.TileCached [TILE_2BIT], 0, MAX_2BIT_TILES); memset(IPPU.TileCached [TILE_4BIT], 0, MAX_4BIT_TILES); memset(IPPU.TileCached [TILE_8BIT], 0, MAX_8BIT_TILES); Memory.SDD1Data = NULL; Memory.SDD1Index = NULL; return (true); } void S9xDeinitMemory() { #ifdef __W32_HEAP if (_HEAPOK != _heapchk()) MessageBox(GUI.hWnd, "Deinit", "Heap Corrupt", MB_OK); #endif if (Memory.RAM) { free((char*) Memory.RAM); Memory.RAM = NULL; } if (Memory.SRAM) { free((char*) Memory.SRAM); Memory.SRAM = NULL; } if (Memory.VRAM) { free((char*) Memory.VRAM); Memory.VRAM = NULL; } if (Memory.ROM) { Memory.ROM -= 0x8000; #ifdef DS2_RAM AlignedFree((char*) ROM, PtrAdj.ROM); #else free((char*) Memory.ROM); #endif Memory.ROM = NULL; } if (Memory.BSRAM) { free((char*) Memory.BSRAM); Memory.BSRAM = NULL; } if (IPPU.TileCache [TILE_2BIT]) { free((char*) IPPU.TileCache [TILE_2BIT]); IPPU.TileCache [TILE_2BIT] = NULL; } if (IPPU.TileCache [TILE_4BIT]) { free((char*) IPPU.TileCache [TILE_4BIT]); IPPU.TileCache [TILE_4BIT] = NULL; } if (IPPU.TileCache [TILE_8BIT]) { free((char*) IPPU.TileCache [TILE_8BIT]); IPPU.TileCache [TILE_8BIT] = NULL; } if (IPPU.TileCached [TILE_2BIT]) { free((char*) IPPU.TileCached [TILE_2BIT]); IPPU.TileCached [TILE_2BIT] = NULL; } if (IPPU.TileCached [TILE_4BIT]) { free((char*) IPPU.TileCached [TILE_4BIT]); IPPU.TileCached [TILE_4BIT] = NULL; } if (IPPU.TileCached [TILE_8BIT]) { free((char*) IPPU.TileCached [TILE_8BIT]); IPPU.TileCached [TILE_8BIT] = NULL; } FreeSDD1Data(); Safe(NULL); } void FreeSDD1Data() { if (Memory.SDD1Index) { free((char*) Memory.SDD1Index); Memory.SDD1Index = NULL; } if (Memory.SDD1Data) { free((char*) Memory.SDD1Data); Memory.SDD1Data = NULL; } } #ifndef LOAD_FROM_MEMORY_TEST /* Read variable size MSB int from a file */ static long ReadInt(FILE* f, unsigned nbytes) { long v = 0; while (nbytes--) { int c = fgetc(f); if (c == EOF) return -1; v = (v << 8) | (c & 0xFF); } return (v); } #define IPS_EOF 0x00454F46l static void CheckForIPSPatch(const char* rom_filename, bool header, int32_t* rom_size) { char dir [_MAX_DIR + 1]; char drive [_MAX_DRIVE + 1]; char name [_MAX_FNAME + 1]; char ext [_MAX_EXT + 1]; char fname [_MAX_PATH + 1]; FILE* patch_file = NULL; long offset = header ? 512 : 0; _splitpath(rom_filename, drive, dir, name, ext); _makepath(fname, drive, dir, name, "ips"); if (!(patch_file = fopen(fname, "rb"))) { if (!(patch_file = fopen(S9xGetFilename("ips"), "rb"))) return; } if (fread((unsigned char*)fname, 1, 5, patch_file) != 5 || strncmp(fname, "PATCH", 5) != 0) { fclose(patch_file); return; } int32_t ofs; for (;;) { long len; long rlen; int rchar; ofs = ReadInt(patch_file, 3); if (ofs == -1) goto err_eof; if (ofs == IPS_EOF) break; ofs -= offset; len = ReadInt(patch_file, 2); if (len == -1) goto err_eof; /* Apply patch block */ if (len) { if (ofs + len > MAX_ROM_SIZE) goto err_eof; while (len--) { rchar = fgetc(patch_file); if (rchar == EOF) goto err_eof; Memory.ROM [ofs++] = (uint8_t) rchar; } if (ofs > *rom_size) *rom_size = ofs; } else { rlen = ReadInt(patch_file, 2); if (rlen == -1) goto err_eof; rchar = fgetc(patch_file); if (rchar == EOF) goto err_eof; if (ofs + rlen > MAX_ROM_SIZE) goto err_eof; while (rlen--) Memory.ROM [ofs++] = (uint8_t) rchar; if (ofs > *rom_size) *rom_size = ofs; } } // Check if ROM image needs to be truncated ofs = ReadInt(patch_file, 3); if (ofs != -1 && ofs - offset < *rom_size) { // Need to truncate ROM image *rom_size = ofs - offset; } fclose(patch_file); return; err_eof: if (patch_file) fclose(patch_file); } static uint32_t FileLoader(uint8_t* buffer, const char* filename, int32_t maxsize) { FILE* ROMFile; int32_t TotalFileSize = 0; int len = 0; char dir [_MAX_DIR + 1]; char drive [_MAX_DRIVE + 1]; char name [_MAX_FNAME + 1]; char ext [_MAX_EXT + 1]; char fname [_MAX_PATH + 1]; unsigned long FileSize = 0; _splitpath(filename, drive, dir, name, ext); _makepath(fname, drive, dir, name, ext); #ifdef __WIN32__ // memmove required: Overlapping addresses [Neb] memmove(&ext [0], &ext[1], 4); #endif if ((ROMFile = fopen(fname, "rb")) == NULL) return (0); strcpy(Memory.ROMFilename, fname); Memory.HeaderCount = 0; uint8_t* ptr = buffer; bool more = false; do { FileSize = fread(ptr, 1, maxsize + 0x200 - (ptr - Memory.ROM), ROMFile); fclose(ROMFile); int calc_size = FileSize & ~0x1FFF; // round to the lower 0x2000 if ((FileSize - calc_size == 512 && !Settings.ForceNoHeader) || Settings.ForceHeader) { // memmove required: Overlapping addresses [Neb] // DS2 DMA notes: Can be split into 512-byte DMA blocks [Neb] #ifdef DS2_DMA __dcache_writeback_all(); { unsigned int i; for (i = 0; i < calc_size; i += 512) { ds2_DMAcopy_32Byte(2 /* channel: emu internal */, ptr + i, ptr + i + 512, 512); ds2_DMA_wait(2); ds2_DMA_stop(2); } } #else memmove(ptr, ptr + 512, calc_size); #endif Memory.HeaderCount++; FileSize -= 512; } ptr += FileSize; TotalFileSize += FileSize; // check for multi file roms if ((ptr - Memory.ROM) < (maxsize + 0x200) && (isdigit(ext [0]) && ext [1] == 0 && ext [0] < '9')) { more = true; ext [0]++; #ifdef __WIN32__ // memmove required: Overlapping addresses [Neb] memmove(&ext [1], &ext [0], 4); ext [0] = '.'; #endif _makepath(fname, drive, dir, name, ext); } else if (ptr - Memory.ROM < maxsize + 0x200 && (((len = strlen(name)) == 7 || len == 8) && strncasecmp(name, "sf", 2) == 0 && isdigit(name [2]) && isdigit(name [3]) && isdigit(name [4]) && isdigit(name [5]) && isalpha(name [len - 1]))) { more = true; name [len - 1]++; #ifdef __WIN32__ // memmove required: Overlapping addresses [Neb] memmove(&ext [1], &ext [0], 4); ext [0] = '.'; #endif _makepath(fname, drive, dir, name, ext); } else more = false; } while (more && (ROMFile = fopen(fname, "rb")) != NULL); if (Memory.HeaderCount == 0) S9xMessage(S9X_INFO, S9X_HEADERS_INFO, "No ROM file header found."); else { if (Memory.HeaderCount == 1) S9xMessage(S9X_INFO, S9X_HEADERS_INFO, "Found ROM file header (and ignored it)."); else S9xMessage(S9X_INFO, S9X_HEADERS_INFO, "Found multiple ROM file headers (and ignored them)."); } return TotalFileSize; } #endif /**********************************************************************************************/ /* LoadROM() */ /* This function loads a Snes-Backup image */ /**********************************************************************************************/ bool LoadROM( #ifdef LOAD_FROM_MEMORY_TEST const struct retro_game_info* game #else const char* filename #endif ) { int32_t TotalFileSize = 0; bool Interleaved = false; bool Tales = false; uint8_t* RomHeader = Memory.ROM; Memory.ExtendedFormat = NOPE; if (CleanUp7110 != NULL) (*CleanUp7110)(); memset(&SNESGameFixes, 0, sizeof(SNESGameFixes)); SNESGameFixes.SRAMInitialValue = 0x60; memset(bytes0x2000, 0, 0x2000); CPU.TriedInterleavedMode2 = false; Memory.CalculatedSize = 0; retry_count = 0; again: Settings.DisplayColor = 0xffff; SET_UI_COLOR(255, 255, 255); #ifdef LOAD_FROM_MEMORY_TEST strncpy(Memory.ROMFilename, game->path, sizeof(Memory.ROMFilename)); Memory.HeaderCount = 0; TotalFileSize = game->size; const uint8_t* src = game->data; Memory.HeaderCount = 0; if ((((game->size & 0x1FFF) == 0x200) && !Settings.ForceNoHeader) || Settings.ForceHeader) { S9xMessage(S9X_INFO, S9X_HEADERS_INFO, "Found ROM file header (and ignored it)."); TotalFileSize -= 0x200; src += 0x200; Memory.HeaderCount = 1; } else { S9xMessage(S9X_INFO, S9X_HEADERS_INFO, "No ROM file header found."); } if (TotalFileSize > MAX_ROM_SIZE) return false; memcpy(Memory.ROM, src, TotalFileSize); #else TotalFileSize = FileLoader(Memory.ROM, filename, MAX_ROM_SIZE); if (!TotalFileSize) return false; // it ends here else if (!Settings.NoPatch) CheckForIPSPatch(filename, Memory.HeaderCount != 0, &TotalFileSize); #endif //fix hacked games here. if ((strncmp("HONKAKUHA IGO GOSEI", (char*)&Memory.ROM[0x7FC0], 19) == 0) && (Memory.ROM[0x7FD5] != 0x31)) { Memory.ROM[0x7FD5] = 0x31; Memory.ROM[0x7FD6] = 0x02; Settings.DisplayColor = BUILD_PIXEL(31, 0, 0); SET_UI_COLOR(255, 0, 0); S9xMessage(S9X_ERROR, S9X_ROM_CONFUSING_FORMAT_INFO, "Warning! Hacked Dump!"); } if ((strncmp("HONKAKUHA IGO GOSEI", (char*)&Memory.ROM[0xFFC0], 19) == 0) && (Memory.ROM[0xFFD5] != 0x31)) { Memory.ROM[0xFFD5] = 0x31; Memory.ROM[0xFFD6] = 0x02; Settings.DisplayColor = BUILD_PIXEL(31, 0, 0); SET_UI_COLOR(255, 0, 0); S9xMessage(S9X_ERROR, S9X_ROM_CONFUSING_FORMAT_INFO, "Warning! Hacked Dump!"); } if ((Memory.ROM[0x7FD5] == 0x42) && (Memory.ROM[0x7FD6] == 0x13) && (strncmp("METAL COMBAT", (char*)&Memory.ROM[0x7FC0], 12) == 0)) { Settings.DisplayColor = BUILD_PIXEL(31, 0, 0); SET_UI_COLOR(255, 0, 0); S9xMessage(S9X_ERROR, S9X_ROM_CONFUSING_FORMAT_INFO, "Warning! Hacked Dump!"); } #ifndef NO_SPEEDHACKS // SNESAdvance speed hacks (from the speed-hacks branch of CatSFC) if (strncmp("YOSHI'S ISLAND", (char *) &Memory.ROM[0x7FC0], 14) == 0) { Memory.ROM[0x0000F4] = 0x42; Memory.ROM[0x0000F5] = 0x3B; } else if (strncmp("SUPER MARIOWORLD", (char *) &Memory.ROM[0x7FC0], 16) == 0) { Memory.ROM[0x00006D] = 0x42; } else if (strncmp("ALL_STARS + WORLD", (char *) &Memory.ROM[0x7FC0], 17) == 0) { Memory.ROM[0x0003D0] = 0x42; Memory.ROM[0x0003D1] = 0x5B; Memory.ROM[0x018522] = 0x42; Memory.ROM[0x018523] = 0x5B; Memory.ROM[0x02C804] = 0x42; Memory.ROM[0x02C805] = 0xBA; Memory.ROM[0x0683B5] = 0x42; Memory.ROM[0x0683B6] = 0x5B; Memory.ROM[0x0696AC] = 0x42; Memory.ROM[0x0696AD] = 0xBA; Memory.ROM[0x089233] = 0xDB; Memory.ROM[0x089234] = 0x61; Memory.ROM[0x0895DF] = 0x42; Memory.ROM[0x0895E0] = 0x5B; Memory.ROM[0x0A7A9D] = 0x42; Memory.ROM[0x0A7A9E] = 0xBA; Memory.ROM[0x1072E7] = 0x42; Memory.ROM[0x1072E8] = 0xD9; Memory.ROM[0x107355] = 0x42; Memory.ROM[0x107356] = 0x5B; Memory.ROM[0x1073CF] = 0x42; Memory.ROM[0x1073D0] = 0x5B; Memory.ROM[0x107443] = 0x42; Memory.ROM[0x107444] = 0x5B; Memory.ROM[0x107498] = 0x42; Memory.ROM[0x107499] = 0x5B; Memory.ROM[0x107505] = 0x42; Memory.ROM[0x107506] = 0x5B; Memory.ROM[0x107539] = 0x42; Memory.ROM[0x10753A] = 0x5B; Memory.ROM[0x107563] = 0x42; Memory.ROM[0x107564] = 0x5B; Memory.ROM[0x1801D4] = 0x42; Memory.ROM[0x1801D5] = 0x10; Memory.ROM[0x18041D] = 0x42; Memory.ROM[0x18041E] = 0x79; } #endif int hi_score=ScoreHiROM(true, 0); int lo_score=ScoreLoROM(true, 0); if (Memory.HeaderCount == 0 && !Settings.ForceNoHeader && ((hi_score > lo_score && ScoreHiROM(true, 0) > hi_score) || (hi_score <= lo_score && ScoreLoROM(true, 0) > lo_score))) { #ifdef DS2_DMA __dcache_writeback_all(); { unsigned int i; for (i = 0; i < TotalFileSize; i += 512) { ds2_DMAcopy_32Byte(2 /* channel: emu internal */, Memory.ROM + i, Memory.ROM + i + 512, 512); ds2_DMA_wait(2); ds2_DMA_stop(2); } } #else // memmove required: Overlapping addresses [Neb] memmove(Memory.ROM, Memory.ROM + 512, TotalFileSize - 512); #endif TotalFileSize -= 512; S9xMessage(S9X_INFO, S9X_HEADER_WARNING, "Try specifying the -nhd command line option if the game doesn't work\n"); } Memory.CalculatedSize = TotalFileSize & ~0x1FFF; // round down to lower 0x2000 memset(Memory.ROM + Memory.CalculatedSize, 0, MAX_ROM_SIZE - Memory.CalculatedSize); if (Memory.CalculatedSize > 0x400000 && !(Memory.ROM[0x7FD5] == 0x32 && ((Memory.ROM[0x7FD6] & 0xF0) == 0x40)) && //exclude S-DD1 !(Memory.ROM[0xFFD5] == 0x3A && ((Memory.ROM[0xFFD6] & 0xF0) == 0xF0))) //exclude SPC7110 { //you might be a Jumbo! Memory.ExtendedFormat = YEAH; } //If both vectors are invalid, it's type 1 LoROM if (Memory.ExtendedFormat == NOPE && ((Memory.ROM[0x7FFC] | (Memory.ROM[0x7FFD] << 8)) < 0x8000) && ((Memory.ROM[0xFFFC] | (Memory.ROM[0xFFFD] << 8)) < 0x8000)) { if (Settings.DisplayColor == 0xffff) { Settings.DisplayColor = BUILD_PIXEL(0, 31, 0); SET_UI_COLOR(0, 255, 0); } if (!Settings.ForceInterleaved) S9xDeinterleaveType1(TotalFileSize, Memory.ROM); } //CalculatedSize is now set, so rescore hi_score = ScoreHiROM(false, 0); lo_score = ScoreLoROM(false, 0); if (Memory.ExtendedFormat != NOPE) { int loromscore, hiromscore, swappedlorom, swappedhirom; loromscore = ScoreLoROM(false, 0); hiromscore = ScoreHiROM(false, 0); swappedlorom = ScoreLoROM(false, 0x400000); swappedhirom = ScoreHiROM(false, 0x400000); //set swapped here. if (max(swappedlorom, swappedhirom) >= max(loromscore, hiromscore)) { Memory.ExtendedFormat = BIGFIRST; hi_score = swappedhirom; lo_score = swappedlorom; RomHeader = Memory.ROM + 0x400000; } else { Memory.ExtendedFormat = SMALLFIRST; lo_score = loromscore; hi_score = hiromscore; RomHeader = Memory.ROM; } } Interleaved = Settings.ForceInterleaved || Settings.ForceInterleaved2; if (Settings.ForceLoROM || (!Settings.ForceHiROM && lo_score >= hi_score)) { Memory.LoROM = true; Memory.HiROM = false; // Ignore map type byte if not 0x2x or 0x3x if ((RomHeader [0x7fd5] & 0xf0) == 0x20 || (RomHeader [0x7fd5] & 0xf0) == 0x30) { switch (RomHeader [0x7fd5] & 0xf) { case 1: Interleaved = true; break; case 5: Interleaved = true; Tales = true; break; } } } else { if ((RomHeader [0xffd5] & 0xf0) == 0x20 || (RomHeader [0xffd5] & 0xf0) == 0x30) { switch (RomHeader [0xffd5] & 0xf) { case 0: case 3: Interleaved = true; break; } } Memory.LoROM = false; Memory.HiROM = true; } // More if (!Settings.ForceHiROM && !Settings.ForceLoROM && !Settings.ForceInterleaved && !Settings.ForceInterleaved2 && !Settings.ForceNotInterleaved && !Settings.ForcePAL && !Settings.ForceSuperFX && !Settings.ForceDSP1 && !Settings.ForceSA1 && !Settings.ForceC4 && !Settings.ForceSDD1) { #ifdef DETECT_NASTY_FX_INTERLEAVE //MK: Damn. YI trips a BRK currently. Maybe even on a real cart. #ifdef MSB_FIRST if (strncmp((char*) &ROM [0x7fc0], "YOSHI'S ISLAND", 14) == 0 && (ROM[0x7FDE] + (ROM[0x7FDF] << 8)) == 57611 && ROM[0x10002] == 0xA9) #else if (strncmp((char*) &ROM [0x7fc0], "YOSHI'S ISLAND", 14) == 0 && (*(uint16_t*)&ROM[0x7FDE]) == 57611 && ROM[0x10002] == 0xA9) #endif { Interleaved = true; Settings.ForceInterleaved2 = true; } #endif if (strncmp((char*) &Memory.ROM [0x7fc0], "YUYU NO QUIZ DE GO!GO!", 22) == 0) { Memory.LoROM = true; Memory.HiROM = false; Interleaved = false; } } if (!Settings.ForceNotInterleaved && Interleaved) { CPU.TriedInterleavedMode2 = true; S9xMessage(S9X_INFO, S9X_ROM_INTERLEAVED_INFO, "ROM image is in interleaved format - converting..."); if (Tales) { if (Memory.ExtendedFormat == BIGFIRST) { S9xDeinterleaveType1(0x400000, Memory.ROM); S9xDeinterleaveType1(Memory.CalculatedSize - 0x400000, Memory.ROM + 0x400000); } else { S9xDeinterleaveType1(Memory.CalculatedSize - 0x400000, Memory.ROM); S9xDeinterleaveType1(0x400000, Memory.ROM + Memory.CalculatedSize - 0x400000); } Memory.LoROM = false; Memory.HiROM = true; } else if (Settings.ForceInterleaved2) S9xDeinterleaveType2(false); else if (Settings.ForceInterleaveGD24 && Memory.CalculatedSize == 0x300000) { bool t = Memory.LoROM; Memory.LoROM = Memory.HiROM; Memory.HiROM = t; S9xDeinterleaveGD24(Memory.CalculatedSize, Memory.ROM); } else { if (Settings.DisplayColor == 0xffff) { Settings.DisplayColor = BUILD_PIXEL(0, 31, 0); SET_UI_COLOR(0, 255, 0); } bool t = Memory.LoROM; Memory.LoROM = Memory.HiROM; Memory.HiROM = t; S9xDeinterleaveType1(Memory.CalculatedSize, Memory.ROM); } hi_score = ScoreHiROM(false, 0); lo_score = ScoreLoROM(false, 0); if ((Memory.HiROM && (lo_score >= hi_score || hi_score < 0)) || (Memory.LoROM && (hi_score > lo_score || lo_score < 0))) { if (retry_count == 0) { S9xMessage(S9X_INFO, S9X_ROM_CONFUSING_FORMAT_INFO, "ROM lied about its type! Trying again."); Settings.ForceNotInterleaved = true; Settings.ForceInterleaved = false; retry_count++; goto again; } } } if (Memory.ExtendedFormat == SMALLFIRST) Tales = true; FreeSDD1Data(); InitROM(Tales); #ifdef WANT_CHEATS S9xLoadCheatFile(S9xGetFilename("cht")); S9xInitCheatData(); S9xApplyCheats(); #endif S9xReset(); return (true); } /* compatibility wrapper */ void S9xDeinterleaveMode2(void) { S9xDeinterleaveType2(true); } void S9xDeinterleaveType2(bool reset) { if (Settings.DisplayColor == 0xffff || Settings.DisplayColor == BUILD_PIXEL(0, 31, 0)) { Settings.DisplayColor = BUILD_PIXEL(31, 14, 6); SET_UI_COLOR(255, 119, 25); } S9xMessage(S9X_INFO, S9X_ROM_INTERLEAVED_INFO, "ROM image is in interleaved format - converting..."); int nblocks = Memory.CalculatedSize >> 16; int step = 64; while (nblocks <= step) step >>= 1; nblocks = step; uint8_t blocks [256]; int i; for (i = 0; i < nblocks * 2; i++) { blocks [i] = (i & ~0xF) | ((i & 3) << 2) | ((i & 12) >> 2); } #ifdef DS2_DMA unsigned int TmpAdj; uint8_t* tmp = (uint8_t*) AlignedMalloc(0x10000, 32, &TmpAdj); #else uint8_t* tmp = (uint8_t*) malloc(0x10000); #endif if (tmp) { #ifdef DS2_DMA __dcache_writeback_all(); #endif for (i = 0; i < nblocks * 2; i++) { int j; for (j = i; j < nblocks * 2; j++) { if (blocks [j] == i) { #ifdef DS2_DMA ds2_DMAcopy_32Byte(2 /* channel: emu internal */, tmp, &Memory.ROM [blocks [j] * 0x10000], 0x10000); ds2_DMA_wait(2); ds2_DMA_stop(2); ds2_DMAcopy_32Byte(2 /* channel: emu internal */, &Memory.ROM [blocks [j] * 0x10000], &Memory.ROM [blocks [i] * 0x10000], 0x10000); ds2_DMA_wait(2); ds2_DMA_stop(2); ds2_DMAcopy_32Byte(2 /* channel: emu internal */, &Memory.ROM [blocks [i] * 0x10000], tmp, 0x10000); ds2_DMA_wait(2); ds2_DMA_stop(2); #else // memmove converted: Different mallocs [Neb] memcpy(tmp, &Memory.ROM [blocks [j] * 0x10000], 0x10000); // memmove converted: Different addresses, or identical if blocks[i] == blocks[j] [Neb] memcpy(&Memory.ROM [blocks [j] * 0x10000], &Memory.ROM [blocks [i] * 0x10000], 0x10000); // memmove converted: Different mallocs [Neb] memcpy(&Memory.ROM [blocks [i] * 0x10000], tmp, 0x10000); #endif uint8_t b = blocks [j]; blocks [j] = blocks [i]; blocks [i] = b; break; } } } free((char*) tmp); tmp = NULL; } if (reset) { InitROM(false); S9xReset(); } } //CRC32 for char arrays uint32_t caCRC32(uint8_t* array, uint32_t size, uint32_t crc32) { uint32_t i; for (i = 0; i < size; i++) crc32 = ((crc32 >> 8) & 0x00FFFFFF) ^ crc32Table[(crc32 ^ array[i]) & 0xFF]; return ~crc32; } void InitROM(bool Interleaved) { SuperFX.nRomBanks = Memory.CalculatedSize >> 15; Settings.MultiPlayer5Master = Settings.MultiPlayer5; Settings.MouseMaster = Settings.Mouse; Settings.SuperScopeMaster = Settings.SuperScope; Settings.DSP1Master = Settings.ForceDSP1; Settings.SuperFX = false; Settings.SA1 = false; Settings.C4 = false; Settings.SDD1 = false; Settings.SRTC = false; Settings.SPC7110 = false; Settings.SPC7110RTC = false; Settings.BS = false; Settings.OBC1 = false; Settings.SETA = false; s7r.DataRomSize = 0; Memory.CalculatedChecksum = 0; uint8_t* RomHeader; RomHeader = Memory.ROM + 0x7FB0; if (Memory.ExtendedFormat == BIGFIRST) RomHeader += 0x400000; if (Memory.HiROM) RomHeader += 0x8000; if (!Settings.BS) { Settings.BS = (-1 != is_bsx(Memory.ROM + 0x7FC0)); if (Settings.BS) { Memory.LoROM = true; Memory.HiROM = false; } else { Settings.BS = (-1 != is_bsx(Memory.ROM + 0xFFC0)); if (Settings.BS) { Memory.HiROM = true; Memory.LoROM = false; } } } memset(Memory.BlockIsRAM, 0, MEMMAP_NUM_BLOCKS); memset(Memory.BlockIsROM, 0, MEMMAP_NUM_BLOCKS); memset(Memory.ROMId, 0, 5); memset(Memory.CompanyId, 0, 3); ParseSNESHeader(RomHeader); // Try to auto-detect the DSP1 chip if (!Settings.ForceNoDSP1 && (Memory.ROMType & 0xf) >= 3 && (Memory.ROMType & 0xf0) == 0) Settings.DSP1Master = true; if (Memory.HiROM) { // Enable S-RTC (Real Time Clock) emulation for Dai Kaijyu Monogatari 2 Settings.SRTC = ((Memory.ROMType & 0xf0) >> 4) == 5; if (((Memory.ROMSpeed & 0x0F) == 0x0A) && ((Memory.ROMType & 0xF0) == 0xF0)) { Settings.SPC7110 = true; if ((Memory.ROMType & 0x0F) == 0x09) Settings.SPC7110RTC = true; } if (Settings.BS) BSHiROMMap(); else if (Settings.SPC7110) SPC7110HiROMMap(); else if ((Memory.ROMSpeed & ~0x10) == 0x25) TalesROMMap(Interleaved); else HiROMMap(); } else { Settings.SuperFX = Settings.ForceSuperFX; if (Memory.ROMType == 0x25) Settings.OBC1 = true; //BS-X BIOS if (Memory.ROMType == 0xE5) Settings.BS = true; if ((Memory.ROMType & 0xf0) == 0x10) Settings.SuperFX = !Settings.ForceNoSuperFX; Settings.SDD1 = Settings.ForceSDD1; if ((Memory.ROMType & 0xf0) == 0x40) Settings.SDD1 = !Settings.ForceNoSDD1; if (((Memory.ROMType & 0xF0) == 0xF0) & ((Memory.ROMSpeed & 0x0F) != 5)) { Memory.SRAMSize = 2; SNESGameFixes.SRAMInitialValue = 0x00; if ((Memory.ROMType & 0x0F) == 6) { if (Memory.ROM[0x7FD7] == 0x09) { Settings.SETA = ST_011; SetSETA = &S9xSetST011; GetSETA = &S9xGetST011; } else { Settings.SETA = ST_010; SetSETA = &S9xSetST010; GetSETA = &S9xGetST010; } } else { Settings.SETA = ST_018; Memory.SRAMSize = 2; } } Settings.C4 = Settings.ForceC4; if ((Memory.ROMType & 0xf0) == 0xf0 && (strncmp(Memory.ROMName, "MEGAMAN X", 9) == 0 || strncmp(Memory.ROMName, "ROCKMAN X", 9) == 0)) Settings.C4 = !Settings.ForceNoC4; if (Settings.SETA && Settings.SETA != ST_018) SetaDSPMap(); else if (Settings.SuperFX) { SuperFXROMMap(); Settings.MultiPlayer5Master = false; Settings.DSP1Master = false; Settings.SA1 = false; Settings.C4 = false; Settings.SDD1 = false; } else if (Settings.ForceSA1 || (!Settings.ForceNoSA1 && (Memory.ROMSpeed & ~0x10) == 0x23 && (Memory.ROMType & 0xf) > 3 && (Memory.ROMType & 0xf0) == 0x30)) { Settings.SA1 = true; Settings.DSP1Master = false; Settings.C4 = false; Settings.SDD1 = false; SA1ROMMap(); } else if ((Memory.ROMSpeed & ~0x10) == 0x25) TalesROMMap(Interleaved); else if (Memory.ExtendedFormat != NOPE) JumboLoROMMap(Interleaved); else if (strncmp((char*) &Memory.ROM [0x7fc0], "SOUND NOVEL-TCOOL", 17) == 0 || strncmp((char*) &Memory.ROM [0x7fc0], "DERBY STALLION 96", 17) == 0) { LoROM24MBSMap(); Settings.DSP1Master = false; } else if (strncmp((char*) &Memory.ROM [0x7fc0], "THOROUGHBRED BREEDER3", 21) == 0 || strncmp((char*) &Memory.ROM [0x7fc0], "RPG-TCOOL 2", 11) == 0) { SRAM512KLoROMMap(); Settings.DSP1Master = false; } else if (strncmp((char*) &Memory.ROM [0x7fc0], "ADD-ON BASE CASSETE", 19) == 0) { Settings.MultiPlayer5Master = false; Settings.MouseMaster = false; Settings.SuperScopeMaster = false; Settings.DSP1Master = false; SufamiTurboLoROMMap(); Memory.SRAMSize = 3; } else if ((Memory.ROMSpeed & ~0x10) == 0x22 && strncmp(Memory.ROMName, "Super Street Fighter", 20) != 0) AlphaROMMap(); else if (Settings.BS) BSLoROMMap(); else LoROMMap(); } if (Settings.BS) Memory.ROMRegion = 0; uint32_t sum1 = 0; uint32_t sum2 = 0; if (0 == Memory.CalculatedChecksum) { int power2 = 0; int size = Memory.CalculatedSize; while (size >>= 1) power2++; size = 1 << power2; uint32_t remainder = Memory.CalculatedSize - size; int i; for (i = 0; i < size; i++) sum1 += Memory.ROM [i]; for (i = 0; i < (int) remainder; i++) sum2 += Memory.ROM [size + i]; int sub = 0; if (Settings.BS && Memory.ROMType != 0xE5) { if (Memory.HiROM) { for (i = 0; i < 48; i++) sub += Memory.ROM[0xffb0 + i]; } else if (Memory.LoROM) { for (i = 0; i < 48; i++) sub += Memory.ROM[0x7fb0 + i]; } sum1 -= sub; } if (remainder) sum1 += sum2 * (size / remainder); sum1 &= 0xffff; Memory.CalculatedChecksum = sum1; } //now take a CRC32 Memory.ROMCRC32 = caCRC32(Memory.ROM, Memory.CalculatedSize, 0xFFFFFFFF); if (Settings.ForceNTSC) Settings.PAL = false; else if (Settings.ForcePAL) Settings.PAL = true; else { //Korea refers to South Korea, which uses NTSC switch (Memory.ROMRegion) { case 13: case 1: case 0: Settings.PAL = false; break; default: Settings.PAL = true; break; } } if (Settings.PAL) { Settings.FrameTime = Settings.FrameTimePAL; Memory.ROMFramesPerSecond = 50; } else { Settings.FrameTime = Settings.FrameTimeNTSC; Memory.ROMFramesPerSecond = 60; } Memory.ROMName[ROM_NAME_LEN - 1] = 0; if (strlen(Memory.ROMName)) { char* p = Memory.ROMName + strlen(Memory.ROMName) - 1; while (p > Memory.ROMName && *(p - 1) == ' ') p--; *p = 0; } { Memory.SRAMMask = Memory.SRAMSize ? ((1 << (Memory.SRAMSize + 3)) * 128) - 1 : 0; } if ((Memory.ROMChecksum + Memory.ROMComplementChecksum != 0xffff) || Memory.ROMChecksum != Memory.CalculatedChecksum || ((uint32_t)Memory.CalculatedSize > (uint32_t)(((1 << (Memory.ROMSize - 7)) * 128) * 1024))) { if (Settings.DisplayColor == 0xffff || Settings.DisplayColor != BUILD_PIXEL(31, 0, 0)) { Settings.DisplayColor = BUILD_PIXEL(31, 31, 0); SET_UI_COLOR(255, 255, 0); } } #ifndef USE_BLARGG_APU IAPU.OneCycle = ONE_APU_CYCLE; #endif Settings.Shutdown = Settings.ShutdownMaster; SetDSP = &DSP1SetByte; GetDSP = &DSP1GetByte; ResetSpeedMap(); ApplyROMFixes(); sprintf(Memory.ROMName, "%s", Safe(Memory.ROMName)); sprintf(Memory.ROMId, "%s", Safe(Memory.ROMId)); sprintf(Memory.CompanyId, "%s", Safe(Memory.CompanyId)); sprintf(String, "\"%s\" [%s] %s, %s, Type: %s, Mode: %s, TV: %s, S-RAM: %s, ROMId: %s Company: %2.2s CRC32: %08X", Memory.ROMName, (Memory.ROMChecksum + Memory.ROMComplementChecksum != 0xffff || Memory.ROMChecksum != Memory.CalculatedChecksum) ? "bad checksum" : "checksum ok", MapType(), Size(), KartContents(), MapMode(), TVStandard(), StaticRAMSize(), Memory.ROMId, Memory.CompanyId, Memory.ROMCRC32); S9xMessage(S9X_INFO, S9X_ROM_INFO, String); Settings.ForceHeader = Settings.ForceHiROM = Settings.ForceLoROM = Settings.ForceInterleaved = Settings.ForceNoHeader = Settings.ForceNotInterleaved = Settings.ForceInterleaved2 = false; } void FixROMSpeed() { int c; if (CPU.FastROMSpeed == 0) CPU.FastROMSpeed = SLOW_ONE_CYCLE; for (c = 0x800; c < 0x1000; c++) { if (c & 0x8 || c & 0x400) Memory.MemorySpeed [c] = (uint8_t) CPU.FastROMSpeed; } } void ResetSpeedMap() { int i; memset(Memory.MemorySpeed, SLOW_ONE_CYCLE, 0x1000); for (i = 0; i < 0x400; i += 0x10) { Memory.MemorySpeed[i + 2] = Memory.MemorySpeed[0x800 + i + 2] = ONE_CYCLE; Memory.MemorySpeed[i + 3] = Memory.MemorySpeed[0x800 + i + 3] = ONE_CYCLE; Memory.MemorySpeed[i + 4] = Memory.MemorySpeed[0x800 + i + 4] = ONE_CYCLE; Memory.MemorySpeed[i + 5] = Memory.MemorySpeed[0x800 + i + 5] = ONE_CYCLE; } FixROMSpeed(); } void WriteProtectROM() { // memmove converted: Different mallocs [Neb] memcpy((void*) Memory.WriteMap, (void*) Memory.Map, sizeof(Memory.Map)); int c; for (c = 0; c < 0x1000; c++) { if (Memory.BlockIsROM [c]) Memory.WriteMap [c] = (uint8_t*) MAP_NONE; } } void MapRAM() { int c; if (Memory.LoROM && !Settings.SDD1) { // Banks 70->77, S-RAM for (c = 0; c < 0x0f; c++) { int i; for (i = 0; i < 8; i++) { Memory.Map [(c << 4) + 0xF00 + i] = Memory.Map [(c << 4) + 0x700 + i] = (uint8_t*) MAP_LOROM_SRAM; Memory.BlockIsRAM [(c << 4) + 0xF00 + i] = Memory.BlockIsRAM [(c << 4) + 0x700 + i] = true; Memory.BlockIsROM [(c << 4) + 0xF00 + i] = Memory.BlockIsROM [(c << 4) + 0x700 + i] = false; } } } else if (Memory.LoROM && Settings.SDD1) { // Banks 70->77, S-RAM for (c = 0; c < 0x0f; c++) { int i; for (i = 0; i < 8; i++) { Memory.Map [(c << 4) + 0x700 + i] = (uint8_t*) MAP_LOROM_SRAM; Memory.BlockIsRAM [(c << 4) + 0x700 + i] = true; Memory.BlockIsROM [(c << 4) + 0x700 + i] = false; } } } // Banks 7e->7f, RAM for (c = 0; c < 16; c++) { Memory.Map [c + 0x7e0] = Memory.RAM; Memory.Map [c + 0x7f0] = Memory.RAM + 0x10000; Memory.BlockIsRAM [c + 0x7e0] = true; Memory.BlockIsRAM [c + 0x7f0] = true; Memory.BlockIsROM [c + 0x7e0] = false; Memory.BlockIsROM [c + 0x7f0] = false; } WriteProtectROM(); } void MapExtraRAM() { int c; // Banks 7e->7f, RAM for (c = 0; c < 16; c++) { Memory.Map [c + 0x7e0] = Memory.RAM; Memory.Map [c + 0x7f0] = Memory.RAM + 0x10000; Memory.BlockIsRAM [c + 0x7e0] = true; Memory.BlockIsRAM [c + 0x7f0] = true; Memory.BlockIsROM [c + 0x7e0] = false; Memory.BlockIsROM [c + 0x7f0] = false; } // Banks 70->73, S-RAM for (c = 0; c < 16; c++) { Memory.Map [c + 0x700] = Memory.SRAM; Memory.Map [c + 0x710] = Memory.SRAM + 0x8000; Memory.Map [c + 0x720] = Memory.SRAM + 0x10000; Memory.Map [c + 0x730] = Memory.SRAM + 0x18000; Memory.BlockIsRAM [c + 0x700] = true; Memory.BlockIsROM [c + 0x700] = false; Memory.BlockIsRAM [c + 0x710] = true; Memory.BlockIsROM [c + 0x710] = false; Memory.BlockIsRAM [c + 0x720] = true; Memory.BlockIsROM [c + 0x720] = false; Memory.BlockIsRAM [c + 0x730] = true; Memory.BlockIsROM [c + 0x730] = false; } } void LoROMMap() { int c; int i; int j; int mask[4]; for (j = 0; j < 4; j++) mask[j] = 0x00ff; mask[0] = (Memory.CalculatedSize / 0x8000) - 1; int x; bool foundZeros; bool pastZeros; for (j = 0; j < 3; j++) { x = 1; foundZeros = false; pastZeros = false; mask[j + 1] = mask[j]; while (x > 0x100 && !pastZeros) { if (mask[j]&x) { x <<= 1; if (foundZeros) pastZeros = true; } else { foundZeros = true; pastZeros = false; mask[j + 1] |= x; x <<= 1; } } } // Banks 00->3f and 80->bf for (c = 0; c < 0x400; c += 16) { Memory.Map [c + 0] = Memory.Map [c + 0x800] = Memory.RAM; Memory.Map [c + 1] = Memory.Map [c + 0x801] = Memory.RAM; Memory.BlockIsRAM [c + 0] = Memory.BlockIsRAM [c + 0x800] = true; Memory.BlockIsRAM [c + 1] = Memory.BlockIsRAM [c + 0x801] = true; Memory.Map [c + 2] = Memory.Map [c + 0x802] = (uint8_t*) MAP_PPU; if (Settings.SETA == ST_018) Memory.Map [c + 3] = Memory.Map [c + 0x803] = (uint8_t*) MAP_SETA_RISC; else Memory.Map [c + 3] = Memory.Map [c + 0x803] = (uint8_t*) MAP_PPU; Memory.Map [c + 4] = Memory.Map [c + 0x804] = (uint8_t*) MAP_CPU; Memory.Map [c + 5] = Memory.Map [c + 0x805] = (uint8_t*) MAP_CPU; if (Settings.DSP1Master) { Memory.Map [c + 6] = Memory.Map [c + 0x806] = (uint8_t*) MAP_DSP; Memory.Map [c + 7] = Memory.Map [c + 0x807] = (uint8_t*) MAP_DSP; } else if (Settings.C4) { Memory.Map [c + 6] = Memory.Map [c + 0x806] = (uint8_t*) MAP_C4; Memory.Map [c + 7] = Memory.Map [c + 0x807] = (uint8_t*) MAP_C4; } else if (Settings.OBC1) { Memory.Map [c + 6] = Memory.Map [c + 0x806] = (uint8_t*) MAP_OBC_RAM; Memory.Map [c + 7] = Memory.Map [c + 0x807] = (uint8_t*) MAP_OBC_RAM; } else { Memory.Map [c + 6] = Memory.Map [c + 0x806] = (uint8_t*) bytes0x2000 - 0x6000; Memory.Map [c + 7] = Memory.Map [c + 0x807] = (uint8_t*) bytes0x2000 - 0x6000; } for (i = c + 8; i < c + 16; i++) { int e = 3; int d = c >> 4; while (d > mask[0]) { d &= mask[e]; e--; } Memory.Map [i] = Memory.Map [i + 0x800] = Memory.ROM + (((d) - 1) * 0x8000); Memory.BlockIsROM [i] = Memory.BlockIsROM [i + 0x800] = true; } } if (Settings.DSP1Master) { // Banks 30->3f and b0->bf for (c = 0x300; c < 0x400; c += 16) { for (i = c + 8; i < c + 16; i++) { Memory.Map [i] = Memory.Map [i + 0x800] = (uint8_t*) MAP_DSP; Memory.BlockIsROM [i] = Memory.BlockIsROM [i + 0x800] = false; } } } // Banks 40->7f and c0->ff for (c = 0; c < 0x400; c += 16) { for (i = c; i < c + 8; i++) Memory.Map [i + 0x400] = Memory.Map [i + 0xc00] = &Memory.ROM [(c << 11) % Memory.CalculatedSize]; for (i = c + 8; i < c + 16; i++) { int e = 3; int d = (c + 0x400) >> 4; while (d > mask[0]) { d &= mask[e]; e--; } Memory.Map [i + 0x400] = Memory.Map [i + 0xc00] = Memory.ROM + ((( d) - 1) * 0x8000); } for (i = c; i < c + 16; i++) Memory.BlockIsROM [i + 0x400] = Memory.BlockIsROM [i + 0xc00] = true; } if (Settings.DSP1Master) { for (c = 0; c < 0x100; c++) { Memory.Map [c + 0xe00] = (uint8_t*) MAP_DSP; Memory.BlockIsROM [c + 0xe00] = false; } } int sum = 0, k, l, bankcount; bankcount = 1 << (Memory.ROMSize - 7); //Mbits //safety for corrupt headers if (bankcount > 128) bankcount = (Memory.CalculatedSize / 0x8000) / 4; bankcount *= 4; //to banks bankcount <<= 4; //Map banks bankcount += 0x800; //normalize for (k = 0x800; k < (bankcount); k += 16) { uint8_t* bank = 0x8000 + Memory.Map[k + 8]; for (l = 0; l < 0x8000; l++) sum += bank[l]; } Memory.CalculatedChecksum = sum & 0xFFFF; MapRAM(); WriteProtectROM(); } void SetaDSPMap() { int c; int i; int j; int mask[4]; for (j = 0; j < 4; j++) mask[j] = 0x00ff; mask[0] = (Memory.CalculatedSize / 0x8000) - 1; int x; bool foundZeros; bool pastZeros; for (j = 0; j < 3; j++) { x = 1; foundZeros = false; pastZeros = false; mask[j + 1] = mask[j]; while (x > 0x100 && !pastZeros) { if (mask[j]&x) { x <<= 1; if (foundZeros) pastZeros = true; } else { foundZeros = true; pastZeros = false; mask[j + 1] |= x; x <<= 1; } } } // Banks 00->3f and 80->bf for (c = 0; c < 0x400; c += 16) { Memory.Map [c + 0] = Memory.Map [c + 0x800] = Memory.RAM; Memory.Map [c + 1] = Memory.Map [c + 0x801] = Memory.RAM; Memory.BlockIsRAM [c + 0] = Memory.BlockIsRAM [c + 0x800] = true; Memory.BlockIsRAM [c + 1] = Memory.BlockIsRAM [c + 0x801] = true; Memory.Map [c + 2] = Memory.Map [c + 0x802] = (uint8_t*) MAP_PPU; Memory.Map [c + 3] = Memory.Map [c + 0x803] = (uint8_t*) MAP_PPU; Memory.Map [c + 4] = Memory.Map [c + 0x804] = (uint8_t*) MAP_CPU; Memory.Map [c + 5] = Memory.Map [c + 0x805] = (uint8_t*) MAP_CPU; Memory.Map [c + 6] = Memory.Map [c + 0x806] = (uint8_t*) bytes0x2000 - 0x6000; Memory.Map [c + 7] = Memory.Map [c + 0x807] = (uint8_t*) bytes0x2000 - 0x6000; for (i = c + 8; i < c + 16; i++) { int e = 3; int d = c >> 4; while (d > mask[0]) { d &= mask[e]; e--; } Memory.Map [i] = Memory.Map [i + 0x800] = Memory.ROM + (((d) - 1) * 0x8000); Memory.BlockIsROM [i] = Memory.BlockIsROM [i + 0x800] = true; } } // Banks 40->7f and c0->ff for (c = 0; c < 0x400; c += 16) { for (i = c + 8; i < c + 16; i++) { int e = 3; int d = (c + 0x400) >> 4; while (d > mask[0]) { d &= mask[e]; e--; } Memory.Map [i + 0x400] = Memory.Map [i + 0xc00] = Memory.ROM + ((( d) - 1) * 0x8000); } //only upper half is ROM for (i = c + 8; i < c + 16; i++) Memory.BlockIsROM [i + 0x400] = Memory.BlockIsROM [i + 0xc00] = true; } memset(Memory.SRAM, 0, 0x1000); for (c = 0x600; c < 0x680; c += 0x10) { for (i = 0; i < 0x08; i++) { //where does the SETA chip access, anyway? //please confirm this? Memory.Map[c + 0x80 + i] = (uint8_t*)MAP_SETA_DSP; Memory.BlockIsROM [c + 0x80 + i] = false; Memory.BlockIsRAM [c + 0x80 + i] = true; } for (i = 0; i < 0x04; i++) { //and this! Memory.Map[c + i] = (uint8_t*)MAP_SETA_DSP; Memory.BlockIsROM [c + i] = false; } } int sum = 0, k, l, bankcount; bankcount = 1 << (Memory.ROMSize - 7); //Mbits //safety for corrupt headers if (bankcount > 128) bankcount = (Memory.CalculatedSize / 0x8000) / 4; bankcount *= 4; //to banks bankcount <<= 4; //Map banks bankcount += 0x800; //normalize for (k = 0x800; k < (bankcount); k += 16) { uint8_t* bank = 0x8000 + Memory.Map[k + 8]; for (l = 0; l < 0x8000; l++) sum += bank[l]; } Memory.CalculatedChecksum = sum & 0xFFFF; MapRAM(); WriteProtectROM(); } void BSLoROMMap() { int c; int i; if (Settings.BS) Memory.SRAMSize = 5; // Banks 00->3f and 80->bf for (c = 0; c < 0x400; c += 16) { Memory.Map [c + 0] = Memory.Map [c + 0x800] = Memory.RAM; Memory.Map [c + 1] = Memory.Map [c + 0x801] = Memory.RAM; Memory.BlockIsRAM [c + 0] = Memory.BlockIsRAM [c + 0x800] = true; Memory.BlockIsRAM [c + 1] = Memory.BlockIsRAM [c + 0x801] = true; Memory.Map [c + 2] = Memory.Map [c + 0x802] = (uint8_t*) MAP_PPU; Memory.Map [c + 3] = Memory.Map [c + 0x803] = (uint8_t*) MAP_PPU; Memory.Map [c + 4] = Memory.Map [c + 0x804] = (uint8_t*) MAP_CPU; Memory.Map [c + 5] = Memory.Map [c + 0x805] = (uint8_t*) Memory.RAM; Memory.BlockIsRAM [c + 5] = Memory.BlockIsRAM [c + 0x805] = true; Memory.Map [c + 6] = Memory.Map [c + 0x806] = (uint8_t*) Memory.RAM; Memory.BlockIsRAM [c + 6] = Memory.BlockIsRAM [c + 0x806] = true; Memory.Map [c + 7] = Memory.Map [c + 0x807] = (uint8_t*) Memory.RAM; Memory.BlockIsRAM [c + 7] = Memory.BlockIsRAM [c + 0x807] = true; for (i = c + 8; i < c + 16; i++) { Memory.Map [i] = Memory.Map [i + 0x800] = &Memory.ROM [(c << 11) % Memory.CalculatedSize] - 0x8000; Memory.BlockIsROM [i] = Memory.BlockIsROM [i + 0x800] = true; } } for (c = 0; c < 8; c++) { Memory.Map[(c << 4) + 0x105] = (uint8_t*)MAP_LOROM_SRAM; Memory.BlockIsROM [(c << 4) + 0x105] = false; Memory.BlockIsRAM [(c << 4) + 0x105] = true; } for (c = 1; c <= 4; c++) { for (i = 0; i < 16; i++) { Memory.Map[0x400 + i + (c << 4)] = (uint8_t*)MAP_LOROM_SRAM; Memory.BlockIsRAM[0x400 + i + (c << 4)] = true; Memory.BlockIsROM[0x400 + i + (c << 4)] = false; } } for (i = 0; i < 0x80; i++) { Memory.Map[0x700 + i] = &Memory.BSRAM[0x10000 * (i / 16)]; Memory.BlockIsRAM[0x700 + i] = true; Memory.BlockIsROM[0x700 + i] = false; } for (i = 0; i < 8; i++) { Memory.Map[0x205 + (i << 4)] = Memory.Map[0x285 + (i << 4)] = Memory.Map[0x305 + (i << 4)] = Memory.Map[0x385 + (i << 4)] = Memory.Map[0x705 + (i << 4)]; Memory.BlockIsRAM[0x205 + (i << 4)] = Memory.BlockIsRAM[0x285 + (i << 4)] = Memory.BlockIsRAM[0x305 + (i << 4)] = Memory.BlockIsRAM[0x385 + (i << 4)] = true; Memory.BlockIsROM[0x205 + (i << 4)] = Memory.BlockIsROM[0x285 + (i << 4)] = Memory.BlockIsROM[0x305 + (i << 4)] = Memory.BlockIsROM[0x385 + (i << 4)] = false; } for (c = 0; c < 8; c++) { Memory.Map[(c << 4) + 0x005] = Memory.BSRAM - 0x5000; Memory.BlockIsROM [(c << 4) + 0x005] = false; Memory.BlockIsRAM [(c << 4) + 0x005] = true; } MapRAM(); WriteProtectROM(); } void HiROMMap() { int i; int c; int j; int mask[4]; for (j = 0; j < 4; j++) mask[j] = 0x00ff; mask[0] = (Memory.CalculatedSize / 0x10000) - 1; if (Settings.ForceSA1 || (!Settings.ForceNoSA1 && (Memory.ROMSpeed & ~0x10) == 0x23 && (Memory.ROMType & 0xf) > 3 && (Memory.ROMType & 0xf0) == 0x30)) { Settings.DisplayColor = BUILD_PIXEL(31, 0, 0); SET_UI_COLOR(255, 0, 0); } int x; bool foundZeros; bool pastZeros; for (j = 0; j < 3; j++) { x = 1; foundZeros = false; pastZeros = false; mask[j + 1] = mask[j]; while (x > 0x100 && !pastZeros) { if (mask[j]&x) { x <<= 1; if (foundZeros) pastZeros = true; } else { foundZeros = true; pastZeros = false; mask[j + 1] |= x; x <<= 1; } } } // Banks 00->3f and 80->bf for (c = 0; c < 0x400; c += 16) { Memory.Map [c + 0] = Memory.Map [c + 0x800] = Memory.RAM; Memory.BlockIsRAM [c + 0] = Memory.BlockIsRAM [c + 0x800] = true; Memory.Map [c + 1] = Memory.Map [c + 0x801] = Memory.RAM; Memory.BlockIsRAM [c + 1] = Memory.BlockIsRAM [c + 0x801] = true; Memory.Map [c + 2] = Memory.Map [c + 0x802] = (uint8_t*) MAP_PPU; Memory.Map [c + 3] = Memory.Map [c + 0x803] = (uint8_t*) MAP_PPU; Memory.Map [c + 4] = Memory.Map [c + 0x804] = (uint8_t*) MAP_CPU; Memory.Map [c + 5] = Memory.Map [c + 0x805] = (uint8_t*) MAP_CPU; if (Settings.DSP1Master) { Memory.Map [c + 6] = Memory.Map [c + 0x806] = (uint8_t*) MAP_DSP; Memory.Map [c + 7] = Memory.Map [c + 0x807] = (uint8_t*) MAP_DSP; } else { Memory.Map [c + 6] = Memory.Map [c + 0x806] = (uint8_t*) MAP_NONE; Memory.Map [c + 7] = Memory.Map [c + 0x807] = (uint8_t*) MAP_NONE; } for (i = c + 8; i < c + 16; i++) { int e = 3; int d = c >> 4; while (d > mask[0]) { d &= mask[e]; e--; } Memory.Map [i] = Memory.Map [i + 0x800] = Memory.ROM + (d * 0x10000); Memory.BlockIsROM [i] = Memory.BlockIsROM [i + 0x800] = true; } } // Banks 30->3f and b0->bf, address ranges 6000->7fff is S-RAM. for (c = 0; c < 16; c++) { Memory.Map [0x306 + (c << 4)] = (uint8_t*) MAP_HIROM_SRAM; Memory.Map [0x307 + (c << 4)] = (uint8_t*) MAP_HIROM_SRAM; Memory.Map [0xb06 + (c << 4)] = (uint8_t*) MAP_HIROM_SRAM; Memory.Map [0xb07 + (c << 4)] = (uint8_t*) MAP_HIROM_SRAM; Memory.BlockIsRAM [0x306 + (c << 4)] = true; Memory.BlockIsRAM [0x307 + (c << 4)] = true; Memory.BlockIsRAM [0xb06 + (c << 4)] = true; Memory.BlockIsRAM [0xb07 + (c << 4)] = true; } // Banks 40->7f and c0->ff for (c = 0; c < 0x400; c += 16) { for (i = c; i < c + 16; i++) { int e = 3; int d = (c) >> 4; while (d > mask[0]) { d &= mask[e]; e--; } Memory.Map [i + 0x400] = Memory.Map [i + 0xc00] = Memory.ROM + (d * 0x10000); Memory.BlockIsROM [i + 0x400] = Memory.BlockIsROM [i + 0xc00] = true; } } int bankmax = 0x40 + (1 << (Memory.ROMSize - 6)); //safety for corrupt headers if (bankmax > 128) bankmax = 0x80; int sum = 0; for (i = 0x40; i < bankmax; i++) { uint8_t* bank_low = (uint8_t*)Memory.Map[i << 4]; for (c = 0; c < 0x10000; c++) sum += bank_low[c]; } Memory.CalculatedChecksum = sum & 0xFFFF; MapRAM(); WriteProtectROM(); } void TalesROMMap(bool Interleaved) { int c; int i; if (Interleaved) { if (Settings.DisplayColor == 0xffff) { Settings.DisplayColor = BUILD_PIXEL(0, 31, 0); SET_UI_COLOR(0, 255, 0); } } uint32_t OFFSET0 = 0x400000; uint32_t OFFSET1 = 0x400000; uint32_t OFFSET2 = 0x000000; if (Interleaved) { OFFSET0 = 0x000000; OFFSET1 = 0x000000; OFFSET2 = Memory.CalculatedSize - 0x400000; //changed to work with interleaved DKJM2. } // Banks 00->3f and 80->bf for (c = 0; c < 0x400; c += 16) { Memory.Map [c + 0] = Memory.Map [c + 0x800] = Memory.RAM; Memory.Map [c + 1] = Memory.Map [c + 0x801] = Memory.RAM; Memory.BlockIsRAM [c + 0] = Memory.BlockIsRAM [c + 0x800] = true; Memory.BlockIsRAM [c + 1] = Memory.BlockIsRAM [c + 0x801] = true; Memory.Map [c + 2] = Memory.Map [c + 0x802] = (uint8_t*) MAP_PPU; Memory.Map [c + 3] = Memory.Map [c + 0x803] = (uint8_t*) MAP_PPU; Memory.Map [c + 4] = Memory.Map [c + 0x804] = (uint8_t*) MAP_CPU; Memory.Map [c + 5] = Memory.Map [c + 0x805] = (uint8_t*) MAP_CPU; //makes more sense to map the range here. //ToP seems to use sram to skip intro??? if (c >= 0x300) { Memory.Map [c + 6] = Memory.Map [c + 0x806] = (uint8_t*) MAP_HIROM_SRAM; Memory.Map [c + 7] = Memory.Map [c + 0x807] = (uint8_t*) MAP_HIROM_SRAM; Memory.BlockIsRAM [6 + c] = Memory.BlockIsRAM [7 + c] = Memory.BlockIsRAM [0x806 + c] = Memory.BlockIsRAM [0x807 + c] = true; } else { Memory.Map [c + 6] = Memory.Map [c + 0x806] = (uint8_t*) MAP_NONE; Memory.Map [c + 7] = Memory.Map [c + 0x807] = (uint8_t*) MAP_NONE; } for (i = c + 8; i < c + 16; i++) { Memory.Map [i] = &Memory.ROM [((c << 12) % (Memory.CalculatedSize - 0x400000)) + OFFSET0]; Memory.Map [i + 0x800] = &Memory.ROM [((c << 12) % 0x400000) + OFFSET2]; Memory.BlockIsROM [i] = true; Memory.BlockIsROM [i + 0x800] = true; } } // Banks 40->7f and c0->ff for (c = 0; c < 0x400; c += 16) { for (i = c; i < c + 8; i++) { Memory.Map [i + 0x400] = &Memory.ROM [((c << 12) % (Memory.CalculatedSize - 0x400000)) + OFFSET1]; Memory.Map [i + 0x408] = &Memory.ROM [((c << 12) % (Memory.CalculatedSize - 0x400000)) + OFFSET1]; Memory.Map [i + 0xc00] = &Memory.ROM [((c << 12) % 0x400000) + OFFSET2]; Memory.Map [i + 0xc08] = &Memory.ROM [((c << 12) % 0x400000) + OFFSET2]; Memory.BlockIsROM [i + 0x400] = true; Memory.BlockIsROM [i + 0x408] = true; Memory.BlockIsROM [i + 0xc00] = true; Memory.BlockIsROM [i + 0xc08] = true; } } if ((strncmp("TALES", (char*)Memory.Map[8] + 0xFFC0, 5) == 0)) { if (((*(Memory.Map[8] + 0xFFDE)) == (*(Memory.Map[0x808] + 0xFFDE)))) { Settings.DisplayColor = BUILD_PIXEL(31, 0, 0); SET_UI_COLOR(255, 0, 0); } } Memory.ROMChecksum = *(Memory.Map[8] + 0xFFDE) + (*(Memory.Map[8] + 0xFFDF) << 8); Memory.ROMComplementChecksum = *(Memory.Map[8] + 0xFFDC) + (* (Memory.Map[8] + 0xFFDD) << 8); int sum = 0; for (i = 0x40; i < 0x80; i++) { uint8_t* bank_low = (uint8_t*)Memory.Map[i << 4]; uint8_t* bank_high = (uint8_t*)Memory.Map[(i << 4) + 0x800]; for (c = 0; c < 0x10000; c++) { sum += bank_low[c]; sum += bank_high[c]; } } Memory.CalculatedChecksum = sum & 0xFFFF; MapRAM(); WriteProtectROM(); } void AlphaROMMap() { int c; int i; // Banks 00->3f and 80->bf for (c = 0; c < 0x400; c += 16) { Memory.Map [c + 0] = Memory.Map [c + 0x800] = Memory.RAM; Memory.Map [c + 1] = Memory.Map [c + 0x801] = Memory.RAM; Memory.BlockIsRAM [c + 0] = Memory.BlockIsRAM [c + 0x800] = true; Memory.BlockIsRAM [c + 1] = Memory.BlockIsRAM [c + 0x801] = true; Memory.Map [c + 2] = Memory.Map [c + 0x802] = (uint8_t*) MAP_PPU; Memory.Map [c + 3] = Memory.Map [c + 0x803] = (uint8_t*) MAP_PPU; Memory.Map [c + 4] = Memory.Map [c + 0x804] = (uint8_t*) MAP_CPU; Memory.Map [c + 5] = Memory.Map [c + 0x805] = (uint8_t*) MAP_CPU; Memory.Map [c + 6] = Memory.Map [c + 0x806] = (uint8_t*) MAP_NONE; Memory.Map [c + 7] = Memory.Map [c + 0x807] = (uint8_t*) MAP_NONE; for (i = c + 8; i < c + 16; i++) { Memory.Map [i] = Memory.Map [i + 0x800] = &Memory.ROM [c << 11] - 0x8000; Memory.BlockIsROM [i] = true; } } // Banks 40->7f and c0->ff for (c = 0; c < 0x400; c += 16) { for (i = c; i < c + 16; i++) { Memory.Map [i + 0x400] = &Memory.ROM [(c << 12) % Memory.CalculatedSize]; Memory.Map [i + 0xc00] = &Memory.ROM [(c << 12) % Memory.CalculatedSize]; Memory.BlockIsROM [i + 0x400] = Memory.BlockIsROM [i + 0xc00] = true; } } MapRAM(); WriteProtectROM(); } void DetectSuperFxRamSize() { if (Memory.ROM[0x7FDA] == 0x33) Memory.SRAMSize = Memory.ROM[0x7FBD]; else { if (strncmp(Memory.ROMName, "STAR FOX 2", 10) == 0) Memory.SRAMSize = 6; else Memory.SRAMSize = 5; } } void SuperFXROMMap() { int c; int i; DetectSuperFxRamSize(); // Banks 00->3f and 80->bf for (c = 0; c < 0x400; c += 16) { Memory.Map [c + 0] = Memory.Map [c + 0x800] = Memory.RAM; Memory.Map [c + 1] = Memory.Map [c + 0x801] = Memory.RAM; Memory.BlockIsRAM [c + 0] = Memory.BlockIsRAM [c + 0x800] = true; Memory.BlockIsRAM [c + 1] = Memory.BlockIsRAM [c + 0x801] = true; Memory.Map [c + 2] = Memory.Map [c + 0x802] = (uint8_t*) MAP_PPU; Memory.Map [c + 3] = Memory.Map [c + 0x803] = (uint8_t*) MAP_PPU; Memory.Map [c + 4] = Memory.Map [c + 0x804] = (uint8_t*) MAP_CPU; Memory.Map [c + 5] = Memory.Map [c + 0x805] = (uint8_t*) MAP_CPU; Memory.Map [0x006 + c] = Memory.Map [0x806 + c] = (uint8_t*) Memory.SRAM - 0x6000; Memory.Map [0x007 + c] = Memory.Map [0x807 + c] = (uint8_t*) Memory.SRAM - 0x6000; Memory.BlockIsRAM [0x006 + c] = Memory.BlockIsRAM [0x007 + c] = Memory.BlockIsRAM [0x806 + c] = Memory.BlockIsRAM [0x807 + c] = true; for (i = c + 8; i < c + 16; i++) { Memory.Map [i] = Memory.Map [i + 0x800] = &Memory.ROM [c << 11] - 0x8000; Memory.BlockIsROM [i] = Memory.BlockIsROM [i + 0x800] = true; } } // Banks 40->7f and c0->ff for (c = 0; c < 0x400; c += 16) { for (i = c; i < c + 16; i++) { Memory.Map [i + 0x400] = Memory.Map [i + 0xc00] = &Memory.ROM [(c << 12) % Memory.CalculatedSize]; Memory.BlockIsROM [i + 0x400] = Memory.BlockIsROM [i + 0xc00] = true; } } // Banks 7e->7f, RAM for (c = 0; c < 16; c++) { Memory.Map [c + 0x7e0] = Memory.RAM; Memory.Map [c + 0x7f0] = Memory.RAM + 0x10000; Memory.BlockIsRAM [c + 0x7e0] = true; Memory.BlockIsRAM [c + 0x7f0] = true; Memory.BlockIsROM [c + 0x7e0] = false; Memory.BlockIsROM [c + 0x7f0] = false; } // Banks 70->71, S-RAM for (c = 0; c < 32; c++) { Memory.Map [c + 0x700] = Memory.SRAM + (((c >> 4) & 1) << 16); Memory.BlockIsRAM [c + 0x700] = true; Memory.BlockIsROM [c + 0x700] = false; } // Replicate the first 2Mb of the ROM at ROM + 2MB such that each 32K // block is repeated twice in each 64K block. #ifdef DS2_DMA __dcache_writeback_all(); #endif for (c = 0; c < 64; c++) { #ifdef DS2_DMA ds2_DMAcopy_32Byte(2 /* channel: emu internal */, &ROM [0x200000 + c * 0x10000], &ROM [c * 0x8000], 0x8000); ds2_DMAcopy_32Byte(3 /* channel: emu internal 2 */, &ROM [0x208000 + c * 0x10000], &ROM [c * 0x8000], 0x8000); ds2_DMA_wait(2); ds2_DMA_wait(3); ds2_DMA_stop(2); ds2_DMA_stop(3); #else // memmove converted: Different addresses [Neb] memcpy(&Memory.ROM [0x200000 + c * 0x10000], &Memory.ROM [c * 0x8000], 0x8000); // memmove converted: Different addresses [Neb] memcpy(&Memory.ROM [0x208000 + c * 0x10000], &Memory.ROM [c * 0x8000], 0x8000); #endif } WriteProtectROM(); } void SA1ROMMap() { int c; int i; // Banks 00->3f and 80->bf for (c = 0; c < 0x400; c += 16) { Memory.Map [c + 0] = Memory.Map [c + 0x800] = Memory.RAM; Memory.Map [c + 1] = Memory.Map [c + 0x801] = Memory.RAM; Memory.BlockIsRAM [c + 0] = Memory.BlockIsRAM [c + 0x800] = true; Memory.BlockIsRAM [c + 1] = Memory.BlockIsRAM [c + 0x801] = true; Memory.Map [c + 2] = Memory.Map [c + 0x802] = (uint8_t*) MAP_PPU; Memory.Map [c + 3] = Memory.Map [c + 0x803] = (uint8_t*) &Memory.FillRAM [0x3000] - 0x3000; Memory.Map [c + 4] = Memory.Map [c + 0x804] = (uint8_t*) MAP_CPU; Memory.Map [c + 5] = Memory.Map [c + 0x805] = (uint8_t*) MAP_CPU; Memory.Map [c + 6] = Memory.Map [c + 0x806] = (uint8_t*) MAP_BWRAM; Memory.Map [c + 7] = Memory.Map [c + 0x807] = (uint8_t*) MAP_BWRAM; for (i = c + 8; i < c + 16; i++) { Memory.Map [i] = Memory.Map [i + 0x800] = &Memory.ROM [c << 11] - 0x8000; Memory.BlockIsROM [i] = Memory.BlockIsROM [i + 0x800] = true; } } // Banks 40->7f for (c = 0; c < 0x400; c += 16) { for (i = c; i < c + 16; i++) Memory.Map [i + 0x400] = (uint8_t*) &Memory.SRAM [(c << 12) & 0x1ffff]; for (i = c; i < c + 16; i++) Memory.BlockIsROM [i + 0x400] = false; } // c0->ff for (c = 0; c < 0x400; c += 16) { for (i = c; i < c + 16; i++) { Memory.Map [i + 0xc00] = &Memory.ROM [(c << 12) % Memory.CalculatedSize]; Memory.BlockIsROM [i + 0xc00] = true; } } for (c = 0; c < 16; c++) { Memory.Map [c + 0x7e0] = Memory.RAM; Memory.Map [c + 0x7f0] = Memory.RAM + 0x10000; Memory.BlockIsRAM [c + 0x7e0] = true; Memory.BlockIsRAM [c + 0x7f0] = true; Memory.BlockIsROM [c + 0x7e0] = false; Memory.BlockIsROM [c + 0x7f0] = false; } WriteProtectROM(); // Now copy the map and correct it for the SA1 CPU. // memmove converted: Different mallocs [Neb] memcpy((void*) SA1.WriteMap, (void*) Memory.WriteMap, sizeof(Memory.WriteMap)); // memmove converted: Different mallocs [Neb] memcpy((void*) SA1.Map, (void*) Memory.Map, sizeof(Memory.Map)); // Banks 00->3f and 80->bf for (c = 0; c < 0x400; c += 16) { SA1.Map [c + 0] = SA1.Map [c + 0x800] = &Memory.FillRAM [0x3000]; SA1.Map [c + 1] = SA1.Map [c + 0x801] = (uint8_t*) MAP_NONE; SA1.WriteMap [c + 0] = SA1.WriteMap [c + 0x800] = &Memory.FillRAM [0x3000]; SA1.WriteMap [c + 1] = SA1.WriteMap [c + 0x801] = (uint8_t*) MAP_NONE; } // Banks 60->6f for (c = 0; c < 0x100; c++) SA1.Map [c + 0x600] = SA1.WriteMap [c + 0x600] = (uint8_t*) MAP_BWRAM_BITMAP; Memory.BWRAM = Memory.SRAM; } void LoROM24MBSMap() { int c; int i; // Banks 00->3f and 80->bf for (c = 0; c < 0x400; c += 16) { Memory.Map [c + 0] = Memory.Map [c + 0x800] = Memory.RAM; Memory.Map [c + 1] = Memory.Map [c + 0x801] = Memory.RAM; Memory.BlockIsRAM [c + 0] = Memory.BlockIsRAM [c + 0x800] = true; Memory.BlockIsRAM [c + 1] = Memory.BlockIsRAM [c + 0x801] = true; Memory.Map [c + 2] = Memory.Map [c + 0x802] = (uint8_t*) MAP_PPU; Memory.Map [c + 3] = Memory.Map [c + 0x803] = (uint8_t*) MAP_PPU; Memory.Map [c + 4] = Memory.Map [c + 0x804] = (uint8_t*) MAP_CPU; Memory.Map [c + 5] = Memory.Map [c + 0x805] = (uint8_t*) MAP_CPU; Memory.Map [c + 6] = Memory.Map [c + 0x806] = (uint8_t*) MAP_NONE; Memory.Map [c + 7] = Memory.Map [c + 0x807] = (uint8_t*) MAP_NONE; for (i = c + 8; i < c + 16; i++) { Memory.Map [i] = Memory.Map [i + 0x800] = &Memory.ROM [c << 11] - 0x8000; Memory.BlockIsROM [i] = Memory.BlockIsROM [i + 0x800] = true; } } // Banks 00->3f and 80->bf for (c = 0; c < 0x200; c += 16) { Memory.Map [c + 0x800] = Memory.RAM; Memory.Map [c + 0x801] = Memory.RAM; Memory.BlockIsRAM [c + 0x800] = true; Memory.BlockIsRAM [c + 0x801] = true; Memory.Map [c + 0x802] = (uint8_t*) MAP_PPU; Memory.Map [c + 0x803] = (uint8_t*) MAP_PPU; Memory.Map [c + 0x804] = (uint8_t*) MAP_CPU; Memory.Map [c + 0x805] = (uint8_t*) MAP_CPU; Memory.Map [c + 0x806] = (uint8_t*) MAP_NONE; Memory.Map [c + 0x807] = (uint8_t*) MAP_NONE; for (i = c + 8; i < c + 16; i++) { Memory.Map [i + 0x800] = &Memory.ROM [c << 11] - 0x8000 + 0x200000; Memory.BlockIsROM [i + 0x800] = true; } } // Banks 40->7f and c0->ff for (c = 0; c < 0x400; c += 16) { for (i = c; i < c + 8; i++) Memory.Map [i + 0x400] = Memory.Map [i + 0xc00] = &Memory.ROM [(c << 11) + 0x200000]; for (i = c + 8; i < c + 16; i++) Memory.Map [i + 0x400] = Memory.Map [i + 0xc00] = &Memory.ROM [(c << 11) + 0x200000 - 0x8000]; for (i = c; i < c + 16; i++) Memory.BlockIsROM [i + 0x400] = Memory.BlockIsROM [i + 0xc00] = true; } MapExtraRAM(); WriteProtectROM(); } void SufamiTurboLoROMMap() { int c; int i; // Banks 00->3f and 80->bf for (c = 0; c < 0x400; c += 16) { Memory.Map [c + 0] = Memory.Map [c + 0x800] = Memory.RAM; Memory.Map [c + 1] = Memory.Map [c + 0x801] = Memory.RAM; Memory.BlockIsRAM [c + 0] = Memory.BlockIsRAM [c + 0x800] = true; Memory.BlockIsRAM [c + 1] = Memory.BlockIsRAM [c + 0x801] = true; Memory.Map [c + 2] = Memory.Map [c + 0x802] = (uint8_t*) MAP_PPU; Memory.Map [c + 3] = Memory.Map [c + 0x803] = (uint8_t*) MAP_PPU; Memory.Map [c + 4] = Memory.Map [c + 0x804] = (uint8_t*) MAP_CPU; Memory.Map [c + 5] = Memory.Map [c + 0x805] = (uint8_t*) MAP_CPU; Memory.Map [c + 6] = Memory.Map [c + 0x806] = (uint8_t*) MAP_NONE; Memory.Map [c + 7] = Memory.Map [c + 0x807] = (uint8_t*) MAP_NONE; for (i = c + 8; i < c + 16; i++) { Memory.Map [i] = Memory.Map [i + 0x800] = &Memory.ROM [c << 11] - 0x8000; Memory.BlockIsROM [i] = Memory.BlockIsROM [i + 0x800] = true; } } // Banks 40->7f and c0->ff for (c = 0; c < 0x400; c += 16) { for (i = c; i < c + 8; i++) Memory.Map [i + 0x400] = Memory.Map [i + 0xc00] = &Memory.ROM [(c << 11) + 0x200000]; for (i = c + 8; i < c + 16; i++) Memory.Map [i + 0x400] = Memory.Map [i + 0xc00] = &Memory.ROM [(c << 11) + 0x200000 - 0x8000]; for (i = c; i < c + 16; i++) Memory.BlockIsROM [i + 0x400] = Memory.BlockIsROM [i + 0xc00] = true; } if (Settings.DSP1Master) { for (c = 0; c < 0x100; c++) { Memory.Map [c + 0xe00] = (uint8_t*) MAP_DSP; Memory.BlockIsROM [c + 0xe00] = false; } } // Banks 7e->7f, RAM for (c = 0; c < 16; c++) { Memory.Map [c + 0x7e0] = Memory.RAM; Memory.Map [c + 0x7f0] = Memory.RAM + 0x10000; Memory.BlockIsRAM [c + 0x7e0] = true; Memory.BlockIsRAM [c + 0x7f0] = true; Memory.BlockIsROM [c + 0x7e0] = false; Memory.BlockIsROM [c + 0x7f0] = false; } // Banks 60->67, S-RAM for (c = 0; c < 0x80; c++) { Memory.Map [c + 0x600] = (uint8_t*) MAP_LOROM_SRAM; Memory.BlockIsRAM [c + 0x600] = true; Memory.BlockIsROM [c + 0x600] = false; } WriteProtectROM(); } void SRAM512KLoROMMap() { int c; int i; // Banks 00->3f and 80->bf for (c = 0; c < 0x400; c += 16) { Memory.Map [c + 0] = Memory.Map [c + 0x800] = Memory.RAM; Memory.Map [c + 1] = Memory.Map [c + 0x801] = Memory.RAM; Memory.BlockIsRAM [c + 0] = Memory.BlockIsRAM [c + 0x800] = true; Memory.BlockIsRAM [c + 1] = Memory.BlockIsRAM [c + 0x801] = true; Memory.Map [c + 2] = Memory.Map [c + 0x802] = (uint8_t*) MAP_PPU; Memory.Map [c + 3] = Memory.Map [c + 0x803] = (uint8_t*) MAP_PPU; Memory.Map [c + 4] = Memory.Map [c + 0x804] = (uint8_t*) MAP_CPU; Memory.Map [c + 5] = Memory.Map [c + 0x805] = (uint8_t*) MAP_CPU; Memory.Map [c + 6] = Memory.Map [c + 0x806] = (uint8_t*) MAP_NONE; Memory.Map [c + 7] = Memory.Map [c + 0x807] = (uint8_t*) MAP_NONE; for (i = c + 8; i < c + 16; i++) { Memory.Map [i] = Memory.Map [i + 0x800] = &Memory.ROM [c << 11] - 0x8000; Memory.BlockIsROM [i] = Memory.BlockIsROM [i + 0x800] = true; } } // Banks 40->7f and c0->ff for (c = 0; c < 0x400; c += 16) { for (i = c; i < c + 8; i++) Memory.Map [i + 0x400] = Memory.Map [i + 0xc00] = &Memory.ROM [(c << 11) + 0x200000]; for (i = c + 8; i < c + 16; i++) Memory.Map [i + 0x400] = Memory.Map [i + 0xc00] = &Memory.ROM [(c << 11) + 0x200000 - 0x8000]; for (i = c; i < c + 16; i++) Memory.BlockIsROM [i + 0x400] = Memory.BlockIsROM [i + 0xc00] = true; } MapExtraRAM(); WriteProtectROM(); } void BSHiROMMap() { int c; int i; Memory.SRAMSize = 5; // Banks 00->3f and 80->bf for (c = 0; c < 0x400; c += 16) { Memory.Map [c + 0] = Memory.Map [c + 0x800] = Memory.RAM; Memory.BlockIsRAM [c + 0] = Memory.BlockIsRAM [c + 0x800] = true; Memory.Map [c + 1] = Memory.Map [c + 0x801] = Memory.RAM; Memory.BlockIsRAM [c + 1] = Memory.BlockIsRAM [c + 0x801] = true; Memory.Map [c + 2] = Memory.Map [c + 0x802] = (uint8_t*) MAP_PPU; Memory.Map [c + 3] = Memory.Map [c + 0x803] = (uint8_t*) MAP_PPU; Memory.Map [c + 4] = Memory.Map [c + 0x804] = (uint8_t*) MAP_CPU; // XXX: How large is SRAM?? Memory.Map [c + 5] = Memory.Map [c + 0x805] = (uint8_t*) Memory.RAM; Memory.BlockIsRAM [c + 5] = Memory.BlockIsRAM [c + 0x805] = true; Memory.Map [c + 6] = Memory.Map [c + 0x806] = (uint8_t*) Memory.RAM; Memory.BlockIsRAM [c + 6] = Memory.BlockIsRAM [c + 0x806] = true; Memory.Map [c + 7] = Memory.Map [c + 0x807] = (uint8_t*) Memory.RAM; Memory.BlockIsRAM [c + 7] = Memory.BlockIsRAM [c + 0x807] = true; for (i = c + 8; i < c + 16; i++) { Memory.Map [i] = Memory.Map [i + 0x800] = &Memory.ROM [(c << 12) % Memory.CalculatedSize]; Memory.BlockIsROM [i] = Memory.BlockIsROM [i + 0x800] = true; } } // Banks 60->7d offset 0000->7fff & 60->7f offset 8000->ffff PSRAM // XXX: How large is PSRAM? //not adjusted, but The Dumper says "4 Mbits" for (c = 0x600; c < 0x7e0; c += 16) { for (i = c; i < c + 8; i++) { Memory.Map [i] = &Memory.ROM [0x400000 + (c << 11)]; Memory.BlockIsRAM [i] = true; } for (i = c + 8; i < c + 16; i++) { Memory.Map [i] = &Memory.ROM [0x400000 + (c << 11) - 0x8000]; Memory.BlockIsRAM [i] = true; } } // Banks 40->7f and c0->ff for (c = 0; c < 0x400; c += 16) { for (i = c; i < c + 16; i++) { Memory.Map [i + 0x400] = Memory.Map [i + 0xc00] = &Memory.ROM [(c << 12) % Memory.CalculatedSize]; Memory.BlockIsROM [i + 0x400] = Memory.BlockIsROM [i + 0xc00] = true; } } for (i = 0; i < 0x80; i++) { Memory.Map[0x700 + i] = &Memory.BSRAM[0x10000 * (i / 16)]; Memory.BlockIsRAM[0x700 + i] = true; Memory.BlockIsROM[0x700 + i] = false; } for (i = 0; i < 8; i++) { Memory.Map[0x205 + (i << 4)] = Memory.Map[0x285 + (i << 4)] = Memory.Map[0x305 + (i << 4)] = Memory.Map[0x385 + (i << 4)] = Memory.Map[0x705 + (i << 4)]; Memory.BlockIsRAM[0x205 + (i << 4)] = Memory.BlockIsRAM[0x285 + (i << 4)] = Memory.BlockIsRAM[0x305 + (i << 4)] = Memory.BlockIsRAM[0x385 + (i << 4)] = true; Memory.BlockIsROM[0x205 + (i << 4)] = Memory.BlockIsROM[0x285 + (i << 4)] = Memory.BlockIsROM[0x305 + (i << 4)] = Memory.BlockIsROM[0x385 + (i << 4)] = false; } MapRAM(); WriteProtectROM(); } void JumboLoROMMap(bool Interleaved) { int c; int i; uint32_t OFFSET0 = 0x400000; uint32_t OFFSET2 = 0x000000; if (Interleaved) { OFFSET0 = 0x000000; OFFSET2 = Memory.CalculatedSize - 0x400000; //changed to work with interleaved DKJM2. } // Banks 00->3f and 80->bf for (c = 0; c < 0x400; c += 16) { Memory.Map [c + 0] = Memory.Map [c + 0x800] = Memory.RAM; Memory.Map [c + 1] = Memory.Map [c + 0x801] = Memory.RAM; Memory.BlockIsRAM [c + 0] = Memory.BlockIsRAM [c + 0x800] = true; Memory.BlockIsRAM [c + 1] = Memory.BlockIsRAM [c + 0x801] = true; Memory.Map [c + 2] = Memory.Map [c + 0x802] = (uint8_t*) MAP_PPU; Memory.Map [c + 3] = Memory.Map [c + 0x803] = (uint8_t*) MAP_PPU; Memory.Map [c + 4] = Memory.Map [c + 0x804] = (uint8_t*) MAP_CPU; Memory.Map [c + 5] = Memory.Map [c + 0x805] = (uint8_t*) MAP_CPU; if (Settings.DSP1Master) { Memory.Map [c + 6] = Memory.Map [c + 0x806] = (uint8_t*) MAP_DSP; Memory.Map [c + 7] = Memory.Map [c + 0x807] = (uint8_t*) MAP_DSP; } else if (Settings.C4) { Memory.Map [c + 6] = Memory.Map [c + 0x806] = (uint8_t*) MAP_C4; Memory.Map [c + 7] = Memory.Map [c + 0x807] = (uint8_t*) MAP_C4; } else { Memory.Map [c + 6] = Memory.Map [c + 0x806] = (uint8_t*) bytes0x2000 - 0x6000; Memory.Map [c + 7] = Memory.Map [c + 0x807] = (uint8_t*) bytes0x2000 - 0x6000; } for (i = c + 8; i < c + 16; i++) { Memory.Map [i] = &Memory.ROM [((c << 11) % (Memory.CalculatedSize - 0x400000)) + OFFSET0] - 0x8000; Memory.Map [i + 0x800] = &Memory.ROM [((c << 11) % (0x400000)) + OFFSET2] - 0x8000; Memory.BlockIsROM [i + 0x800] = Memory.BlockIsROM [i] = true; } } if (Settings.DSP1Master) { // Banks 30->3f and b0->bf for (c = 0x300; c < 0x400; c += 16) { for (i = c + 8; i < c + 16; i++) { Memory.Map [i + 0x800] = (uint8_t*) MAP_DSP; Memory.BlockIsROM [i] = Memory.BlockIsROM [i + 0x800] = false; } } } // Banks 40->7f and c0->ff for (c = 0x400; c < 0x800; c += 16) { //updated mappings to correct A15 mirroring for (i = c; i < c + 8; i++) { Memory.Map [i] = &Memory.ROM [((c << 11) % (Memory.CalculatedSize - 0x400000)) + OFFSET0]; Memory.Map [i + 0x800] = &Memory.ROM [((c << 11) % 0x400000) + OFFSET2]; } for (i = c + 8; i < c + 16; i++) { Memory.Map [i] = &Memory.ROM [((c << 11) % (Memory.CalculatedSize - 0x400000)) + OFFSET0] - 0x8000; Memory.Map [i + 0x800] = &Memory.ROM [((c << 11) % 0x400000) + OFFSET2 ] - 0x8000; } for (i = c; i < c + 16; i++) Memory.BlockIsROM [i] = Memory.BlockIsROM [i + 0x800] = true; } //ROM type has to be 64 Mbit header! int sum = 0, k, l; for (k = 0; k < 256; k++) { uint8_t* bank = 0x8000 + Memory.Map[8 + (k << 4)]; //use upper half of the banks, and adjust for LoROM. for (l = 0; l < 0x8000; l++) sum += bank[l]; } Memory.CalculatedChecksum = sum & 0xFFFF; MapRAM(); WriteProtectROM(); } void SPC7110HiROMMap() { int c; int i; // Banks 00->3f and 80->bf for (c = 0; c < 0x400; c += 16) { Memory.Map [c + 0] = Memory.Map [c + 0x800] = Memory.RAM; Memory.BlockIsRAM [c + 0] = Memory.BlockIsRAM [c + 0x800] = true; Memory.Map [c + 1] = Memory.Map [c + 0x801] = Memory.RAM; Memory.BlockIsRAM [c + 1] = Memory.BlockIsRAM [c + 0x801] = true; Memory.Map [c + 2] = Memory.Map [c + 0x802] = (uint8_t*) MAP_PPU; Memory.Map [c + 3] = Memory.Map [c + 0x803] = (uint8_t*) MAP_PPU; Memory.Map [c + 4] = Memory.Map [c + 0x804] = (uint8_t*) MAP_CPU; Memory.Map [c + 5] = Memory.Map [c + 0x805] = (uint8_t*) MAP_CPU; Memory.Map [c + 6] = (uint8_t*) MAP_HIROM_SRAM; Memory.Map [c + 7] = (uint8_t*) MAP_HIROM_SRAM; Memory.Map [c + 0x806] = Memory.Map [c + 0x807] = (uint8_t*) MAP_NONE; for (i = c + 8; i < c + 16; i++) { Memory.Map [i] = Memory.Map [i + 0x800] = &Memory.ROM [(c << 12) % Memory.CalculatedSize]; Memory.BlockIsROM [i] = Memory.BlockIsROM [i + 0x800] = true; } } // Banks 30->3f and b0->bf, address ranges 6000->7fff is S-RAM. for (c = 0; c < 16; c++) { Memory.Map [0x306 + (c << 4)] = (uint8_t*) MAP_HIROM_SRAM; Memory.Map [0x307 + (c << 4)] = (uint8_t*) MAP_HIROM_SRAM; Memory.Map [0xb06 + (c << 4)] = (uint8_t*) MAP_NONE; Memory.Map [0xb07 + (c << 4)] = (uint8_t*) MAP_NONE; Memory.BlockIsRAM [0x306 + (c << 4)] = true; Memory.BlockIsRAM [0x307 + (c << 4)] = true; } // Banks 40->7f and c0->ff for (c = 0; c < 0x400; c += 16) { for (i = c; i < c + 16; i++) { Memory.Map [i + 0x400] = Memory.Map [i + 0xc00] = &Memory.ROM [(c << 12) % Memory.CalculatedSize]; Memory.BlockIsROM [i + 0x400] = Memory.BlockIsROM [i + 0xc00] = true; } } for (c = 0; c < 0x10; c++) { Memory.Map [0x500 + c] = (uint8_t*)MAP_SPC7110_DRAM; Memory.BlockIsROM [0x500 + c] = true; } for (c = 0; c < 0x100; c++) { Memory.Map [0xD00 + c] = (uint8_t*) MAP_SPC7110_ROM; Memory.Map [0xE00 + c] = (uint8_t*) MAP_SPC7110_ROM; Memory.Map [0xF00 + c] = (uint8_t*) MAP_SPC7110_ROM; Memory.BlockIsROM [0xD00 + c] = Memory.BlockIsROM [0xE00 + c] = Memory.BlockIsROM [0xF00 + c] = true; } S9xSpc7110Init(); int sum = 0; for (i = 0; i < (int)Memory.CalculatedSize; i++) sum += Memory.ROM[i]; if (Memory.CalculatedSize == 0x300000) sum <<= 1; Memory.CalculatedChecksum = sum & 0xFFFF; MapRAM(); WriteProtectROM(); } void SPC7110Sram(uint8_t newstate) { if (newstate & 0x80) { Memory.Map[6] = (uint8_t*)MAP_HIROM_SRAM; Memory.Map[7] = (uint8_t*)MAP_HIROM_SRAM; Memory.Map[0x306] = (uint8_t*)MAP_HIROM_SRAM; Memory.Map[0x307] = (uint8_t*)MAP_HIROM_SRAM; } else { Memory.Map[6] = (uint8_t*)MAP_RONLY_SRAM; Memory.Map[7] = (uint8_t*)MAP_RONLY_SRAM; Memory.Map[0x306] = (uint8_t*)MAP_RONLY_SRAM; Memory.Map[0x307] = (uint8_t*)MAP_RONLY_SRAM; } } const char* TVStandard() { return (Settings.PAL ? "PAL" : "NTSC"); } const char* Speed() { return (Memory.ROMSpeed & 0x10 ? "120ns" : "200ns"); } const char* MapType() { return (Memory.HiROM ? "HiROM" : "LoROM"); } const char* StaticRAMSize() { static char tmp [20]; if (Memory.SRAMSize > 16) return ("Corrupt"); sprintf(tmp, "%dKB", (Memory.SRAMMask + 1) / 1024); return (tmp); } const char* Size() { static char tmp [20]; if (Memory.ROMSize < 7 || Memory.ROMSize - 7 > 23) return ("Corrupt"); sprintf(tmp, "%dMbits", 1 << (Memory.ROMSize - 7)); return (tmp); } const char* KartContents() { static char tmp [30]; static const char* CoPro [16] = { "DSP1", "SuperFX", "OBC1", "SA-1", "S-DD1", "S-RTC", "CoPro#6", "CoPro#7", "CoPro#8", "CoPro#9", "CoPro#10", "CoPro#11", "CoPro#12", "CoPro#13", "CoPro#14", "CoPro-Custom" }; static const char* Contents [3] = { "ROM", "ROM+RAM", "ROM+RAM+BAT" }; if (Memory.ROMType == 0 && !Settings.BS) return ("ROM only"); sprintf(tmp, "%s", Contents [(Memory.ROMType & 0xf) % 3]); if (Settings.BS) sprintf(tmp, "%s+%s", tmp, "BSX"); else if (Settings.SPC7110 && Settings.SPC7110RTC) sprintf(tmp, "%s+%s", tmp, "SPC7110+RTC"); else if (Settings.SPC7110) sprintf(tmp, "%s+%s", tmp, "SPC7110"); else if (Settings.SETA != 0) { switch (Settings.SETA) { case ST_010: sprintf(tmp, "%s+%s", tmp, "ST-010"); break; case ST_011: sprintf(tmp, "%s+%s", tmp, "ST-011"); break; case ST_018: sprintf(tmp, "%s+%s", tmp, "ST-018"); break; } } else if ((Memory.ROMType & 0xf) >= 3) sprintf(tmp, "%s+%s", tmp, CoPro [(Memory.ROMType & 0xf0) >> 4]); return (tmp); } const char* MapMode() { static char tmp [4]; sprintf(tmp, "%02x", Memory.ROMSpeed & ~0x10); return (tmp); } const char* ROMID() { return (Memory.ROMId); } void ApplyROMFixes() { #ifdef __W32_HEAP if (_HEAPOK != _heapchk()) MessageBox(GUI.hWnd, "ApplyROMFixes", "Heap Corrupt", MB_OK); #endif //don't steal my work! -MK if (Memory.ROMCRC32 == 0x1B4A5616 && strncmp(Memory.ROMName, "RUDORA NO HIHOU", 15) == 0) { strncpy(Memory.ROMName, "THIS SCRIPT WAS STOLEN", 22); Settings.DisplayColor = BUILD_PIXEL(31, 0, 0); SET_UI_COLOR(255, 0, 0); } /* HACKS NSRT can fix that we hadn't detected before. [14:25:13] <@Nach> case 0x0c572ef0: //So called Hook (US)(2648) [14:25:13] <@Nach> case 0x6810aa95: //Bazooka Blitzkreig swapped sizes hack -handled [14:25:17] <@Nach> case 0x61E29C06: //The Tick region hack [14:25:19] <@Nach> case 0x1EF90F74: //Jikkyou Keiba Simulation Stable Star PAL hack [14:25:23] <@Nach> case 0x4ab225b5: //So called Krusty's Super Fun House (E) [14:25:25] <@Nach> case 0x77fd806a: //Donkey Kong Country 2 (E) v1.1 bad dump -handled [14:25:27] <@Nach> case 0x340f23e5: //Donkey Kong Country 3 (U) copier hack - handled */ if (Memory.ROMCRC32 == 0x6810aa95 || Memory.ROMCRC32 == 0x340f23e5 || Memory.ROMCRC32 == 0x77fd806a || strncmp(Memory.ROMName, "HIGHWAY BATTLE 2", 16) == 0 || (strcmp(Memory.ROMName, "FX SKIING NINTENDO 96") == 0 && Memory.ROM[0x7FDA] == 0)) { Settings.DisplayColor = BUILD_PIXEL(31, 0, 0); SET_UI_COLOR(255, 0, 0); } //Ambiguous chip function pointer assignments //DSP switching: if (strncmp(Memory.ROMName, "DUNGEON MASTER", 14) == 0) { //Set DSP-2 SetDSP = &DSP2SetByte; GetDSP = &DSP2GetByte; } #ifdef DSP_DUMMY_LOOPS if (strncmp(ROMName, "SD\x0b6\x0de\x0dd\x0c0\x0de\x0d1GX", 10) == 0) { //Set DSP-3 SetDSP = &DSP3SetByte; GetDSP = &DSP3GetByte; } #endif if (strncmp(Memory.ROMName, "TOP GEAR 3000", 13) == 0 || strncmp(Memory.ROMName, "PLANETS CHAMP TG3000", 20) == 0) { //Set DSP-4 SetDSP = &DSP4SetByte; GetDSP = &DSP4GetByte; } //memory map corrections if (strncmp(Memory.ROMName, "XBAND", 5) == 0) { int c; for (c = 0xE00; c < 0xE10; c++) { Memory.Map [c] = (uint8_t*) MAP_LOROM_SRAM; Memory.BlockIsRAM [c] = true; Memory.BlockIsROM [c] = false; } WriteProtectROM(); } //not MAD-1 compliant if (strcmp(Memory.ROMName, "WANDERERS FROM YS") == 0) { int c; for (c = 0; c < 0xE0; c++) { Memory.Map[c + 0x700] = (uint8_t*)MAP_LOROM_SRAM; Memory.BlockIsROM[c + 0x700] = false; Memory.BlockIsRAM[c + 0x700] = true; } WriteProtectROM(); } if (strcmp(Memory.ROMName, "GOGO ACKMAN3") == 0 || strcmp(Memory.ROMName, "HOME ALONE") == 0) { // Banks 00->3f and 80->bf int c; for (c = 0; c < 0x400; c += 16) { Memory.Map [c + 6] = Memory.Map [c + 0x806] = Memory.SRAM; Memory.Map [c + 7] = Memory.Map [c + 0x807] = Memory.SRAM; Memory.BlockIsROM [c + 6] = Memory.BlockIsROM [c + 0x806] = false; Memory.BlockIsROM [c + 7] = Memory.BlockIsROM [c + 0x807] = false; Memory.BlockIsRAM [c + 6] = Memory.BlockIsRAM [c + 0x806] = true; Memory.BlockIsRAM [c + 7] = Memory.BlockIsRAM [c + 0x807] = true; } WriteProtectROM(); } if (strcmp(Memory.ROMName, "RADICAL DREAMERS") == 0 || strcmp(Memory.ROMName, "TREASURE CONFLIX") == 0) { int c; for (c = 0; c < 0x80; c++) { Memory.Map [c + 0x700] = Memory.ROM + 0x200000 + 0x1000 * (c & 0xf0); Memory.BlockIsRAM [c + 0x700] = true; Memory.BlockIsROM [c + 0x700] = false; } for (c = 0; c < 0x400; c += 16) { Memory.Map [c + 5] = Memory.Map [c + 0x805] = Memory.ROM + 0x300000; Memory.BlockIsRAM [c + 5] = Memory.BlockIsRAM [c + 0x805] = true; } WriteProtectROM(); } if (strncmp(Memory.ROMName, "WAR 2410", 8) == 0) { Memory.Map [0x005] = (uint8_t*) Memory.RAM; Memory.BlockIsRAM [0x005] = true; Memory.BlockIsROM [0x005] = false; } if (strcmp(Memory.ROMName, "BATMAN--REVENGE JOKER") == 0) { Memory.HiROM = false; Memory.LoROM = true; LoROMMap(); } //NMI hacks CPU.NMITriggerPoint = 4; if (strcmp(Memory.ROMName, "CACOMA KNIGHT") == 0) CPU.NMITriggerPoint = 25; //Disabling a speed-up // Games which spool sound samples between the SNES and sound CPU using // H-DMA as the sample is playing. if (strcmp(Memory.ROMName, "EARTHWORM JIM 2") == 0 || strcmp(Memory.ROMName, "PRIMAL RAGE") == 0 || strcmp(Memory.ROMName, "CLAY FIGHTER") == 0 || strcmp(Memory.ROMName, "ClayFighter 2") == 0 || strncasecmp(Memory.ROMName, "MADDEN", 6) == 0 || strncmp(Memory.ROMName, "NHL", 3) == 0 || strcmp(Memory.ROMName, "WeaponLord") == 0 || strncmp(Memory.ROMName, "WAR 2410", 8) == 0) Settings.Shutdown = false; //APU timing hacks #ifndef USE_BLARGG_APU // Stunt Racer FX if (strcmp(Memory.ROMId, "CQ ") == 0 || // Illusion of Gaia strncmp(Memory.ROMId, "JG", 2) == 0 || strcmp(Memory.ROMName, "GAIA GENSOUKI 1 JPN") == 0) IAPU.OneCycle = 13; // RENDERING RANGER R2 if (strcmp(Memory.ROMId, "AVCJ") == 0 || //Mark Davis strncmp(Memory.ROMName, "THE FISHING MASTER", 18) == 0 || //needs >= actual APU timing. (21 is .002 Mhz slower) // Star Ocean strncmp(Memory.ROMId, "ARF", 3) == 0 || // Tales of Phantasia strncmp(Memory.ROMId, "ATV", 3) == 0 || // Act Raiser 1 & 2 strncasecmp(Memory.ROMName, "ActRaiser", 9) == 0 || // Soulblazer strcmp(Memory.ROMName, "SOULBLAZER - 1 USA") == 0 || strcmp(Memory.ROMName, "SOULBLADER - 1") == 0 || // Terranigma strncmp(Memory.ROMId, "AQT", 3) == 0 || // Robotrek strncmp(Memory.ROMId, "E9 ", 3) == 0 || strcmp(Memory.ROMName, "SLAP STICK 1 JPN") == 0 || // ZENNIHON PURORESU2 strncmp(Memory.ROMId, "APR", 3) == 0 || // Bomberman 4 strncmp(Memory.ROMId, "A4B", 3) == 0 || // UFO KAMEN YAKISOBAN strncmp(Memory.ROMId, "Y7 ", 3) == 0 || strncmp(Memory.ROMId, "Y9 ", 3) == 0 || // Panic Bomber World strncmp(Memory.ROMId, "APB", 3) == 0 || ((strncmp(Memory.ROMName, "Parlor", 6) == 0 || strcmp(Memory.ROMName, "HEIWA Parlor!Mini8") == 0 || strncmp(Memory.ROMName, "SANKYO Fever! ̨��ް!", 21) == 0) && strcmp(Memory.CompanyId, "A0") == 0) || strcmp(Memory.ROMName, "DARK KINGDOM") == 0 || strcmp(Memory.ROMName, "ZAN3 SFC") == 0 || strcmp(Memory.ROMName, "HIOUDEN") == 0 || strcmp(Memory.ROMName, "�ݼɳ�") == 0 || //Tenshi no Uta strcmp(Memory.ROMName, "FORTUNE QUEST") == 0 || strcmp(Memory.ROMName, "FISHING TO BASSING") == 0 || strncmp(Memory.ROMName, "TokyoDome '95Battle 7", 21) == 0 || strcmp(Memory.ROMName, "OHMONO BLACKBASS") == 0 || strncmp(Memory.ROMName, "SWORD WORLD SFC", 15) == 0 || strcmp(Memory.ROMName, "MASTERS") == 0 || //Augusta 2 J strcmp(Memory.ROMName, "SFC ���ײ�ް") == 0 || //Kamen Rider strncmp(Memory.ROMName, "LETs PACHINKO(", 14) == 0) //A set of BS games IAPU.OneCycle = 15; #endif //Specific game fixes Settings.StarfoxHack = strcmp(Memory.ROMName, "STAR FOX") == 0 || strcmp(Memory.ROMName, "STAR WING") == 0; Settings.WinterGold = strcmp(Memory.ROMName, "FX SKIING NINTENDO 96") == 0 || strcmp(Memory.ROMName, "DIRT RACER") == 0 || Settings.StarfoxHack; if ((strcmp(Memory.ROMName, "LEGEND") == 0 && !Settings.PAL) || strcmp(Memory.ROMName, "King Arthurs World") == 0) SNESGameFixes.EchoOnlyOutput = true; Settings.DaffyDuck = (strcmp(Memory.ROMName, "DAFFY DUCK: MARV MISS") == 0) || (strcmp(Memory.ROMName, "ROBOCOP VS THE TERMIN") == 0) || (strcmp(Memory.ROMName, "ROBOCOP VS TERMINATOR") == 0); //ROBOCOP VS THE TERMIN Settings.HBlankStart = (256 * Settings.H_Max) / SNES_HCOUNTER_MAX; //OAM hacks because we don't fully understand the //behavior of the SNES. //Totally wacky display... //seems to need a disproven behavior, so //we're definitely overlooking some other bug? if (strncmp(Memory.ROMName, "UNIRACERS", 9) == 0) SNESGameFixes.Uniracers = true; //is this even useful now? if (strcmp(Memory.ROMName, "ALIENS vs. PREDATOR") == 0) SNESGameFixes.alienVSpredetorFix = true; if (strcmp(Memory.ROMName, "���̧߰н�") == 0 || //Super Famista strcmp(Memory.ROMName, "���̧߰н� 2") == 0 || //Super Famista 2 strcmp(Memory.ROMName, "ZENKI TENCHIMEIDOU") == 0 || strcmp(Memory.ROMName, "GANBA LEAGUE") == 0) SNESGameFixes.APU_OutPorts_ReturnValueFix = true; if (strcmp(Memory.ROMName, "FURAI NO SIREN") == 0) SNESGameFixes.SoundEnvelopeHeightReading2 = true; //CPU timing hacks Settings.H_Max = (SNES_CYCLES_PER_SCANLINE * Settings.CyclesPercentage) / 100; // A Couple of HDMA related hacks - Lantus if ((strcmp(Memory.ROMName, "SFX SUPERBUTOUDEN2") == 0) || (strcmp(Memory.ROMName, "ALIEN vs. PREDATOR") == 0) || (strcmp(Memory.ROMName, "STONE PROTECTORS") == 0) || (strcmp(Memory.ROMName, "SUPER BATTLETANK 2") == 0)) Settings.H_Max = (SNES_CYCLES_PER_SCANLINE * 130) / 100; if (strcmp(Memory.ROMName, "HOME IMPROVEMENT") == 0) Settings.H_Max = (SNES_CYCLES_PER_SCANLINE * 200) / 100; if (strcmp(Memory.ROMId, "ASRJ") == 0 && Settings.CyclesPercentage == 100) // Street Racer Settings.H_Max = (SNES_CYCLES_PER_SCANLINE * 95) / 100; // Power Rangers Fight if (strncmp(Memory.ROMId, "A3R", 3) == 0 || // Clock Tower strncmp(Memory.ROMId, "AJE", 3) == 0) Settings.H_Max = (SNES_CYCLES_PER_SCANLINE * 103) / 100; if (strncmp(Memory.ROMId, "A3M", 3) == 0 && Settings.CyclesPercentage == 100) // Mortal Kombat 3. Fixes cut off speech sample Settings.H_Max = (SNES_CYCLES_PER_SCANLINE * 110) / 100; //Darkness Beyond Twilight //Crimson beyond blood that flows //buried in the stream of time //is where your power grows //I pledge myself to conquer //all the foes who stand //before the might gift betsowed //in my unworthy hand if (strcmp(Memory.ROMName, "\x0bd\x0da\x0b2\x0d4\x0b0\x0bd\x0de") == 0 && Settings.CyclesPercentage == 100) Settings.H_Max = (SNES_CYCLES_PER_SCANLINE * 101) / 100; #ifdef DETECT_NASTY_FX_INTERLEAVE //XXX: Test without these. Win32 port indicates they aren't needed? //Apparently are needed! if (strcmp(Memory.ROMName, "WILD TRAX") == 0 || strcmp(Memory.ROMName, "STAR FOX 2") == 0 || strcmp(Memory.ROMName, "YOSSY'S ISLAND") == 0 || strcmp(Memory.ROMName, "YOSHI'S ISLAND") == 0) CPU.TriedInterleavedMode2 = true; #endif // Start Trek: Deep Sleep 9 if (strncmp(Memory.ROMId, "A9D", 3) == 0 && Settings.CyclesPercentage == 100) Settings.H_Max = (SNES_CYCLES_PER_SCANLINE * 110) / 100; //SA-1 Speedup settings SA1.WaitAddress = NULL; SA1.WaitByteAddress1 = NULL; SA1.WaitByteAddress2 = NULL; /* Bass Fishing */ if (strcmp(Memory.ROMId, "ZBPJ") == 0) { SA1.WaitAddress = SA1.Map [0x0093f1 >> MEMMAP_SHIFT] + 0x93f1; SA1.WaitByteAddress1 = Memory.FillRAM + 0x304a; } /* DAISENRYAKU EXPERTWW2 */ if (strcmp(Memory.ROMId, "AEVJ") == 0) { SA1.WaitAddress = SA1.Map [0x0ed18d >> MEMMAP_SHIFT] + 0xd18d; SA1.WaitByteAddress1 = Memory.FillRAM + 0x3000; } /* debjk2 */ if (strcmp(Memory.ROMId, "A2DJ") == 0) SA1.WaitAddress = SA1.Map [0x008b62 >> MEMMAP_SHIFT] + 0x8b62; /* Dragon Ballz HD */ if (strcmp(Memory.ROMId, "AZIJ") == 0) { SA1.WaitAddress = SA1.Map [0x008083 >> MEMMAP_SHIFT] + 0x8083; SA1.WaitByteAddress1 = Memory.FillRAM + 0x3020; } /* SFC SDGUNDAMGNEXT */ if (strcmp(Memory.ROMId, "ZX3J") == 0) { SA1.WaitAddress = SA1.Map [0x0087f2 >> MEMMAP_SHIFT] + 0x87f2; SA1.WaitByteAddress1 = Memory.FillRAM + 0x30c4; } /* ShougiNoHanamichi */ if (strcmp(Memory.ROMId, "AARJ") == 0) { SA1.WaitAddress = SA1.Map [0xc1f85a >> MEMMAP_SHIFT] + 0xf85a; SA1.WaitByteAddress1 = Memory.SRAM + 0x0c64; SA1.WaitByteAddress2 = Memory.SRAM + 0x0c66; } /* KATO HIFUMI9DAN SYOGI */ if (strcmp(Memory.ROMId, "A23J") == 0) { SA1.WaitAddress = SA1.Map [0xc25037 >> MEMMAP_SHIFT] + 0x5037; SA1.WaitByteAddress1 = Memory.SRAM + 0x0c06; SA1.WaitByteAddress2 = Memory.SRAM + 0x0c08; } /* idaten */ if (strcmp(Memory.ROMId, "AIIJ") == 0) { SA1.WaitAddress = SA1.Map [0xc100be >> MEMMAP_SHIFT] + 0x00be; SA1.WaitByteAddress1 = Memory.SRAM + 0x1002; SA1.WaitByteAddress2 = Memory.SRAM + 0x1004; } /* igotais */ if (strcmp(Memory.ROMId, "AITJ") == 0) SA1.WaitAddress = SA1.Map [0x0080b7 >> MEMMAP_SHIFT] + 0x80b7; /* J96 DREAM STADIUM */ if (strcmp(Memory.ROMId, "AJ6J") == 0) SA1.WaitAddress = SA1.Map [0xc0f74a >> MEMMAP_SHIFT] + 0xf74a; /* JumpinDerby */ if (strcmp(Memory.ROMId, "AJUJ") == 0) SA1.WaitAddress = SA1.Map [0x00d926 >> MEMMAP_SHIFT] + 0xd926; /* JKAKINOKI SHOUGI */ if (strcmp(Memory.ROMId, "AKAJ") == 0) SA1.WaitAddress = SA1.Map [0x00f070 >> MEMMAP_SHIFT] + 0xf070; /* HOSHI NO KIRBY 3 & KIRBY'S DREAM LAND 3 JAP & US */ if (strcmp(Memory.ROMId, "AFJJ") == 0 || strcmp(Memory.ROMId, "AFJE") == 0) { SA1.WaitAddress = SA1.Map [0x0082d4 >> MEMMAP_SHIFT] + 0x82d4; SA1.WaitByteAddress1 = Memory.SRAM + 0x72a4; } /* KIRBY SUPER DELUXE JAP */ if (strcmp(Memory.ROMId, "AKFJ") == 0) { SA1.WaitAddress = SA1.Map [0x008c93 >> MEMMAP_SHIFT] + 0x8c93; SA1.WaitByteAddress1 = Memory.FillRAM + 0x300a; SA1.WaitByteAddress2 = Memory.FillRAM + 0x300e; } /* KIRBY SUPER DELUXE US */ if (strcmp(Memory.ROMId, "AKFE") == 0) { SA1.WaitAddress = SA1.Map [0x008cb8 >> MEMMAP_SHIFT] + 0x8cb8; SA1.WaitByteAddress1 = Memory.FillRAM + 0x300a; SA1.WaitByteAddress2 = Memory.FillRAM + 0x300e; } /* SUPER MARIO RPG JAP & US */ if (strcmp(Memory.ROMId, "ARWJ") == 0 || strcmp(Memory.ROMId, "ARWE") == 0) { SA1.WaitAddress = SA1.Map [0xc0816f >> MEMMAP_SHIFT] + 0x816f; SA1.WaitByteAddress1 = Memory.FillRAM + 0x3000; } /* marvelous.zip */ if (strcmp(Memory.ROMId, "AVRJ") == 0) { SA1.WaitAddress = SA1.Map [0x0085f2 >> MEMMAP_SHIFT] + 0x85f2; SA1.WaitByteAddress1 = Memory.FillRAM + 0x3024; } /* AUGUSTA3 MASTERS NEW */ if (strcmp(Memory.ROMId, "AO3J") == 0) { SA1.WaitAddress = SA1.Map [0x00dddb >> MEMMAP_SHIFT] + 0xdddb; SA1.WaitByteAddress1 = Memory.FillRAM + 0x37b4; } /* OSHABERI PARODIUS */ if (strcmp(Memory.ROMId, "AJOJ") == 0) SA1.WaitAddress = SA1.Map [0x8084e5 >> MEMMAP_SHIFT] + 0x84e5; /* PANIC BOMBER WORLD */ if (strcmp(Memory.ROMId, "APBJ") == 0) SA1.WaitAddress = SA1.Map [0x00857a >> MEMMAP_SHIFT] + 0x857a; /* PEBBLE BEACH NEW */ if (strcmp(Memory.ROMId, "AONJ") == 0) { SA1.WaitAddress = SA1.Map [0x00df33 >> MEMMAP_SHIFT] + 0xdf33; SA1.WaitByteAddress1 = Memory.FillRAM + 0x37b4; } /* PGA EUROPEAN TOUR */ if (strcmp(Memory.ROMId, "AEPE") == 0) { SA1.WaitAddress = SA1.Map [0x003700 >> MEMMAP_SHIFT] + 0x3700; SA1.WaitByteAddress1 = Memory.FillRAM + 0x3102; } /* PGA TOUR 96 */ if (strcmp(Memory.ROMId, "A3GE") == 0) { SA1.WaitAddress = SA1.Map [0x003700 >> MEMMAP_SHIFT] + 0x3700; SA1.WaitByteAddress1 = Memory.FillRAM + 0x3102; } /* POWER RANGERS 4 */ if (strcmp(Memory.ROMId, "A4RE") == 0) { SA1.WaitAddress = SA1.Map [0x009899 >> MEMMAP_SHIFT] + 0x9899; SA1.WaitByteAddress1 = Memory.FillRAM + 0x3000; } /* PACHISURO PALUSUPE */ if (strcmp(Memory.ROMId, "AGFJ") == 0) { // Never seems to turn on the SA-1! } /* SD F1 GRAND PRIX */ if (strcmp(Memory.ROMId, "AGFJ") == 0) SA1.WaitAddress = SA1.Map [0x0181bc >> MEMMAP_SHIFT] + 0x81bc; /* SHOUGI MARJONG */ if (strcmp(Memory.ROMId, "ASYJ") == 0) { SA1.WaitAddress = SA1.Map [0x00f2cc >> MEMMAP_SHIFT] + 0xf2cc; SA1.WaitByteAddress1 = Memory.SRAM + 0x7ffe; SA1.WaitByteAddress2 = Memory.SRAM + 0x7ffc; } /* shogisai2 */ if (strcmp(Memory.ROMId, "AX2J") == 0) SA1.WaitAddress = SA1.Map [0x00d675 >> MEMMAP_SHIFT] + 0xd675; /* SHINING SCORPION */ if (strcmp(Memory.ROMId, "A4WJ") == 0) SA1.WaitAddress = SA1.Map [0xc048be >> MEMMAP_SHIFT] + 0x48be; /* SHIN SHOUGI CLUB */ if (strcmp(Memory.ROMId, "AHJJ") == 0) { SA1.WaitAddress = SA1.Map [0xc1002a >> MEMMAP_SHIFT] + 0x002a; SA1.WaitByteAddress1 = Memory.SRAM + 0x0806; SA1.WaitByteAddress2 = Memory.SRAM + 0x0808; } //Other // Additional game fixes by sanmaiwashi ... if (strcmp(Memory.ROMName, "SFX ŲĶ������ɶ��� 1") == 0) //Gundam Knight Story { bytes0x2000 [0xb18] = 0x4c; bytes0x2000 [0xb19] = 0x4b; bytes0x2000 [0xb1a] = 0xea; SNESGameFixes.SRAMInitialValue = 0x6b; } // HITOMI3 if (strcmp(Memory.ROMName, "HITOMI3") == 0) { Memory.SRAMSize = 1; Memory.SRAMMask = Memory.SRAMSize ? ((1 << (Memory.SRAMSize + 3)) * 128) - 1 : 0; } //sram value fixes if (strcmp(Memory.ROMName, "SUPER DRIFT OUT") == 0 || strcmp(Memory.ROMName, "SATAN IS OUR FATHER!") == 0 || strcmp(Memory.ROMName, "goemon 4") == 0) SNESGameFixes.SRAMInitialValue = 0x00; #define RomPatch(adr,ov,nv) \ if (Memory.ROM [adr] == ov) \ Memory.ROM [adr] = nv // Love Quest if (strcmp(Memory.ROMName, "LOVE QUEST") == 0) { RomPatch(0x1385ec, 0xd0, 0xea); RomPatch(0x1385ed, 0xb2, 0xea); } //BNE D0 into nops //seems like the next instruction is a BRA //otherwise, this one's too complex for MKendora // Nangoku Syonen Papuwa Kun if (strcmp(Memory.ROMName, "NANGOKUSYONEN PAPUWA") == 0) RomPatch(0x1f0d1, 0xa0, 0x6b); //turns an LDY into an RTL? //this is a cmp on $00:2140 // Super Batter Up if (strcmp(Memory.ROMName, "Super Batter Up") == 0) { RomPatch(0x27ae0, 0xd0, 0xea); RomPatch(0x27ae1, 0xfa, 0xea); } //BNE } int is_bsx(unsigned char* p) { unsigned c; if (p[0x19] & 0x4f) goto notbsx; c = p[0x1a]; if ((c != 0x33) && (c != 0xff)) // 0x33 = Manufacturer: Nintendo goto notbsx; c = (p[0x17] << 8) | p[0x16]; if ((c != 0x0000) && (c != 0xffff)) { if ((c & 0x040f) != 0) goto notbsx; if ((c & 0xff) > 0xc0) goto notbsx; } c = p[0x18]; if ((c & 0xce) || ((c & 0x30) == 0)) goto notbsx; if ((p[0x15] & 0x03) != 0) goto notbsx; c = p[0x13]; if ((c != 0x00) && (c != 0xff)) goto notbsx; if (p[0x14] != 0x00) goto notbsx; if (bs_name(p) != 0) goto notbsx; return 0; // It's a Satellaview ROM! notbsx: return -1; } int bs_name(unsigned char* p) { unsigned c; int lcount; int numv; // number of valid name characters seen so far numv = 0; for (lcount = 16; lcount > 0; lcount--) { if (check_char(c = *p++) != 0) { c = *p++; if (c < 0x20) { if ((numv != 0x0b) || (c != 0)) // Dr. Mario Hack goto notBsName; } numv++; lcount--; continue; } else { if (c == 0) { if (numv == 0) goto notBsName; continue; } if (c < 0x20) goto notBsName; if (c >= 0x80) { if ((c < 0xa0) || (c >= 0xf0)) goto notBsName; } numv++; } } if (numv > 0) return 0; notBsName: return -1; } void ParseSNESHeader(uint8_t* RomHeader) { Memory.SRAMSize = RomHeader [0x28]; strncpy(Memory.ROMName, (char*) &RomHeader[0x10], ROM_NAME_LEN - 1); Memory.ROMSpeed = RomHeader [0x25]; Memory.ROMType = RomHeader [0x26]; Memory.ROMSize = RomHeader [0x27]; Memory.ROMChecksum = RomHeader [0x2e] + (RomHeader [0x2f] << 8); Memory.ROMComplementChecksum = RomHeader [0x2c] + (RomHeader [0x2d] << 8); Memory.ROMRegion = RomHeader[0x29]; // memmove converted: Different mallocs [Neb] memcpy(Memory.ROMId, &RomHeader [0x2], 4); if (RomHeader[0x2A] == 0x33) // memmove converted: Different mallocs [Neb] memcpy(Memory.CompanyId, &RomHeader [0], 2); else sprintf(Memory.CompanyId, "%02X", RomHeader[0x2A]); } #undef INLINE #define INLINE #include "getset.h"