/ MCUME_teensy41 / teensysnes / memory.cpp
memory.cpp
   1  /*****************************************************************************\
   2       Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
   3                  This file is licensed under the Snes9x License.
   4     For further information, consult the LICENSE file in the root directory.
   5  \*****************************************************************************/
   6  
   7  #include <Arduino.h>
   8  
   9  #include "snes9x.h"
  10  #include "memory.h"
  11  #include "apu.h"
  12  #include "controls.h"
  13  #include "hacks.h"
  14  
  15  CMemory		Memory;
  16  uint32		OpenBus = 0;
  17  
  18  #define match_nn(str) (strncmp(Memory.ROMName, (str), strlen((str))) == 0)
  19  
  20  static int First512BytesCountZeroes(void)
  21  {
  22  	int zeroCount = 0;
  23  	for (int i = 0; i < 512; i++)
  24  	{
  25  		if (Memory.ROM[i] == 0)
  26  			zeroCount++;
  27  	}
  28  	return zeroCount;
  29  }
  30  
  31  static void sanitize(char *b, int size)
  32  {
  33  	for (int pos = 0; pos < size; pos++)
  34  	{
  35  		if (b[pos] == 0)
  36  			continue;
  37  		if (b[pos] < 32 || b[pos] > 126)
  38  			b[pos] = '_';
  39  	}
  40  	b[size - 1] = 0;
  41  }
  42  
  43  static bool8 allASCII (uint8 *b, int size)
  44  {
  45  	for (int i = 0; i < size; i++)
  46  	{
  47  		if (b[i] < 32 || b[i] > 126)
  48  			return (FALSE);
  49  	}
  50  
  51  	return (TRUE);
  52  }
  53  
  54  static void ShowInfoString (void)
  55  {
  56  	const char *contents[3] = { "ROM", "ROM+RAM", "ROM+RAM+BAT" };
  57  	char contentstr[20], sizestr[20], sramstr[20];
  58  
  59  	bool8 isChecksumOK = (Memory.ROMChecksum + Memory.ROMComplementChecksum == 0xffff) &
  60  						 (Memory.ROMChecksum == Memory.CalculatedChecksum);
  61  
  62  	if (!isChecksumOK || ((uint32) Memory.CalculatedSize > (uint32) (((1 << (Memory.ROMSize - 7)) * 128) * 1024)))
  63  	{
  64  		// Use yellow tint to indicate corrupted ROM.
  65  		Settings.DisplayColor = BUILD_PIXEL(31, 31, 0);
  66  	}
  67  	else if (Memory.ROMIsPatched)
  68  	{
  69  		// Use slight blue tint to indicate ROM was patched.
  70  		Settings.DisplayColor = BUILD_PIXEL(26, 26, 31);
  71  	}
  72  	else
  73  	{
  74  		Settings.DisplayColor = BUILD_PIXEL(31, 31, 31);
  75  	}
  76  
  77  	strcpy(contentstr, contents[(Memory.ROMType & 0xf) % 3]);
  78  
  79  	if (Settings.DSP == 1)
  80  		strcat(contentstr, "+DSP-1");
  81  	else if (Settings.DSP == 2)
  82  		strcat(contentstr, "+DSP-2");
  83  
  84  	if (Memory.ROMSize < 7 || Memory.ROMSize - 7 > 23)
  85  		strcpy(sizestr, "Corrupt");
  86  	else
  87  		sprintf(sizestr, "%dMbits", 1 << (Memory.ROMSize - 7));
  88  
  89  	if (Memory.SRAMSize > 16)
  90  		strcpy(sramstr, "Corrupt");
  91  	else
  92  		sprintf(sramstr, "%dKbits", 8 * (Memory.SRAMMask + 1) / 1024);
  93  
  94  	sprintf(String, "\"%s\" [%s] %s, %s, %s, %s, SRAM:%s, ID:%s, CRC32:%08X",
  95  		Memory.ROMName,
  96  		isChecksumOK ? "checksum ok" : "bad checksum",
  97  		Memory.HiROM ? "HiROM" : "LoROM",
  98  		sizestr,
  99  		contentstr,
 100  		(Settings.Region == S9X_PAL) ? "PAL" : "NTSC",
 101  		sramstr,
 102  		Memory.ROMId,
 103  		Memory.ROMCRC32);
 104  
 105  	S9xMessage(S9X_INFO, S9X_ROM_INFO, String);
 106  }
 107  
 108  static uint32 map_mirror (uint32 size, uint32 pos)
 109  {
 110  	// from bsnes
 111  	if (size == 0)
 112  		return (0);
 113  	if (pos < size)
 114  		return (pos);
 115  
 116  	uint32	mask = 1 << 31;
 117  	while (!(pos & mask))
 118  		mask >>= 1;
 119  
 120  	if (size <= (pos & mask))
 121  		return (map_mirror(size, pos - mask));
 122  	else
 123  		return (mask + map_mirror(size - mask, pos - mask));
 124  }
 125  
 126  static void map_lorom (uint32 bank_s, uint32 bank_e, uint32 addr_s, uint32 addr_e, uint32 size)
 127  {
 128  	uint32	c, i, p, addr;
 129  
 130  	for (c = bank_s; c <= bank_e; c++)
 131  	{
 132  		for (i = addr_s; i <= addr_e; i += 0x1000)
 133  		{
 134  			p = (c << 4) | (i >> 12);
 135  			addr = (c & 0x7f) * 0x8000;
 136  			Memory.ReadMap[p] = Memory.ROM + map_mirror(size, addr) - (i & 0x8000);
 137  		}
 138  	}
 139  }
 140  
 141  static void map_hirom (uint32 bank_s, uint32 bank_e, uint32 addr_s, uint32 addr_e, uint32 size)
 142  {
 143  	uint32	c, i, p, addr;
 144  
 145  	for (c = bank_s; c <= bank_e; c++)
 146  	{
 147  		for (i = addr_s; i <= addr_e; i += 0x1000)
 148  		{
 149  			p = (c << 4) | (i >> 12);
 150  			addr = c << 16;
 151  			Memory.ReadMap[p] = Memory.ROM + map_mirror(size, addr);
 152  		}
 153  	}
 154  }
 155  
 156  static void map_space (uint32 bank_s, uint32 bank_e, uint32 addr_s, uint32 addr_e, uint8 *data)
 157  {
 158  	uint32	c, i, p;
 159  
 160  	for (c = bank_s; c <= bank_e; c++)
 161  	{
 162  		for (i = addr_s; i <= addr_e; i += 0x1000)
 163  		{
 164  			p = (c << 4) | (i >> 12);
 165  			Memory.ReadMap[p] = data;
 166  			Memory.WriteMap[p] = data;
 167  		}
 168  	}
 169  }
 170  
 171  static void map_index (uint32 bank_s, uint32 bank_e, uint32 addr_s, uint32 addr_e, int index, int type)
 172  {
 173  	uint32	c, i, p;
 174  
 175  	for (c = bank_s; c <= bank_e; c++)
 176  	{
 177  		for (i = addr_s; i <= addr_e; i += 0x1000)
 178  		{
 179  			p = (c << 4) | (i >> 12);
 180  			Memory.ReadMap[p] = (uint8 *) (pint) index;
 181  			Memory.WriteMap[p] = (uint8 *) (pint) index;
 182  		}
 183  	}
 184  }
 185  
 186  static void Map_Initialize (void)
 187  {
 188  	for (int c = 0; c < MEMMAP_NUM_BLOCKS; c++)
 189  	{
 190  		Memory.ReadMap[c]  = (uint8 *) MAP_NONE;
 191  		Memory.WriteMap[c] = (uint8 *) MAP_NONE;
 192  	}
 193  
 194  	// will be overwritten
 195  	map_space(0x00, 0x3f, 0x0000, 0x1fff, Memory.RAM);
 196  	map_index(0x00, 0x3f, 0x2000, 0x3fff, MAP_PPU, MAP_TYPE_I_O);
 197  	map_index(0x00, 0x3f, 0x4000, 0x5fff, MAP_CPU, MAP_TYPE_I_O);
 198  	map_space(0x80, 0xbf, 0x0000, 0x1fff, Memory.RAM);
 199  	map_index(0x80, 0xbf, 0x2000, 0x3fff, MAP_PPU, MAP_TYPE_I_O);
 200  	map_index(0x80, 0xbf, 0x4000, 0x5fff, MAP_CPU, MAP_TYPE_I_O);
 201  }
 202  
 203  static void Map_Finalize (void)
 204  {
 205  	// Map Work RAM
 206  	map_space(0x7e, 0x7e, 0x0000, 0xffff, Memory.RAM);
 207  	map_space(0x7f, 0x7f, 0x0000, 0xffff, Memory.RAM + 0x10000);
 208  }
 209  
 210  static void Map_DSP (void)
 211  {
 212  	switch (DSP0.maptype)
 213  	{
 214  		case M_DSP1_LOROM_S:
 215  			map_index(0x20, 0x3f, 0x8000, 0xffff, MAP_DSP, MAP_TYPE_I_O);
 216  			map_index(0xa0, 0xbf, 0x8000, 0xffff, MAP_DSP, MAP_TYPE_I_O);
 217  			break;
 218  
 219  		case M_DSP1_LOROM_L:
 220  			map_index(0x60, 0x6f, 0x0000, 0x7fff, MAP_DSP, MAP_TYPE_I_O);
 221  			map_index(0xe0, 0xef, 0x0000, 0x7fff, MAP_DSP, MAP_TYPE_I_O);
 222  			break;
 223  
 224  		case M_DSP1_HIROM:
 225  			map_index(0x00, 0x1f, 0x6000, 0x7fff, MAP_DSP, MAP_TYPE_I_O);
 226  			map_index(0x80, 0x9f, 0x6000, 0x7fff, MAP_DSP, MAP_TYPE_I_O);
 227  			break;
 228  
 229  		case M_DSP2_LOROM:
 230  			map_index(0x20, 0x3f, 0x6000, 0x6fff, MAP_DSP, MAP_TYPE_I_O);
 231  			map_index(0x20, 0x3f, 0x8000, 0xbfff, MAP_DSP, MAP_TYPE_I_O);
 232  			map_index(0xa0, 0xbf, 0x6000, 0x6fff, MAP_DSP, MAP_TYPE_I_O);
 233  			map_index(0xa0, 0xbf, 0x8000, 0xbfff, MAP_DSP, MAP_TYPE_I_O);
 234  			break;
 235  	}
 236  }
 237  
 238  static void Map_LoROMMap (void)
 239  {
 240  	Map_Initialize();
 241  
 242  	map_lorom(0x00, 0x3f, 0x8000, 0xffff, Memory.CalculatedSize);
 243  	map_lorom(0x40, 0x7f, 0x0000, 0xffff, Memory.CalculatedSize);
 244  	map_lorom(0x80, 0xbf, 0x8000, 0xffff, Memory.CalculatedSize);
 245  	map_lorom(0xc0, 0xff, 0x0000, 0xffff, Memory.CalculatedSize);
 246  
 247  	if (Settings.DSP)
 248  		Map_DSP();
 249  
 250  	if (Memory.SRAMSize > 0)
 251  	{
 252  		uint32 hi = (Memory.ROMSize > 11 || Memory.SRAMSize > 5) ? 0x7fff : 0xffff;
 253  		map_index(0x70, 0x7d, 0x0000, hi, MAP_LOROM_SRAM, MAP_TYPE_RAM);
 254  		map_index(0xf0, 0xff, 0x0000, hi, MAP_LOROM_SRAM, MAP_TYPE_RAM);
 255  	}
 256  
 257  	Map_Finalize();
 258  }
 259  
 260  static void Map_HiROMMap (void)
 261  {
 262  	Map_Initialize();
 263  
 264  	map_hirom(0x00, 0x3f, 0x8000, 0xffff, Memory.CalculatedSize);
 265  	map_hirom(0x40, 0x7f, 0x0000, 0xffff, Memory.CalculatedSize);
 266  	map_hirom(0x80, 0xbf, 0x8000, 0xffff, Memory.CalculatedSize);
 267  	map_hirom(0xc0, 0xff, 0x0000, 0xffff, Memory.CalculatedSize);
 268  
 269  	if (Settings.DSP)
 270  		Map_DSP();
 271  
 272  	map_index(0x20, 0x3f, 0x6000, 0x7fff, MAP_HIROM_SRAM, MAP_TYPE_RAM);
 273  	map_index(0xa0, 0xbf, 0x6000, 0x7fff, MAP_HIROM_SRAM, MAP_TYPE_RAM);
 274  
 275  	Map_Finalize();
 276  }
 277  
 278  static uint16 checksum_calc_sum (uint8 *data, uint32 length)
 279  {
 280  	uint16	sum = 0;
 281  
 282  	for (size_t i = 0; i < length; i++)
 283  		sum += data[i];
 284  
 285  	return (sum);
 286  }
 287  
 288  static uint16 checksum_mirror_sum (uint8 *start, uint32 *length, uint32 mask)
 289  {
 290  	// from NSRT
 291  	while (!(*length & mask) && mask)
 292  		mask >>= 1;
 293  
 294  	uint16	part1 = checksum_calc_sum(start, mask);
 295  	uint16	part2 = 0;
 296  
 297  	uint32	next_length = *length - mask;
 298  	if (next_length)
 299  	{
 300  		part2 = checksum_mirror_sum(start + mask, &next_length, mask >> 1);
 301  
 302  		while (next_length < mask)
 303  		{
 304  			next_length += next_length;
 305  			part2 += part2;
 306  		}
 307  
 308  		*length = mask + mask;
 309  	}
 310  
 311  	return (part1 + part2);
 312  }
 313  
 314  static uint16 CalcChecksum (uint8 *data, uint32 length)
 315  {
 316  	if (length & 0x7fff)
 317  		return checksum_calc_sum(data, length);
 318  	else
 319  		return checksum_mirror_sum(data, &length, 0x800000);
 320  }
 321  
 322  static int ScoreHiROM (void)
 323  {
 324  	uint8	*buf = Memory.ROM + 0xff00;
 325  	int		score = 0;
 326  
 327  	if (buf[0xd5] & 0x1)
 328  		score += 2;
 329  
 330  	// Mode23 is SA-1
 331  	if (buf[0xd5] == 0x23)
 332  		score -= 2;
 333  
 334  	if (buf[0xd4] == 0x20)
 335  		score += 2;
 336  
 337  	if ((buf[0xdc] + (buf[0xdd] << 8)) + (buf[0xde] + (buf[0xdf] << 8)) == 0xffff)
 338  	{
 339  		score += 2;
 340  		if (0 != (buf[0xde] + (buf[0xdf] << 8)))
 341  			score++;
 342  	}
 343  
 344  	if (buf[0xda] == 0x33)
 345  		score += 2;
 346  
 347  	if ((buf[0xd5] & 0xf) < 4)
 348  		score += 2;
 349  
 350  	if (!(buf[0xfd] & 0x80))
 351  		score -= 6;
 352  
 353  	if ((buf[0xfc] + (buf[0xfd] << 8)) > 0xffb0)
 354  		score -= 2; // reduced after looking at a scan by Cowering
 355  
 356  	if (Memory.CalculatedSize > 1024 * 1024 * 3)
 357  		score += 4;
 358  
 359  	if ((1 << (buf[0xd7] - 7)) > 48)
 360  		score -= 1;
 361  
 362  	if (!allASCII(&buf[0xb0], 6))
 363  		score -= 1;
 364  
 365  	if (!allASCII(&buf[0xc0], ROM_NAME_LEN - 1))
 366  		score -= 1;
 367  
 368  	return (score);
 369  }
 370  
 371  static int ScoreLoROM (void)
 372  {
 373  	uint8	*buf = Memory.ROM + 0x7f00;
 374  	int		score = 0;
 375  
 376  	if (!(buf[0xd5] & 0x1))
 377  		score += 3;
 378  
 379  	// Mode23 is SA-1
 380  	if (buf[0xd5] == 0x23)
 381  		score += 2;
 382  
 383  	if ((buf[0xdc] + (buf[0xdd] << 8)) + (buf[0xde] + (buf[0xdf] << 8)) == 0xffff)
 384  	{
 385  		score += 2;
 386  		if (0 != (buf[0xde] + (buf[0xdf] << 8)))
 387  			score++;
 388  	}
 389  
 390  	if (buf[0xda] == 0x33)
 391  		score += 2;
 392  
 393  	if ((buf[0xd5] & 0xf) < 4)
 394  		score += 2;
 395  
 396  	if (!(buf[0xfd] & 0x80))
 397  		score -= 6;
 398  
 399  	if ((buf[0xfc] + (buf[0xfd] << 8)) > 0xffb0)
 400  		score -= 2; // reduced per Cowering suggestion
 401  
 402  	if (Memory.CalculatedSize <= 1024 * 1024 * 16)
 403  		score += 2;
 404  
 405  	if ((1 << (buf[0xd7] - 7)) > 48)
 406  		score -= 1;
 407  
 408  	if (!allASCII(&buf[0xb0], 6))
 409  		score -= 1;
 410  
 411  	if (!allASCII(&buf[0xc0], ROM_NAME_LEN - 1))
 412  		score -= 1;
 413  
 414  	return (score);
 415  }
 416  
 417  int ApplyGameSpecificHacks (void)
 418  {
 419  	int applied = 0;
 420  
 421  	for (const s9x_hack_t *hack = &GameHacks[0]; hack->checksum; hack++)
 422  	{
 423  		if (hack->checksum == Memory.ROMCRC32)
 424  		{
 425  			printf("Applying patch %s: '%s'\n", hack->name, hack->patch);
 426  
 427  			char *ptr = (char*)hack->patch;
 428  
 429  			while (ptr && *ptr)
 430  			{
 431  				int offset = strtol(ptr, &ptr, 16);
 432  				int value = strtol(ptr + 1, &ptr, 16);
 433  
 434  				if ((ptr = strchr(ptr, ',')))
 435  					ptr++;
 436  
 437  				// We only care about opcode 0x42 for now
 438  				if ((value != 0x42) && ((value >> 8) != 0x42))
 439  				{
 440  					printf(" - Warning: Ignoring patch %X=%X...\n", offset, value);
 441  				}
 442  				else if (offset < 1 || offset >= Memory.CalculatedSize)
 443  				{
 444  					printf(" - Warning: Offset %d (%X) is out of range...\n", offset, offset);
 445  				}
 446  				else if (value & 0xFF00) // 16 bit replacement
 447  				{
 448  					printf(" - Applying 16bit patch %X=%X\n", offset, value);
 449  					// Memory.ROM[offset] = (value >> 8) & 0xFF;
 450  					// Memory.ROM[offset + 1] = value & 0xFF;
 451  					applied++;
 452  				}
 453  				else // 8 bit replacement
 454  				{
 455  					printf(" - Applying 8bit patch %X=%X\n", offset, value);
 456  					// Memory.ROM[offset] = value;
 457  					applied++;
 458  				}
 459  			}
 460  		}
 461  	}
 462  
 463  	return applied;
 464  }
 465  
 466  static bool8 InitROM ()
 467  {
 468  	if (!Memory.ROM || Memory.ROM_SIZE < 0x200)
 469  		return (FALSE);
 470  
 471  	if ((Memory.ROM_SIZE & 0x7FF) == 512 || First512BytesCountZeroes() > 400)
 472  	{
 473  		emu_printf("Found ROM file header (and ignored it).\n");
 474  		memmove(Memory.ROM, Memory.ROM + 512, Memory.ROM_SIZE - 512);
 475  		Memory.ROM_SIZE -= 512;
 476  	}
 477  
 478  	Memory.CalculatedSize = ((Memory.ROM_SIZE + 0x1fff) / 0x2000) * 0x2000;
 479  
 480  	//// these two games fail to be detected
 481  	if (strncmp((char *) &Memory.ROM[0x7fc0], "YUYU NO QUIZ DE GO!GO!", 22) == 0 ||
 482  		(strncmp((char *) &Memory.ROM[0xffc0], "BATMAN--REVENGE JOKER",  21) == 0))
 483  	{
 484  		Memory.LoROM = TRUE;
 485  		Memory.HiROM = FALSE;
 486  	}
 487  	else
 488  	{
 489  		Memory.LoROM = (ScoreLoROM() >= ScoreHiROM());
 490  		Memory.HiROM = !Memory.LoROM;
 491  	}
 492  
 493  	//// Parse ROM header and read ROM informatoin
 494  
 495  	uint8 *RomHeader = Memory.ROM + (Memory.HiROM ? 0xFFB0 : 0x7FB0);
 496  
 497  	strncpy(Memory.ROMName, (char *) &RomHeader[0x10], ROM_NAME_LEN - 1);
 498  	sanitize(Memory.ROMName, ROM_NAME_LEN);
 499  
 500  	Memory.ROMName[ROM_NAME_LEN - 1] = 0;
 501  	if (strlen(Memory.ROMName))
 502  	{
 503  		char *p = Memory.ROMName + strlen(Memory.ROMName);
 504  		if (p > Memory.ROMName + 21 && Memory.ROMName[20] == ' ')
 505  			p = Memory.ROMName + 21;
 506  		while (p > Memory.ROMName && *(p - 1) == ' ')
 507  			p--;
 508  		*p = 0;
 509  	}
 510  
 511  	Memory.ROMSize   = RomHeader[0x27];
 512  	Memory.SRAMSize  = RomHeader[0x28];
 513  	Memory.ROMSpeed  = RomHeader[0x25];
 514  	Memory.ROMType   = RomHeader[0x26];
 515  	Memory.ROMRegion = RomHeader[0x29];
 516  	Memory.ROMChecksum           = RomHeader[0x2E] + (RomHeader[0x2F] << 8);
 517  	Memory.ROMComplementChecksum = RomHeader[0x2C] + (RomHeader[0x2D] << 8);
 518  
 519  	memmove(Memory.ROMId, &RomHeader[0x02], 4);
 520  	sanitize(Memory.ROMId, 4);
 521  
 522  	//// Detect DSP 1 & 2
 523  	if (Memory.ROMType == 0x03 || (Memory.ROMType == 0x05 && Memory.ROMSpeed != 0x20))
 524  	{
 525  		Settings.DSP = 1;
 526  		if (Memory.HiROM)
 527  		{
 528  			DSP0.boundary = 0x7000;
 529  			DSP0.maptype = M_DSP1_HIROM;
 530  		}
 531  		else
 532  		if (Memory.CalculatedSize > 0x100000)
 533  		{
 534  			DSP0.boundary = 0x4000;
 535  			DSP0.maptype = M_DSP1_LOROM_L;
 536  		}
 537  		else
 538  		{
 539  			DSP0.boundary = 0xc000;
 540  			DSP0.maptype = M_DSP1_LOROM_S;
 541  		}
 542  
 543  		SetDSP = &DSP1SetByte;
 544  		GetDSP = &DSP1GetByte;
 545  	}
 546  	else
 547  	if (Memory.ROMType == 0x05 && Memory.ROMSpeed == 0x20)
 548  	{
 549  		Settings.DSP = 2;
 550  		DSP0.boundary = 0x10000;
 551  		DSP0.maptype = M_DSP2_LOROM;
 552  		SetDSP = &DSP2SetByte;
 553  		GetDSP = &DSP2GetByte;
 554  	}
 555  	else
 556  	{
 557  		Settings.DSP = 0;
 558  		SetDSP = NULL;
 559  		GetDSP = NULL;
 560  	}
 561  
 562  	//// SRAM size
 563  	if (strncmp("HITOMI3 ", Memory.ROMName, 8) == 0)
 564  	{
 565  		Memory.SRAMSize = 1;
 566  	}
 567  	Memory.SRAMMask = Memory.SRAMSize ? ((1 << (Memory.SRAMSize + 3)) * 128) - 1 : 0;
 568  	Memory.SRAMBytes = Memory.SRAMSize ? ((1 << (Memory.SRAMSize + 3)) * 128) : 0;
 569  	if (Memory.SRAMBytes > 0x8000)
 570  	{
 571  		emu_printf("\n\nWARNING: Default SRAM size too small!, need bytes");
 572      emu_printi(Memory.SRAMBytes);
 573  	}
 574  
 575  	//// Map memory
 576  	if (Memory.HiROM)
 577  	{
 578  		Map_HiROMMap();
 579  	}
 580      else
 581  	{
 582  		Map_LoROMMap();
 583  	}
 584  
 585  	//// Checksums
 586  	Memory.ROMCRC32 = crc32_le(0, Memory.ROM, Memory.CalculatedSize);
 587  	Memory.CalculatedChecksum = CalcChecksum(Memory.ROM, Memory.CalculatedSize);
 588  
 589  	//// ROM Region
 590  	if ((Memory.ROMRegion >= 2) && (Memory.ROMRegion <= 12))
 591  	{
 592  		Settings.Region = S9X_PAL;
 593  		Settings.FrameRate = 50;
 594  	}
 595  	else
 596  	{
 597  		Settings.Region = S9X_NTSC;
 598  		Settings.FrameRate = 60;
 599  	}
 600  
 601  	// Setup APU timings
 602  	S9xAPUTimingSetSpeedup(0);
 603  
 604  	//// Apply Game hacks
 605  	if (!Settings.DisableGameSpecificHacks)
 606  	{
 607  		ApplyGameSpecificHacks();
 608  	}
 609  
 610  	//// Show ROM information
 611  	ShowInfoString();
 612  
 613  	//// Reset system, then we're ready
 614  	S9xReset();
 615  
 616      return (TRUE);
 617  }
 618  
 619  
 620  // Public functions
 621  
 622  bool8 S9xMemoryInit (void)
 623  {
 624  	memset(&Memory, 0, sizeof(Memory));
 625  
 626  	Memory.RAM  = (uint8 *) emu_Malloc(0x20000); // calloc(1, 0x20000); // 128k
 627  	Memory.VRAM = (uint8 *) emu_SMalloc(0x10000); //calloc(1, 0x10000); // 64k Malloc?
 628  	Memory.SRAM = (uint8 *) emu_Malloc(0x8000); //calloc(1, 0x8000);  // 32k
 629  	Memory.ROM_MAX_SIZE = 0x600000;
 630  	//Memory.ROM  = (uint8 *) calloc(1, Memory.ROM_MAX_SIZE);
 631  	// Note: we don't care if ROM alloc fails. It's just to grab a large heap block
 632  	//       before it gets fragmented. The actual useful alloc is done in S9xLoadROM()
 633  
 634  	if (!Memory.RAM || !Memory.SRAM || !Memory.VRAM)
 635  	{
 636  		S9xMemoryDeinit();
 637  		return (FALSE);
 638  	}
 639  
 640  	return (TRUE);
 641  }
 642  
 643  void S9xMemoryDeinit (void)
 644  {
 645  	emu_Free(Memory.RAM); //free(Memory.RAM);
 646  	emu_Free(Memory.SRAM); //free(Memory.SRAM);
 647  	emu_Free(Memory.VRAM); // free(Memory.VRAM);
 648  	emu_SFree(Memory.ROM); //free(Memory.ROM);
 649  
 650  	Memory.RAM = NULL;
 651  	Memory.SRAM = NULL;
 652  	Memory.VRAM = NULL;
 653  	Memory.ROM = NULL;
 654  }
 655  
 656  
 657  bool8 S9xLoadROM (const char *filename)
 658  {
 659  	//FILE *stream = fopen(filename, "rb");
 660  	//if (!stream)
 661  	//	return (FALSE);
 662  
 663  	//fseek(stream, 0, SEEK_END);
 664  	//Memory.ROM_SIZE = ftell(stream);
 665  
 666  	Memory.ROM_SIZE = emu_FileSize((char*)filename); 
 667  	Memory.ROM = (uint8 *) emu_SMalloc(Memory.ROM_SIZE);
 668  
 669  	// We shrink if possible because we need all the memory we can get for savestates and buffers
 670  	//uint8 *temp = (uint8 *)realloc(Memory.ROM, Memory.ROM_SIZE);
 671  	//if (temp)
 672  	//{
 673  	//	Memory.ROM_MAX_SIZE = Memory.ROM_SIZE;
 674  	//	Memory.ROM = temp;
 675  	//}
 676  
 677  	if (!Memory.ROM || Memory.ROM_MAX_SIZE < Memory.ROM_SIZE)
 678  	{
 679  		//fclose(stream);
 680  		return (FALSE);
 681  	}
 682  
 683  	//fseek(stream, 0, SEEK_SET);
 684  	//fread(Memory.ROM, Memory.ROM_SIZE, 1, stream);
 685  	//fclose(stream);
 686  
 687  	emu_LoadFile((char*)filename, (char*)Memory.ROM, Memory.ROM_SIZE);
 688  
 689    emu_printf("loaded");
 690  	return InitROM();
 691  }
 692  
 693  // BPS % UPS % IPS
 694  #if 0
 695  
 696  static long ReadInt (Stream *r, unsigned nbytes)
 697  {
 698  	long	v = 0;
 699  
 700  	while (nbytes--)
 701  	{
 702  		int	c = r->get_char();
 703  		if (c == EOF)
 704  			return (-1);
 705  		v = (v << 8) | (c & 0xFF);
 706  	}
 707  
 708  	return (v);
 709  }
 710  
 711  static bool8 ReadIPSPatch (Stream *r, long offset, int32 &rom_size)
 712  {
 713  	const int32	IPS_EOF = 0x00454F46l;
 714  	int32		ofs;
 715  	char		fname[6];
 716  
 717  	fname[5] = 0;
 718  	for (int i = 0; i < 5; i++)
 719  	{
 720  		int	c = r->get_char();
 721  		if (c == EOF)
 722  			return (0);
 723  		fname[i] = (char) c;
 724  	}
 725  
 726  	if (strncmp(fname, "PATCH", 5))
 727  		return (0);
 728  
 729  	for (;;)
 730  	{
 731  		long	len, rlen;
 732  		int		rchar;
 733  
 734  		ofs = ReadInt(r, 3);
 735  		if (ofs == -1)
 736  			return (0);
 737  
 738  		if (ofs == IPS_EOF)
 739  			break;
 740  
 741  		ofs -= offset;
 742  
 743  		len = ReadInt(r, 2);
 744  		if (len == -1)
 745  			return (0);
 746  
 747  		if (len)
 748  		{
 749  			if (ofs + len > Memory.ROM_SIZE)
 750  				return (0);
 751  
 752  			while (len--)
 753  			{
 754  				rchar = r->get_char();
 755  				if (rchar == EOF)
 756  					return (0);
 757  				Memory.ROM[ofs++] = (uint8) rchar;
 758  			}
 759  
 760  			if (ofs > rom_size)
 761  				rom_size = ofs;
 762  		}
 763  		else
 764  		{
 765  			rlen = ReadInt(r, 2);
 766  			if (rlen == -1)
 767  				return (0);
 768  
 769  			rchar = r->get_char();
 770  			if (rchar == EOF)
 771  				return (0);
 772  
 773  			if (ofs + rlen > Memory.ROM_SIZE)
 774  				return (0);
 775  
 776  			while (rlen--)
 777  				Memory.ROM[ofs++] = (uint8) rchar;
 778  
 779  			if (ofs > rom_size)
 780  				rom_size = ofs;
 781  		}
 782  	}
 783  
 784  	ofs = ReadInt(r, 3);
 785  	if (ofs != -1 && ofs - offset < rom_size)
 786  		rom_size = ofs - offset;
 787  
 788  	ROMIsPatched = 1;
 789  	return (1);
 790  }
 791  /*
 792  void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &rom_size)
 793  {
 794  	ROMIsPatched = false;
 795  
 796  	FSTREAM		patch_file  = NULL;
 797  	uint32		i;
 798  	long		offset = header ? 512 : 0;
 799  	int			ret;
 800  	bool		flag;
 801  	char		dir[_MAX_DIR + 1], drive[_MAX_DRIVE + 1], name[_MAX_FNAME + 1], ext[_MAX_EXT + 1], ips[_MAX_EXT + 3], fname[PATH_MAX + 1];
 802  	const char	*n;
 803  
 804  	_splitpath(rom_filename, drive, dir, name, ext);
 805  
 806  	// IPS
 807  
 808  	_makepath(fname, drive, dir, name, "ips");
 809  
 810  	if ((patch_file = OPEN_FSTREAM(fname, "rb")) != NULL)
 811  	{
 812  		printf("Using IPS patch %s", fname);
 813  
 814          Stream *s = new fStream(patch_file);
 815  		ret = ReadIPSPatch(s, offset, rom_size);
 816          s->closeStream();
 817  
 818  		if (ret)
 819  		{
 820  			printf("!\n");
 821  			return;
 822  		}
 823  		else
 824  			printf(" failed!\n");
 825  	}
 826  
 827  	if (_MAX_EXT > 6)
 828  	{
 829  		i = 0;
 830  		flag = false;
 831  
 832  		do
 833  		{
 834  			snprintf(ips, 8, "%03d.ips", i);
 835  			_makepath(fname, drive, dir, name, ips);
 836  
 837  			if (!(patch_file = OPEN_FSTREAM(fname, "rb")))
 838  				break;
 839  
 840  			printf("Using IPS patch %s", fname);
 841  
 842              Stream *s = new fStream(patch_file);
 843  			ret = ReadIPSPatch(s, offset, rom_size);
 844              s->closeStream();
 845  
 846  			if (ret)
 847  			{
 848  				printf("!\n");
 849  				flag = true;
 850  			}
 851  			else
 852  			{
 853  				printf(" failed!\n");
 854  				break;
 855  			}
 856  		} while (++i < 1000);
 857  
 858  		if (flag)
 859  			return;
 860  	}
 861  
 862  	if (_MAX_EXT > 3)
 863  	{
 864  		i = 0;
 865  		flag = false;
 866  
 867  		do
 868  		{
 869  			snprintf(ips, _MAX_EXT + 2, "ips%d", i);
 870  			if (strlen(ips) > _MAX_EXT)
 871  				break;
 872  			_makepath(fname, drive, dir, name, ips);
 873  
 874  			if (!(patch_file = OPEN_FSTREAM(fname, "rb")))
 875  				break;
 876  
 877  			printf("Using IPS patch %s", fname);
 878  
 879              Stream *s = new fStream(patch_file);
 880  			ret = ReadIPSPatch(s, offset, rom_size);
 881              s->closeStream();
 882  
 883  			if (ret)
 884  			{
 885  				printf("!\n");
 886  				flag = true;
 887  			}
 888  			else
 889  			{
 890  				printf(" failed!\n");
 891  				break;
 892  			}
 893  		} while (++i != 0);
 894  
 895  		if (flag)
 896  			return;
 897  	}
 898  
 899  	if (_MAX_EXT > 2)
 900  	{
 901  		i = 0;
 902  		flag = false;
 903  
 904  		do
 905  		{
 906  			snprintf(ips, 4, "ip%d", i);
 907  			_makepath(fname, drive, dir, name, ips);
 908  
 909  			if (!(patch_file = OPEN_FSTREAM(fname, "rb")))
 910  				break;
 911  
 912  			printf("Using IPS patch %s", fname);
 913  
 914              Stream *s = new fStream(patch_file);
 915  			ret = ReadIPSPatch(s, offset, rom_size);
 916              s->closeStream();
 917  
 918  			if (ret)
 919  			{
 920  				printf("!\n");
 921  				flag = true;
 922  			}
 923  			else
 924  			{
 925  				printf(" failed!\n");
 926  				break;
 927  			}
 928  		} while (++i < 10);
 929  
 930  		if (flag)
 931  			return;
 932  	}
 933  
 934  	n = S9xGetFilename(".ips", PATCH_DIR);
 935  
 936  	if ((patch_file = OPEN_FSTREAM(n, "rb")) != NULL)
 937  	{
 938  		printf("Using IPS patch %s", n);
 939  
 940          Stream *s = new fStream(patch_file);
 941  		ret = ReadIPSPatch(s, offset, rom_size);
 942          s->closeStream();
 943  
 944  		if (ret)
 945  		{
 946  			printf("!\n");
 947  			return;
 948  		}
 949  		else
 950  			printf(" failed!\n");
 951  	}
 952  
 953  	if (_MAX_EXT > 6)
 954  	{
 955  		i = 0;
 956  		flag = false;
 957  
 958  		do
 959  		{
 960  			snprintf(ips, 9, ".%03d.ips", i);
 961  			n = S9xGetFilename(ips, PATCH_DIR);
 962  
 963  			if (!(patch_file = OPEN_FSTREAM(n, "rb")))
 964  				break;
 965  
 966  			printf("Using IPS patch %s", n);
 967  
 968              Stream *s = new fStream(patch_file);
 969  			ret = ReadIPSPatch(s, offset, rom_size);
 970              s->closeStream();
 971  
 972  			if (ret)
 973  			{
 974  				printf("!\n");
 975  				flag = true;
 976  			}
 977  			else
 978  			{
 979  				printf(" failed!\n");
 980  				break;
 981  			}
 982  		} while (++i < 1000);
 983  
 984  		if (flag)
 985  			return;
 986  	}
 987  
 988  	if (_MAX_EXT > 3)
 989  	{
 990  		i = 0;
 991  		flag = false;
 992  
 993  		do
 994  		{
 995  			snprintf(ips, _MAX_EXT + 3, ".ips%d", i);
 996  			if (strlen(ips) > _MAX_EXT + 1)
 997  				break;
 998  			n = S9xGetFilename(ips, PATCH_DIR);
 999  
1000  			if (!(patch_file = OPEN_FSTREAM(n, "rb")))
1001  				break;
1002  
1003  			printf("Using IPS patch %s", n);
1004  
1005              Stream *s = new fStream(patch_file);
1006  			ret = ReadIPSPatch(s, offset, rom_size);
1007              s->closeStream();
1008  
1009  			if (ret)
1010  			{
1011  				printf("!\n");
1012  				flag = true;
1013  			}
1014  			else
1015  			{
1016  				printf(" failed!\n");
1017  				break;
1018  			}
1019  		} while (++i != 0);
1020  
1021  		if (flag)
1022  			return;
1023  	}
1024  
1025  	if (_MAX_EXT > 2)
1026  	{
1027  		i = 0;
1028  		flag = false;
1029  
1030  		do
1031  		{
1032  			snprintf(ips, 5, ".ip%d", i);
1033  			n = S9xGetFilename(ips, PATCH_DIR);
1034  
1035  			if (!(patch_file = OPEN_FSTREAM(n, "rb")))
1036  				break;
1037  
1038  			printf("Using IPS patch %s", n);
1039  
1040              Stream *s = new fStream(patch_file);
1041  			ret = ReadIPSPatch(s, offset, rom_size);
1042              s->closeStream();
1043  
1044  			if (ret)
1045  			{
1046  				printf("!\n");
1047  				flag = true;
1048  			}
1049  			else
1050  			{
1051  				printf(" failed!\n");
1052  				break;
1053  			}
1054  		} while (++i < 10);
1055  
1056  		if (flag)
1057  			return;
1058  	}
1059  }
1060  */
1061  #endif