📄 memmap.cpp
字号:
/* * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. * * (c) Copyright 1996 - 2001 Gary Henderson (gary@daniver.demon.co.uk) and * Jerremy Koot (jkoot@snes9x.com) * * Super FX C emulator code * (c) Copyright 1997 - 1999 Ivar (Ivar@snes9x.com) and * Gary Henderson. * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_. * * DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson. * C4 asm and some C emulation code (c) Copyright 2000 zsKnight and _Demo_. * C4 C code (c) Copyright 2001 Gary Henderson (gary@daniver.demon.co.uk). * * DOS port code contains the works of other authors. See headers in * individual files. * * Snes9x homepage: www.snes9x.com * * Permission to use, copy, modify and distribute Snes9x in both binary and * source form, for non-commercial purposes, is hereby granted without fee, * providing that this license information and copyright notice appear with * all copies and any derived work. * * This software is provided 'as-is', without any express or implied * warranty. In no event shall the authors be held liable for any damages * arising from the use of this software. * * Snes9x is freeware for PERSONAL USE only. Commercial users should * seek permission of the copyright holders first. Commercial use includes * charging money for Snes9x or software derived from Snes9x. * * The copyright holders request that bug fixes and improvements to the code * should be forwarded to them so everyone can benefit from the modifications * in future versions. * * Super NES and Super Nintendo Entertainment System are trademarks of * Nintendo Co., Limited and its subsidiary companies. */#include <string.h>#include <ctype.h>#ifdef __linux#include <unistd.h>#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 "srtc.h"#ifndef ZSNES_FX#include "fxemu.h"extern struct FxInit_s SuperFX;#elseSTART_EXTERN_Cextern uint8 *SFXPlotTable;END_EXTERN_C#endifstatic uint8 bytes256 [256];extern char *rom_filename;bool8 CMemory::AllASCII (uint8 *b, int size){ for (int i = 0; i < size; i++) { if (b[i] < 32 || b[i] > 126) return (FALSE); } return (TRUE);}int CMemory::ScoreHiROM (bool8 skip_header){ int score = 0; int o = skip_header ? 0xff00 + 0x200 : 0xff00; if ((Memory.ROM [o + 0xdc] + (Memory.ROM [o + 0xdd] << 8) + Memory.ROM [o + 0xde] + (Memory.ROM [o + 0xdf] << 8)) == 0xffff) score += 2; if (Memory.ROM [o + 0xda] == 0x33) score += 2; if ((Memory.ROM [o + 0xd5] & 0xf) < 4) score += 2; if (!(Memory.ROM [o + 0xfd] & 0x80)) score -= 4; if (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);}int CMemory::ScoreLoROM (bool8 skip_header){ int score = 0; int o = skip_header ? 0x7f00 + 0x200 : 0x7f00; if ((Memory.ROM [o + 0xdc] + (Memory.ROM [o + 0xdd] << 8) + Memory.ROM [o + 0xde] + (Memory.ROM [o + 0xdf] << 8)) == 0xffff) score += 2; if (Memory.ROM [o + 0xda] == 0x33) score += 2; if ((Memory.ROM [o + 0xd5] & 0xf) < 4) score += 2; if (CalculatedSize <= 1024 * 1024 * 16) score += 2; if (!(Memory.ROM [o + 0xfd] & 0x80)) 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);} char *CMemory::Safe (const char *s){ static char *safe = NULL; static int safe_len = 0; int len = strlen (s); if (!safe || len + 1 > safe_len) { delete safe; safe = new char [safe_len = len + 1]; } for (int i = 0; i < len; i++) { if (s [i] >= 32 && s [i] < 127) safe [i] = s[i]; else safe [i] = '?'; } safe [len] = 0; return (safe);}/**********************************************************************************************//* Init() *//* This function allocates all the memory needed by the emulator *//**********************************************************************************************/bool8 CMemory::Init (){ RAM = new uint8 [0x20000]; SRAM = new uint8 [0x20000]; VRAM = new uint8 [0x10000]; ROM = new uint8 [MAX_ROM_SIZE + 0x200 + 0x8000]; FillRAM = NULL; IPPU.TileCache [TILE_2BIT] = new uint8 [MAX_2BIT_TILES * 128]; IPPU.TileCache [TILE_4BIT] = new uint8 [MAX_4BIT_TILES * 128]; IPPU.TileCache [TILE_8BIT] = new uint8 [MAX_8BIT_TILES * 128]; IPPU.TileCached [TILE_2BIT] = new uint8 [MAX_2BIT_TILES]; IPPU.TileCached [TILE_4BIT] = new uint8 [MAX_4BIT_TILES]; IPPU.TileCached [TILE_8BIT] = new uint8 [MAX_8BIT_TILES]; if( !RAM || !SRAM || !VRAM || !ROM || !IPPU.TileCache [TILE_2BIT] || !IPPU.TileCache [TILE_4BIT] || !IPPU.TileCache [TILE_8BIT] || !IPPU.TileCached [TILE_2BIT] || !IPPU.TileCached [TILE_4BIT] || !IPPU.TileCached [TILE_8BIT]) return (FALSE); // FillRAM uses first 32K of ROM image area, otherwise space just // wasted. Might be read by the SuperFX code. FillRAM = ROM; // Add 0x8000 to ROM image pointer to stop SuperFX code accessing // unallocated memory (can cause crash on some ports). ROM += 0x8000; C4RAM = ROM + 0x400000 + 8192 * 8; ::ROM = ROM; ::SRAM = SRAM; ::RegRAM = FillRAM;#ifdef ZSNES_FX SFXPlotTable = ROM + 0x400000;#else SuperFX.pvRegisters = &Memory.FillRAM [0x3000]; SuperFX.nRamBanks = 1; SuperFX.pvRam = ::SRAM; SuperFX.nRomBanks = (2 * 1024 * 1024) / (32 * 1024); SuperFX.pvRom = (uint8 *) ROM;#endif ZeroMemory (IPPU.TileCached [TILE_2BIT], MAX_2BIT_TILES); ZeroMemory (IPPU.TileCached [TILE_4BIT], MAX_4BIT_TILES); ZeroMemory (IPPU.TileCached [TILE_8BIT], MAX_8BIT_TILES); return (TRUE);}void CMemory::Deinit (){ ROM -= 0x8000; delete RAM; delete SRAM; delete VRAM; delete ROM; delete IPPU.TileCache [TILE_2BIT]; delete IPPU.TileCache [TILE_4BIT]; delete IPPU.TileCache [TILE_8BIT]; delete IPPU.TileCached [TILE_2BIT]; delete IPPU.TileCached [TILE_4BIT]; delete IPPU.TileCached [TILE_8BIT];}/**********************************************************************************************//* LoadROM() *//* This function loads a Snes-Backup image *//**********************************************************************************************/bool8 CMemory::LoadROM (const char *filename){ unsigned long FileSize = 0; int retry_count = 0; STREAM ROMFile; bool8 Interleaved = FALSE; bool8 Tales = FALSE; 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]; int i; CPU.TriedInterleavedMode2 = FALSE; CalculatedSize = 0;again: _splitpath (filename, drive, dir, name, ext); _makepath (fname, drive, dir, name, ext);#ifdef __WIN32__ memmove (&ext [0], &ext[1], 4);#endif int32 TotalFileSize = 0;#ifdef UNZIP_SUPPORT if (strcasecmp (ext, "zip") == 0) { bool8 LoadZip (const char *, int32 *, int32 *); if (!LoadZip (fname, &TotalFileSize, &HeaderCount)) return (FALSE); strcpy (ROMFilename, fname); } else#endif { if ((ROMFile = OPEN_STREAM (fname, "rb")) == NULL) return (FALSE); strcpy (ROMFilename, fname); HeaderCount = 0; uint8 *ptr = ROM; bool8 more = FALSE; do { FileSize = READ_STREAM (ptr, MAX_ROM_SIZE + 0x200 - (ptr - ROM), ROMFile); CLOSE_STREAM (ROMFile); int calc_size = (FileSize / 0x2000) * 0x2000; if ((FileSize - calc_size == 512 && !Settings.ForceNoHeader) || Settings.ForceHeader) { memmove (ptr, ptr + 512, calc_size); HeaderCount++; FileSize -= 512; } ptr += FileSize; TotalFileSize += FileSize; int len; if (ptr - ROM < MAX_ROM_SIZE + 0x200 && (isdigit (ext [0]) && ext [1] == 0 && ext [0] < '9')) { more = TRUE; ext [0]++;#ifdef __WIN32__ memmove (&ext [1], &ext [0], 4); ext [0] = '.';#endif _makepath (fname, drive, dir, name, ext); } else if (ptr - ROM < MAX_ROM_SIZE + 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 (&ext [1], &ext [0], 4); ext [0] = '.';#endif _makepath (fname, drive, dir, name, ext); } else more = FALSE; } while (more && (ROMFile = OPEN_STREAM (fname, "rb")) != NULL); } if (HeaderCount == 0) S9xMessage (S9X_INFO, S9X_HEADERS_INFO, "No ROM file header found."); else { if (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)."); } CheckForIPSPatch (filename, HeaderCount != 0, TotalFileSize); ZeroMemory (ROM + TotalFileSize, MAX_ROM_SIZE - TotalFileSize); CalculatedSize = (TotalFileSize / 0x2000) * 0x2000; int orig_hi_score, orig_lo_score; int hi_score, lo_score; orig_hi_score = hi_score = ScoreHiROM (FALSE); orig_lo_score = lo_score = ScoreLoROM (FALSE); if (HeaderCount == 0 && ((hi_score > lo_score && ScoreHiROM (TRUE) > hi_score) || (hi_score <= lo_score && ScoreLoROM (TRUE) > lo_score))) { S9xMessage (S9X_INFO, S9X_HEADER_WARNING, "Try specifying the -hd command line option if the game doesn't work\n"); } Interleaved = Settings.ForceInterleaved || Settings.ForceInterleaved2; if (Settings.ForceLoROM || (!Settings.ForceHiROM && lo_score >= hi_score)) { LoROM = TRUE; HiROM = FALSE; // Ignore map type byte if not 0x2x or 0x3x if ((ROM [0x7fd5] & 0xf0) == 0x20 || (ROM [0x7fd5] & 0xf0) == 0x30) { switch (ROM [0x7fd5] & 0xf) { case 1: if (strncmp ((char *) &ROM [0x7fc0], "TREASURE HUNTER G", 17) != 0) Interleaved = TRUE; break; case 2:#if 0 if (!Settings.ForceLoROM && strncmp ((char *) &ROM [0x7fc0], "SUPER FORMATION SOCCE", 21) != 0 && strncmp ((char *) &ROM [0x7fc0], "Star Ocean", 10) != 0) { LoROM = FALSE; HiROM = TRUE; }#endif break; case 5: Interleaved = TRUE; Tales = TRUE; break; } } } else { if ((ROM [0xffd5] & 0xf0) == 0x20 || (ROM [0xffd5] & 0xf0) == 0x30) { switch (ROM [0xffd5] & 0xf) { case 0: case 3: Interleaved = TRUE; break; } } LoROM = FALSE; HiROM = TRUE; } if (!Settings.ForceNotInterleaved && Interleaved) { CPU.TriedInterleavedMode2 = TRUE; S9xMessage (S9X_INFO, S9X_ROM_INTERLEAVED_INFO, "ROM image is in interleaved format - converting..."); int nblocks = CalculatedSize >> 16;#if 0 int step = 64; while (nblocks <= step) step >>= 1; nblocks = step;#endif uint8 blocks [256]; if (Tales) { nblocks = 0x60; for (i = 0; i < 0x40; i += 2) { blocks [i + 0] = (i >> 1) + 0x20; blocks [i + 1] = (i >> 1) + 0x00; } for (i = 0; i < 0x80; i += 2) { blocks [i + 0x40] = (i >> 1) + 0x80; blocks [i + 0x41] = (i >> 1) + 0x40; } LoROM = FALSE; HiROM = TRUE; } else if (Settings.ForceInterleaved2) { for (i = 0; i < nblocks * 2; i++) { blocks [i] = (i & ~0x1e) | ((i & 2) << 2) | ((i & 4) << 2) | ((i & 8) >> 2) | ((i & 16) >> 2); } } else { bool8 t = LoROM; LoROM = HiROM; HiROM = t; for (i = 0; i < nblocks; i++) { blocks [i * 2] = i + nblocks; blocks [i * 2 + 1] = i; } } uint8 *tmp = new uint8 [0x8000]; for (i = 0; i < nblocks * 2; i++) { for (int j = i; j < nblocks * 2; j++) { if (blocks [j] == i) { memmove (tmp, &ROM [blocks [j] * 0x8000], 0x8000); memmove (&ROM [blocks [j] * 0x8000], &ROM [blocks [i] * 0x8000], 0x8000); memmove (&ROM [blocks [i] * 0x8000], tmp, 0x8000); uint8 b = blocks [j]; blocks [j] = blocks [i]; blocks [i] = b; break; } } } delete tmp; hi_score = ScoreHiROM (FALSE); lo_score = ScoreLoROM (FALSE); if ((HiROM && (lo_score >= hi_score || hi_score < 0)) || (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; } } } InitROM (Tales); S9xApplyCheats (); S9xReset (); return (TRUE);}void S9xDeinterleaveMode2 (){ S9xMessage (S9X_INFO, S9X_ROM_INTERLEAVED_INFO, "ROM image is in interleaved format - converting..."); int nblocks = Memory.CalculatedSize >> 15; int step = 64; while (nblocks <= step) step >>= 1; nblocks = step; uint8 blocks [256]; int i; for (i = 0; i < nblocks * 2; i++) { blocks [i] = (i & ~0x1e) | ((i & 2) << 2) | ((i & 4) << 2) | ((i & 8) >> 2) | ((i & 16) >> 2); } uint8 *tmp = new uint8 [0x8000]; for (i = 0; i < nblocks * 2; i++) { for (int j = i; j < nblocks * 2; j++) { if (blocks [j] == i) { memmove (tmp, &Memory.ROM [blocks [j] * 0x8000], 0x8000); memmove (&Memory.ROM [blocks [j] * 0x8000], &Memory.ROM [blocks [i] * 0x8000], 0x8000); memmove (&Memory.ROM [blocks [i] * 0x8000], tmp, 0x8000); uint8 b = blocks [j]; blocks [j] = blocks [i]; blocks [i] = b; break; } } } delete tmp; Memory.InitROM (FALSE); S9xReset ();}void CMemory::InitROM (bool8 Interleaved){#ifndef ZSNES_FX SuperFX.nRomBanks = CalculatedSize >> 15;#endif 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; ZeroMemory (BlockIsRAM, MEMMAP_NUM_BLOCKS);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -