www.pudn.com > sn068s.zip > ROMLOAD.CPP
/* 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
#include
#include
#include
#include
#include
#include "romload.h"
#include "helper.h"
#include "CPU.h"
#include "SPC.h"
#include "mem.h"
#include "snes.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];
unsigned char BlockIsROM[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 long SaveRamLength = 0;
int Allocate_ROM();
int NumBanks;
int ROM_format;
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
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(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);
// NumBanks is 64k blocks
int Allocate_ROM()
{
// 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;
// De-allocate any previous memory
if (AllocROMAddress) free(AllocROMAddress);
AllocROMAddress=(unsigned char *)malloc(NumBanks * 65536 + (12 << 10));
if (!AllocROMAddress) return NumBanks * 65536 + (12 << 10);
RomAddress= // Force 4k alignment/8k misalignment
(unsigned char *)(((unsigned long)
((AllocROMAddress + 0x1FFF)) & ~0x1FFF) + 0x1000);
memset(RomAddress, 0xFF, NumBanks * 65536);
return 0;
}
unsigned long 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)) 0;
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)) 0;
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)));
BlockSpeed[bank * 8 + block] = 8;
}
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)));
BlockSpeed[bank * 8 + i] = 8;
}
}
inline void map_unmapped(int bank, int block)
{
set_block_handlers(bank, block, &UNSUPPORTED_READ, &UNSUPPORTED_WRITE);
BlockIsROM[bank * 8 + block] = 0;
BlockSpeed[bank * 8 + block] = 8;
}
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 *) (Blank - (bank << 16)), (void *) (Dummy - (bank << 16)));
map_unmapped(bank, block);
BlockIsROM[bank * 8 + block] = (0 - 1);
BlockSpeed[bank * 8 + block] = 8;
}
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)
{
set_block_read_pointer(bank, block,
SRAM + (sram_block << 13) - (bank << 16) - (block << 13));
set_block_write_handler(bank, block, &SRAM_WRITE);
BlockSpeed[bank * 8 + block] = 8;
}
inline void map_no_sram(int bank, int block)
{
map_blank(bank, block);
BlockIsROM[bank * 8 + block] = 0;
BlockSpeed[bank * 8 + block] = 8;
}
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);
BlockSpeed[bank * 8 + block] = 8;
}
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);
BlockSpeed[bank * 8 + block] = 8;
}
inline void map_sram_64k(int bank, int sram_block, int mask)
{
for (int i = 0; i < 8; i++) map_sram(bank, i, sram_block + (i & mask));
}
inline void map_no_sram_64k(int bank)
{
for (int i = 0; i < 8; i++) map_no_sram(bank, i);
}
inline void map_sram_2k_64k(int bank)
{
for (int i = 0; i < 8; i++) map_sram_2k(bank, i);
}
inline void map_sram_4k_64k(int bank)
{
for (int i = 0; i < 8; i++) map_sram_4k(bank, i);
}
inline void map_rom_32k_lorom(int bank)
{
for (int i = 4; i < 8; i++)
{
set_block_pointers(bank, i, (void *) (RomAddress - (bank & 0x80 ? 0x800000 : 0) - ((bank & 0x7F) + 1) * 0x8000), (void *) (Dummy - (bank << 16)));
BlockIsROM[bank * 8 + i] = (0 - 1);
BlockSpeed[bank * 8 + i] = 8;
}
}
inline void map_rom_32k_megamanx(int bank)
{
for (int i = 4; i < 8; i++)
{
set_block_pointers(bank, i, (void *) (RomAddress - (bank & 0x80 ? 0x800000 : 0) - (bank & 0x40 ? 0x400000 : 0) - ((bank & 0x3F) + 1) * 0x8000), (void *) (Dummy - (bank << 16)));
BlockIsROM[bank * 8 + i] = (0 - 1);
BlockSpeed[bank * 8 + i] = 8;
}
}
inline void map_rom_32k_hirom(int bank)
{
for (int i = 4; i < 8; i++)
{
set_block_pointers(bank, i, (void *) (RomAddress - (bank & 0x80 ? 0x800000 : 0)), (void *) (Dummy - (bank << 16)));
BlockIsROM[bank * 8 + i] = (0 - 1);
BlockSpeed[bank * 8 + i] = 8;
}
}
inline void map_rom_64k(int bank)
{
for (int i = 0; i < 8; i++)
{
set_block_pointers(bank, i, (void *) (RomAddress - (bank & 0x80 ? 0xC00000 : 0x400000)), (void *) (Dummy - (bank << 16)));
BlockIsROM[bank * 8 + i] = (0 - 1);
BlockSpeed[bank * 8 + i] = 8;
}
}
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);
BlockSpeed[bank * 8 + 1] = 6;
BlockSpeed[bank * 8 + 2] = 6;
}
void Set_SNES_Map()
{
int b;
for (b = 0; b <= 0x3F; b++)
{
map_ports(b);
map_ports(b + 0x80);
}
map_wram_128k(0x7E);
}
void Set_LoROM_Map()
{
int b;
for (b = 0; b <= 0xFF; b++)
{
map_unmapped_64k(b);
}
enum SPECIAL_ROM {
SR_NOT_SPECIAL, SR_MEGAMANX
};
SPECIAL_ROM special_rom = SR_NOT_SPECIAL;
if (!strcmp(rom_name, "MEGAMAN X ")
|| !strcmp(rom_name, "ROCKMAN X "))
{
// special: perform 00/80 -> 40/C0 mirroring similar to HiROM
//special_rom = SR_MEGAMANX;
printf("Mega Man X detected\n");
}
switch (special_rom)
{
case SR_MEGAMANX:
for (b = 0; b <= 0x3F; b++)
{
if (b < NumBanks * 2)
{
map_rom_32k_megamanx(b);
map_rom_32k_megamanx(b + 0x80);
map_rom_32k_megamanx(b + 0x40);
map_rom_32k_megamanx(b + 0xC0);
} else {
map_blank_32k(b);
map_blank_32k(b + 0x80);
map_blank_32k(b + 0x40);
map_blank_32k(b + 0xC0);
}
}
break;
default:
for (b = 0; b <= 0x7F; b++)
{
if (b < NumBanks * 2)
{
map_rom_32k_lorom(b);
map_rom_32k_lorom(b + 0x80);
} else {
map_blank_32k(b);
map_blank_32k(b + 0x80);
}
}
}
SRAM_Mask = SaveRamLength - 1;
for (b = 0x70; b <= 0x7F; b++)
{
switch (SaveRamLength)
{
case 0: // No SRAM
map_no_sram_64k(b);
break;
case 0x800: // 2k SRAM
map_sram_2k_64k(b);
break;
case 0x1000: // 4k SRAM
map_sram_4k_64k(b);
break;
default:
switch (SaveRamLength)
{
case 0x10000: // 64k SRAM
map_sram_64k(b, 0, 7);
break;
case 0x8000: // 32k SRAM
map_sram_64k(b, 0, 3);
break;
case 0x4000: // 16k SRAM
map_sram_64k(b, 0, 1);
break;
case 0x2000: // 8k SRAM
default:
map_sram_64k(b, 0, 0);
break;
}
}
}
Set_SNES_Map();
}
void Set_HiROM_Map()
{
int b;
for (b = 0; b <= 0xFF; b++)
{
map_unmapped_64k(b);
}
for (b = 0; b <= 0x3F; b++)
{
if (b < NumBanks)
{
// Set 32k banks
map_rom_32k_hirom(b);
map_rom_32k_hirom(b + 0x80);
// Set 64k banks
map_rom_64k(b + 0x40);
map_rom_64k(b + 0xC0);
} else {
// Set 32k banks
map_blank_32k(b);
map_blank_32k(b + 0x80);
// Set 64k banks
map_blank_64k(b + 0x40);
map_blank_64k(b + 0xC0);
}
}
SRAM_Mask = SaveRamLength >= 0x2000 ? 0x1FFF : SaveRamLength - 1;
switch (SaveRamLength) // Setup mapper for rest of 32k ROM banks + SRAM
{
case 0: // No SRAM
for (b = 0x30; b <= 0x3F; b++)
{
map_no_sram(b, 3);
map_no_sram(b + 0x80, 3);
}
break;
case 0x800: // 2k SRAM
case 0x1000: // 4k SRAM
case 0x2000: // 8k SRAM
for (b = 0x30; b <= 0x3F; b++)
{
switch (SaveRamLength)
{
case 0x800: // 2k SRAM
map_sram_2k(b, 3);
map_sram_2k(b + 0x80, 3);
break;
case 0x1000: // 4k SRAM
map_sram_4k(b, 3);
map_sram_4k(b + 0x80, 3);
break;
case 0x2000: // 8k SRAM
map_sram(b, 3, 0);
map_sram(b + 0x80, 3, 0);
}
}
break;
case 0x4000: // 16k SRAM
for (b = 0x30; b <= 0x3F; b++)
{
map_sram(b, 3, b & 1);
map_sram(b + 0x80, 3, b & 1);
}
break;
case 0x8000: // 32k SRAM
for (b = 0x30; b <= 0x3F; b++)
{
map_sram(b, 3, b & 3);
map_sram(b + 0x80, 3, b & 3);
}
break;
case 0x10000: // 64k SRAM
for (b = 0x30; b <= 0x3F; b++)
{
map_sram(b, 3, b & 7);
map_sram(b + 0x80, 3, b & 7);
}
break;
}
Set_SNES_Map();
}
int ROM_has_header = Undetected;
/* Off = LoROM, On = HiROM, Undetected = autodetect */
int ROM_memory_map = Undetected;
int ROM_interleaved = Undetected;
int ROM_video_standard = Undetected;
void Load_32k(FILE *infile)
{
// Read in as 32k blocks and (de)interleave
for (int cnt = 0; cnt < NumBanks; cnt++) // Read first half
fread(RomAddress + cnt * 65536 + 32768, 1, 32768, infile);
for (int cnt = 0; cnt < NumBanks; cnt++) // Read second half
fread(RomAddress + cnt * 65536, 1, 32768, infile);
}
void Load_64k(FILE *infile)
{
for (int cnt = 0; cnt < NumBanks; cnt++) // Read in ROM
{
fread(RomAddress + cnt * 65536, 1, 65536, infile);
}
}
unsigned check_for_header(FILE *fp, int filesize)
{
unsigned ROM_start;
fseek(fp, 0, SEEK_END);
filesize = ftell(fp);
// Easiest way to detect ROM header
// Improvement suggested by Gridle (implemented 22/4/99)
// check against even multiple of 1k instead of 32k
// If ROM filesize is even multiple of 1k, assume no header
// If ROM filesize is even multiple of 1k, +512, assume header
if ((((filesize % 1024) == 0) || (ROM_has_header == Off)) &&
(ROM_has_header != On)) ROM_start = 0;
else if (((filesize % 1024) == ROM_Header_Size) || (ROM_has_header == On))
ROM_start = ROM_Header_Size;
else { // Basic header detection failure
/* Gridle 04/03/1998 (dmy)
ROM header in SMC files at 0x100 - 0x1FF usually is zero. I couldn't find
any other reliable way to check if the ROM is really SMC or BIN.
Originally I checked everything from 0x10 - 0x1FF, but one of my ROMs
(Brainies) had some stupid pirate group stuff just before 0x100, so I
changed this to search from 0x100 - 0x1FF.
This is now changed to 0x100 - 0x1F9 because of the king arthur ROM.
Charles Bilyue' 06/01/1999 (dmy)
(Check was later changed to 0x110 - 0x1F9 for some reason?)
LoROM checksums at 7FDC/7FDE, 81DC/81DE with header
HiROM checksums at FFDC/FFDE, 101DC/101DE with header
*/
ROM_Header Header; // For checking if the ROM has a header
fseek(fp,0,SEEK_SET);
fread(&Header,ROM_Header_Size,1,fp);
ROM_start=ROM_Header_Size;
for (unsigned cnt = 0x110 - 11; cnt < 0x1FA - 11; cnt++)
if (Header.RestOfHeader[cnt] != 0){ ROM_start = 0; break; }
}
/*
if (ROM_start == ROM_Header_Size)
printf("Header detected and ignored.\n");
else
printf("No header detected.\n");
*/
return ROM_start;
}
static bool open_rom_normal(char *Filename)
{
FILE *infile = fopen(Filename, "rb");
if (!infile) return FALSE; // File aint there m8
unsigned ROM_start; // This is where the ROM code itself starts.
fseek(infile, 0, SEEK_END);
int infilesize = ftell(infile);
ROM_start = check_for_header(infile, infilesize);
if (ROM_start == ROM_Header_Size)
printf("Header detected and ignored.\n");
else
printf("No header detected.\n");
ROM_format = Undetected;
fseek(infile, 0x7FC0 + ROM_start, SEEK_SET);
fread(&RomInfoLo, sizeof(SNESRomInfoStruct), 1, infile);
fseek(infile, 0xFFC0 + ROM_start, SEEK_SET);
fread(&RomInfoHi, sizeof(SNESRomInfoStruct), 1, infile);
if ((RomInfoLo.Checksum ^ RomInfoLo.Complement) == 0xFFFF)
{
if ((RomInfoLo.ROM_makeup & 0x0F) == 1)
{
strcpy(rom_romhilo, "Interleaved HiROM detected");
ROM_format = HiROM_Interleaved;
} else {
strcpy(rom_romhilo, "LoROM detected");
ROM_format = LoROM;
}
} else {
if (((RomInfoHi.Checksum ^ RomInfoHi.Complement) == 0xFFFF))
{
strcpy(rom_romhilo, "HiROM detected");
ROM_format = HiROM;
} else {
strcpy(rom_romhilo, "Detection failed, using LoROM");
ROM_format = LoROM;
}
}
switch (ROM_interleaved)
{
case On: ROM_format |= Interleaved; break;
case Off: ROM_format &= ~Interleaved; break;
}
switch (ROM_memory_map)
{
case HiROM:
if (!(ROM_format & HiROM)) ROM_format = HiROM;
strcpy(rom_romhilo, "HiROM forced"); break;
case LoROM:
if (ROM_format & HiROM) ROM_format = LoROM;
strcpy(rom_romhilo, "LoROM forced"); break;
}
NumBanks = (((infilesize - ROM_start) + 65535) / 65536);
if (NumBanks > 64) NumBanks = 64; // Maximum 32Mbit ROM size for LoROM
if (Allocate_ROM()) // Dynamic allocation of ROM
{
fclose(infile);
return FALSE; // return false if no memory left
}
fseek(infile, ROM_start, SEEK_SET);
switch(ROM_format)
{
case HiROM:
DisplayRomStats(&RomInfoHi);
Load_64k(infile);
Set_HiROM_Map();
break;
case HiROM_Interleaved:
DisplayRomStats(&RomInfoLo);
Load_32k(infile);
Set_HiROM_Map();
break;
case LoROM_Interleaved:
printf("Interleaved LoROM not supported - basic LoROM loader used\n");
case LoROM:
default:
DisplayRomStats(&RomInfoLo);
Load_64k(infile);
Set_LoROM_Map();
break;
}
fclose(infile);
return TRUE;
}
bool Load_32k_split(FILE *infile, char *Filename, int parts, long total_size)
{
char tempname[MAXPATH];
long bytes_read = 0;
int part = 1;
int infilesize;
unsigned ROM_start;
fnsplit(Filename, fn_drive, fn_dir, fn_file, fn_ext);
// Read in as 32k blocks and interleave
for (int cnt = 0;
cnt < NumBanks && part <= parts; cnt++) // Read first half
{
infilesize = fread(RomAddress + cnt * 65536 + 32768, 1, 32768, infile);
if (infilesize != EOF) bytes_read += infilesize;
while ((bytes_read % 32768) || (infilesize < 1))
{
// partial bank read, must complete (or nothing read, go to next file)
// next file
fclose(infile);
if (++part > parts)
{
if (bytes_read != total_size) return FALSE;
else break;
}
sprintf(fn_ext, ".%d", part);
fnmerge(tempname, fn_drive, fn_dir, fn_file, fn_ext);
FILE *infile=fopen(tempname,"rb");
if (!infile) return FALSE;
fseek(infile, 0, SEEK_END);
infilesize = ftell(infile);
ROM_start = check_for_header(infile, infilesize);
total_size -= ROM_start;
fseek(infile,ROM_start,SEEK_SET);
infilesize =
fread(RomAddress + cnt * 65536 + 32768 + (bytes_read % 32768), 1,
32768 - (bytes_read % 32768), infile);
if (infilesize != EOF) bytes_read += infilesize;
}
}
for (int cnt = 0;
cnt < NumBanks && part <= parts; cnt++) // Read second half
{
infilesize = fread(RomAddress + cnt * 65536, 1, 32768, infile);
if (infilesize != EOF) bytes_read += infilesize;
while ((bytes_read % 32768) || (infilesize < 1))
{
// partial bank read, must complete (or nothing read, go to next file)
// next file
if (++part > parts)
{
if (bytes_read != total_size) return FALSE;
else break;
}
fclose(infile);
sprintf(fn_ext, ".%d", part);
fnmerge(tempname, fn_drive, fn_dir, fn_file, fn_ext);
FILE *infile=fopen(tempname,"rb");
if (!infile) return FALSE;
fseek(infile, 0, SEEK_END);
infilesize = ftell(infile);
ROM_start = check_for_header(infile, infilesize);
total_size -= ROM_start;
fseek(infile,ROM_start,SEEK_SET);
infilesize =
fread(RomAddress + cnt * 65536 + (bytes_read % 32768), 1,
32768 - (bytes_read % 32768), infile);
if (infilesize != EOF) bytes_read += infilesize;
}
}
fclose(infile);
return TRUE;
}
static bool open_rom_split(char *Filename)
{
char tempname[MAXPATH];
int parts;
long total_size = 0;
fnsplit(Filename, fn_drive, fn_dir, fn_file, fn_ext);
for (parts = 1; parts < 1000; parts++)
{
sprintf(fn_ext, ".%d", parts + 1);
fnmerge(tempname, fn_drive, fn_dir, fn_file, fn_ext);
FILE *infile=fopen(tempname,"rb");
if (!infile) break;
fseek(infile, 0, SEEK_END);
total_size += ftell(infile);
fclose(infile);
}
if (parts == 1) return open_rom_normal(Filename);
printf("Split ROM image detected - %d parts found.\n", parts);
FILE *infile=fopen(Filename,"rb");
if (!infile) return FALSE; // File aint there m8
unsigned ROM_start; // This is where the ROM code itself starts.
fseek(infile, 0, SEEK_END);
int infilesize = ftell(infile);
ROM_start = check_for_header(infile, infilesize);
total_size += infilesize - ROM_start;
ROM_format = Undetected;
unsigned long RomInfoHi_Read;
fseek(infile,0x7FC0+ROM_start,SEEK_SET);
if (fread(&RomInfoLo,sizeof(SNESRomInfoStruct),1,infile) != 1)
{
fclose(infile);
return FALSE;
}
fseek(infile,0xFFC0+ROM_start,SEEK_SET);
RomInfoHi_Read = fread(&RomInfoHi,sizeof(SNESRomInfoStruct),1,infile);
// if checksum and complement match, or HiROM info block couldn't be read
if ((RomInfoLo.Checksum^RomInfoLo.Complement) == 0xFFFF ||
RomInfoHi_Read != 1)
{
if ((RomInfoLo.ROM_makeup&0x0F)==1)
{
strcpy(rom_romhilo,"Interleaved HiROM detected");
ROM_format = HiROM_Interleaved;
} else {
strcpy(rom_romhilo,"LoROM detected");
ROM_format = LoROM;
}
} else {
if (((RomInfoHi.Checksum^RomInfoHi.Complement) == 0xFFFF))
{
strcpy(rom_romhilo,"HiROM detected");
ROM_format = HiROM;
} else {
strcpy(rom_romhilo,"Detection failed, using LoROM");
ROM_format = LoROM;
}
}
switch (ROM_memory_map)
{
case HiROM:
if (!(ROM_format & HiROM)) ROM_format = HiROM;
strcpy(rom_romhilo,"HiROM forced"); break;
case LoROM:
if (ROM_format & HiROM) ROM_format = LoROM;
strcpy(rom_romhilo,"LoROM forced"); break;
}
switch (ROM_interleaved)
{
case On: ROM_format |= Interleaved; break;
case Off: ROM_format &= ~Interleaved; break;
}
NumBanks = ((total_size + 65535) / 65536);
if (NumBanks > 64) NumBanks = 64; // Maximum 32Mbit ROM size for LoROM
if (Allocate_ROM()) // Dynamic allocation of ROM
{
fclose(infile);
return FALSE; // return false if no memory left
}
fseek(infile,ROM_start,SEEK_SET);
switch(ROM_format)
{
long bytes_read;
case HiROM:
DisplayRomStats(&RomInfoHi);
Set_HiROM_Map();
bytes_read = fread(RomAddress,1,total_size,infile);
fclose(infile);
fnsplit(Filename, fn_drive, fn_dir, fn_file, fn_ext);
for (int part = 2; part <= parts; part++)
{
sprintf(fn_ext, ".%d", part);
fnmerge(tempname, fn_drive, fn_dir, fn_file, fn_ext);
FILE *infile=fopen(tempname,"rb");
if (!infile) break;
fseek(infile, 0, SEEK_END);
infilesize = ftell(infile);
ROM_start = check_for_header(infile, infilesize);
total_size -= ROM_start;
fseek(infile,ROM_start,SEEK_SET);
infilesize =
fread(RomAddress + bytes_read, 1, total_size - bytes_read, infile);
fclose(infile);
if (infilesize == EOF) break;
if (total_size == bytes_read) break;
bytes_read += infilesize;
}
if (infilesize == EOF) return FALSE;
if (!infile) return FALSE;
break;
case HiROM_Interleaved:
DisplayRomStats(&RomInfoLo);
Set_HiROM_Map();
return Load_32k_split(infile, Filename, parts, total_size);
break;
case LoROM_Interleaved:
printf("Split interleaved LoROM not supported - split basic LoROM loader used\n");
case LoROM:
default:
DisplayRomStats(&RomInfoLo);
Set_LoROM_Map();
bytes_read = fread(RomAddress,1,total_size,infile);
fclose(infile);
fnsplit(Filename, fn_drive, fn_dir, fn_file, fn_ext);
for (int part = 2; part <= parts; part++)
{
sprintf(fn_ext, ".%d", part);
fnmerge(tempname, fn_drive, fn_dir, fn_file, fn_ext);
FILE *infile=fopen(tempname,"rb");
if (!infile) break;
fseek(infile, 0, SEEK_END);
infilesize = ftell(infile);
ROM_start = check_for_header(infile, infilesize);
total_size -= ROM_start;
fseek(infile,ROM_start,SEEK_SET);
infilesize =
fread(RomAddress + bytes_read, 1, total_size - bytes_read, infile);
fclose(infile);
if (infilesize == EOF) break;
if (total_size == bytes_read) break;
bytes_read += infilesize;
}
if (infilesize == EOF) return FALSE;
if (!infile) return FALSE;
break;
}
return TRUE;
}
int open_rom(char *Filename)
{
ROMFileType filetype;
SaveSRAM(SRAM_filename); // Ensures SRAM saved before loading new ROM
snes_rom_loaded = FALSE;
SaveRamLength = 0;
if (ROM_filename){ free(ROM_filename); ROM_filename = 0; }
filetype = GetROMFileType(Filename);
ROM_filename = (char *) malloc(strlen(Filename));
if (!rom_romfile) rom_romfile=(char *)malloc(100);
if (!rom_romhilo) rom_romhilo=(char *)malloc(100);
if (!rom_romtype) rom_romtype=(char *)malloc(50);
if (!rom_romsize) rom_romsize=(char *)malloc(50);
if (!rom_romname) rom_romname=(char *)malloc(50);
if (!rom_sram) rom_sram =(char *)malloc(50);
if (!rom_country) rom_country=(char *)malloc(50);
if (!ROM_filename || !rom_romfile || !rom_romhilo
|| !rom_romtype || !rom_romsize || !rom_romname
|| !rom_sram || !rom_country)
return FALSE;
strcpy(ROM_filename,Filename);
strcpy(rom_romfile, Filename);
switch (filetype)
{
case ROMFileType_split: snes_rom_loaded = open_rom_split(Filename); break;
case ROMFileType_normal:
default: snes_rom_loaded = open_rom_normal(Filename);
}
if (snes_rom_loaded == FALSE) return FALSE;
Reset_Memory();
Reset_SRAM();
snes_reset();
LoadSRAM(SRAM_filename); // This loads in the Save RAM
printf("RES: %04X\n"
"NMI N,E: %04X,%04X\n"
"IRQ N,E: %04X,%04X\n"
"BRK N,E: %04X,%04X\n"
"COP N,E: %04X,%04X\n",
cpu_65c816_PC,
NMI_Nvector, NMI_Evector,
IRQ_Nvector, IRQ_Evector,
BRK_Nvector, IRQ_Evector,
COP_Nvector, COP_Evector);
return TRUE;
}
char *TypeTable[]={
"ROM",
"ROM+RAM",
"ROM+SRAM",
"ROM+DSP1",
"ROM+RAM+DSP1",
"ROM+SRAM+DSP1",
"Unknown",
"Unknown FX chip",
"FX-V1",
"FX(Argonaut)",
"FX-V2",
"FX(SA-1)",
"FX(?KSS?)",
"FX(Capcom)",
"FX(S-DD1)",
"FX(PLGS)",
"FX(Gameboy)",
"FX(BS-X)",
"FX(Capcom C4)",
"FX(SETA) (DSP2?)"
};
char *CountryTable[]={
"Japan",
"USA",
"Europe, Oceania, Asia",
"Sweden",
"Finland",
"Denmark",
"France",
"Holland",
"Spain",
"Germany, Austria, Switz.",
"Italy",
"Hong Kong, China",
"Indonesia",
"Korea"
};
void DisplayRomStats(SNESRomInfoStruct *RomInfo)
{
char TempBuffer[30];
// ROM Type
switch(RomInfo->ROM_type)
{
case 0: // ROM
case 1: // ROM/RAM
case 2: // ROM/SRAM
case 3: // ROM/DSP1
case 4: // ROM/RAM/DSP1
case 5: // ROM/SRAM/DSP1
strcpy(rom_romtype, TypeTable[RomInfo->ROM_type]); break;
case 0x10 ... 0x12: case 0x16:
case 0x20 ... 0x26: case 0x30 ... 0x34:
case 0x40 ... 0x42: case 0x44: case 0x46:
case 0x50 ... 0x54: case 0x56:
case 0x60 ... 0x66: case 0x70 ... 0x76:
case 0x80 ... 0x86: case 0x90 ... 0x96:
case 0xA0 ... 0xA6: case 0xB0 ... 0xB6:
case 0xC0 ... 0xC6: case 0xD0 ... 0xD6:
case 0xE0 ... 0xE2: case 0xE4: case 0xE6:
case 0xF0 ... 0xF2: case 0xF4 ... 0xF5:
// Unknown FX chip
strcpy(rom_romtype, TypeTable[7]);
case 0x13: // FX-V1
strcpy(rom_romtype, TypeTable[8]); break;
case 0x14: // FX(Argonaut)
strcpy(rom_romtype, TypeTable[9]); break;
case 0x15: // FX-V2
strcpy(rom_romtype, TypeTable[10]); break;
case 0x35: // FX(SA-1)
strcpy(rom_romtype, TypeTable[11]); break;
case 0x36: // FX(?KSS?)
strcpy(rom_romtype, TypeTable[12]); break;
case 0x43: // FX(Capcom)
strcpy(rom_romtype, TypeTable[13]); break;
case 0x45: // FX(S-DD1)
strcpy(rom_romtype, TypeTable[14]); break;
case 0x55: // FX(PLGS)
strcpy(rom_romtype, TypeTable[15]); break;
case 0xE3: // FX(Gameboy)
strcpy(rom_romtype, TypeTable[16]); break;
case 0xE5: // FX(BS-X)
strcpy(rom_romtype, TypeTable[17]); break;
case 0xF3: // FX(Capcom C4)
strcpy(rom_romtype, TypeTable[18]); break;
case 0xF6: // FX(SETA) (DSP2?)
strcpy(rom_romtype, TypeTable[19]); break;
default: // Unknown
strcpy(rom_romtype, TypeTable[6]);
}
// ROM Size
strcpy(rom_romsize, itoa(1 << ((RomInfo->ROM_size) - 7), TempBuffer, 10));
strcat(rom_romsize, "Mbits");
// ROM SRAM size
SaveRamLength = RomInfo->SRAM_size;
if (((RomInfo->ROM_type) == 2) || ((RomInfo->ROM_type) >= 5) &&
SaveRamLength)
{
SaveRamLength = 1024 << SaveRamLength;
strcpy(rom_sram, itoa(SaveRamLength * 8 / 1024, TempBuffer, 10));
strcat(rom_sram, "Kbits");
if (SaveRamLength > 65536) SaveRamLength = 65536;
} else {
SaveRamLength = 0;
strcpy(rom_sram,"No SRAM");
}
// ROM Country
if (RomInfo->Country_code <= 13)
{
strcpy(rom_country, CountryTable[ RomInfo->Country_code ]);
if (((RomInfo->Country_code < 2) && (ROM_video_standard != PAL_video))
|| (ROM_video_standard == NTSC_video))
{
strcat(rom_country,
(ROM_video_standard != NTSC_video) ? " (NTSC)" : " (NTSC forced)");
set_snes_ntsc();
}
else if (((RomInfo->Country_code < 14) && (ROM_video_standard != NTSC_video))
|| (ROM_video_standard == PAL_video))
{
strcat(rom_country,
(ROM_video_standard != PAL_video) ? " (PAL)" : " (PAL forced)");
set_snes_pal();
}
} else {
switch (ROM_video_standard)
{
case PAL_video:
strcpy(rom_country, "Unknown (PAL forced)");
set_snes_pal();
break;
case NTSC_video:
strcpy(rom_country, "Unknown (NTSC forced)");
set_snes_ntsc();
break;
default:
strcpy(rom_country, "Unknown (Using NTSC)");
set_snes_ntsc();
}
}
// ROM Name
for (int i = 0; i < 21; i++)
rom_name[i] = RomInfo->ROM_Title[i];
rom_name[21] = 0;
strcpy(rom_romname,rom_name);
// Print information
printf("\nROM title: %s\n", rom_romname);
printf("ROM type: %s\n",rom_romtype);
if ((RomInfo->ROM_type) > 2)
printf("Some extra hardware used by this ROM is not yet supported!\n");
printf("%s\n",rom_romhilo);
printf("ROM size: %s\n",rom_romsize);
printf("SRAM size: %s\n",rom_sram);
printf("Country: %s\n",rom_country);
}