📄 romload.cpp
字号:
/*
SNEeSe, an Open Source Super NES emulator.
Copyright (c) 1998-2004 Charles Bilyue'.
Portions Copyright (c) 2003-2004 Daniel Horchner.
This is free software. See 'LICENSE' for details.
You must read and accept the license prior to use.
*/
/* ROM IMAGE LOADING MECHANISM
Original code by Savoury SnaX & Santeri Saarimaa
New development by Charles Bilyue'
Supports (with or without header):
Single-part non-interleaved ROMs (LoROM and HiROM)
Single-part interleaved HiROMs
Multi-part non-interleaved ROMs (LoROM and HiROM, *.1-style)
Multi-part interleaved HiROMs (*.1-style)
If a header exists, it is ignored
Single-part ROM extensions
SFC = Super FamiCom
FIG = Pro Fighter
SMC = Super MagiCom
SWC = Super WildCard
BIN = Binary
Multi-part ROM extensions
SF*a.058,SF*a.078 = Game Doctor
*.1 = Other miscellaneous multi-part ROM
TO DO:
Interleaved LoROM loading (??? need info)
Other memory maps
*/
#include "wrapaleg.h"
#include <iostream>
using namespace std;
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "romload.h"
#include "helper.h"
#include "cpu/cpu.h"
#include "apu/spc.h"
#include "cpu/mem.h"
#include "snes.h"
#include "platform.h"
#include "multiio.h"
char *rom_romfile = 0;
char *rom_romhilo = 0;
char *rom_romtype = 0;
char *rom_romsize = 0;
char *rom_romname = 0;
char *rom_sram = 0;
char *rom_country = 0;
char rom_name[22];
extern "C" unsigned char BlockSpeed[256*8];
unsigned char BlockSpeed[256*8];
unsigned char *RomAddress; // Address of SNES ROM
// Used to determine size of file for saving/loading, and to restrict writes
// to non-existant SRAM
unsigned SaveRamLength = 0;
int Allocate_ROM();
int ROM_format;
typedef struct {
int bank_count;
unsigned char overflow_mask;
unsigned char bank_lookup[256];
} ROM_MIRRORING_DATA;
ROM_MIRRORING_DATA rmd_32k, rmd_64k;
void setup_rom_mirroring(ROM_MIRRORING_DATA *rmd)
{
int copycount, missing, count, next, banks_mirror_size;
/* Compute a mask used to wrap invalid ROM bank numbers.
*/
if (((rmd->bank_count * 2 - 1) & (rmd->bank_count - 1)) ==
(rmd->bank_count - 1))
/* compute mask for even power of two */
{
banks_mirror_size = rmd->bank_count;
}
else
/* compute mask */
{
int i;
/* compute the smallest even power of 2 greater than
ROM bank count, and use that to compute the mask */
for (i = 0; (rmd->bank_count >> i) > 0; i++);
banks_mirror_size = (1 << i);
}
rmd -> overflow_mask = banks_mirror_size - 1;
/* identity-map all the present banks */
for (copycount = 0; copycount < rmd->bank_count; copycount++)
{
rmd -> bank_lookup [copycount] = copycount;
}
/* mirror-map all the not-present banks */
for (next = rmd->bank_count, missing = banks_mirror_size - rmd->bank_count,
count = 1; missing; count <<= 1, missing >>= 1)
{
if (missing & 1)
{
for (copycount = count; copycount; copycount--, next++)
{
rmd -> bank_lookup[next] =
rmd -> bank_lookup[next - count];
}
}
}
}
SNESRomInfoStruct RomInfoLo, RomInfoHi;
int LoadSRAM(char *SRAM_filename)
{
if (!snes_rom_loaded || !SaveRamLength) return 0; // No SRAM
// Return if we can't get SRAM filename
if (CreateSRAMFilename(ROM_filename)) return 0;
FILE *Infile = fopen(SRAM_filename, "rb");
if (!Infile) return 0; // Can't open file
fread(SRAM, 1, SaveRamLength, Infile); // Read Save Ram
/* Apply mirroring for small SRAMs, for reads */
switch (SaveRamLength)
{
case (2 << 10):
memcpy(SRAM + (2 << 10), SRAM, (2 << 10));
case (4 << 10):
memcpy(SRAM + (4 << 10), SRAM, (4 << 10));
}
fclose(Infile);
return -1;
}
int SaveSRAM(char *SRAM_filename)
{
if (!snes_rom_loaded || !SaveRamLength) return 0; // No SRAM
// Return if we can't get SRAM filename
if (CreateSRAMFilename(ROM_filename)) return 0;
FILE *Outfile = fopen(SRAM_filename, "wb");
if (!Outfile) return 0; // Can't open file
fwrite(SRAM, 1, SaveRamLength, Outfile); // Write Save Ram
fclose(Outfile);
return -1;
}
char *ROM_filename = 0;
char fn_drive[MAXDRIVE], fn_dir[MAXDIR], fn_file[MAXFILE], fn_ext[MAXEXT];
char SRAM_filename[MAXPATH];
char save_dir[MAXPATH];
char save_extension[MAXEXT];
ROMFileType GetROMFileType(const char *ROM_filename)
{
fnsplit(ROM_filename, fn_drive, fn_dir, fn_file, fn_ext);
if (!fn_ext) return ROMFileType_normal;
if (!strcmp(fn_ext, ".1")) return ROMFileType_split;
/*
if (fn_file)
{
if (!strnicmp(fn_file, "SF", 2)
&& (!strcmp(fn_ext, ".058") || !strcmp(fn_ext, ".078")))
{
printf("Game Doctor ROM detected.\n");
return ROMFileType_gamedoctor;
}
}
if (!stricmp(fn_ext, ".zip"))
{
printf("Compressed ROM detected.\n");
return ROMFileType_compressed;
}
if (!stricmp(fn_ext, ".rar"))
{
printf("Compressed ROM detected.\n");
return ROMFileType_compressed;
}*/
return ROMFileType_normal;
}
bool CreateSRAMFilename(char *ROM_filename)
{
int length, slength;
SRAM_filename[0] = 0;
length = 1; // 1 for the null
fnsplit(ROM_filename, fn_drive, fn_dir, fn_file, fn_ext);
if (!fn_file) return TRUE;
length += strlen(fn_file);
if (strlen(save_extension))
{
length += strlen(save_extension);
if (save_extension[0] != '.') ++length; // One for leading period
}
slength = strlen(save_dir);
if (slength)
{
length += slength;
if (save_dir[slength - 1] != '/' && save_dir[slength - 1] != '\\')
++length; // One for trailing slash
} else {
if (strlen(fn_drive))
{
length += strlen(fn_drive);
}
slength = strlen(fn_dir);
if (slength)
{
length += slength;
if (fn_dir[slength - 1] != '/' && fn_dir[slength - 1] != '\\')
++length; // One for trailing slash
}
}
if (length > MAXPATH) return TRUE;
if (strlen(save_dir))
{
strcat(SRAM_filename, save_dir);
if (save_dir[slength - 1] != '/' && save_dir[slength - 1] != '\\')
strcat(SRAM_filename, "/"); // Add missing trailing slash
} else {
if (strlen(fn_drive))
{
strcat(SRAM_filename, fn_drive);
}
if (strlen(fn_dir))
{
strcat(SRAM_filename, fn_dir);
if (fn_dir[slength - 1] != '/' && fn_dir[slength - 1] != '\\')
strcat(SRAM_filename, "/"); // Add missing trailing slash
}
}
strcat(SRAM_filename, fn_file);
if (strlen(save_extension))
{
if (save_extension[0] != '.')
strcat(SRAM_filename, "."); // Add missing leading period
strcat(SRAM_filename, save_extension);
}
return FALSE;
}
void DisplayRomStats(SNESRomInfoStruct *RomInfo);
// ROM is now dynamically allocated. This is to add large ROM support
// without raising RAM requirements when using smaller ROMs.
static unsigned char *AllocROMAddress = 0;
void Free_ROM()
{
if (AllocROMAddress) free(AllocROMAddress);
AllocROMAddress = (unsigned char *)0;
}
int Allocate_ROM()
{
// De-allocate any previous memory
Free_ROM();
AllocROMAddress =
(unsigned char *) malloc (rmd_64k.bank_count * (64 << 10) + (12 << 10));
if (!AllocROMAddress) return rmd_64k.bank_count * (64 << 10) + (12 << 10);
RomAddress = // Force 4k alignment/8k misalignment
(unsigned char *)(((unsigned)
((AllocROMAddress + ((8 << 10) - 1))) & ~((8 << 10) - 1)) + (4 << 10));
memset(RomAddress, 0xFF, rmd_64k.bank_count * (64 << 10));
return 0;
}
unsigned SRAM_Mask;
inline void set_block_read_handler(int bank, int block, void (*read)(void))
{
Read_Bank8Mapping [bank * 8 + block] = (void (*)(void)) read;
Read_Bank8Offset [bank * 8 + block] = (void *) 0;
}
inline void set_block_read_pointer(int bank, int block, void *read)
{
Read_Bank8Mapping [bank * 8 + block] =
(void (*)(void)) Read_Direct_Safeguard;
Read_Bank8Offset [bank * 8 + block] = (void *) read;
}
inline void set_block_write_handler(int bank, int block, void (*write)(void))
{
Write_Bank8Mapping[bank * 8 + block] = (void (*)(void)) write;
Write_Bank8Offset[bank * 8 + block] = (void *) 0;
}
inline void set_block_write_pointer(int bank, int block, void *write)
{
Write_Bank8Mapping[bank * 8 + block] =
(void (*)(void)) Write_Direct_Safeguard;
Write_Bank8Offset[bank * 8 + block] = (void *) write;
}
inline void set_block_handlers(int bank, int block, void (*read)(void), void (*write)(void))
{
set_block_read_handler(bank, block, read);
set_block_write_handler(bank, block, write);
}
inline void set_block_pointers(int bank, int block, void *read, void *write)
{
set_block_read_pointer(bank, block, read);
set_block_write_pointer(bank, block, write);
}
inline void map_wram(int bank, int block)
{
set_block_pointers(bank, block, (void *) (WRAM - (bank << 16)), (void *) (WRAM - (bank << 16)));
}
inline void map_wram_128k(int bank)
{
for (int i = 0; i < 8; i++)
{
set_block_pointers(bank, i, (void *) (WRAM - (bank << 16)), (void *) (WRAM - (bank << 16)));
set_block_pointers(bank + 1, i, (void *) (WRAM - (bank << 16)), (void *) (WRAM - (bank << 16)));
}
}
inline void map_unmapped(int bank, int block)
{
set_block_handlers(bank, block, &CPU_OPEN_BUS_READ, &IGNORE_WRITE);
}
inline void map_unmapped_32k(int bank)
{
for (int i = 4; i < 8; i++) map_unmapped(bank, i);
}
inline void map_unmapped_64k(int bank)
{
for (int i = 0; i < 8; i++) map_unmapped(bank, i);
}
inline void map_blank(int bank, int block)
{
set_block_pointers(bank, block, (void *) 0, (void *) (Dummy - (bank << 16)));
map_unmapped(bank, block);
}
inline void map_blank_32k(int bank)
{
for (int i = 4; i < 8; i++) map_blank(bank, i);
}
inline void map_blank_64k(int bank)
{
for (int i = 0; i < 8; i++) map_blank(bank, i);
}
inline void map_sram(int bank, int block, int sram_block,
void (*sram_write_handler)(void))
{
set_block_read_pointer(bank, block,
SRAM + (sram_block << 13) - (bank << 16) - (block << 13));
// set_block_write_pointer(bank, block,
// SRAM + (sram_block << 13) - (bank << 16) - (block << 13));
set_block_write_handler(bank, block, sram_write_handler);
}
inline void map_no_sram(int bank, int block)
{
map_blank(bank, block);
}
inline void map_sram_2k(int bank, int block)
{
set_block_read_pointer(bank, block, SRAM - (bank << 16) - (block << 13));
set_block_write_handler(bank, block, &SRAM_WRITE_2k);
}
inline void map_sram_4k(int bank, int block)
{
set_block_read_pointer(bank, block, SRAM - (bank << 16) - (block << 13));
set_block_write_handler(bank, block, &SRAM_WRITE_4k);
}
inline void map_sram_32k(int bank, int sram_block, int mask,
void (*sram_write_handler)(void))
{
for (int i = 0; i < 4; i++) map_sram(bank, i, sram_block + (i & mask),
sram_write_handler);
}
inline void map_no_sram_32k(int bank)
{
for (int i = 0; i < 4; i++) map_no_sram(bank, i);
}
inline void map_sram_2k_32k(int bank)
{
for (int i = 0; i < 4; i++) map_sram_2k(bank, i);
}
inline void map_sram_4k_32k(int bank)
{
for (int i = 0; i < 4; i++) map_sram_4k(bank, i);
}
inline void map_rom_32k_lorom(int bank)
{
int needed_bank;
needed_bank = rmd_32k.bank_lookup [(bank ^ 0x80) & rmd_32k.overflow_mask];
for (int i = 4; i < 8; i++)
{
set_block_pointers(bank, i, (void *) (RomAddress - ((bank - needed_bank) << 16) - (needed_bank + 1) * 0x8000), (void *) (Dummy - (bank << 16)));
}
}
inline void map_rom_32k_lorom_40_C0(int bank)
{
int needed_bank;
needed_bank = rmd_32k.bank_lookup [(bank ^ 0x80) & rmd_32k.overflow_mask];
for (int i = 0; i < 4; i++)
{
set_block_pointers(bank, i, (void *) (RomAddress - ((bank - needed_bank) << 16) - (needed_bank & 0x7F) * 0x8000), (void *) (Dummy - (bank << 16)));
}
map_rom_32k_lorom(bank);
}
inline void map_rom_32k_hirom(int bank)
{
int needed_bank;
needed_bank = rmd_64k.bank_lookup [
((bank & 0x80 ? 0 : 0x40) + (bank & 0x3F)) & rmd_64k.overflow_mask];
for (int i = 4; i < 8; i++)
{
set_block_pointers(bank, i, (void *) (RomAddress - ((bank - needed_bank) << 16)), (void *) (Dummy - (bank << 16)));
}
}
inline void map_rom_64k(int bank)
{
int needed_bank;
needed_bank = rmd_64k.bank_lookup [
((bank & 0x80 ? 0 : 0x40) + (bank & 0x3F)) & rmd_64k.overflow_mask];
for (int i = 0; i < 8; i++)
{
set_block_pointers(bank, i, (void *) (RomAddress - ((bank - needed_bank) << 16)), (void *) (Dummy - (bank << 16)));
}
}
inline void map_ports(int bank)
{
map_wram(bank, 0);
set_block_handlers(bank, 1, &PPU_READ, &PPU_WRITE);
set_block_handlers(bank, 2, &PPU_READ, &PPU_WRITE);
}
static inline void set_rom_speed(int A23, unsigned char MEMSEL)
{
int bank, speed;
speed = (MEMSEL & 1) ? 6 : 8;
for (bank = (A23 ? 0x80 : 0); bank < (A23 ? 0xC0 : 0x40); bank++)
{
BlockSpeed[bank * 8 + 4] = speed;
BlockSpeed[bank * 8 + 5] = speed;
BlockSpeed[bank * 8 + 6] = speed;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -