backport more changes from snes9x master

This commit is contained in:
Daryl Borth 2018-08-11 14:56:31 -06:00
parent e8f2613841
commit 856a1ac127
38 changed files with 3601 additions and 3133 deletions

View File

@ -32,7 +32,7 @@ Wii homebrew is WiiBrew (www.wiibrew.org).
| UPDATE HISTORY | | UPDATE HISTORY |
•˜———–—––-- - —————————––––– ———–—––-- - —————————––––– ———–—––-- - ————————• •˜———–—––-- - —————————––––– ———–—––-- - —————————––––– ———–—––-- - ————————•
[4.3.8 - August 5, 2018] [4.3.8]
* Add MSU1 support (thanks qwertymodo!) * Add MSU1 support (thanks qwertymodo!)
* Add BPS soft-patching support (thanks qwertymodo!) * Add BPS soft-patching support (thanks qwertymodo!)

View File

@ -16,6 +16,8 @@
#include "fileop.h" #include "fileop.h"
#include "filebrowser.h" #include "filebrowser.h"
#define MAX_CHEATS 100
extern SCheatData Cheat; extern SCheatData Cheat;
/**************************************************************************** /****************************************************************************
@ -32,20 +34,23 @@ static bool LoadCheatFile (int length)
while (offset < length) while (offset < length)
{ {
if(Cheat.num_cheats >= MAX_CHEATS || (length - offset) < 28) if(Cheat.g.size() >= MAX_CHEATS || (length - offset) < 28)
break; break;
memcpy (data, savebuffer+offset, 28); memcpy (data, savebuffer+offset, 28);
offset += 28; offset += 28;
Cheat.c [Cheat.num_cheats].enabled = 0; // cheats always off SCheat c;
Cheat.c [Cheat.num_cheats].byte = data [1]; char name[21];
Cheat.c [Cheat.num_cheats].address = data [2] | (data [3] << 8) | (data [4] << 16); char cheat[10];
Cheat.c [Cheat.num_cheats].saved_byte = data [5]; c.enabled = (data[0] & 4) == 0;
Cheat.c [Cheat.num_cheats].saved = (data [0] & 8) != 0; c.byte = data[1];
memcpy (Cheat.c [Cheat.num_cheats].name, &data[8], 20); c.address = data[2] | (data[3] << 8) | (data[4] << 16);
Cheat.c [Cheat.num_cheats].name[20] = 0; memcpy (name, &data[8], 20);
Cheat.num_cheats++; name[20] = 0;
snprintf (cheat, 10, "%x=%x", c.address, c.byte);
S9xAddCheatGroup (name, cheat);
} }
return true; return true;
} }
@ -59,8 +64,7 @@ static bool LoadCheatFile (int length)
void void
WiiSetupCheats() WiiSetupCheats()
{ {
memset(Cheat.c, 0, sizeof(Cheat.c)); S9xDeleteCheats();
Cheat.num_cheats = 0;
char filepath[1024]; char filepath[1024];
int offset = 0; int offset = 0;

View File

@ -484,7 +484,7 @@ int WiiFileLoader()
if(size <= 0) if(size <= 0)
return 0; return 0;
SNESROMSize = Memory.HeaderRemove(size, Memory.HeaderCount, Memory.ROM); SNESROMSize = Memory.HeaderRemove(size, Memory.ROM);
return SNESROMSize; return SNESROMSize;
} }

View File

@ -2063,11 +2063,14 @@ static int MenuGameSettings()
else if(cheatsBtn.GetState() == STATE_CLICKED) else if(cheatsBtn.GetState() == STATE_CLICKED)
{ {
cheatsBtn.ResetState(); cheatsBtn.ResetState();
if(Cheat.num_cheats > 0)
if(Cheat.g.size() > 0) {
menu = MENU_GAMESETTINGS_CHEATS; menu = MENU_GAMESETTINGS_CHEATS;
else }
else {
InfoPrompt("Cheats file not found!"); InfoPrompt("Cheats file not found!");
} }
}
else if(screenshotBtn.GetState() == STATE_CLICKED) else if(screenshotBtn.GetState() == STATE_CLICKED)
{ {
if (WindowPrompt("Preview Screenshot", "Save a new Preview Screenshot? Current Screenshot image will be overwritten.", "OK", "Cancel")) if (WindowPrompt("Preview Screenshot", "Save a new Preview Screenshot? Current Screenshot image will be overwritten.", "OK", "Cancel"))
@ -2116,10 +2119,10 @@ static int MenuGameCheats()
u16 i = 0; u16 i = 0;
OptionList options; OptionList options;
for(i=0; i < Cheat.num_cheats; i++) for(i=0; i < Cheat.g.size(); i++)
{ {
sprintf (options.name[i], "%s", Cheat.c[i].name); sprintf (options.name[i], "%s", Cheat.g[i].name);
sprintf (options.value[i], "%s", Cheat.c[i].enabled == true ? "On" : "Off"); sprintf (options.value[i], "%s", Cheat.g[i].enabled == true ? "On" : "Off");
} }
options.length = i; options.length = i;
@ -2168,11 +2171,11 @@ static int MenuGameCheats()
if(ret >= 0) if(ret >= 0)
{ {
if(Cheat.c[ret].enabled) if(Cheat.g[ret].enabled)
S9xDisableCheat(ret); S9xDisableCheatGroup(ret);
else else
S9xEnableCheat(ret); S9xEnableCheatGroup(ret);
sprintf (options.value[ret], "%s", Cheat.c[ret].enabled == true ? "On" : "Off"); sprintf (options.value[ret], "%s", Cheat.g[ret].enabled == true ? "On" : "Off");
optionBrowser.TriggerUpdate(); optionBrowser.TriggerUpdate();
} }
@ -3193,17 +3196,11 @@ static int MenuSettingsVideo()
Settings.DisplayFrameRate ^= 1; Settings.DisplayFrameRate ^= 1;
break; break;
case 8: case 8:
GCSettings.sfxOverclock++; GCSettings.superFxSpeed += 10;
if (GCSettings.sfxOverclock > 2)
GCSettings.sfxOverclock = 0; if(GCSettings.superFxSpeed > 200) {
switch(GCSettings.sfxOverclock) GCSettings.superFxSpeed = 100;
{
case 0: Settings.SuperFXSpeedPerLine = 0.417 * 10.5e6; reset_sfx = true; break;
case 1: Settings.SuperFXSpeedPerLine = 0.417 * 40.5e6; reset_sfx = true; break;
case 2: Settings.SuperFXSpeedPerLine = 0.417 * 60.5e6; reset_sfx = true; break;
} }
if (reset_sfx) S9xResetSuperFX();
S9xReset();
break; break;
} }
@ -3247,15 +3244,7 @@ static int MenuSettingsVideo()
sprintf (options.value[6], "PAL (60Hz)"); break; sprintf (options.value[6], "PAL (60Hz)"); break;
} }
sprintf (options.value[7], "%s", Settings.DisplayFrameRate ? "On" : "Off"); sprintf (options.value[7], "%s", Settings.DisplayFrameRate ? "On" : "Off");
switch(GCSettings.sfxOverclock) sprintf (options.value[8], "%d%", GCSettings.superFxSpeed);
{
case 0:
sprintf (options.value[8], "Default"); break;
case 1:
sprintf (options.value[8], "40 Mhz"); break;
case 2:
sprintf (options.value[8], "60 Mhz"); break;
}
optionBrowser.TriggerUpdate(); optionBrowser.TriggerUpdate();
} }

View File

@ -150,7 +150,7 @@ preparePrefsData ()
createXMLSetting("FilterMethod", "Filter Method", toStr(GCSettings.FilterMethod)); createXMLSetting("FilterMethod", "Filter Method", toStr(GCSettings.FilterMethod));
createXMLSetting("xshift", "Horizontal Video Shift", toStr(GCSettings.xshift)); createXMLSetting("xshift", "Horizontal Video Shift", toStr(GCSettings.xshift));
createXMLSetting("yshift", "Vertical Video Shift", toStr(GCSettings.yshift)); createXMLSetting("yshift", "Vertical Video Shift", toStr(GCSettings.yshift));
createXMLSetting("sfxOverclock", "SuperFX Overclock", toStr(GCSettings.sfxOverclock)); createXMLSetting("superFxSpeed", "SuperFX Speed", toStr(GCSettings.superFxSpeed));
createXMLSection("Menu", "Menu Settings"); createXMLSection("Menu", "Menu Settings");
@ -285,19 +285,17 @@ decodePrefsData ()
int verMinor = version[2] - '0'; int verMinor = version[2] - '0';
int verPoint = version[4] - '0'; int verPoint = version[4] - '0';
// first we'll check that the versioning is valid // check that the versioning is valid
if(!(verMajor >= 0 && verMajor <= 9 && if(!(verMajor >= 4 && verMajor <= 9 &&
verMinor >= 0 && verMinor <= 9 && verMinor >= 0 && verMinor <= 9 &&
verPoint >= 0 && verPoint <= 9)) verPoint >= 0 && verPoint <= 9)) {
result = false; result = false;
else if(verMajor < 4) // less than version 4.0.0 }
result = false; // reset settings else {
else if(verMajor == 4 && verMinor == 0 && verPoint < 2) // anything less than 4.0.2
result = false; // reset settings
else
result = true; result = true;
} }
} }
}
if(result) if(result)
{ {
@ -337,7 +335,7 @@ decodePrefsData ()
//Emulation Settings //Emulation Settings
loadXMLSetting(&GCSettings.sfxOverclock, "sfxOverclock"); loadXMLSetting(&GCSettings.superFxSpeed, "superFxSpeed");
// Menu Settings // Menu Settings
@ -391,7 +389,7 @@ void FixInvalidSettings()
if(!(GCSettings.yshift > -50 && GCSettings.yshift < 50)) if(!(GCSettings.yshift > -50 && GCSettings.yshift < 50))
GCSettings.yshift = 0; GCSettings.yshift = 0;
if(!(GCSettings.MusicVolume >= 0 && GCSettings.MusicVolume <= 100)) if(!(GCSettings.MusicVolume >= 0 && GCSettings.MusicVolume <= 100))
GCSettings.MusicVolume = 40; GCSettings.MusicVolume = 20;
if(!(GCSettings.SFXVolume >= 0 && GCSettings.SFXVolume <= 100)) if(!(GCSettings.SFXVolume >= 0 && GCSettings.SFXVolume <= 100))
GCSettings.SFXVolume = 40; GCSettings.SFXVolume = 40;
if(GCSettings.language < 0 || GCSettings.language >= LANG_LENGTH) if(GCSettings.language < 0 || GCSettings.language >= LANG_LENGTH)
@ -443,7 +441,7 @@ DefaultSettings ()
GCSettings.WiimoteOrientation = 0; GCSettings.WiimoteOrientation = 0;
GCSettings.ExitAction = 0; GCSettings.ExitAction = 0;
GCSettings.MusicVolume = 40; GCSettings.MusicVolume = 20;
GCSettings.SFXVolume = 40; GCSettings.SFXVolume = 40;
GCSettings.Rumble = 1; GCSettings.Rumble = 1;
GCSettings.PreviewImage = 0; GCSettings.PreviewImage = 0;
@ -460,6 +458,8 @@ DefaultSettings ()
GCSettings.language = LANG_ENGLISH; GCSettings.language = LANG_ENGLISH;
#endif #endif
GCSettings.superFxSpeed = 100;
/****************** SNES9x Settings ***********************/ /****************** SNES9x Settings ***********************/
// Default ALL to false // Default ALL to false
@ -488,6 +488,7 @@ DefaultSettings ()
// Graphics // Graphics
Settings.Transparency = true; Settings.Transparency = true;
Settings.SupportHiRes = true; Settings.SupportHiRes = true;
Settings.MaxSpriteTilesPerLine = 34;
Settings.SkipFrames = AUTO_FRAMERATE; Settings.SkipFrames = AUTO_FRAMERATE;
Settings.TurboSkipFrames = 19; Settings.TurboSkipFrames = 19;
Settings.DisplayFrameRate = false; Settings.DisplayFrameRate = false;
@ -498,10 +499,7 @@ DefaultSettings ()
Settings.FrameTimePAL = 20000; Settings.FrameTimePAL = 20000;
Settings.FrameTimeNTSC = 16667; Settings.FrameTimeNTSC = 16667;
GCSettings.sfxOverclock = 0; Settings.SuperFXClockMultiplier = 100;
/* Initialize SuperFX CPU to normal speed by default */
Settings.SuperFXSpeedPerLine = 0.417 * 10.5e6;
} }
/**************************************************************************** /****************************************************************************
@ -700,6 +698,8 @@ bool LoadPrefs()
CreateDirectory(dirPath); CreateDirectory(dirPath);
sprintf(dirPath, "%s%s", pathPrefix[GCSettings.LoadMethod], GCSettings.ArtworkFolder); sprintf(dirPath, "%s%s", pathPrefix[GCSettings.LoadMethod], GCSettings.ArtworkFolder);
CreateDirectory(dirPath); CreateDirectory(dirPath);
sprintf(dirPath, "%s%s", pathPrefix[GCSettings.LoadMethod], GCSettings.CheatFolder);
CreateDirectory(dirPath);
} }
ResetText(); ResetText();

View File

@ -761,3 +761,27 @@ void S9xAPULoadState (uint8 *block)
ptr += sizeof(int32); ptr += sizeof(int32);
spc::remainder = GET_LE32(ptr); spc::remainder = GET_LE32(ptr);
} }
bool8 S9xSPCDump (const char *filename)
{
FILE *fs;
uint8 buf[SNES_SPC::spc_file_size];
size_t ignore;
fs = fopen(filename, "wb");
if (!fs)
return (FALSE);
S9xSetSoundMute(TRUE);
spc_core->init_header(buf);
spc_core->save_spc(buf);
ignore = fwrite(buf, SNES_SPC::spc_file_size, 1, fs);
fclose(fs);
S9xSetSoundMute(FALSE);
return (TRUE);
}

View File

@ -200,6 +200,7 @@ void S9xAPUAllowTimeOverflow (bool);
void S9xAPULoadState (uint8 *); void S9xAPULoadState (uint8 *);
void S9xAPUSaveState (uint8 *); void S9xAPUSaveState (uint8 *);
void S9xDumpSPCSnapshot (void); void S9xDumpSPCSnapshot (void);
bool8 S9xSPCDump (const char *);
bool8 S9xInitSound (int, int); bool8 S9xInitSound (int, int);
bool8 S9xOpenSoundDevice (void); bool8 S9xOpenSoundDevice (void);

View File

@ -17,13 +17,20 @@
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja (c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso, (c) Copyright 2009 - 2018 BearOso,
OV2 OV2
(c) Copyright 2017 qwertymodo
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
BS-X C emulator code BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom, (c) Copyright 2005 - 2006 Dreamer Nom,
@ -117,6 +124,9 @@
Sound emulator code used in 1.52+ Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
S-SMP emulator code used in 1.54+
(c) Copyright 2016 byuu
SH assembler code partly based on x86 assembler code SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
@ -130,7 +140,7 @@
(c) Copyright 2006 - 2007 Shay Green (c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso (c) Copyright 2004 - 2018 BearOso
Win32 GUI code Win32 GUI code
(c) Copyright 2003 - 2006 blip, (c) Copyright 2003 - 2006 blip,
@ -138,11 +148,16 @@
Matthew Kendora, Matthew Kendora,
Nach, Nach,
nitsuja nitsuja
(c) Copyright 2009 - 2010 OV2 (c) Copyright 2009 - 2018 OV2
Mac OS GUI code Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2011 zones
Libretro port
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
@ -246,6 +261,9 @@ const char * S9xGoldFingerToRaw (const char *code, uint32 &address, bool8 &sram,
if (sscanf(tmp, "%x", &address) != 1) if (sscanf(tmp, "%x", &address) != 1)
return ("Invalid Gold Finger code."); return ("Invalid Gold Finger code.");
// Correct GoldFinger Address
address = (address & 0x7FFF) | ((address & 0x7F8000) << 1) | 0x8000;
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
{ {
unsigned int byte; unsigned int byte;

View File

@ -17,13 +17,20 @@
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja (c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso, (c) Copyright 2009 - 2018 BearOso,
OV2 OV2
(c) Copyright 2017 qwertymodo
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
BS-X C emulator code BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom, (c) Copyright 2005 - 2006 Dreamer Nom,
@ -117,6 +124,9 @@
Sound emulator code used in 1.52+ Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
S-SMP emulator code used in 1.54+
(c) Copyright 2016 byuu
SH assembler code partly based on x86 assembler code SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
@ -130,7 +140,7 @@
(c) Copyright 2006 - 2007 Shay Green (c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso (c) Copyright 2004 - 2018 BearOso
Win32 GUI code Win32 GUI code
(c) Copyright 2003 - 2006 blip, (c) Copyright 2003 - 2006 blip,
@ -138,11 +148,16 @@
Matthew Kendora, Matthew Kendora,
Nach, Nach,
nitsuja nitsuja
(c) Copyright 2009 - 2010 OV2 (c) Copyright 2009 - 2018 OV2
Mac OS GUI code Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2011 zones
Libretro port
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
@ -178,22 +193,31 @@
#ifndef _CHEATS_H_ #ifndef _CHEATS_H_
#define _CHEATS_H_ #define _CHEATS_H_
#define MAX_CHEATS 150 #include "port.h"
#include <vector>
struct SCheat struct SCheat
{ {
uint32 address; uint32 address;
uint8 byte; uint8 byte;
uint8 saved_byte; uint8 saved_byte;
bool8 conditional;
bool8 cond_true;
uint8 cond_byte;
bool8 enabled; bool8 enabled;
bool8 saved; };
char name[22];
struct SCheatGroup
{
char *name;
bool8 enabled;
std::vector<struct SCheat> c;
}; };
struct SCheatData struct SCheatData
{ {
struct SCheat c[MAX_CHEATS]; std::vector<struct SCheatGroup> g;
uint32 num_cheats; bool8 enabled;
uint8 CWRAM[0x20000]; uint8 CWRAM[0x20000];
uint8 CSRAM[0x10000]; uint8 CSRAM[0x10000];
uint8 CIRAM[0x2000]; uint8 CIRAM[0x2000];
@ -235,20 +259,23 @@ typedef enum
extern SCheatData Cheat; extern SCheatData Cheat;
extern Watch watches[16]; extern Watch watches[16];
void S9xApplyCheat (uint32); int S9xAddCheatGroup (const char *name, const char *cheat);
void S9xApplyCheats (void); int S9xModifyCheatGroup (uint32 index, const char *name, const char *cheat);
void S9xRemoveCheat (uint32); void S9xEnableCheatGroup (uint32 index);
void S9xRemoveCheats (void); void S9xDisableCheatGroup (uint32 index);
void S9xDeleteCheat (uint32);
void S9xDeleteCheats (void); void S9xDeleteCheats (void);
void S9xEnableCheat (uint32); char *S9xCheatGroupToText (uint32 index);
void S9xDisableCheat (uint32); void S9xDeleteCheatGroup (uint32 index);
void S9xAddCheat (bool8, bool8, uint32, uint8); bool8 S9xLoadCheatFile (const char *filename);
bool8 S9xSaveCheatFile (const char *filename);
void S9xUpdateCheatsInMemory (void);
int S9xImportCheatsFromDatabase(const char *filename);
void S9xCheatsDisable (void);
void S9xCheatsEnable (void);
char *S9xCheatValidate (char *cheat);
void S9xInitCheatData (void); void S9xInitCheatData (void);
void S9xInitWatchedAddress (void); void S9xInitWatchedAddress (void);
bool8 S9xLoadCheatFile (const char *);
bool8 S9xSaveCheatFile (const char *);
void S9xStartCheatSearch (SCheatData *); void S9xStartCheatSearch (SCheatData *);
void S9xSearchForChange (SCheatData *, S9xCheatComparisonType, S9xCheatDataSize, bool8, bool8); void S9xSearchForChange (SCheatData *, S9xCheatComparisonType, S9xCheatDataSize, bool8, bool8);
void S9xSearchForValue (SCheatData *, S9xCheatComparisonType, S9xCheatDataSize, uint32, bool8, bool8); void S9xSearchForValue (SCheatData *, S9xCheatComparisonType, S9xCheatDataSize, uint32, bool8, bool8);

View File

@ -17,13 +17,20 @@
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja (c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso, (c) Copyright 2009 - 2018 BearOso,
OV2 OV2
(c) Copyright 2017 qwertymodo
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
BS-X C emulator code BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom, (c) Copyright 2005 - 2006 Dreamer Nom,
@ -117,6 +124,9 @@
Sound emulator code used in 1.52+ Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
S-SMP emulator code used in 1.54+
(c) Copyright 2016 byuu
SH assembler code partly based on x86 assembler code SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
@ -130,7 +140,7 @@
(c) Copyright 2006 - 2007 Shay Green (c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso (c) Copyright 2004 - 2018 BearOso
Win32 GUI code Win32 GUI code
(c) Copyright 2003 - 2006 blip, (c) Copyright 2003 - 2006 blip,
@ -138,11 +148,16 @@
Matthew Kendora, Matthew Kendora,
Nach, Nach,
nitsuja nitsuja
(c) Copyright 2009 - 2010 OV2 (c) Copyright 2009 - 2018 OV2
Mac OS GUI code Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2011 zones
Libretro port
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
@ -174,45 +189,190 @@
Nintendo Co., Limited and its subsidiary companies. Nintendo Co., Limited and its subsidiary companies.
***********************************************************************************/ ***********************************************************************************/
#include "snes9x.h" #include "snes9x.h"
#include "memmap.h" #include "memmap.h"
#include "cheats.h" #include "cheats.h"
#include "bml.h"
static uint8 S9xGetByteFree (uint32); static inline uint8 S9xGetByteFree (uint32 Address)
static void S9xSetByteFree (uint8, uint32);
static uint8 S9xGetByteFree (uint32 address)
{ {
uint32 Cycles = CPU.Cycles; int block = (Address & 0xffffff) >> MEMMAP_SHIFT;
uint32 WaitAddress = CPU.WaitAddress; uint8 *GetAddress = Memory.Map[block];
uint8 byte; uint8 byte;
byte = S9xGetByte(address); if (GetAddress >= (uint8 *) CMemory::MAP_LAST)
{
CPU.WaitAddress = WaitAddress; byte = *(GetAddress + (Address & 0xffff));
CPU.Cycles = Cycles;
return (byte); return (byte);
} }
static void S9xSetByteFree (uint8 byte, uint32 address) switch ((pint) GetAddress)
{ {
uint32 Cycles = CPU.Cycles; case CMemory::MAP_CPU:
uint32 WaitAddress = CPU.WaitAddress; byte = S9xGetCPU(Address & 0xffff);
return (byte);
S9xSetByte(byte, address); case CMemory::MAP_PPU:
if (CPU.InDMAorHDMA && (Address & 0xff00) == 0x2100)
return (OpenBus);
CPU.WaitAddress = WaitAddress; byte = S9xGetPPU(Address & 0xffff);
CPU.Cycles = Cycles; return (byte);
case CMemory::MAP_LOROM_SRAM:
case CMemory::MAP_SA1RAM:
// Address & 0x7fff : offset into bank
// Address & 0xff0000 : bank
// bank >> 1 | offset : SRAM address, unbound
// unbound & SRAMMask : SRAM offset
byte = *(Memory.SRAM + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask));
return (byte);
case CMemory::MAP_LOROM_SRAM_B:
byte = *(Multi.sramB + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Multi.sramMaskB));
return (byte);
case CMemory::MAP_HIROM_SRAM:
case CMemory::MAP_RONLY_SRAM:
byte = *(Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask));
return (byte);
case CMemory::MAP_BWRAM:
byte = *(Memory.BWRAM + ((Address & 0x7fff) - 0x6000));
return (byte);
case CMemory::MAP_DSP:
byte = S9xGetDSP(Address & 0xffff);
return (byte);
case CMemory::MAP_SPC7110_ROM:
byte = S9xGetSPC7110Byte(Address);
return (byte);
case CMemory::MAP_SPC7110_DRAM:
byte = S9xGetSPC7110(0x4800);
return (byte);
case CMemory::MAP_C4:
byte = S9xGetC4(Address & 0xffff);
return (byte);
case CMemory::MAP_OBC_RAM:
byte = S9xGetOBC1(Address & 0xffff);
return (byte);
case CMemory::MAP_SETA_DSP:
byte = S9xGetSetaDSP(Address);
return (byte);
case CMemory::MAP_SETA_RISC:
byte = S9xGetST018(Address);
return (byte);
case CMemory::MAP_BSX:
byte = S9xGetBSX(Address);
return (byte);
case CMemory::MAP_NONE:
default:
byte = OpenBus;
return (byte);
}
}
static inline void S9xSetByteFree (uint8 Byte, uint32 Address)
{
int block = (Address & 0xffffff) >> MEMMAP_SHIFT;
uint8 *SetAddress = Memory.Map[block];
if (SetAddress >= (uint8 *) CMemory::MAP_LAST)
{
*(SetAddress + (Address & 0xffff)) = Byte;
return;
}
switch ((pint) SetAddress)
{
case CMemory::MAP_CPU:
S9xSetCPU(Byte, Address & 0xffff);
return;
case CMemory::MAP_PPU:
if (CPU.InDMAorHDMA && (Address & 0xff00) == 0x2100)
return;
S9xSetPPU(Byte, Address & 0xffff);
return;
case CMemory::MAP_LOROM_SRAM:
if (Memory.SRAMMask)
{
*(Memory.SRAM + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask)) = Byte;
CPU.SRAMModified = TRUE;
}
return;
case CMemory::MAP_LOROM_SRAM_B:
if (Multi.sramMaskB)
{
*(Multi.sramB + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Multi.sramMaskB)) = Byte;
CPU.SRAMModified = TRUE;
}
return;
case CMemory::MAP_HIROM_SRAM:
if (Memory.SRAMMask)
{
*(Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask)) = Byte;
CPU.SRAMModified = TRUE;
}
return;
case CMemory::MAP_BWRAM:
*(Memory.BWRAM + ((Address & 0x7fff) - 0x6000)) = Byte;
CPU.SRAMModified = TRUE;
return;
case CMemory::MAP_SA1RAM:
*(Memory.SRAM + (Address & 0xffff)) = Byte;
return;
case CMemory::MAP_DSP:
S9xSetDSP(Byte, Address & 0xffff);
return;
case CMemory::MAP_C4:
S9xSetC4(Byte, Address & 0xffff);
return;
case CMemory::MAP_OBC_RAM:
S9xSetOBC1(Byte, Address & 0xffff);
return;
case CMemory::MAP_SETA_DSP:
S9xSetSetaDSP(Byte, Address);
return;
case CMemory::MAP_SETA_RISC:
S9xSetST018(Byte, Address);
return;
case CMemory::MAP_BSX:
S9xSetBSX(Byte, Address);
return;
case CMemory::MAP_NONE:
default:
return;
}
} }
void S9xInitWatchedAddress (void) void S9xInitWatchedAddress (void)
{ {
for (unsigned int i = 0; i < sizeof(watches) / sizeof(watches[0]); i++) for (unsigned int i = 0; i < sizeof(watches) / sizeof(watches[0]); i++)
watches[i].on = false; watches[i].on = false;
} }
void S9xInitCheatData (void) void S9xInitCheatData (void)
@ -222,133 +382,416 @@ void S9xInitCheatData (void)
Cheat.FillRAM = Memory.FillRAM; Cheat.FillRAM = Memory.FillRAM;
} }
void S9xAddCheat (bool8 enable, bool8 save_current_value, uint32 address, uint8 byte)
{
if (Cheat.num_cheats < sizeof(Cheat.c) / sizeof(Cheat.c[0]))
{
Cheat.c[Cheat.num_cheats].address = address;
Cheat.c[Cheat.num_cheats].byte = byte;
Cheat.c[Cheat.num_cheats].enabled = enable;
if (save_current_value) void S9xUpdateCheatInMemory (SCheat *c)
{ {
Cheat.c[Cheat.num_cheats].saved_byte = S9xGetByteFree(address); uint8 byte;
Cheat.c[Cheat.num_cheats].saved = TRUE;
if (!c->enabled)
return;
byte = S9xGetByteFree (c->address);
if (byte != c->byte)
{
/* The game wrote a different byte to the address, update saved_byte */
c->saved_byte = byte;
if (c->conditional)
{
if (c->saved_byte != c->cond_byte && c->cond_true)
{
/* Condition is now false, let the byte stand */
c->cond_true = false;
}
else if (c->saved_byte == c->cond_byte && !c->cond_true)
{
c->cond_true = true;
S9xSetByteFree (c->byte, c->address);
}
}
else
S9xSetByteFree (c->byte, c->address);
}
else if (c->conditional)
{
if (byte == c->cond_byte)
{
c->cond_true = true;
c->saved_byte = byte;
S9xSetByteFree (c->byte, c->address);
} }
Cheat.num_cheats++;
} }
} }
void S9xDeleteCheat (uint32 which1) void S9xDisableCheat (SCheat *c)
{ {
if (which1 < Cheat.num_cheats) if (!c->enabled)
return;
if (!Cheat.enabled)
{ {
if (Cheat.c[which1].enabled) c->enabled = false;
S9xRemoveCheat(which1); return;
memmove(&Cheat.c[which1], &Cheat.c[which1 + 1], sizeof(Cheat.c[0]) * (Cheat.num_cheats - which1 - 1));
Cheat.num_cheats--;
} }
/* Make sure we restore the up-to-date written byte */
S9xUpdateCheatInMemory (c);
c->enabled = false;
if (c->conditional && !c->cond_true)
return;
S9xSetByteFree (c->saved_byte, c->address);
c->cond_true = false;
}
void S9xDeleteCheatGroup (uint32 g)
{
unsigned int i;
if (g >= Cheat.g.size ())
return;
for (i = 0; i < Cheat.g[g].c.size (); i++)
{
S9xDisableCheat (&Cheat.g[g].c[i]);
}
delete[] Cheat.g[g].name;
Cheat.g.erase (Cheat.g.begin () + g);
} }
void S9xDeleteCheats (void) void S9xDeleteCheats (void)
{ {
S9xRemoveCheats(); unsigned int i;
Cheat.num_cheats = 0;
for (i = 0; i < Cheat.g.size (); i++)
{
S9xDisableCheatGroup (i);
delete[] Cheat.g[i].name;
} }
void S9xRemoveCheat (uint32 which1) Cheat.g.clear ();
{ }
if (Cheat.c[which1].saved)
{
uint32 address = Cheat.c[which1].address;
int block = (address & 0xffffff) >> MEMMAP_SHIFT; void S9xEnableCheat (SCheat *c)
uint8 *ptr = Memory.Map[block]; {
uint8 byte;
if (c->enabled)
return;
c->enabled = true;
if (!Cheat.enabled)
return;
byte = S9xGetByteFree(c->address);
if (c->conditional)
{
if (byte != c->cond_byte)
return;
c->cond_true = true;
}
c->saved_byte = byte;
S9xSetByteFree (c->byte, c->address);
}
void S9xEnableCheatGroup (uint32 num)
{
unsigned int i;
for (i = 0; i < Cheat.g[num].c.size (); i++)
{
S9xEnableCheat (&Cheat.g[num].c[i]);
}
Cheat.g[num].enabled = true;
}
void S9xDisableCheatGroup (uint32 num)
{
unsigned int i;
for (i = 0; i < Cheat.g[num].c.size (); i++)
{
S9xDisableCheat (&Cheat.g[num].c[i]);
}
Cheat.g[num].enabled = false;
}
SCheat S9xTextToCheat (char *text)
{
SCheat c;
unsigned int byte = 0;
unsigned int cond_byte = 0;
c.enabled = false;
c.conditional = false;
if (!S9xGameGenieToRaw (text, c.address, c.byte))
{
byte = c.byte;
}
else if (!S9xProActionReplayToRaw (text, c.address, c.byte))
{
byte = c.byte;
}
else if (sscanf (text, "%x = %x ? %x", &c.address, &cond_byte, &byte) == 3)
{
c.conditional = true;
}
else if (sscanf (text, "%x = %x", &c.address, &byte) == 2)
{
}
else if (sscanf (text, "%x / %x / %x", &c.address, &cond_byte, &byte) == 3)
{
c.conditional = true;
}
else if (sscanf (text, "%x / %x", &c.address, &byte) == 2)
{
}
if (ptr >= (uint8 *) CMemory::MAP_LAST)
*(ptr + (address & 0xffff)) = Cheat.c[which1].saved_byte;
else else
S9xSetByteFree(Cheat.c[which1].saved_byte, address); {
c.address = 0;
byte = 0;
}
c.byte = byte;
c.cond_byte = cond_byte;
return c;
}
SCheatGroup S9xCreateCheatGroup (const char *name, const char *cheat)
{
SCheatGroup g;
char *code;
char *code_string = strdup (cheat);
g.name = strdup (name);
g.enabled = false;
for (code = strtok (code_string, "+"); code; code = strtok (NULL, "+"))
{
if (code)
{
SCheat c = S9xTextToCheat (code);
if (c.address)
g.c.push_back (c);
} }
} }
void S9xRemoveCheats (void) delete[] code_string;
{
for (uint32 i = 0; i < Cheat.num_cheats; i++) return g;
if (Cheat.c[i].enabled)
S9xRemoveCheat(i);
} }
void S9xEnableCheat (uint32 which1) int S9xAddCheatGroup (const char *name, const char *cheat)
{ {
if (which1 < Cheat.num_cheats && !Cheat.c[which1].enabled) SCheatGroup g = S9xCreateCheatGroup (name, cheat);
{ if (g.c.size () == 0)
Cheat.c[which1].enabled = TRUE; return -1;
S9xApplyCheat(which1);
} Cheat.g.push_back (g);
return Cheat.g.size () - 1;
} }
void S9xDisableCheat (uint32 which1) int S9xModifyCheatGroup (uint32 num, const char *name, const char *cheat)
{ {
if (which1 < Cheat.num_cheats && Cheat.c[which1].enabled) if (num >= Cheat.g.size())
{ return -1;
S9xRemoveCheat(which1);
Cheat.c[which1].enabled = FALSE; S9xDisableCheatGroup (num);
} delete[] Cheat.g[num].name;
Cheat.g[num] = S9xCreateCheatGroup (name, cheat);
return num;
} }
void S9xApplyCheat (uint32 which1) char *S9xCheatToText (SCheat *c)
{ {
uint32 address = Cheat.c[which1].address; int size = 10; /* 6 address, 1 =, 2 byte, 1 NUL */
char *text;
if (!Cheat.c[which1].saved) if (c->conditional)
{ size += 3; /* additional 2 byte, 1 ? */
Cheat.c[which1].saved_byte = S9xGetByteFree(address);
Cheat.c[which1].saved = TRUE;
}
int block = (address & 0xffffff) >> MEMMAP_SHIFT; text = new char[size];
uint8 *ptr = Memory.Map[block];
if (ptr >= (uint8 *) CMemory::MAP_LAST) if (c->conditional)
*(ptr + (address & 0xffff)) = Cheat.c[which1].byte; snprintf (text, size, "%06x=%02x?%02x", c->address, c->cond_byte, c->byte);
else else
S9xSetByteFree(Cheat.c[which1].byte, address); snprintf (text, size, "%06x=%02x", c->address, c->byte);
return text;
} }
void S9xApplyCheats (void) char *S9xCheatGroupToText (SCheatGroup *g)
{ {
if (Settings.ApplyCheats) std::string text = "";
unsigned int i;
if (g->c.size () == 0)
return NULL;
for (i = 0; i < g->c.size (); i++)
{ {
for (uint32 i = 0; i < Cheat.num_cheats; i++) char *tmp = S9xCheatToText (&g->c[i]);
if (Cheat.c[i].enabled) if (i != 0)
S9xApplyCheat(i); text += " + ";
text += tmp;
delete[] tmp;
}
return strdup (text.c_str ());
}
char *S9xCheatValidate (char *code_string)
{
SCheatGroup g = S9xCreateCheatGroup ("temp", code_string);
delete[] g.name;
if (g.c.size() > 0)
{
return S9xCheatGroupToText (&g);
}
return NULL;
}
char *S9xCheatGroupToText (uint32 num)
{
if (num >= Cheat.g.size ())
return NULL;
return S9xCheatGroupToText (&Cheat.g[num]);
}
void S9xUpdateCheatsInMemory (void)
{
unsigned int i;
unsigned int j;
if (!Cheat.enabled)
return;
for (i = 0; i < Cheat.g.size (); i++)
{
for (j = 0; j < Cheat.g[i].c.size (); j++)
{
S9xUpdateCheatInMemory (&Cheat.g[i].c[j]);
}
} }
} }
bool8 S9xLoadCheatFile (const char *filename) static int S9xCheatIsDuplicate (char *name, char *code)
{
unsigned int i;
for (i = 0; i < Cheat.g.size(); i++)
{
if (!strcmp (name, Cheat.g[i].name))
{
char *code_string = S9xCheatGroupToText (i);
char *validated = S9xCheatValidate (code);
if (validated && !strcmp (code_string, validated))
{
free (code_string);
free (validated);
return TRUE;
}
free (code_string);
free (validated);
}
}
return FALSE;
}
static void S9xLoadCheatsFromBMLNode (bml_node *n)
{
unsigned int i;
for (i = 0; i < n->child.size (); i++)
{
if (!strcasecmp (n->child[i]->name, "cheat"))
{
char *desc = NULL;
char *code = NULL;
bool8 enabled = false;
bml_node *c = n->child[i];
bml_node *tmp = NULL;
tmp = bml_find_sub(c, "name");
if (!tmp)
desc = (char *) "";
else
desc = tmp->data;
tmp = bml_find_sub(c, "code");
if (tmp)
code = tmp->data;
if (bml_find_sub(c, "enable"))
enabled = true;
if (code && !S9xCheatIsDuplicate (desc, code))
{
int index = S9xAddCheatGroup (desc, code);
if (enabled)
S9xEnableCheatGroup (index);
}
}
}
return;
}
static bool8 S9xLoadCheatFileClassic (const char *filename)
{ {
FILE *fs; FILE *fs;
uint8 data[28]; uint8 data[28];
Cheat.num_cheats = 0;
fs = fopen(filename, "rb"); fs = fopen(filename, "rb");
if (!fs) if (!fs)
return (FALSE); return (FALSE);
while (fread ((void *) data, 1, 28, fs) == 28) while (fread ((void *) data, 1, 28, fs) == 28)
{ {
Cheat.c[Cheat.num_cheats].enabled = (data[0] & 4) == 0; SCheat c;
Cheat.c[Cheat.num_cheats].byte = data[1]; char name[21];
Cheat.c[Cheat.num_cheats].address = data[2] | (data[3] << 8) | (data[4] << 16); char cheat[10];
Cheat.c[Cheat.num_cheats].saved_byte = data[5]; c.enabled = (data[0] & 4) == 0;
Cheat.c[Cheat.num_cheats].saved = (data[0] & 8) != 0; c.byte = data[1];
memmove(Cheat.c[Cheat.num_cheats].name, &data[8], 20); c.address = data[2] | (data[3] << 8) | (data[4] << 16);
Cheat.c[Cheat.num_cheats++].name[20] = 0; memcpy (name, &data[8], 20);
name[20] = 0;
snprintf (cheat, 10, "%x=%x", c.address, c.byte);
S9xAddCheatGroup (name, cheat);
if (c.enabled)
S9xEnableCheatGroup (Cheat.g.size () - 1);
} }
fclose(fs); fclose(fs);
@ -356,51 +799,147 @@ bool8 S9xLoadCheatFile (const char *filename)
return (TRUE); return (TRUE);
} }
bool8 S9xLoadCheatFile (const char *filename)
{
bml_node *bml = NULL;
bml_node *n = NULL;
bml = bml_parse_file (filename);
if (!bml)
{
return S9xLoadCheatFileClassic (filename);
}
n = bml_find_sub (bml, "cheat");
if (n)
{
S9xLoadCheatsFromBMLNode (bml);
}
bml_free_node (bml);
if (!n)
{
return S9xLoadCheatFileClassic (filename);
}
return (TRUE);
}
bool8 S9xSaveCheatFile (const char *filename) bool8 S9xSaveCheatFile (const char *filename)
{ {
if (Cheat.num_cheats == 0) unsigned int i;
FILE *file = NULL;
if (Cheat.g.size () == 0)
{ {
remove (filename); remove (filename);
return (TRUE); return TRUE;
} }
FILE *fs; file = fopen (filename, "w");
uint8 data[28];
fs = fopen(filename, "wb"); if (!file)
if (!fs) return FALSE;
return (FALSE);
for (uint32 i = 0; i < Cheat.num_cheats; i++) for (i = 0; i < Cheat.g.size (); i++)
{ {
ZeroMemory(data, 28); char *txt = S9xCheatGroupToText (i);
if (i == 0) fprintf (file,
"cheat\n"
" name: %s\n"
" code: %s\n"
"%s\n",
Cheat.g[i].name ? Cheat.g[i].name : "",
txt,
Cheat.g[i].enabled ? " enable\n" : ""
);
delete[] txt;
}
fclose (file);
return TRUE;
}
void S9xCheatsDisable (void)
{ {
data[6] = 254; unsigned int i;
data[7] = 252;
}
if (!Cheat.c[i].enabled) if (!Cheat.enabled)
data[0] |= 4; return;
if (Cheat.c[i].saved) for (i = 0; i < Cheat.g.size (); i++)
data[0] |= 8;
data[1] = Cheat.c[i].byte;
data[2] = (uint8) (Cheat.c[i].address >> 0);
data[3] = (uint8) (Cheat.c[i].address >> 8);
data[4] = (uint8) (Cheat.c[i].address >> 16);
data[5] = Cheat.c[i].saved_byte;
memmove(&data[8], Cheat.c[i].name, 19);
if (fwrite(data, 28, 1, fs) != 1)
{ {
fclose(fs); if (Cheat.g[i].enabled)
return (FALSE); {
S9xDisableCheatGroup (i);
Cheat.g[i].enabled = TRUE;
} }
} }
return (fclose(fs) == 0); Cheat.enabled = FALSE;
}
void S9xCheatsEnable (void)
{
unsigned int i;
if (Cheat.enabled)
return;
Cheat.enabled = TRUE;
for (i = 0; i < Cheat.g.size (); i++)
{
if (Cheat.g[i].enabled)
{
Cheat.g[i].enabled = FALSE;
S9xEnableCheatGroup (i);
}
}
}
int S9xImportCheatsFromDatabase (const char *filename)
{
bml_node *bml;
char sha256_txt[65];
char hextable[] = "0123456789abcdef";
unsigned int i;
bml = bml_parse_file (filename);
if (!bml)
return -1; /* No file */
for (i = 0; i < 32; i++)
{
sha256_txt[i * 2] = hextable[Memory.ROMSHA256[i] >> 4];
sha256_txt[i * 2 + 1] = hextable[Memory.ROMSHA256[i] & 0xf];
}
sha256_txt[64] = '\0';
for (i = 0; i < bml->child.size (); i++)
{
if (!strcasecmp (bml->child[i]->name, "cartridge"))
{
bml_node *n;
if ((n = bml_find_sub (bml->child[i], "sha256")))
{
if (!strcasecmp (n->data, sha256_txt))
{
S9xLoadCheatsFromBMLNode (bml->child[i]);
bml_free_node (bml);
return 0;
}
}
}
}
bml_free_node (bml);
return -2; /* No codes */
} }

View File

@ -17,13 +17,20 @@
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja (c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso, (c) Copyright 2009 - 2018 BearOso,
OV2 OV2
(c) Copyright 2017 qwertymodo
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
BS-X C emulator code BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom, (c) Copyright 2005 - 2006 Dreamer Nom,
@ -117,6 +124,9 @@
Sound emulator code used in 1.52+ Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
S-SMP emulator code used in 1.54+
(c) Copyright 2016 byuu
SH assembler code partly based on x86 assembler code SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
@ -130,7 +140,7 @@
(c) Copyright 2006 - 2007 Shay Green (c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso (c) Copyright 2004 - 2018 BearOso
Win32 GUI code Win32 GUI code
(c) Copyright 2003 - 2006 blip, (c) Copyright 2003 - 2006 blip,
@ -138,11 +148,16 @@
Matthew Kendora, Matthew Kendora,
Nach, Nach,
nitsuja nitsuja
(c) Copyright 2009 - 2010 OV2 (c) Copyright 2009 - 2018 OV2
Mac OS GUI code Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2011 zones
Libretro port
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
@ -181,6 +196,7 @@
#include <string> #include <string>
#include <algorithm> #include <algorithm>
#include <assert.h> #include <assert.h>
#include <ctype.h>
#include "snes9x.h" #include "snes9x.h"
#include "memmap.h" #include "memmap.h"
@ -194,10 +210,6 @@
#include "netplay.h" #include "netplay.h"
#endif #endif
#ifdef GEKKO
#include "../snes9xgx.h"
#endif
using namespace std; using namespace std;
#define NONE (-2) #define NONE (-2)
@ -215,7 +227,8 @@ using namespace std;
#define SUPERSCOPE 10 #define SUPERSCOPE 10
#define ONE_JUSTIFIER 11 #define ONE_JUSTIFIER 11
#define TWO_JUSTIFIERS 12 #define TWO_JUSTIFIERS 12
#define NUMCTLS 13 // This must be LAST #define MACSRIFLE 13
#define NUMCTLS 14 // This must be LAST
#define POLL_ALL NUMCTLS #define POLL_ALL NUMCTLS
@ -229,6 +242,8 @@ using namespace std;
#define JUSTIFIER_START 0x20 #define JUSTIFIER_START 0x20
#define JUSTIFIER_SELECT 0x08 #define JUSTIFIER_SELECT 0x08
#define MACSRIFLE_TRIGGER 0x01
#define MAP_UNKNOWN (-1) #define MAP_UNKNOWN (-1)
#define MAP_NONE 0 #define MAP_NONE 0
#define MAP_BUTTON 1 #define MAP_BUTTON 1
@ -309,6 +324,14 @@ static struct
int8 pads[4]; int8 pads[4];
} mp5[2]; } mp5[2];
static struct
{
int16 x, y;
uint8 buttons;
uint32 ID;
struct crosshair crosshair;
} macsrifle;
static set<struct exemulti *> exemultis; static set<struct exemulti *> exemultis;
static set<uint32> pollmap[NUMCTLS + 1]; static set<uint32> pollmap[NUMCTLS + 1];
static map<uint32, s9xcommand_t> keymap; static map<uint32, s9xcommand_t> keymap;
@ -429,7 +452,6 @@ static const int ptrspeeds[4] = { 1, 1, 4, 8 };
S(ToggleBG2), \ S(ToggleBG2), \
S(ToggleBG3), \ S(ToggleBG3), \
S(ToggleEmuTurbo), \ S(ToggleEmuTurbo), \
S(ToggleHDMA), \
S(ToggleSprites), \ S(ToggleSprites), \
S(ToggleTransparency) \ S(ToggleTransparency) \
@ -455,6 +477,7 @@ static const char *command_names[LAST_COMMAND + 1] =
static void DisplayStateChange (const char *, bool8); static void DisplayStateChange (const char *, bool8);
static void DoGunLatch (int, int); static void DoGunLatch (int, int);
static void DoMacsRifleLatch (int, int);
static int maptype (int); static int maptype (int);
static bool strless (const char *, const char *); static bool strless (const char *, const char *);
static int findstr (const char *, const char **, int); static int findstr (const char *, const char **, int);
@ -505,6 +528,12 @@ static void DoGunLatch (int x, int y)
PPU.GunHLatch = (uint16) x; PPU.GunHLatch = (uint16) x;
} }
static void DoMacsRifleLatch (int x, int y)
{
PPU.GunVLatch = (uint16) (y + 42);// + (int16) macsrifle.adjust_y;
PPU.GunHLatch = (uint16) (x + 76);// + (int16) macsrifle.adjust_x;
}
static int maptype (int t) static int maptype (int t)
{ {
switch (t) switch (t)
@ -516,6 +545,7 @@ static int maptype (int t)
case S9xButtonMouse: case S9xButtonMouse:
case S9xButtonSuperscope: case S9xButtonSuperscope:
case S9xButtonJustifier: case S9xButtonJustifier:
case S9xButtonMacsRifle:
case S9xButtonCommand: case S9xButtonCommand:
case S9xButtonPseudopointer: case S9xButtonPseudopointer:
case S9xButtonPort: case S9xButtonPort:
@ -543,6 +573,7 @@ void S9xControlsReset (void)
mouse[0].buttons &= ~0x30; mouse[0].buttons &= ~0x30;
mouse[1].buttons &= ~0x30; mouse[1].buttons &= ~0x30;
justifier.buttons &= ~JUSTIFIER_SELECT; justifier.buttons &= ~JUSTIFIER_SELECT;
macsrifle.buttons = 0;
} }
void S9xControlsSoftReset (void) void S9xControlsSoftReset (void)
@ -556,6 +587,9 @@ void S9xControlsSoftReset (void)
read_idx[i][j]=0; read_idx[i][j]=0;
FLAG_LATCH = FALSE; FLAG_LATCH = FALSE;
curcontrollers[0] = newcontrollers[0];
curcontrollers[1] = newcontrollers[1];
} }
void S9xUnmapAllControls (void) void S9xUnmapAllControls (void)
@ -627,7 +661,18 @@ void S9xUnmapAllControls (void)
if (!(superscope.crosshair.set & 4)) if (!(superscope.crosshair.set & 4))
superscope.crosshair.bg = 1; superscope.crosshair.bg = 1;
ZeroMemory(pseudobuttons, sizeof(pseudobuttons)); macsrifle.x = macsrifle.y = 0;
macsrifle.buttons = 0;
macsrifle.ID = InvalidControlID;
if (!(macsrifle.crosshair.set & 1))
macsrifle.crosshair.img = 2;
if (!(macsrifle.crosshair.set & 2))
macsrifle.crosshair.fg = 5;
if (!(macsrifle.crosshair.set & 4))
macsrifle.crosshair.bg = 1;
memset(pseudobuttons, 0, sizeof(pseudobuttons));
turbo_time = 1; turbo_time = 1;
} }
@ -683,6 +728,16 @@ void S9xSetController (int port, enum controllers controller, int8 id1, int8 id2
newcontrollers[port] = ONE_JUSTIFIER + id1; newcontrollers[port] = ONE_JUSTIFIER + id1;
return; return;
case CTL_MACSRIFLE:
if (!Settings.MacsRifleMaster)
{
S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select SNES M.A.C.S. Rifle: MacsRifleMaster disabled");
break;
}
newcontrollers[port] = MACSRIFLE;
return;
case CTL_MP5: case CTL_MP5:
if (id1 < -1 || id1 > 7) if (id1 < -1 || id1 > 7)
break; break;
@ -786,6 +841,26 @@ bool S9xVerifyControllers (void)
break; break;
case MACSRIFLE:
if (!Settings.MacsRifleMaster)
{
S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select SNES M.A.C.S. Rifle: MacsRifleMaster disabled");
newcontrollers[port] = NONE;
ret = true;
break;
}
if (used[i]++ > 0)
{
snprintf(buf, sizeof(buf), "M.A.C.S. Rifle used more than once! Disabling extra instances");
S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, buf);
newcontrollers[port] = NONE;
ret = true;
break;
}
break;
case MP5: case MP5:
if (!Settings.MultiPlayer5Master) if (!Settings.MultiPlayer5Master)
{ {
@ -887,6 +962,11 @@ void S9xGetController (int port, enum controllers *controller, int8 *id1, int8 *
*controller = CTL_JUSTIFIER; *controller = CTL_JUSTIFIER;
*id1 = i - ONE_JUSTIFIER; *id1 = i - ONE_JUSTIFIER;
return; return;
case MACSRIFLE:
*controller = CTL_MACSRIFLE;
*id1 = 1;
return;
} }
} }
@ -955,6 +1035,13 @@ void S9xReportControllers (void)
else else
c += sprintf(c, "Blue and Pink Justifiers. "); c += sprintf(c, "Blue and Pink Justifiers. ");
break; break;
case MACSRIFLE:
if (port == 0)
c += sprintf(c, "M.A.C.S. Rifle (cannot fire). ");
else
c += sprintf(c, "M.A.C.S. Rifle. ");
break;
} }
} }
@ -1042,6 +1129,17 @@ char * S9xGetCommandName (s9xcommand_t command)
break; break;
case S9xButtonMacsRifle:
if (!command.button.macsrifle.trigger)
return (strdup("None"));
s = "MacsRifle";
c = ' ';
if (command.button.macsrifle.trigger) { s += c; s += "Trigger"; c = '+'; }
break;
case S9xButtonCommand: case S9xButtonCommand:
if (command.button.command >= LAST_COMMAND) if (command.button.command >= LAST_COMMAND)
return (strdup("None")); return (strdup("None"));
@ -1049,7 +1147,7 @@ char * S9xGetCommandName (s9xcommand_t command)
return (strdup(command_names[command.button.command])); return (strdup(command_names[command.button.command]));
case S9xPointer: case S9xPointer:
if (!command.pointer.aim_mouse0 && !command.pointer.aim_mouse1 && !command.pointer.aim_scope && !command.pointer.aim_justifier0 && !command.pointer.aim_justifier1) if (!command.pointer.aim_mouse0 && !command.pointer.aim_mouse1 && !command.pointer.aim_scope && !command.pointer.aim_justifier0 && !command.pointer.aim_justifier1 && !command.pointer.aim_macsrifle)
return (strdup("None")); return (strdup("None"));
s = "Pointer"; s = "Pointer";
@ -1060,6 +1158,7 @@ char * S9xGetCommandName (s9xcommand_t command)
if (command.pointer.aim_scope ) { s += c; s += "Superscope"; c = '+'; } if (command.pointer.aim_scope ) { s += c; s += "Superscope"; c = '+'; }
if (command.pointer.aim_justifier0) { s += c; s += "Justifier1"; c = '+'; } if (command.pointer.aim_justifier0) { s += c; s += "Justifier1"; c = '+'; }
if (command.pointer.aim_justifier1) { s += c; s += "Justifier2"; c = '+'; } if (command.pointer.aim_justifier1) { s += c; s += "Justifier2"; c = '+'; }
if (command.pointer.aim_macsrifle) { s += c; s += "MacsRifle"; c = '+'; }
break; break;
@ -1244,7 +1343,7 @@ s9xcommand_t S9xGetCommandT (const char *name)
int i, j; int i, j;
const char *s; const char *s;
ZeroMemory(&cmd, sizeof(cmd)); memset(&cmd, 0, sizeof(cmd));
cmd.type = S9xBadMapping; cmd.type = S9xBadMapping;
cmd.multi_press = 0; cmd.multi_press = 0;
cmd.button_norpt = 0; cmd.button_norpt = 0;
@ -1393,6 +1492,19 @@ s9xcommand_t S9xGetCommandT (const char *name)
cmd.type = S9xButtonJustifier; cmd.type = S9xButtonJustifier;
} }
else else
if (!strncmp(name, "MacsRifle ", 10))
{
s = name + 10;
i = 0;
if ((cmd.button.macsrifle.trigger = strncmp(s, "Trigger", 7) ? 0 : 1)) { s += i = 7; }
if (i == 0 || *s != 0 || *(s - 1) == '+')
return (cmd);
cmd.type = S9xButtonMacsRifle;
}
else
if (!strncmp(name, "Pointer ", 8)) if (!strncmp(name, "Pointer ", 8))
{ {
s = name + 8; s = name + 8;
@ -1402,7 +1514,8 @@ s9xcommand_t S9xGetCommandT (const char *name)
if ((cmd.pointer.aim_mouse1 = strncmp(s, "Mouse2", 6) ? 0 : 1)) { s += i = 6; if (*s == '+') s++; } if ((cmd.pointer.aim_mouse1 = strncmp(s, "Mouse2", 6) ? 0 : 1)) { s += i = 6; if (*s == '+') s++; }
if ((cmd.pointer.aim_scope = strncmp(s, "Superscope", 10) ? 0 : 1)) { s += i = 10; if (*s == '+') s++; } if ((cmd.pointer.aim_scope = strncmp(s, "Superscope", 10) ? 0 : 1)) { s += i = 10; if (*s == '+') s++; }
if ((cmd.pointer.aim_justifier0 = strncmp(s, "Justifier1", 10) ? 0 : 1)) { s += i = 10; if (*s == '+') s++; } if ((cmd.pointer.aim_justifier0 = strncmp(s, "Justifier1", 10) ? 0 : 1)) { s += i = 10; if (*s == '+') s++; }
if ((cmd.pointer.aim_justifier1 = strncmp(s, "Justifier2", 10) ? 0 : 1)) { s += i = 10; } if ((cmd.pointer.aim_justifier1 = strncmp(s, "Justifier2", 10) ? 0 : 1)) { s += i = 10; if (*s == '+') s++; }
if ((cmd.pointer.aim_macsrifle = strncmp(s, "MacsRifle", 9) ? 0 : 1)) { s += i = 9; }
if (i == 0 || *s != 0 || *(s - 1) == '+') if (i == 0 || *s != 0 || *(s - 1) == '+')
return (cmd); return (cmd);
@ -1703,6 +1816,7 @@ void S9xUnmapID (uint32 id)
if (superscope.ID == id) superscope.ID = InvalidControlID; if (superscope.ID == id) superscope.ID = InvalidControlID;
if (justifier.ID[0] == id) justifier.ID[0] = InvalidControlID; if (justifier.ID[0] == id) justifier.ID[0] = InvalidControlID;
if (justifier.ID[1] == id) justifier.ID[1] = InvalidControlID; if (justifier.ID[1] == id) justifier.ID[1] = InvalidControlID;
if (macsrifle.ID == id) macsrifle.ID = InvalidControlID;
if (id >= PseudoPointerBase) if (id >= PseudoPointerBase)
pseudopointer[id - PseudoPointerBase].mapped = false; pseudopointer[id - PseudoPointerBase].mapped = false;
@ -1768,6 +1882,10 @@ bool S9xMapButton (uint32 id, s9xcommand_t mapping, bool poll)
t = ONE_JUSTIFIER + mapping.button.justifier.idx; t = ONE_JUSTIFIER + mapping.button.justifier.idx;
break; break;
case S9xButtonMacsRifle:
t = MACSRIFLE;
break;
case S9xButtonCommand: case S9xButtonCommand:
case S9xButtonPseudopointer: case S9xButtonPseudopointer:
case S9xButtonPort: case S9xButtonPort:
@ -1874,6 +1992,12 @@ bool S9xMapPointer (uint32 id, s9xcommand_t mapping, bool poll)
fprintf(stderr, "ERROR: Rejecting attempt to control Justifier2 with two pointers\n"); fprintf(stderr, "ERROR: Rejecting attempt to control Justifier2 with two pointers\n");
return (false); return (false);
} }
if (mapping.pointer.aim_macsrifle && macsrifle.ID != InvalidControlID && macsrifle.ID != id)
{
fprintf(stderr, "ERROR: Rejecting attempt to control M.A.C.S. Rifle with two pointers\n");
return (false);
}
} }
S9xUnmapID(id); S9xUnmapID(id);
@ -1892,6 +2016,7 @@ bool S9xMapPointer (uint32 id, s9xcommand_t mapping, bool poll)
if (mapping.pointer.aim_scope ) pollmap[SUPERSCOPE ].insert(id); if (mapping.pointer.aim_scope ) pollmap[SUPERSCOPE ].insert(id);
if (mapping.pointer.aim_justifier0) pollmap[ONE_JUSTIFIER ].insert(id); if (mapping.pointer.aim_justifier0) pollmap[ONE_JUSTIFIER ].insert(id);
if (mapping.pointer.aim_justifier1) pollmap[TWO_JUSTIFIERS].insert(id); if (mapping.pointer.aim_justifier1) pollmap[TWO_JUSTIFIERS].insert(id);
if (mapping.pointer.aim_macsrifle ) pollmap[MACSRIFLE ].insert(id);
break; break;
case S9xPointerPort: case S9xPointerPort:
@ -1911,6 +2036,7 @@ bool S9xMapPointer (uint32 id, s9xcommand_t mapping, bool poll)
if (mapping.pointer.aim_scope ) superscope.ID = id; if (mapping.pointer.aim_scope ) superscope.ID = id;
if (mapping.pointer.aim_justifier0) justifier.ID[0] = id; if (mapping.pointer.aim_justifier0) justifier.ID[0] = id;
if (mapping.pointer.aim_justifier1) justifier.ID[1] = id; if (mapping.pointer.aim_justifier1) justifier.ID[1] = id;
if (mapping.pointer.aim_macsrifle ) macsrifle.ID = id;
return (true); return (true);
} }
@ -2054,7 +2180,6 @@ void S9xApplyCommand (s9xcommand_t cmd, int16 data1, int16 data2)
{ {
uint16 r, s, t, st; uint16 r, s, t, st;
s = t = st = 0;
r = cmd.button.joypad.buttons; r = cmd.button.joypad.buttons;
st = r & joypad[cmd.button.joypad.idx].togglestick & joypad[cmd.button.joypad.idx].toggleturbo; st = r & joypad[cmd.button.joypad.idx].togglestick & joypad[cmd.button.joypad.idx].toggleturbo;
r ^= st; r ^= st;
@ -2180,6 +2305,17 @@ void S9xApplyCommand (s9xcommand_t cmd, int16 data1, int16 data2)
return; return;
case S9xButtonMacsRifle:
i = 0;
if (cmd.button.macsrifle.trigger) i |= MACSRIFLE_TRIGGER;
if(data1)
macsrifle.buttons |= i;
else
macsrifle.buttons &= ~i;
return;
case S9xButtonCommand: case S9xButtonCommand:
if (((enum command_numbers) cmd.button.command) >= LAST_COMMAND) if (((enum command_numbers) cmd.button.command) >= LAST_COMMAND)
{ {
@ -2336,7 +2472,7 @@ void S9xApplyCommand (s9xcommand_t cmd, int16 data1, int16 data2)
if (S9xUnfreezeGame(filename)) if (S9xUnfreezeGame(filename))
{ {
sprintf(buf, "%s.%.*s loaded", def, _MAX_EXT - 1, "oops"); snprintf(buf, 256, "%s.%.*s loaded", def, _MAX_EXT - 1, "oops");
S9xSetInfoString (buf); S9xSetInfoString (buf);
} }
else else
@ -2373,7 +2509,7 @@ void S9xApplyCommand (s9xcommand_t cmd, int16 data1, int16 data2)
if (S9xUnfreezeGame(filename)) if (S9xUnfreezeGame(filename))
{ {
sprintf(buf, "%s.%03d loaded", def, i - QuickLoad000); snprintf(buf, 256, "%s.%03d loaded", def, i - QuickLoad000);
S9xSetInfoString(buf); S9xSetInfoString(buf);
} }
else else
@ -2400,7 +2536,7 @@ void S9xApplyCommand (s9xcommand_t cmd, int16 data1, int16 data2)
_splitpath(Memory.ROMFilename, drive, dir, def, ext); _splitpath(Memory.ROMFilename, drive, dir, def, ext);
snprintf(filename, PATH_MAX + 1, "%s%s%s.%03d", S9xGetDirectory(SNAPSHOT_DIR), SLASH_STR, def, i - QuickSave000); snprintf(filename, PATH_MAX + 1, "%s%s%s.%03d", S9xGetDirectory(SNAPSHOT_DIR), SLASH_STR, def, i - QuickSave000);
sprintf(buf, "%s.%03d saved", def, i - QuickSave000); snprintf(buf, 256, "%s.%03d saved", def, i - QuickSave000);
S9xSetInfoString(buf); S9xSetInfoString(buf);
S9xFreezeGame(filename); S9xFreezeGame(filename);
@ -2458,11 +2594,6 @@ void S9xApplyCommand (s9xcommand_t cmd, int16 data1, int16 data2)
DisplayStateChange("Sprites", !(Settings.BG_Forced & 16)); DisplayStateChange("Sprites", !(Settings.BG_Forced & 16));
break; break;
case ToggleHDMA:
Settings.DisableHDMA = !Settings.DisableHDMA;
DisplayStateChange("HDMA emulation", !Settings.DisableHDMA);
break;
case ToggleTransparency: case ToggleTransparency:
Settings.Transparency = !Settings.Transparency; Settings.Transparency = !Settings.Transparency;
DisplayStateChange("Transparency effects", Settings.Transparency); DisplayStateChange("Transparency effects", Settings.Transparency);
@ -2580,6 +2711,12 @@ void S9xApplyCommand (s9xcommand_t cmd, int16 data1, int16 data2)
justifier.y[1] = data2; justifier.y[1] = data2;
} }
if (cmd.pointer.aim_macsrifle)
{
macsrifle.x = data1;
macsrifle.y = data2;
}
return; return;
case S9xButtonPseudopointer: case S9xButtonPseudopointer:
@ -2876,8 +3013,9 @@ void S9xSetJoypadLatch (bool latch)
switch (i = curcontrollers[n]) switch (i = curcontrollers[n])
{ {
case MP5: case MP5:
for (int j = 0, k = mp5[n].pads[j]; j < 4; k = mp5[n].pads[++j]) for (int j = 0, k; j < 4; ++j)
{ {
k = mp5[n].pads[j];
if (k == NONE) if (k == NONE)
continue; continue;
do_polling(k); do_polling(k);
@ -2934,6 +3072,10 @@ void S9xSetJoypadLatch (bool latch)
do_polling(ONE_JUSTIFIER); do_polling(ONE_JUSTIFIER);
break; break;
case MACSRIFLE:
do_polling(i);
break;
default: default:
break; break;
} }
@ -2984,6 +3126,10 @@ uint8 S9xReadJOYSERn (int n)
case TWO_JUSTIFIERS: case TWO_JUSTIFIERS:
return (bits); return (bits);
case MACSRIFLE:
do_polling(i);
return (bits | ((macsrifle.buttons & 0x01) ? 1 : 0));
default: default:
return (bits); return (bits);
} }
@ -3079,6 +3225,10 @@ uint8 S9xReadJOYSERn (int n)
return (bits | 1); return (bits | 1);
} }
case MACSRIFLE:
do_polling(i);
return (bits | ((macsrifle.buttons & 0x01) ? 1 : 0));
default: default:
read_idx[n][0]++; read_idx[n][0]++;
return (bits); return (bits);
@ -3146,6 +3296,13 @@ void S9xDoAutoJoypad (void)
WRITE_WORD(Memory.FillRAM + 0x421c + n * 2, 0); WRITE_WORD(Memory.FillRAM + 0x421c + n * 2, 0);
break; break;
case MACSRIFLE:
read_idx[n][0] = 16;
Memory.FillRAM[0x4218 + n * 2] = 0xff;
Memory.FillRAM[0x4219 + n * 2] = macsrifle.buttons;
WRITE_WORD(Memory.FillRAM + 0x421c + n * 2, 0);
break;
default: default:
WRITE_WORD(Memory.FillRAM + 0x4218 + n * 2, 0); WRITE_WORD(Memory.FillRAM + 0x4218 + n * 2, 0);
WRITE_WORD(Memory.FillRAM + 0x421c + n * 2, 0); WRITE_WORD(Memory.FillRAM + 0x421c + n * 2, 0);
@ -3167,8 +3324,9 @@ void S9xControlEOF (void)
switch (i = curcontrollers[n]) switch (i = curcontrollers[n])
{ {
case MP5: case MP5:
for (j = 0, i = mp5[n].pads[j]; j < 4; i = mp5[n].pads[++j]) for (j = 0; j < 4; ++j)
{ {
i = mp5[n].pads[j];
if (i == NONE) if (i == NONE)
continue; continue;
@ -3211,9 +3369,6 @@ void S9xControlEOF (void)
DoGunLatch(superscope.x, superscope.y); DoGunLatch(superscope.x, superscope.y);
c = &superscope.crosshair; c = &superscope.crosshair;
#ifdef GEKKO
if(GCSettings.crosshair)
#endif
if (IPPU.RenderThisFrame) if (IPPU.RenderThisFrame)
S9xDrawCrosshair(S9xGetCrosshair(c->img), c->fg, c->bg, superscope.x, superscope.y); S9xDrawCrosshair(S9xGetCrosshair(c->img), c->fg, c->bg, superscope.x, superscope.y);
} }
@ -3224,9 +3379,6 @@ void S9xControlEOF (void)
if (n == 1 && !justifier.offscreen[1]) if (n == 1 && !justifier.offscreen[1])
{ {
c = &justifier.crosshair[1]; c = &justifier.crosshair[1];
#ifdef GEKKO
if(GCSettings.crosshair)
#endif
if (IPPU.RenderThisFrame) if (IPPU.RenderThisFrame)
S9xDrawCrosshair(S9xGetCrosshair(c->img), c->fg, c->bg, justifier.x[1], justifier.y[1]); S9xDrawCrosshair(S9xGetCrosshair(c->img), c->fg, c->bg, justifier.x[1], justifier.y[1]);
} }
@ -3246,9 +3398,6 @@ void S9xControlEOF (void)
if (!justifier.offscreen[0]) if (!justifier.offscreen[0])
{ {
c = &justifier.crosshair[0]; c = &justifier.crosshair[0];
#ifdef GEKKO
if(GCSettings.crosshair)
#endif
if (IPPU.RenderThisFrame) if (IPPU.RenderThisFrame)
S9xDrawCrosshair(S9xGetCrosshair(c->img), c->fg, c->bg, justifier.x[0], justifier.y[0]); S9xDrawCrosshair(S9xGetCrosshair(c->img), c->fg, c->bg, justifier.x[0], justifier.y[0]);
} }
@ -3256,6 +3405,18 @@ void S9xControlEOF (void)
break; break;
case MACSRIFLE:
if (n == 1)
{
DoMacsRifleLatch(macsrifle.x, macsrifle.y);
c = &macsrifle.crosshair;
if (IPPU.RenderThisFrame)
S9xDrawCrosshair(S9xGetCrosshair(c->img), c->fg, c->bg, macsrifle.x, macsrifle.y);
}
break;
default: default:
break; break;
} }
@ -3361,6 +3522,7 @@ void S9xSetControllerCrosshair (enum crosscontrols ctl, int8 idx, const char *fg
case X_SUPERSCOPE: c = &superscope.crosshair; break; case X_SUPERSCOPE: c = &superscope.crosshair; break;
case X_JUSTIFIER1: c = &justifier.crosshair[0]; break; case X_JUSTIFIER1: c = &justifier.crosshair[0]; break;
case X_JUSTIFIER2: c = &justifier.crosshair[1]; break; case X_JUSTIFIER2: c = &justifier.crosshair[1]; break;
case X_MACSRIFLE: c = &macsrifle.crosshair; break;
default: default:
fprintf(stderr, "S9xSetControllerCrosshair() called with an invalid controller ID %d\n", ctl); fprintf(stderr, "S9xSetControllerCrosshair() called with an invalid controller ID %d\n", ctl);
return; return;
@ -3378,6 +3540,7 @@ void S9xSetControllerCrosshair (enum crosscontrols ctl, int8 idx, const char *fg
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
{ {
for (j = 0; color_names[i][j] && fg[j] == color_names[i][j]; j++) ; for (j = 0; color_names[i][j] && fg[j] == color_names[i][j]; j++) ;
if (isalnum(fg[j])) if (isalnum(fg[j]))
continue; continue;
@ -3405,6 +3568,7 @@ void S9xSetControllerCrosshair (enum crosscontrols ctl, int8 idx, const char *fg
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
{ {
for (j = 0; color_names[i][j] && bg[j] == color_names[i][j]; j++) ; for (j = 0; color_names[i][j] && bg[j] == color_names[i][j]; j++) ;
if (isalnum(bg[j])) if (isalnum(bg[j]))
continue; continue;
@ -3450,6 +3614,7 @@ void S9xGetControllerCrosshair (enum crosscontrols ctl, int8 *idx, const char **
case X_SUPERSCOPE: c = &superscope.crosshair; break; case X_SUPERSCOPE: c = &superscope.crosshair; break;
case X_JUSTIFIER1: c = &justifier.crosshair[0]; break; case X_JUSTIFIER1: c = &justifier.crosshair[0]; break;
case X_JUSTIFIER2: c = &justifier.crosshair[1]; break; case X_JUSTIFIER2: c = &justifier.crosshair[1]; break;
case X_MACSRIFLE: c = &macsrifle.crosshair; break;
default: default:
fprintf(stderr, "S9xGetControllerCrosshair() called with an invalid controller ID %d\n", ctl); fprintf(stderr, "S9xGetControllerCrosshair() called with an invalid controller ID %d\n", ctl);
return; return;
@ -3467,8 +3632,8 @@ void S9xGetControllerCrosshair (enum crosscontrols ctl, int8 *idx, const char **
void S9xControlPreSaveState (struct SControlSnapshot *s) void S9xControlPreSaveState (struct SControlSnapshot *s)
{ {
ZeroMemory(s, sizeof(*s)); memset(s, 0, sizeof(*s));
s->ver = 3; s->ver = 4;
for (int j = 0; j < 2; j++) for (int j = 0; j < 2; j++)
{ {
@ -3517,7 +3682,11 @@ void S9xControlPreSaveState (struct SControlSnapshot *s)
for (int k = 0; k < 2; k++) for (int k = 0; k < 2; k++)
COPY(mp5[j].pads[k]); COPY(mp5[j].pads[k]);
assert(i == sizeof(s->internal)); COPY(macsrifle.x);
COPY(macsrifle.y);
COPY(macsrifle.buttons);
assert(i == sizeof(s->internal) + sizeof(s->internal_macs));
#undef COPY #undef COPY
@ -3590,6 +3759,15 @@ void S9xControlPostLoadState (struct SControlSnapshot *s)
assert(i == sizeof(s->internal)); assert(i == sizeof(s->internal));
if (s->ver > 3)
{
COPY(macsrifle.x);
COPY(macsrifle.y);
COPY(macsrifle.buttons);
assert(i == sizeof(s->internal) + sizeof(s->internal_macs));
}
#undef COPY #undef COPY
} }
@ -3708,3 +3886,30 @@ void MovieSetJustifier (int i, uint8 in[11])
justifier.offscreen[0] = *ptr++; justifier.offscreen[0] = *ptr++;
justifier.offscreen[1] = *ptr; justifier.offscreen[1] = *ptr;
} }
bool MovieGetMacsRifle (int i, uint8 out[5])
{
if (i < 0 || i > 1 || curcontrollers[i] != MACSRIFLE)
return (false);
uint8 *ptr = out;
WRITE_WORD(ptr, macsrifle.x); ptr += 2;
WRITE_WORD(ptr, macsrifle.y); ptr += 2;
*ptr = macsrifle.buttons;
return (true);
}
void MovieSetMacsRifle (int i, uint8 in[5])
{
if (i < 0 || i > 1 || curcontrollers[i] != MACSRIFLE)
return;
uint8 *ptr = in;
macsrifle.x = READ_WORD(ptr); ptr += 2;
macsrifle.y = READ_WORD(ptr); ptr += 2;
macsrifle.buttons = *ptr;
}

View File

@ -17,13 +17,20 @@
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja (c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso, (c) Copyright 2009 - 2018 BearOso,
OV2 OV2
(c) Copyright 2017 qwertymodo
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
BS-X C emulator code BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom, (c) Copyright 2005 - 2006 Dreamer Nom,
@ -117,6 +124,9 @@
Sound emulator code used in 1.52+ Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
S-SMP emulator code used in 1.54+
(c) Copyright 2016 byuu
SH assembler code partly based on x86 assembler code SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
@ -130,7 +140,7 @@
(c) Copyright 2006 - 2007 Shay Green (c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso (c) Copyright 2004 - 2018 BearOso
Win32 GUI code Win32 GUI code
(c) Copyright 2003 - 2006 blip, (c) Copyright 2003 - 2006 blip,
@ -138,11 +148,16 @@
Matthew Kendora, Matthew Kendora,
Nach, Nach,
nitsuja nitsuja
(c) Copyright 2009 - 2010 OV2 (c) Copyright 2009 - 2018 OV2
Mac OS GUI code Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2011 zones
Libretro port
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
@ -173,7 +188,7 @@
Super NES and Super Nintendo Entertainment System are trademarks of Super NES and Super Nintendo Entertainment System are trademarks of
Nintendo Co., Limited and its subsidiary companies. Nintendo Co., Limited and its subsidiary companies.
***********************************************************************************/ ***********************************************************************************/
#include "port.h"
#ifndef _CONTROLS_H_ #ifndef _CONTROLS_H_
#define _CONTROLS_H_ #define _CONTROLS_H_
@ -185,8 +200,9 @@
#define S9xButtonJustifier 4 #define S9xButtonJustifier 4
#define S9xButtonCommand 5 #define S9xButtonCommand 5
#define S9xButtonMulti 6 #define S9xButtonMulti 6
#define S9xAxisJoypad 7 #define S9xButtonMacsRifle 7
#define S9xPointer 8 #define S9xAxisJoypad 8
#define S9xPointer 9
#define S9xButtonPseudopointer 254 #define S9xButtonPseudopointer 254
#define S9xAxisPseudopointer 253 #define S9xAxisPseudopointer 253
@ -259,6 +275,11 @@ typedef struct
uint8 aim_offscreen:1; // Pretend we're pointing the gun offscreen (ignore the pointer) uint8 aim_offscreen:1; // Pretend we're pointing the gun offscreen (ignore the pointer)
} justifier; } justifier;
struct
{
uint8 trigger:1;
} macsrifle;
int32 multi_idx; int32 multi_idx;
uint16 command; uint16 command;
} button; } button;
@ -296,6 +317,7 @@ typedef struct
uint16 aim_scope:1; uint16 aim_scope:1;
uint16 aim_justifier0:1; uint16 aim_justifier0:1;
uint16 aim_justifier1:1; uint16 aim_justifier1:1;
uint16 aim_macsrifle:1;
} pointer; } pointer;
uint8 port[4]; uint8 port[4];
@ -315,7 +337,8 @@ enum controllers
CTL_MOUSE, // use id1 to specify 0-1 CTL_MOUSE, // use id1 to specify 0-1
CTL_SUPERSCOPE, CTL_SUPERSCOPE,
CTL_JUSTIFIER, // use id1: 0=one justifier, 1=two justifiers CTL_JUSTIFIER, // use id1: 0=one justifier, 1=two justifiers
CTL_MP5 // use id1-id4 to specify pad 0-7 (or -1) CTL_MP5, // use id1-id4 to specify pad 0-7 (or -1)
CTL_MACSRIFLE
}; };
void S9xSetController (int port, enum controllers controller, int8 id1, int8 id2, int8 id3, int8 id4); // port=0-1 void S9xSetController (int port, enum controllers controller, int8 id1, int8 id2, int8 id3, int8 id4); // port=0-1
@ -445,6 +468,7 @@ struct SControlSnapshot
uint8 dummy3[8]; uint8 dummy3[8];
bool8 pad_read, pad_read_last; bool8 pad_read, pad_read_last;
uint8 internal[60]; // yes, we need to save this! uint8 internal[60]; // yes, we need to save this!
uint8 internal_macs[5];
}; };
void S9xControlPreSaveState (struct SControlSnapshot *s); void S9xControlPreSaveState (struct SControlSnapshot *s);

View File

@ -17,13 +17,20 @@
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja (c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso, (c) Copyright 2009 - 2018 BearOso,
OV2 OV2
(c) Copyright 2017 qwertymodo
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
BS-X C emulator code BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom, (c) Copyright 2005 - 2006 Dreamer Nom,
@ -117,6 +124,9 @@
Sound emulator code used in 1.52+ Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
S-SMP emulator code used in 1.54+
(c) Copyright 2016 byuu
SH assembler code partly based on x86 assembler code SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
@ -130,7 +140,7 @@
(c) Copyright 2006 - 2007 Shay Green (c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso (c) Copyright 2004 - 2018 BearOso
Win32 GUI code Win32 GUI code
(c) Copyright 2003 - 2006 blip, (c) Copyright 2003 - 2006 blip,
@ -138,11 +148,16 @@
Matthew Kendora, Matthew Kendora,
Nach, Nach,
nitsuja nitsuja
(c) Copyright 2009 - 2010 OV2 (c) Copyright 2009 - 2018 OV2
Mac OS GUI code Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2011 zones
Libretro port
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
@ -208,12 +223,14 @@ static void S9xResetCPU (void)
static void S9xSoftResetCPU (void) static void S9xSoftResetCPU (void)
{ {
CPU.Cycles = 182; // Or 188. This is the cycle count just after the jump to the Reset Vector. CPU.Cycles = 182; // Or 188. This is the cycle count just after the jump to the Reset Vector.
CPU.PrevCycles = -1; CPU.PrevCycles = CPU.Cycles;
CPU.V_Counter = 0; CPU.V_Counter = 0;
CPU.Flags = CPU.Flags & (DEBUG_MODE_FLAG | TRACE_FLAG); CPU.Flags = CPU.Flags & (DEBUG_MODE_FLAG | TRACE_FLAG);
CPU.PCBase = NULL; CPU.PCBase = NULL;
CPU.IRQActive = FALSE; CPU.NMIPending = FALSE;
CPU.IRQPending = 0; CPU.IRQLine = FALSE;
CPU.IRQTransition = FALSE;
CPU.IRQExternal = FALSE;
CPU.MemSpeed = SLOW_ONE_CYCLE; CPU.MemSpeed = SLOW_ONE_CYCLE;
CPU.MemSpeedx2 = SLOW_ONE_CYCLE * 2; CPU.MemSpeedx2 = SLOW_ONE_CYCLE * 2;
CPU.FastROMSpeed = SLOW_ONE_CYCLE; CPU.FastROMSpeed = SLOW_ONE_CYCLE;
@ -226,9 +243,6 @@ static void S9xSoftResetCPU (void)
CPU.WhichEvent = HC_RENDER_EVENT; CPU.WhichEvent = HC_RENDER_EVENT;
CPU.NextEvent = Timings.RenderPos; CPU.NextEvent = Timings.RenderPos;
CPU.WaitingForInterrupt = FALSE; CPU.WaitingForInterrupt = FALSE;
CPU.WaitAddress = 0xffffffff;
CPU.WaitCounter = 0;
CPU.PBPCAtOpcodeStart = 0xffffffff;
CPU.AutoSaveTimer = 0; CPU.AutoSaveTimer = 0;
CPU.SRAMModified = FALSE; CPU.SRAMModified = FALSE;
@ -252,6 +266,9 @@ static void S9xSoftResetCPU (void)
Timings.H_Max = Timings.H_Max_Master; Timings.H_Max = Timings.H_Max_Master;
Timings.V_Max = Timings.V_Max_Master; Timings.V_Max = Timings.V_Max_Master;
Timings.NMITriggerPos = 0xffff; Timings.NMITriggerPos = 0xffff;
Timings.NextIRQTimer = 0x0fffffff;
Timings.IRQFlagChanging = IRQ_NONE;
if (Model->_5A22 == 2) if (Model->_5A22 == 2)
Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2; Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2;
else else
@ -261,7 +278,6 @@ static void S9xSoftResetCPU (void)
ICPU.S9xOpcodes = S9xOpcodesE1; ICPU.S9xOpcodes = S9xOpcodesE1;
ICPU.S9xOpLengths = S9xOpLengthsM1X1; ICPU.S9xOpLengths = S9xOpLengthsM1X1;
ICPU.CPUExecuting = TRUE;
S9xUnpackStatus(); S9xUnpackStatus();
} }
@ -273,11 +289,9 @@ void S9xReset (void)
memset(Memory.RAM, 0x55, 0x20000); memset(Memory.RAM, 0x55, 0x20000);
memset(Memory.VRAM, 0x00, 0x10000); memset(Memory.VRAM, 0x00, 0x10000);
ZeroMemory(Memory.FillRAM, 0x8000); memset(Memory.FillRAM, 0, 0x8000);
if (Settings.BS)
S9xResetBSX(); S9xResetBSX();
S9xResetCPU(); S9xResetCPU();
S9xResetPPU(); S9xResetPPU();
S9xResetDMA(); S9xResetDMA();
@ -310,7 +324,7 @@ void S9xSoftReset (void)
{ {
S9xResetSaveTimer(FALSE); S9xResetSaveTimer(FALSE);
ZeroMemory(Memory.FillRAM, 0x8000); memset(Memory.FillRAM, 0, 0x8000);
if (Settings.BS) if (Settings.BS)
S9xResetBSX(); S9xResetBSX();

View File

@ -17,13 +17,20 @@
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja (c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso, (c) Copyright 2009 - 2018 BearOso,
OV2 OV2
(c) Copyright 2017 qwertymodo
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
BS-X C emulator code BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom, (c) Copyright 2005 - 2006 Dreamer Nom,
@ -117,6 +124,9 @@
Sound emulator code used in 1.52+ Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
S-SMP emulator code used in 1.54+
(c) Copyright 2016 byuu
SH assembler code partly based on x86 assembler code SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
@ -130,7 +140,7 @@
(c) Copyright 2006 - 2007 Shay Green (c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso (c) Copyright 2004 - 2018 BearOso
Win32 GUI code Win32 GUI code
(c) Copyright 2003 - 2006 blip, (c) Copyright 2003 - 2006 blip,
@ -138,11 +148,16 @@
Matthew Kendora, Matthew Kendora,
Nach, Nach,
nitsuja nitsuja
(c) Copyright 2009 - 2010 OV2 (c) Copyright 2009 - 2018 OV2
Mac OS GUI code Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2011 zones
Libretro port
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
@ -287,6 +302,8 @@ static inline uint32 AbsoluteIndexedIndirectSlow (AccessMode a) // (a,X)
static inline uint32 AbsoluteIndexedIndirect (AccessMode a) // (a,X) static inline uint32 AbsoluteIndexedIndirect (AccessMode a) // (a,X)
{ {
uint16 addr = Immediate16Slow(READ); uint16 addr = Immediate16Slow(READ);
AddCycles(ONE_CYCLE);
addr += Registers.X.W; addr += Registers.X.W;
// Address load wraps within the bank // Address load wraps within the bank

View File

@ -17,13 +17,20 @@
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja (c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso, (c) Copyright 2009 - 2018 BearOso,
OV2 OV2
(c) Copyright 2017 qwertymodo
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
BS-X C emulator code BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom, (c) Copyright 2005 - 2006 Dreamer Nom,
@ -117,6 +124,9 @@
Sound emulator code used in 1.52+ Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
S-SMP emulator code used in 1.54+
(c) Copyright 2016 byuu
SH assembler code partly based on x86 assembler code SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
@ -130,7 +140,7 @@
(c) Copyright 2006 - 2007 Shay Green (c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso (c) Copyright 2004 - 2018 BearOso
Win32 GUI code Win32 GUI code
(c) Copyright 2003 - 2006 blip, (c) Copyright 2003 - 2006 blip,
@ -138,11 +148,16 @@
Matthew Kendora, Matthew Kendora,
Nach, Nach,
nitsuja nitsuja
(c) Copyright 2009 - 2010 OV2 (c) Copyright 2009 - 2018 OV2
Mac OS GUI code Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2011 zones
Libretro port
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
@ -187,29 +202,79 @@
#include "missing.h" #include "missing.h"
#endif #endif
static inline void S9xReschedule (void);
void S9xMainLoop (void) void S9xMainLoop (void)
{ {
#define CHECK_FOR_IRQ_CHANGE() \
if (Timings.IRQFlagChanging) \
{ \
if (Timings.IRQFlagChanging == IRQ_CLEAR_FLAG) \
ClearIRQ(); \
else if (Timings.IRQFlagChanging == IRQ_SET_FLAG) \
SetIRQ(); \
Timings.IRQFlagChanging = IRQ_NONE; \
}
for (;;) for (;;)
{ {
if (CPU.Flags) if (CPU.NMIPending)
{
if (CPU.Flags & NMI_FLAG)
{ {
#ifdef DEBUGGER
if (Settings.TraceHCEvent)
S9xTraceFormattedMessage ("Comparing %d to %d\n", Timings.NMITriggerPos, CPU.Cycles);
#endif
if (Timings.NMITriggerPos <= CPU.Cycles) if (Timings.NMITriggerPos <= CPU.Cycles)
{ {
CPU.Flags &= ~NMI_FLAG; CPU.NMIPending = FALSE;
Timings.NMITriggerPos = 0xffff; Timings.NMITriggerPos = 0xffff;
if (CPU.WaitingForInterrupt) if (CPU.WaitingForInterrupt)
{ {
CPU.WaitingForInterrupt = FALSE; CPU.WaitingForInterrupt = FALSE;
Registers.PCw++; Registers.PCw++;
CPU.Cycles += TWO_CYCLES + ONE_DOT_CYCLE / 2;
while (CPU.Cycles >= CPU.NextEvent)
S9xDoHEventProcessing();
} }
CHECK_FOR_IRQ_CHANGE();
S9xOpcode_NMI(); S9xOpcode_NMI();
} }
} }
if (CPU.Cycles >= Timings.NextIRQTimer)
{
#ifdef DEBUGGER
S9xTraceMessage ("Timer triggered\n");
#endif
S9xUpdateIRQPositions(false);
CPU.IRQLine = TRUE;
}
if (CPU.IRQLine || CPU.IRQExternal)
{
if (CPU.WaitingForInterrupt)
{
CPU.WaitingForInterrupt = FALSE;
Registers.PCw++;
CPU.Cycles += TWO_CYCLES + ONE_DOT_CYCLE / 2;
while (CPU.Cycles >= CPU.NextEvent)
S9xDoHEventProcessing();
}
if (!CheckFlag(IRQ))
{
/* The flag pushed onto the stack is the new value */
CHECK_FOR_IRQ_CHANGE();
S9xOpcode_IRQ();
}
}
/* Change IRQ flag for instructions that set it only on last cycle */
CHECK_FOR_IRQ_CHANGE();
#ifdef DEBUGGER #ifdef DEBUGGER
if ((CPU.Flags & BREAK_FLAG) && !(CPU.Flags & SINGLE_STEP_FLAG)) if ((CPU.Flags & BREAK_FLAG) && !(CPU.Flags & SINGLE_STEP_FLAG))
{ {
@ -226,36 +291,7 @@ void S9xMainLoop (void)
} }
} }
} }
#endif
if (CPU.Flags & IRQ_FLAG)
{
if (CPU.IRQPending)
// FIXME: In case of IRQ during WRAM refresh
CPU.IRQPending--;
else
{
if (CPU.WaitingForInterrupt)
{
CPU.WaitingForInterrupt = FALSE;
Registers.PCw++;
}
if (CPU.IRQActive && !Settings.DisableIRQ)
{
if (!CheckFlag(IRQ))
// in IRQ handler $4211 is supposed to be read, so IRQ_FLAG should be cleared.
S9xOpcode_IRQ();
}
else
CPU.Flags &= ~IRQ_FLAG;
}
}
if (CPU.Flags & SCAN_KEYS_FLAG)
break;
#ifdef DEBUGGER
if (CPU.Flags & DEBUG_MODE_FLAG) if (CPU.Flags & DEBUG_MODE_FLAG)
break; break;
@ -268,17 +304,13 @@ void S9xMainLoop (void)
CPU.Flags |= DEBUG_MODE_FLAG; CPU.Flags |= DEBUG_MODE_FLAG;
} }
#endif #endif
}
#ifdef CPU_SHUTDOWN if (CPU.Flags & SCAN_KEYS_FLAG)
CPU.PBPCAtOpcodeStart = Registers.PBPC; break;
#endif
register uint8 Op; register uint8 Op;
register struct SOpcodes *Opcodes; register struct SOpcodes *Opcodes;
CPU.PrevCycles = CPU.Cycles;
if (CPU.PCBase) if (CPU.PCBase)
{ {
Op = CPU.PCBase[Registers.PCw]; Op = CPU.PCBase[Registers.PCw];
@ -304,13 +336,8 @@ void S9xMainLoop (void)
Registers.PCw++; Registers.PCw++;
(*Opcodes[Op].S9xOpcode)(); (*Opcodes[Op].S9xOpcode)();
if (SA1.Executing) if (Settings.SA1)
S9xSA1MainLoop(); S9xSA1MainLoop();
#if (S9X_ACCURACY_LEVEL <= 2)
while (CPU.Cycles >= CPU.NextEvent)
S9xDoHEventProcessing();
#endif
} }
S9xPackStatus(); S9xPackStatus();
@ -325,76 +352,70 @@ void S9xMainLoop (void)
} }
} }
void S9xSetIRQ (uint32 source) static inline void S9xReschedule (void)
{ {
CPU.IRQActive |= source; switch (CPU.WhichEvent)
CPU.IRQPending = Timings.IRQPendCount; {
CPU.Flags |= IRQ_FLAG; case HC_HBLANK_START_EVENT:
CPU.WhichEvent = HC_HDMA_START_EVENT;
CPU.NextEvent = Timings.HDMAStart;
break;
if (CPU.WaitingForInterrupt) case HC_HDMA_START_EVENT:
{ CPU.WhichEvent = HC_HCOUNTER_MAX_EVENT;
// Force IRQ to trigger immediately after WAI - CPU.NextEvent = Timings.H_Max;
// Final Fantasy Mystic Quest crashes without this. break;
CPU.WaitingForInterrupt = FALSE;
Registers.PCw++; case HC_HCOUNTER_MAX_EVENT:
CPU.WhichEvent = HC_HDMA_INIT_EVENT;
CPU.NextEvent = Timings.HDMAInit;
break;
case HC_HDMA_INIT_EVENT:
CPU.WhichEvent = HC_RENDER_EVENT;
CPU.NextEvent = Timings.RenderPos;
break;
case HC_RENDER_EVENT:
CPU.WhichEvent = HC_WRAM_REFRESH_EVENT;
CPU.NextEvent = Timings.WRAMRefreshPos;
break;
case HC_WRAM_REFRESH_EVENT:
CPU.WhichEvent = HC_HBLANK_START_EVENT;
CPU.NextEvent = Timings.HBlankStart;
break;
} }
#ifdef DEBUGGER
S9xTraceMessage("--- /IRQ low");
#endif
}
void S9xClearIRQ (uint32 source)
{
CPU.IRQActive &= ~source;
if (!CPU.IRQActive)
CPU.Flags &= ~IRQ_FLAG;
#ifdef DEBUGGER
S9xTraceMessage("--- /IRQ high");
#endif
} }
void S9xDoHEventProcessing (void) void S9xDoHEventProcessing (void)
{ {
#ifdef DEBUGGER #ifdef DEBUGGER
static char eventname[13][32] = static char eventname[7][32] =
{ {
"", "",
"HC_HBLANK_START_EVENT", "HC_HBLANK_START_EVENT",
"HC_IRQ_1_3_EVENT ",
"HC_HDMA_START_EVENT ", "HC_HDMA_START_EVENT ",
"HC_IRQ_3_5_EVENT ",
"HC_HCOUNTER_MAX_EVENT", "HC_HCOUNTER_MAX_EVENT",
"HC_IRQ_5_7_EVENT ",
"HC_HDMA_INIT_EVENT ", "HC_HDMA_INIT_EVENT ",
"HC_IRQ_7_9_EVENT ",
"HC_RENDER_EVENT ", "HC_RENDER_EVENT ",
"HC_IRQ_9_A_EVENT ", "HC_WRAM_REFRESH_EVENT"
"HC_WRAM_REFRESH_EVENT",
"HC_IRQ_A_1_EVENT "
}; };
#endif #endif
#ifdef DEBUGGER #ifdef DEBUGGER
if (Settings.TraceHCEvent) if (Settings.TraceHCEvent)
S9xTraceFormattedMessage("--- HC event processing (%s) expected HC:%04d executed HC:%04d", S9xTraceFormattedMessage("--- HC event processing (%s) expected HC:%04d executed HC:%04d VC:%04d",
eventname[CPU.WhichEvent], CPU.NextEvent, CPU.Cycles); eventname[CPU.WhichEvent], CPU.NextEvent, CPU.Cycles, CPU.V_Counter);
#endif
#ifdef CPU_SHUTDOWN
CPU.WaitCounter++;
#endif #endif
switch (CPU.WhichEvent) switch (CPU.WhichEvent)
{ {
case HC_HBLANK_START_EVENT: case HC_HBLANK_START_EVENT:
S9xCheckMissingHTimerPosition(Timings.HBlankStart);
S9xReschedule(); S9xReschedule();
break; break;
case HC_HDMA_START_EVENT: case HC_HDMA_START_EVENT:
S9xCheckMissingHTimerPosition(Timings.HDMAStart);
S9xReschedule(); S9xReschedule();
if (PPU.HDMA && CPU.V_Counter <= PPU.ScreenHeight) if (PPU.HDMA && CPU.V_Counter <= PPU.ScreenHeight)
@ -417,10 +438,11 @@ void S9xDoHEventProcessing (void)
S9xAPUEndScanline(); S9xAPUEndScanline();
CPU.Cycles -= Timings.H_Max; CPU.Cycles -= Timings.H_Max;
S9xAPUSetReferenceTime(CPU.Cycles); if (Timings.NMITriggerPos != 0xffff)
if ((Timings.NMITriggerPos != 0xffff) && (Timings.NMITriggerPos >= Timings.H_Max))
Timings.NMITriggerPos -= Timings.H_Max; Timings.NMITriggerPos -= Timings.H_Max;
if (Timings.NextIRQTimer != 0x0fffffff)
Timings.NextIRQTimer -= Timings.H_Max;
S9xAPUSetReferenceTime(CPU.Cycles);
CPU.V_Counter++; CPU.V_Counter++;
if (CPU.V_Counter >= Timings.V_Max) // V ranges from 0 to Timings.V_Max - 1 if (CPU.V_Counter >= Timings.V_Max) // V ranges from 0 to Timings.V_Max - 1
@ -445,12 +467,9 @@ void S9xDoHEventProcessing (void)
// FIXME: reading $4210 will wait 2 cycles, then perform reading, then wait 4 more cycles. // FIXME: reading $4210 will wait 2 cycles, then perform reading, then wait 4 more cycles.
Memory.FillRAM[0x4210] = Model->_5A22; Memory.FillRAM[0x4210] = Model->_5A22;
CPU.Flags &= ~NMI_FLAG;
Timings.NMITriggerPos = 0xffff;
ICPU.Frame++; ICPU.Frame++;
PPU.HVBeamCounterLatched = 0; PPU.HVBeamCounterLatched = 0;
CPU.Flags |= SCAN_KEYS_FLAG;
} }
// From byuu: // From byuu:
@ -477,11 +496,12 @@ void S9xDoHEventProcessing (void)
else else
Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v1; Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v1;
S9xCheckMissingHTimerPosition(0);
if (CPU.V_Counter == PPU.ScreenHeight + FIRST_VISIBLE_LINE) // VBlank starts from V=225(240). if (CPU.V_Counter == PPU.ScreenHeight + FIRST_VISIBLE_LINE) // VBlank starts from V=225(240).
{ {
S9xEndScreenRefresh(); S9xEndScreenRefresh();
CPU.Flags |= SCAN_KEYS_FLAG;
PPU.HDMA = 0; PPU.HDMA = 0;
// Bits 7 and 6 of $4212 are computed when read in S9xGetPPU. // Bits 7 and 6 of $4212 are computed when read in S9xGetPPU.
#ifdef DEBUGGER #ifdef DEBUGGER
@ -511,9 +531,13 @@ void S9xDoHEventProcessing (void)
Memory.FillRAM[0x4210] = 0x80 | Model->_5A22; Memory.FillRAM[0x4210] = 0x80 | Model->_5A22;
if (Memory.FillRAM[0x4200] & 0x80) if (Memory.FillRAM[0x4200] & 0x80)
{ {
#ifdef DEBUGGER
if (Settings.TraceHCEvent)
S9xTraceFormattedMessage ("NMI Scheduled for next scanline.");
#endif
// FIXME: triggered at HC=6, checked just before the final CPU cycle, // FIXME: triggered at HC=6, checked just before the final CPU cycle,
// then, when to call S9xOpcode_NMI()? // then, when to call S9xOpcode_NMI()?
CPU.Flags |= NMI_FLAG; CPU.NMIPending = TRUE;
Timings.NMITriggerPos = 6 + 6; Timings.NMITriggerPos = 6 + 6;
} }
@ -528,13 +552,11 @@ void S9xDoHEventProcessing (void)
if (CPU.V_Counter == FIRST_VISIBLE_LINE) // V=1 if (CPU.V_Counter == FIRST_VISIBLE_LINE) // V=1
S9xStartScreenRefresh(); S9xStartScreenRefresh();
CPU.NextEvent = -1;
S9xReschedule(); S9xReschedule();
break; break;
case HC_HDMA_INIT_EVENT: case HC_HDMA_INIT_EVENT:
S9xCheckMissingHTimerPosition(Timings.HDMAInit);
S9xReschedule(); S9xReschedule();
if (CPU.V_Counter == 0) if (CPU.V_Counter == 0)
@ -551,7 +573,6 @@ void S9xDoHEventProcessing (void)
if (CPU.V_Counter >= FIRST_VISIBLE_LINE && CPU.V_Counter <= PPU.ScreenHeight) if (CPU.V_Counter >= FIRST_VISIBLE_LINE && CPU.V_Counter <= PPU.ScreenHeight)
RenderLine((uint8) (CPU.V_Counter - FIRST_VISIBLE_LINE)); RenderLine((uint8) (CPU.V_Counter - FIRST_VISIBLE_LINE));
S9xCheckMissingHTimerPosition(Timings.RenderPos);
S9xReschedule(); S9xReschedule();
break; break;
@ -561,28 +582,11 @@ void S9xDoHEventProcessing (void)
S9xTraceFormattedMessage("*** WRAM Refresh HC:%04d", CPU.Cycles); S9xTraceFormattedMessage("*** WRAM Refresh HC:%04d", CPU.Cycles);
#endif #endif
S9xCheckMissingHTimerHalt(Timings.WRAMRefreshPos, SNES_WRAM_REFRESH_CYCLES);
CPU.Cycles += SNES_WRAM_REFRESH_CYCLES; CPU.Cycles += SNES_WRAM_REFRESH_CYCLES;
S9xCheckMissingHTimerPosition(Timings.WRAMRefreshPos);
S9xReschedule(); S9xReschedule();
break; break;
case HC_IRQ_1_3_EVENT:
case HC_IRQ_3_5_EVENT:
case HC_IRQ_5_7_EVENT:
case HC_IRQ_7_9_EVENT:
case HC_IRQ_9_A_EVENT:
case HC_IRQ_A_1_EVENT:
if (PPU.HTimerEnabled && (!PPU.VTimerEnabled || (CPU.V_Counter == PPU.VTimerPosition)))
S9xSetIRQ(PPU_IRQ_SOURCE);
else
if (PPU.VTimerEnabled && (CPU.V_Counter == PPU.VTimerPosition))
S9xSetIRQ(PPU_IRQ_SOURCE);
S9xReschedule();
break;
} }
#ifdef DEBUGGER #ifdef DEBUGGER
@ -591,4 +595,3 @@ void S9xDoHEventProcessing (void)
eventname[CPU.WhichEvent], CPU.NextEvent, CPU.Cycles); eventname[CPU.WhichEvent], CPU.NextEvent, CPU.Cycles);
#endif #endif
} }

View File

@ -17,13 +17,20 @@
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja (c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso, (c) Copyright 2009 - 2018 BearOso,
OV2 OV2
(c) Copyright 2017 qwertymodo
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
BS-X C emulator code BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom, (c) Copyright 2005 - 2006 Dreamer Nom,
@ -117,6 +124,9 @@
Sound emulator code used in 1.52+ Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
S-SMP emulator code used in 1.54+
(c) Copyright 2016 byuu
SH assembler code partly based on x86 assembler code SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
@ -130,7 +140,7 @@
(c) Copyright 2006 - 2007 Shay Green (c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso (c) Copyright 2004 - 2018 BearOso
Win32 GUI code Win32 GUI code
(c) Copyright 2003 - 2006 blip, (c) Copyright 2003 - 2006 blip,
@ -138,11 +148,16 @@
Matthew Kendora, Matthew Kendora,
Nach, Nach,
nitsuja nitsuja
(c) Copyright 2009 - 2010 OV2 (c) Copyright 2009 - 2018 OV2
Mac OS GUI code Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2011 zones
Libretro port
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
@ -179,6 +194,9 @@
#define _CPUEXEC_H_ #define _CPUEXEC_H_
#include "ppu.h" #include "ppu.h"
#ifdef DEBUGGER
#include "debug.h"
#endif
struct SOpcodes struct SOpcodes
{ {
@ -193,7 +211,6 @@ struct SICPU
uint8 _Zero; uint8 _Zero;
uint8 _Negative; uint8 _Negative;
uint8 _Overflow; uint8 _Overflow;
bool8 CPUExecuting;
uint32 ShiftedPB; uint32 ShiftedPB;
uint32 ShiftedDB; uint32 ShiftedDB;
uint32 Frame; uint32 Frame;
@ -217,8 +234,6 @@ void S9xMainLoop (void);
void S9xReset (void); void S9xReset (void);
void S9xSoftReset (void); void S9xSoftReset (void);
void S9xDoHEventProcessing (void); void S9xDoHEventProcessing (void);
void S9xClearIRQ (uint32);
void S9xSetIRQ (uint32);
static inline void S9xUnpackStatus (void) static inline void S9xUnpackStatus (void)
{ {
@ -270,84 +285,4 @@ static inline void S9xFixCycles (void)
} }
} }
static inline void S9xReschedule (void)
{
uint8 next = 0;
int32 hpos = 0;
switch (CPU.WhichEvent)
{
case HC_HBLANK_START_EVENT:
case HC_IRQ_1_3_EVENT:
next = HC_HDMA_START_EVENT;
hpos = Timings.HDMAStart;
break;
case HC_HDMA_START_EVENT:
case HC_IRQ_3_5_EVENT:
next = HC_HCOUNTER_MAX_EVENT;
hpos = Timings.H_Max;
break;
case HC_HCOUNTER_MAX_EVENT:
case HC_IRQ_5_7_EVENT:
next = HC_HDMA_INIT_EVENT;
hpos = Timings.HDMAInit;
break;
case HC_HDMA_INIT_EVENT:
case HC_IRQ_7_9_EVENT:
next = HC_RENDER_EVENT;
hpos = Timings.RenderPos;
break;
case HC_RENDER_EVENT:
case HC_IRQ_9_A_EVENT:
next = HC_WRAM_REFRESH_EVENT;
hpos = Timings.WRAMRefreshPos;
break;
case HC_WRAM_REFRESH_EVENT:
case HC_IRQ_A_1_EVENT:
next = HC_HBLANK_START_EVENT;
hpos = Timings.HBlankStart;
break;
}
if (((int32) PPU.HTimerPosition > CPU.NextEvent) && ((int32) PPU.HTimerPosition < hpos))
{
hpos = (int32) PPU.HTimerPosition;
switch (next)
{
case HC_HDMA_START_EVENT:
next = HC_IRQ_1_3_EVENT;
break;
case HC_HCOUNTER_MAX_EVENT:
next = HC_IRQ_3_5_EVENT;
break;
case HC_HDMA_INIT_EVENT:
next = HC_IRQ_5_7_EVENT;
break;
case HC_RENDER_EVENT:
next = HC_IRQ_7_9_EVENT;
break;
case HC_WRAM_REFRESH_EVENT:
next = HC_IRQ_9_A_EVENT;
break;
case HC_HBLANK_START_EVENT:
next = HC_IRQ_A_1_EVENT;
break;
}
}
CPU.NextEvent = hpos;
CPU.WhichEvent = next;
}
#endif #endif

View File

@ -17,13 +17,20 @@
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja (c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso, (c) Copyright 2009 - 2018 BearOso,
OV2 OV2
(c) Copyright 2017 qwertymodo
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
BS-X C emulator code BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom, (c) Copyright 2005 - 2006 Dreamer Nom,
@ -117,6 +124,9 @@
Sound emulator code used in 1.52+ Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
S-SMP emulator code used in 1.54+
(c) Copyright 2016 byuu
SH assembler code partly based on x86 assembler code SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
@ -130,7 +140,7 @@
(c) Copyright 2006 - 2007 Shay Green (c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso (c) Copyright 2004 - 2018 BearOso
Win32 GUI code Win32 GUI code
(c) Copyright 2003 - 2006 blip, (c) Copyright 2003 - 2006 blip,
@ -138,11 +148,16 @@
Matthew Kendora, Matthew Kendora,
Nach, Nach,
nitsuja nitsuja
(c) Copyright 2009 - 2010 OV2 (c) Copyright 2009 - 2018 OV2
Mac OS GUI code Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2011 zones
Libretro port
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
@ -280,7 +295,6 @@ static void Op##OP (void) \
S9xSetPCBase(ICPU.ShiftedPB + newPC.W); \ S9xSetPCBase(ICPU.ShiftedPB + newPC.W); \
else \ else \
Registers.PCw = newPC.W; \ Registers.PCw = newPC.W; \
CPUShutdown(); \
} \ } \
} }
@ -515,9 +529,6 @@ static inline void CPY (uint8 val)
static inline void DEC16 (uint32 OpAddress, s9xwrap_t w) static inline void DEC16 (uint32 OpAddress, s9xwrap_t w)
{ {
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
uint16 Work16 = S9xGetWord(OpAddress, w) - 1; uint16 Work16 = S9xGetWord(OpAddress, w) - 1;
AddCycles(ONE_CYCLE); AddCycles(ONE_CYCLE);
S9xSetWord(Work16, OpAddress, w, WRITE_10); S9xSetWord(Work16, OpAddress, w, WRITE_10);
@ -527,9 +538,6 @@ static inline void DEC16 (uint32 OpAddress, s9xwrap_t w)
static inline void DEC8 (uint32 OpAddress) static inline void DEC8 (uint32 OpAddress)
{ {
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
uint8 Work8 = S9xGetByte(OpAddress) - 1; uint8 Work8 = S9xGetByte(OpAddress) - 1;
AddCycles(ONE_CYCLE); AddCycles(ONE_CYCLE);
S9xSetByte(Work8, OpAddress); S9xSetByte(Work8, OpAddress);
@ -551,9 +559,6 @@ static inline void EOR (uint8 val)
static inline void INC16 (uint32 OpAddress, s9xwrap_t w) static inline void INC16 (uint32 OpAddress, s9xwrap_t w)
{ {
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
uint16 Work16 = S9xGetWord(OpAddress, w) + 1; uint16 Work16 = S9xGetWord(OpAddress, w) + 1;
AddCycles(ONE_CYCLE); AddCycles(ONE_CYCLE);
S9xSetWord(Work16, OpAddress, w, WRITE_10); S9xSetWord(Work16, OpAddress, w, WRITE_10);
@ -563,9 +568,6 @@ static inline void INC16 (uint32 OpAddress, s9xwrap_t w)
static inline void INC8 (uint32 OpAddress) static inline void INC8 (uint32 OpAddress)
{ {
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
uint8 Work8 = S9xGetByte(OpAddress) + 1; uint8 Work8 = S9xGetByte(OpAddress) + 1;
AddCycles(ONE_CYCLE); AddCycles(ONE_CYCLE);
S9xSetByte(Work8, OpAddress); S9xSetByte(Work8, OpAddress);

View File

@ -17,13 +17,20 @@
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja (c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso, (c) Copyright 2009 - 2018 BearOso,
OV2 OV2
(c) Copyright 2017 qwertymodo
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
BS-X C emulator code BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom, (c) Copyright 2005 - 2006 Dreamer Nom,
@ -117,6 +124,9 @@
Sound emulator code used in 1.52+ Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
S-SMP emulator code used in 1.54+
(c) Copyright 2016 byuu
SH assembler code partly based on x86 assembler code SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
@ -130,7 +140,7 @@
(c) Copyright 2006 - 2007 Shay Green (c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso (c) Copyright 2004 - 2018 BearOso
Win32 GUI code Win32 GUI code
(c) Copyright 2003 - 2006 blip, (c) Copyright 2003 - 2006 blip,
@ -138,11 +148,16 @@
Matthew Kendora, Matthew Kendora,
Nach, Nach,
nitsuja nitsuja
(c) Copyright 2009 - 2010 OV2 (c) Copyright 2009 - 2018 OV2
Mac OS GUI code Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2011 zones
Libretro port
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
@ -188,13 +203,9 @@
#endif #endif
#ifdef SA1_OPCODES #ifdef SA1_OPCODES
#define AddCycles(n) { } #define AddCycles(n) { SA1.Cycles += (n); }
#else #else
#if (S9X_ACCURACY_LEVEL >= 3)
#define AddCycles(n) { CPU.Cycles += (n); while (CPU.Cycles >= CPU.NextEvent) S9xDoHEventProcessing(); } #define AddCycles(n) { CPU.Cycles += (n); while (CPU.Cycles >= CPU.NextEvent) S9xDoHEventProcessing(); }
#else
#define AddCycles(n) { CPU.Cycles += (n); }
#endif
#endif #endif
#include "cpuaddr.h" #include "cpuaddr.h"
@ -659,9 +670,6 @@ rOPX (CCSlow, AbsoluteSlow, WRAP_NONE, CPY)
static void Op3AM1 (void) static void Op3AM1 (void)
{ {
AddCycles(ONE_CYCLE); AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
Registers.AL--; Registers.AL--;
SetZN(Registers.AL); SetZN(Registers.AL);
} }
@ -669,9 +677,6 @@ static void Op3AM1 (void)
static void Op3AM0 (void) static void Op3AM0 (void)
{ {
AddCycles(ONE_CYCLE); AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
Registers.A.W--; Registers.A.W--;
SetZN(Registers.A.W); SetZN(Registers.A.W);
} }
@ -679,9 +684,6 @@ static void Op3AM0 (void)
static void Op3ASlow (void) static void Op3ASlow (void)
{ {
AddCycles(ONE_CYCLE); AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
if (CheckMemory()) if (CheckMemory())
{ {
@ -813,9 +815,6 @@ rOPM (53Slow, StackRelativeIndirectIndexedSlow, WRAP_NONE, EOR)
static void Op1AM1 (void) static void Op1AM1 (void)
{ {
AddCycles(ONE_CYCLE); AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
Registers.AL++; Registers.AL++;
SetZN(Registers.AL); SetZN(Registers.AL);
} }
@ -823,9 +822,6 @@ static void Op1AM1 (void)
static void Op1AM0 (void) static void Op1AM0 (void)
{ {
AddCycles(ONE_CYCLE); AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
Registers.A.W++; Registers.A.W++;
SetZN(Registers.A.W); SetZN(Registers.A.W);
} }
@ -833,9 +829,6 @@ static void Op1AM0 (void)
static void Op1ASlow (void) static void Op1ASlow (void)
{ {
AddCycles(ONE_CYCLE); AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
if (CheckMemory()) if (CheckMemory())
{ {
@ -1550,54 +1543,6 @@ mOPM (0CSlow, AbsoluteSlow, WRAP_BANK, TSB)
/* Branch Instructions ***************************************************** */ /* Branch Instructions ***************************************************** */
#ifdef CPU_SHUTDOWN
#ifndef SA1_OPCODES
inline void CPUShutdown (void)
{
if (Settings.Shutdown && Registers.PBPC == CPU.WaitAddress)
{
// Don't skip cycles with a pending NMI or IRQ - could cause delayed interrupt.
if (CPU.WaitCounter == 0 && !(CPU.Flags & (IRQ_FLAG | NMI_FLAG)))
{
CPU.WaitAddress = 0xffffffff;
if (Settings.SA1)
S9xSA1ExecuteDuringSleep();
CPU.Cycles = CPU.NextEvent;
ICPU.CPUExecuting = FALSE;
S9xAPUExecute();
ICPU.CPUExecuting = TRUE;
}
else
if (CPU.WaitCounter >= 2)
CPU.WaitCounter = 1;
else
CPU.WaitCounter--;
}
}
#else
inline void CPUShutdown (void)
{
if (Settings.Shutdown && Registers.PBPC == CPU.WaitAddress)
{
if (CPU.WaitCounter >= 1)
SA1.Executing = FALSE;
else
CPU.WaitCounter++;
}
}
#endif
#else
#define CPUShutdown()
#endif
// BCC // BCC
bOP(90E0, Relative, !CheckCarry(), 0, 0) bOP(90E0, Relative, !CheckCarry(), 0, 0)
bOP(90E1, Relative, !CheckCarry(), 0, 1) bOP(90E1, Relative, !CheckCarry(), 0, 1)
@ -1690,16 +1635,25 @@ static void OpF8 (void)
// CLI // CLI
static void Op58 (void) static void Op58 (void)
{ {
ClearIRQ();
AddCycles(ONE_CYCLE); AddCycles(ONE_CYCLE);
//CHECK_FOR_IRQ();
#ifndef SA1_OPCODES
Timings.IRQFlagChanging = IRQ_CLEAR_FLAG;
#else
ClearIRQ();
#endif
} }
// SEI // SEI
static void Op78 (void) static void Op78 (void)
{ {
SetIRQ();
AddCycles(ONE_CYCLE); AddCycles(ONE_CYCLE);
#ifndef SA1_OPCODES
Timings.IRQFlagChanging = IRQ_SET_FLAG;
#else
SetIRQ();
#endif
} }
// CLV // CLV
@ -1714,9 +1668,6 @@ static void OpB8 (void)
static void OpCAX1 (void) static void OpCAX1 (void)
{ {
AddCycles(ONE_CYCLE); AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
Registers.XL--; Registers.XL--;
SetZN(Registers.XL); SetZN(Registers.XL);
} }
@ -1724,9 +1675,6 @@ static void OpCAX1 (void)
static void OpCAX0 (void) static void OpCAX0 (void)
{ {
AddCycles(ONE_CYCLE); AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
Registers.X.W--; Registers.X.W--;
SetZN(Registers.X.W); SetZN(Registers.X.W);
} }
@ -1734,9 +1682,6 @@ static void OpCAX0 (void)
static void OpCASlow (void) static void OpCASlow (void)
{ {
AddCycles(ONE_CYCLE); AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
if (CheckIndex()) if (CheckIndex())
{ {
@ -1753,9 +1698,6 @@ static void OpCASlow (void)
static void Op88X1 (void) static void Op88X1 (void)
{ {
AddCycles(ONE_CYCLE); AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
Registers.YL--; Registers.YL--;
SetZN(Registers.YL); SetZN(Registers.YL);
} }
@ -1763,9 +1705,6 @@ static void Op88X1 (void)
static void Op88X0 (void) static void Op88X0 (void)
{ {
AddCycles(ONE_CYCLE); AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
Registers.Y.W--; Registers.Y.W--;
SetZN(Registers.Y.W); SetZN(Registers.Y.W);
} }
@ -1773,9 +1712,6 @@ static void Op88X0 (void)
static void Op88Slow (void) static void Op88Slow (void)
{ {
AddCycles(ONE_CYCLE); AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
if (CheckIndex()) if (CheckIndex())
{ {
@ -1794,9 +1730,6 @@ static void Op88Slow (void)
static void OpE8X1 (void) static void OpE8X1 (void)
{ {
AddCycles(ONE_CYCLE); AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
Registers.XL++; Registers.XL++;
SetZN(Registers.XL); SetZN(Registers.XL);
} }
@ -1804,9 +1737,6 @@ static void OpE8X1 (void)
static void OpE8X0 (void) static void OpE8X0 (void)
{ {
AddCycles(ONE_CYCLE); AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
Registers.X.W++; Registers.X.W++;
SetZN(Registers.X.W); SetZN(Registers.X.W);
} }
@ -1814,9 +1744,6 @@ static void OpE8X0 (void)
static void OpE8Slow (void) static void OpE8Slow (void)
{ {
AddCycles(ONE_CYCLE); AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
if (CheckIndex()) if (CheckIndex())
{ {
@ -1833,9 +1760,6 @@ static void OpE8Slow (void)
static void OpC8X1 (void) static void OpC8X1 (void)
{ {
AddCycles(ONE_CYCLE); AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
Registers.YL++; Registers.YL++;
SetZN(Registers.YL); SetZN(Registers.YL);
} }
@ -1843,9 +1767,6 @@ static void OpC8X1 (void)
static void OpC8X0 (void) static void OpC8X0 (void)
{ {
AddCycles(ONE_CYCLE); AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
Registers.Y.W++; Registers.Y.W++;
SetZN(Registers.Y.W); SetZN(Registers.Y.W);
} }
@ -1853,18 +1774,15 @@ static void OpC8X0 (void)
static void OpC8Slow (void) static void OpC8Slow (void)
{ {
AddCycles(ONE_CYCLE); AddCycles(ONE_CYCLE);
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
if (CheckIndex()) if (CheckIndex())
{ {
Registers.YL--; Registers.YL++;
SetZN(Registers.YL); SetZN(Registers.YL);
} }
else else
{ {
Registers.Y.W--; Registers.Y.W++;
SetZN(Registers.Y.W); SetZN(Registers.Y.W);
} }
} }
@ -2371,7 +2289,7 @@ static void Op28E1 (void)
SetFlags(MemoryFlag | IndexFlag); SetFlags(MemoryFlag | IndexFlag);
S9xUnpackStatus(); S9xUnpackStatus();
S9xFixCycles(); S9xFixCycles();
//CHECK_FOR_IRQ(); CHECK_FOR_IRQ();
} }
static void Op28E0 (void) static void Op28E0 (void)
@ -2388,7 +2306,7 @@ static void Op28E0 (void)
} }
S9xFixCycles(); S9xFixCycles();
//CHECK_FOR_IRQ(); CHECK_FOR_IRQ();
} }
static void Op28Slow (void) static void Op28Slow (void)
@ -2416,7 +2334,7 @@ static void Op28Slow (void)
} }
S9xFixCycles(); S9xFixCycles();
//CHECK_FOR_IRQ(); CHECK_FOR_IRQ();
} }
// PLX // PLX
@ -2985,7 +2903,7 @@ void S9xOpcode_NMI (void)
AddCycles(2 * SLOW_ONE_CYCLE); AddCycles(2 * SLOW_ONE_CYCLE);
S9xSA1SetPCBase(Memory.FillRAM[0x2205] | (Memory.FillRAM[0x2206] << 8)); S9xSA1SetPCBase(Memory.FillRAM[0x2205] | (Memory.FillRAM[0x2206] << 8));
#else #else
if (Settings.SA1 && (Memory.FillRAM[0x2209] & 0x20)) if (Settings.SA1 && (Memory.FillRAM[0x2209] & 0x10))
{ {
OpenBus = Memory.FillRAM[0x220d]; OpenBus = Memory.FillRAM[0x220d];
AddCycles(2 * SLOW_ONE_CYCLE); AddCycles(2 * SLOW_ONE_CYCLE);
@ -3069,17 +2987,11 @@ static void Op5CSlow (void)
static void Op4C (void) static void Op4C (void)
{ {
S9xSetPCBase(ICPU.ShiftedPB + ((uint16) Absolute(JUMP))); S9xSetPCBase(ICPU.ShiftedPB + ((uint16) Absolute(JUMP)));
#if defined(CPU_SHUTDOWN) && defined(SA1_OPCODES)
CPUShutdown();
#endif
} }
static void Op4CSlow (void) static void Op4CSlow (void)
{ {
S9xSetPCBase(ICPU.ShiftedPB + ((uint16) AbsoluteSlow(JUMP))); S9xSetPCBase(ICPU.ShiftedPB + ((uint16) AbsoluteSlow(JUMP)));
#if defined(CPU_SHUTDOWN) && defined(SA1_OPCODES)
CPUShutdown();
#endif
} }
static void Op6C (void) static void Op6C (void)
@ -3425,7 +3337,7 @@ static void OpC2 (void)
} }
S9xFixCycles(); S9xFixCycles();
//CHECK_FOR_IRQ(); CHECK_FOR_IRQ();
} }
static void OpC2Slow (void) static void OpC2Slow (void)
@ -3454,7 +3366,7 @@ static void OpC2Slow (void)
} }
S9xFixCycles(); S9xFixCycles();
//CHECK_FOR_IRQ(); CHECK_FOR_IRQ();
} }
static void OpE2 (void) static void OpE2 (void)
@ -3562,7 +3474,7 @@ static void Op40Slow (void)
} }
S9xFixCycles(); S9xFixCycles();
//CHECK_FOR_IRQ(); CHECK_FOR_IRQ();
} }
/* STP/WAI ***************************************************************** */ /* STP/WAI ***************************************************************** */
@ -3570,45 +3482,17 @@ static void Op40Slow (void)
// WAI // WAI
static void OpCB (void) static void OpCB (void)
{ {
// Ok, let's just C-ify the ASM versions separately.
#ifdef SA1_OPCODES #ifdef SA1_OPCODES
SA1.WaitingForInterrupt = TRUE; SA1.WaitingForInterrupt = TRUE;
Registers.PCw--; Registers.PCw--;
#if 0
// XXX: FIXME
if (Settings.Shutdown)
{
SA1.Cycles = SA1.NextEvent;
SA1.Executing = FALSE;
//S9xAPUExecute(); // FIXME
SA1.Executing = TRUE;
}
#endif
#else // SA1_OPCODES
#if 0
if (CPU.IRQActive)
AddCycles(TWO_CYCLES);
else
#endif
{
CPU.WaitingForInterrupt = TRUE;
Registers.PCw--;
#ifdef CPU_SHUTDOWN
if (Settings.Shutdown)
{
CPU.Cycles = CPU.NextEvent;
ICPU.CPUExecuting = FALSE;
S9xAPUExecute();
ICPU.CPUExecuting = TRUE;
}
else
AddCycles(TWO_CYCLES); AddCycles(TWO_CYCLES);
#else #else
AddCycles(TWO_CYCLES); CPU.WaitingForInterrupt = TRUE;
Registers.PCw--;
AddCycles(ONE_CYCLE);
#endif #endif
} }
#endif // SA1_OPCODES
}
// STP // STP
static void OpDB (void) static void OpDB (void)
@ -3650,7 +3534,7 @@ static void Op42 (void)
S9xMessage(S9X_DEBUG, S9X_DEBUG_OUTPUT, buf); S9xMessage(S9X_DEBUG, S9X_DEBUG_OUTPUT, buf);
if (trace != NULL) if (trace != NULL)
fclose(trace); fclose(trace);
trace = fopen("WDMtrace.log", "ab"); ENSURE_TRACE_OPEN(trace, "WDMtrace.log", "ab")
} }
break; break;
@ -4024,4 +3908,3 @@ struct SOpcodes S9xOpcodesSlow[256] =
{ OpFASlow }, { OpFB }, { OpFCSlow }, { OpFDSlow }, { OpFESlow }, { OpFASlow }, { OpFB }, { OpFCSlow }, { OpFDSlow }, { OpFESlow },
{ OpFFSlow } { OpFFSlow }
}; };

View File

@ -17,13 +17,20 @@
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja (c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso, (c) Copyright 2009 - 2018 BearOso,
OV2 OV2
(c) Copyright 2017 qwertymodo
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
BS-X C emulator code BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom, (c) Copyright 2005 - 2006 Dreamer Nom,
@ -117,6 +124,9 @@
Sound emulator code used in 1.52+ Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
S-SMP emulator code used in 1.54+
(c) Copyright 2016 byuu
SH assembler code partly based on x86 assembler code SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
@ -130,7 +140,7 @@
(c) Copyright 2006 - 2007 Shay Green (c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso (c) Copyright 2004 - 2018 BearOso
Win32 GUI code Win32 GUI code
(c) Copyright 2003 - 2006 blip, (c) Copyright 2003 - 2006 blip,
@ -138,11 +148,16 @@
Matthew Kendora, Matthew Kendora,
Nach, Nach,
nitsuja nitsuja
(c) Copyright 2009 - 2010 OV2 (c) Copyright 2009 - 2018 OV2
Mac OS GUI code Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2011 zones
Libretro port
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
@ -181,8 +196,9 @@
void S9xOpcode_NMI (void); void S9xOpcode_NMI (void);
void S9xOpcode_IRQ (void); void S9xOpcode_IRQ (void);
#define CHECK_FOR_IRQ() \ #ifndef SA1_OPCODES
if (CPU.IRQActive && !CheckFlag(IRQ) && !Settings.DisableIRQ) \ #define CHECK_FOR_IRQ() {} // if (CPU.IRQLine) S9xOpcode_IRQ(); }
S9xOpcode_IRQ() #else
#define CHECK_FOR_IRQ() {}
#endif
#endif #endif

View File

@ -17,13 +17,20 @@
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja (c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso, (c) Copyright 2009 - 2018 BearOso,
OV2 OV2
(c) Copyright 2017 qwertymodo
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
BS-X C emulator code BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom, (c) Copyright 2005 - 2006 Dreamer Nom,
@ -117,6 +124,9 @@
Sound emulator code used in 1.52+ Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
S-SMP emulator code used in 1.54+
(c) Copyright 2016 byuu
SH assembler code partly based on x86 assembler code SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
@ -130,7 +140,7 @@
(c) Copyright 2006 - 2007 Shay Green (c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso (c) Copyright 2004 - 2018 BearOso
Win32 GUI code Win32 GUI code
(c) Copyright 2003 - 2006 blip, (c) Copyright 2003 - 2006 blip,
@ -138,11 +148,16 @@
Matthew Kendora, Matthew Kendora,
Nach, Nach,
nitsuja nitsuja
(c) Copyright 2009 - 2010 OV2 (c) Copyright 2009 - 2018 OV2
Mac OS GUI code Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2011 zones
Libretro port
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
@ -185,7 +200,7 @@
#include "missing.h" #include "missing.h"
#endif #endif
#define ADD_CYCLES(n) CPU.Cycles += (n) #define ADD_CYCLES(n) { CPU.Cycles += (n); }
extern uint8 *HDMAMemPointers[8]; extern uint8 *HDMAMemPointers[8];
extern int HDMA_ModeByteCounts[8]; extern int HDMA_ModeByteCounts[8];
@ -598,7 +613,7 @@ bool8 S9xDoDMA (uint8 Channel)
S9xSetPPU(Work, 0x2100 + d->BAddress); S9xSetPPU(Work, 0x2100 + d->BAddress);
UPDATE_COUNTERS; UPDATE_COUNTERS;
count--; count--;
// Fall through
case 1: case 1:
Work = S9xGetByte((d->ABank << 16) + p); Work = S9xGetByte((d->ABank << 16) + p);
S9xSetPPU(Work, 0x2101 + d->BAddress); S9xSetPPU(Work, 0x2101 + d->BAddress);
@ -633,7 +648,7 @@ bool8 S9xDoDMA (uint8 Channel)
b = 1; b = 1;
break; break;
} }
// Fall through
case 1: case 1:
Work = S9xGetByte((d->ABank << 16) + p); Work = S9xGetByte((d->ABank << 16) + p);
S9xSetPPU(Work, 0x2100 + d->BAddress); S9xSetPPU(Work, 0x2100 + d->BAddress);
@ -643,7 +658,7 @@ bool8 S9xDoDMA (uint8 Channel)
b = 2; b = 2;
break; break;
} }
// Fall through
case 2: case 2:
Work = S9xGetByte((d->ABank << 16) + p); Work = S9xGetByte((d->ABank << 16) + p);
S9xSetPPU(Work, 0x2101 + d->BAddress); S9xSetPPU(Work, 0x2101 + d->BAddress);
@ -653,7 +668,7 @@ bool8 S9xDoDMA (uint8 Channel)
b = 3; b = 3;
break; break;
} }
// Fall through
case 3: case 3:
Work = S9xGetByte((d->ABank << 16) + p); Work = S9xGetByte((d->ABank << 16) + p);
S9xSetPPU(Work, 0x2101 + d->BAddress); S9xSetPPU(Work, 0x2101 + d->BAddress);
@ -682,7 +697,7 @@ bool8 S9xDoDMA (uint8 Channel)
b = 1; b = 1;
break; break;
} }
// Fall through
case 1: case 1:
Work = S9xGetByte((d->ABank << 16) + p); Work = S9xGetByte((d->ABank << 16) + p);
S9xSetPPU(Work, 0x2101 + d->BAddress); S9xSetPPU(Work, 0x2101 + d->BAddress);
@ -692,7 +707,7 @@ bool8 S9xDoDMA (uint8 Channel)
b = 2; b = 2;
break; break;
} }
// Fall through
case 2: case 2:
Work = S9xGetByte((d->ABank << 16) + p); Work = S9xGetByte((d->ABank << 16) + p);
S9xSetPPU(Work, 0x2102 + d->BAddress); S9xSetPPU(Work, 0x2102 + d->BAddress);
@ -702,7 +717,7 @@ bool8 S9xDoDMA (uint8 Channel)
b = 3; b = 3;
break; break;
} }
// Fall through
case 3: case 3:
Work = S9xGetByte((d->ABank << 16) + p); Work = S9xGetByte((d->ABank << 16) + p);
S9xSetPPU(Work, 0x2103 + d->BAddress); S9xSetPPU(Work, 0x2103 + d->BAddress);
@ -741,9 +756,6 @@ bool8 S9xDoDMA (uint8 Channel)
break; break;
case 0x18: // VMDATAL case 0x18: // VMDATAL
#ifndef CORRECT_VRAM_READS
IPPU.FirstVRAMRead = TRUE;
#endif
if (!PPU.VMA.FullGraphicCount) if (!PPU.VMA.FullGraphicCount)
{ {
do do
@ -766,9 +778,6 @@ bool8 S9xDoDMA (uint8 Channel)
break; break;
case 0x19: // VMDATAH case 0x19: // VMDATAH
#ifndef CORRECT_VRAM_READS
IPPU.FirstVRAMRead = TRUE;
#endif
if (!PPU.VMA.FullGraphicCount) if (!PPU.VMA.FullGraphicCount)
{ {
do do
@ -837,9 +846,6 @@ bool8 S9xDoDMA (uint8 Channel)
if (d->BAddress == 0x18) if (d->BAddress == 0x18)
{ {
// VMDATAL // VMDATAL
#ifndef CORRECT_VRAM_READS
IPPU.FirstVRAMRead = TRUE;
#endif
if (!PPU.VMA.FullGraphicCount) if (!PPU.VMA.FullGraphicCount)
{ {
switch (b) switch (b)
@ -851,10 +857,10 @@ bool8 S9xDoDMA (uint8 Channel)
REGISTER_2118_linear(Work); REGISTER_2118_linear(Work);
UPDATE_COUNTERS; UPDATE_COUNTERS;
count--; count--;
// Fall through
case 1: case 1:
Work = *(base + p); OpenBus = *(base + p);
REGISTER_2119_linear(Work); REGISTER_2119_linear(OpenBus);
UPDATE_COUNTERS; UPDATE_COUNTERS;
count--; count--;
} }
@ -881,7 +887,7 @@ bool8 S9xDoDMA (uint8 Channel)
REGISTER_2118_tile(Work); REGISTER_2118_tile(Work);
UPDATE_COUNTERS; UPDATE_COUNTERS;
count--; count--;
// Fall through
case 1: case 1:
Work = *(base + p); Work = *(base + p);
REGISTER_2119_tile(Work); REGISTER_2119_tile(Work);
@ -913,7 +919,7 @@ bool8 S9xDoDMA (uint8 Channel)
S9xSetPPU(Work, 0x2100 + d->BAddress); S9xSetPPU(Work, 0x2100 + d->BAddress);
UPDATE_COUNTERS; UPDATE_COUNTERS;
count--; count--;
// Fall through
case 1: case 1:
Work = *(base + p); Work = *(base + p);
S9xSetPPU(Work, 0x2101 + d->BAddress); S9xSetPPU(Work, 0x2101 + d->BAddress);
@ -949,7 +955,7 @@ bool8 S9xDoDMA (uint8 Channel)
b = 1; b = 1;
break; break;
} }
// Fall through
case 1: case 1:
Work = *(base + p); Work = *(base + p);
S9xSetPPU(Work, 0x2100 + d->BAddress); S9xSetPPU(Work, 0x2100 + d->BAddress);
@ -959,7 +965,7 @@ bool8 S9xDoDMA (uint8 Channel)
b = 2; b = 2;
break; break;
} }
// Fall through
case 2: case 2:
Work = *(base + p); Work = *(base + p);
S9xSetPPU(Work, 0x2101 + d->BAddress); S9xSetPPU(Work, 0x2101 + d->BAddress);
@ -969,7 +975,7 @@ bool8 S9xDoDMA (uint8 Channel)
b = 3; b = 3;
break; break;
} }
// Fall through
case 3: case 3:
Work = *(base + p); Work = *(base + p);
S9xSetPPU(Work, 0x2101 + d->BAddress); S9xSetPPU(Work, 0x2101 + d->BAddress);
@ -998,7 +1004,7 @@ bool8 S9xDoDMA (uint8 Channel)
b = 1; b = 1;
break; break;
} }
// Fall through
case 1: case 1:
Work = *(base + p); Work = *(base + p);
S9xSetPPU(Work, 0x2101 + d->BAddress); S9xSetPPU(Work, 0x2101 + d->BAddress);
@ -1008,7 +1014,7 @@ bool8 S9xDoDMA (uint8 Channel)
b = 2; b = 2;
break; break;
} }
// Fall through
case 2: case 2:
Work = *(base + p); Work = *(base + p);
S9xSetPPU(Work, 0x2102 + d->BAddress); S9xSetPPU(Work, 0x2102 + d->BAddress);
@ -1018,7 +1024,7 @@ bool8 S9xDoDMA (uint8 Channel)
b = 3; b = 3;
break; break;
} }
// Fall through
case 3: case 3:
Work = *(base + p); Work = *(base + p);
S9xSetPPU(Work, 0x2103 + d->BAddress); S9xSetPPU(Work, 0x2103 + d->BAddress);
@ -1282,11 +1288,9 @@ bool8 S9xDoDMA (uint8 Channel)
} }
} }
if ((CPU.Flags & NMI_FLAG) && (Timings.NMITriggerPos != 0xffff)) if (CPU.NMIPending && (Timings.NMITriggerPos != 0xffff))
{ {
Timings.NMITriggerPos = CPU.Cycles + Timings.NMIDMADelay; Timings.NMITriggerPos = CPU.Cycles + Timings.NMIDMADelay;
if (Timings.NMITriggerPos >= Timings.H_Max)
Timings.NMITriggerPos -= Timings.H_Max;
} }
// Release the memory used in SPC7110 DMA // Release the memory used in SPC7110 DMA
@ -1373,9 +1377,6 @@ static inline bool8 HDMAReadLineCount (int d)
void S9xStartHDMA (void) void S9xStartHDMA (void)
{ {
if (Settings.DisableHDMA)
PPU.HDMA = 0;
else
PPU.HDMA = Memory.FillRAM[0x420c]; PPU.HDMA = Memory.FillRAM[0x420c];
#ifdef DEBUGGER #ifdef DEBUGGER
@ -1420,13 +1421,14 @@ void S9xStartHDMA (void)
uint8 S9xDoHDMA (uint8 byte) uint8 S9xDoHDMA (uint8 byte)
{ {
struct SDMA *p = &DMA[0]; struct SDMA *p;
uint32 ShiftedIBank; uint32 ShiftedIBank;
uint16 IAddr; uint16 IAddr;
bool8 temp; bool8 temp;
int32 tmpch; int32 tmpch;
int d = 0; int d;
uint8 mask;
CPU.InHDMA = TRUE; CPU.InHDMA = TRUE;
CPU.InDMAorHDMA = TRUE; CPU.InDMAorHDMA = TRUE;
@ -1437,7 +1439,7 @@ uint8 S9xDoHDMA (uint8 byte)
// XXX: Not quite right... // XXX: Not quite right...
ADD_CYCLES(Timings.DMACPUSync); ADD_CYCLES(Timings.DMACPUSync);
for (uint8 mask = 1; mask; mask <<= 1, p++, d++) for (mask = 1, p = &DMA[0], d = 0; mask; mask <<= 1, p++, d++)
{ {
if (byte & mask) if (byte & mask)
{ {
@ -1639,7 +1641,10 @@ uint8 S9xDoHDMA (uint8 byte)
case 1: case 1:
S9xSetPPU(*(HDMAMemPointers[d] + 0), 0x2100 + p->BAddress); S9xSetPPU(*(HDMAMemPointers[d] + 0), 0x2100 + p->BAddress);
ADD_CYCLES(SLOW_ONE_CYCLE); ADD_CYCLES(SLOW_ONE_CYCLE);
S9xSetPPU(*(HDMAMemPointers[d] + 1), 0x2101 + p->BAddress); // XXX: All HDMA should read to MDR first. This one just
// happens to fix Speedy Gonzales.
OpenBus = *(HDMAMemPointers[d] + 1);
S9xSetPPU(OpenBus, 0x2101 + p->BAddress);
ADD_CYCLES(SLOW_ONE_CYCLE); ADD_CYCLES(SLOW_ONE_CYCLE);
HDMAMemPointers[d] += 2; HDMAMemPointers[d] += 2;
break; break;
@ -1752,7 +1757,16 @@ uint8 S9xDoHDMA (uint8 byte)
#undef DOBYTE #undef DOBYTE
} }
}
}
}
for (mask = 1, p = &DMA[0], d = 0; mask; mask <<= 1, p++, d++)
{
if (byte & mask)
{
if (p->DoTransfer)
{
if (p->HDMAIndirectAddressing) if (p->HDMAIndirectAddressing)
p->IndirectAddress += HDMA_ModeByteCounts[p->TransferMode]; p->IndirectAddress += HDMA_ModeByteCounts[p->TransferMode];
else else
@ -1768,7 +1782,6 @@ uint8 S9xDoHDMA (uint8 byte)
byte &= ~mask; byte &= ~mask;
PPU.HDMAEnded |= mask; PPU.HDMAEnded |= mask;
p->DoTransfer = FALSE; p->DoTransfer = FALSE;
continue;
} }
} }
else else

View File

@ -17,13 +17,20 @@
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja (c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso, (c) Copyright 2009 - 2018 BearOso,
OV2 OV2
(c) Copyright 2017 qwertymodo
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
BS-X C emulator code BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom, (c) Copyright 2005 - 2006 Dreamer Nom,
@ -117,6 +124,9 @@
Sound emulator code used in 1.52+ Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
S-SMP emulator code used in 1.54+
(c) Copyright 2016 byuu
SH assembler code partly based on x86 assembler code SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
@ -130,7 +140,7 @@
(c) Copyright 2006 - 2007 Shay Green (c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso (c) Copyright 2004 - 2018 BearOso
Win32 GUI code Win32 GUI code
(c) Copyright 2003 - 2006 blip, (c) Copyright 2003 - 2006 blip,
@ -138,11 +148,16 @@
Matthew Kendora, Matthew Kendora,
Nach, Nach,
nitsuja nitsuja
(c) Copyright 2009 - 2010 OV2 (c) Copyright 2009 - 2018 OV2
Mac OS GUI code Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2011 zones
Libretro port
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
@ -199,10 +214,10 @@ void S9xInitSuperFX (void)
void S9xResetSuperFX (void) void S9xResetSuperFX (void)
{ {
// FIXME: Snes9x can't execute CPU and SuperFX at a time. Don't ask me what is 0.417 :P // FIXME: Snes9x can't execute CPU and SuperFX at a time. Don't ask me what is 0.417 :P
//SuperFX.speedPerLine = (uint32) (0.417 * 10.5e6 * ((1.0 / (float) Memory.ROMFramesPerSecond) / ((float) (Timings.V_Max)))); SuperFX.speedPerLine = (uint32) (0.417 * 10.5e6 * ((1.0 / (float) Memory.ROMFramesPerSecond) / ((float) (Timings.V_Max))));
SuperFX.speedPerLine = (uint32) (Settings.SuperFXSpeedPerLine * ((1.0f / Memory.ROMFramesPerSecond) / ((float) (Timings.V_Max))));
SuperFX.oneLineDone = FALSE; SuperFX.oneLineDone = FALSE;
SuperFX.vFlags = 0; SuperFX.vFlags = 0;
CPU.IRQExternal = FALSE;
FxReset(&SuperFX); FxReset(&SuperFX);
} }
@ -300,13 +315,10 @@ uint8 S9xGetSuperFX (uint16 address)
uint8 byte; uint8 byte;
byte = Memory.FillRAM[address]; byte = Memory.FillRAM[address];
#ifdef CPU_SHUTDOWN
if (address == 0x3030)
CPU.WaitAddress = CPU.PBPCAtOpcodeStart;
#endif
if (address == 0x3031) if (address == 0x3031)
{ {
S9xClearIRQ(GSU_IRQ_SOURCE); CPU.IRQExternal = FALSE;
Memory.FillRAM[0x3031] = byte & 0x7f; Memory.FillRAM[0x3031] = byte & 0x7f;
} }
@ -317,11 +329,11 @@ void S9xSuperFXExec (void)
{ {
if ((Memory.FillRAM[0x3000 + GSU_SFR] & FLG_G) && (Memory.FillRAM[0x3000 + GSU_SCMR] & 0x18) == 0x18) if ((Memory.FillRAM[0x3000 + GSU_SFR] & FLG_G) && (Memory.FillRAM[0x3000 + GSU_SCMR] & 0x18) == 0x18)
{ {
FxEmulate((Memory.FillRAM[0x3000 + GSU_CLSR] & 1) ? SuperFX.speedPerLine * 2 : SuperFX.speedPerLine); FxEmulate(((Memory.FillRAM[0x3000 + GSU_CLSR] & 1) ? SuperFX.speedPerLine * 2 : SuperFX.speedPerLine) * Settings.SuperFXClockMultiplier / 100);
uint16 GSUStatus = Memory.FillRAM[0x3000 + GSU_SFR] | (Memory.FillRAM[0x3000 + GSU_SFR + 1] << 8); uint16 GSUStatus = Memory.FillRAM[0x3000 + GSU_SFR] | (Memory.FillRAM[0x3000 + GSU_SFR + 1] << 8);
if ((GSUStatus & (FLG_G | FLG_IRQ)) == FLG_IRQ) if ((GSUStatus & (FLG_G | FLG_IRQ)) == FLG_IRQ)
S9xSetIRQ(GSU_IRQ_SOURCE); CPU.IRQExternal = TRUE;
} }
} }

View File

@ -17,13 +17,20 @@
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja (c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso, (c) Copyright 2009 - 2018 BearOso,
OV2 OV2
(c) Copyright 2017 qwertymodo
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
BS-X C emulator code BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom, (c) Copyright 2005 - 2006 Dreamer Nom,
@ -117,6 +124,9 @@
Sound emulator code used in 1.52+ Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
S-SMP emulator code used in 1.54+
(c) Copyright 2016 byuu
SH assembler code partly based on x86 assembler code SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
@ -130,7 +140,7 @@
(c) Copyright 2006 - 2007 Shay Green (c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso (c) Copyright 2004 - 2018 BearOso
Win32 GUI code Win32 GUI code
(c) Copyright 2003 - 2006 blip, (c) Copyright 2003 - 2006 blip,
@ -138,11 +148,16 @@
Matthew Kendora, Matthew Kendora,
Nach, Nach,
nitsuja nitsuja
(c) Copyright 2009 - 2010 OV2 (c) Copyright 2009 - 2018 OV2
Mac OS GUI code Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2011 zones
Libretro port
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
@ -188,8 +203,6 @@
#include "bsx.h" #include "bsx.h"
#include "msu1.h" #include "msu1.h"
#if (S9X_ACCURACY_LEVEL >= 2)
#define addCyclesInMemoryAccess \ #define addCyclesInMemoryAccess \
if (!CPU.InDMAorHDMA) \ if (!CPU.InDMAorHDMA) \
{ \ { \
@ -206,18 +219,6 @@
S9xDoHEventProcessing(); \ S9xDoHEventProcessing(); \
} }
#else
#define addCyclesInMemoryAccess \
if (!CPU.InDMAorHDMA) \
CPU.Cycles += speed;
#define addCyclesInMemoryAccess_x2 \
if (!CPU.InDMAorHDMA) \
CPU.Cycles += speed << 1;
#endif
extern uint8 OpenBus; extern uint8 OpenBus;
static inline int32 memory_speed (uint32 address) static inline int32 memory_speed (uint32 address)
@ -248,10 +249,6 @@ inline uint8 S9xGetByte (uint32 Address)
if (GetAddress >= (uint8 *) CMemory::MAP_LAST) if (GetAddress >= (uint8 *) CMemory::MAP_LAST)
{ {
#ifdef CPU_SHUTDOWN
if (Memory.BlockIsRAM[block])
CPU.WaitAddress = CPU.PBPCAtOpcodeStart;
#endif
byte = *(GetAddress + (Address & 0xffff)); byte = *(GetAddress + (Address & 0xffff));
addCyclesInMemoryAccess; addCyclesInMemoryAccess;
return (byte); return (byte);
@ -348,42 +345,39 @@ inline uint8 S9xGetByte (uint32 Address)
inline uint16 S9xGetWord (uint32 Address, enum s9xwrap_t w = WRAP_NONE) inline uint16 S9xGetWord (uint32 Address, enum s9xwrap_t w = WRAP_NONE)
{ {
uint16 word;
uint32 mask = MEMMAP_MASK & (w == WRAP_PAGE ? 0xff : (w == WRAP_BANK ? 0xffff : 0xffffff)); uint32 mask = MEMMAP_MASK & (w == WRAP_PAGE ? 0xff : (w == WRAP_BANK ? 0xffff : 0xffffff));
if ((Address & mask) == mask) if ((Address & mask) == mask)
{ {
PC_t a; PC_t a;
OpenBus = S9xGetByte(Address); word = OpenBus = S9xGetByte(Address);
switch (w) switch (w)
{ {
case WRAP_PAGE: case WRAP_PAGE:
a.xPBPC = Address; a.xPBPC = Address;
a.B.xPCl++; a.B.xPCl++;
return (OpenBus | (S9xGetByte(a.xPBPC) << 8)); return (word | (S9xGetByte(a.xPBPC) << 8));
case WRAP_BANK: case WRAP_BANK:
a.xPBPC = Address; a.xPBPC = Address;
a.W.xPC++; a.W.xPC++;
return (OpenBus | (S9xGetByte(a.xPBPC) << 8)); return (word | (S9xGetByte(a.xPBPC) << 8));
case WRAP_NONE: case WRAP_NONE:
default: default:
return (OpenBus | (S9xGetByte(Address + 1) << 8)); return (word | (S9xGetByte(Address + 1) << 8));
} }
} }
int block = (Address & 0xffffff) >> MEMMAP_SHIFT; int block = (Address & 0xffffff) >> MEMMAP_SHIFT;
uint8 *GetAddress = Memory.Map[block]; uint8 *GetAddress = Memory.Map[block];
int32 speed = memory_speed(Address); int32 speed = memory_speed(Address);
uint16 word;
if (GetAddress >= (uint8 *) CMemory::MAP_LAST) if (GetAddress >= (uint8 *) CMemory::MAP_LAST)
{ {
#ifdef CPU_SHUTDOWN
if (Memory.BlockIsRAM[block])
CPU.WaitAddress = CPU.PBPCAtOpcodeStart;
#endif
word = READ_WORD(GetAddress + (Address & 0xffff)); word = READ_WORD(GetAddress + (Address & 0xffff));
addCyclesInMemoryAccess_x2; addCyclesInMemoryAccess_x2;
return (word); return (word);
@ -401,8 +395,8 @@ inline uint16 S9xGetWord (uint32 Address, enum s9xwrap_t w = WRAP_NONE)
case CMemory::MAP_PPU: case CMemory::MAP_PPU:
if (CPU.InDMAorHDMA) if (CPU.InDMAorHDMA)
{ {
OpenBus = S9xGetByte(Address); word = OpenBus = S9xGetByte(Address);
return (OpenBus | (S9xGetByte(Address + 1) << 8)); return (word | (S9xGetByte(Address + 1) << 8));
} }
word = S9xGetPPU(Address & 0xffff); word = S9xGetPPU(Address & 0xffff);
@ -511,33 +505,14 @@ inline uint16 S9xGetWord (uint32 Address, enum s9xwrap_t w = WRAP_NONE)
inline void S9xSetByte (uint8 Byte, uint32 Address) inline void S9xSetByte (uint8 Byte, uint32 Address)
{ {
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
int block = (Address & 0xffffff) >> MEMMAP_SHIFT; int block = (Address & 0xffffff) >> MEMMAP_SHIFT;
uint8 *SetAddress = Memory.WriteMap[block]; uint8 *SetAddress = Memory.WriteMap[block];
int32 speed = memory_speed(Address); int32 speed = memory_speed(Address);
if (SetAddress >= (uint8 *) CMemory::MAP_LAST) if (SetAddress >= (uint8 *) CMemory::MAP_LAST)
{ {
#ifdef CPU_SHUTDOWN
SetAddress += (Address & 0xffff);
*SetAddress = Byte;
addCyclesInMemoryAccess;
if (Settings.SA1)
{
if (SetAddress == SA1.WaitByteAddress1 || SetAddress == SA1.WaitByteAddress2)
{
SA1.Executing = SA1.S9xOpcodes != NULL;
SA1.WaitCounter = 0;
}
}
#else
*(SetAddress + (Address & 0xffff)) = Byte; *(SetAddress + (Address & 0xffff)) = Byte;
addCyclesInMemoryAccess; addCyclesInMemoryAccess;
#endif
return; return;
} }
@ -594,7 +569,6 @@ inline void S9xSetByte (uint8 Byte, uint32 Address)
case CMemory::MAP_SA1RAM: case CMemory::MAP_SA1RAM:
*(Memory.SRAM + (Address & 0xffff)) = Byte; *(Memory.SRAM + (Address & 0xffff)) = Byte;
SA1.Executing = !SA1.Waiting;
addCyclesInMemoryAccess; addCyclesInMemoryAccess;
return; return;
@ -671,33 +645,14 @@ inline void S9xSetWord (uint16 Word, uint32 Address, enum s9xwrap_t w = WRAP_NON
return; return;
} }
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = 0xffffffff;
#endif
int block = (Address & 0xffffff) >> MEMMAP_SHIFT; int block = (Address & 0xffffff) >> MEMMAP_SHIFT;
uint8 *SetAddress = Memory.WriteMap[block]; uint8 *SetAddress = Memory.WriteMap[block];
int32 speed = memory_speed(Address); int32 speed = memory_speed(Address);
if (SetAddress >= (uint8 *) CMemory::MAP_LAST) if (SetAddress >= (uint8 *) CMemory::MAP_LAST)
{ {
#ifdef CPU_SHUTDOWN
SetAddress += (Address & 0xffff);
WRITE_WORD(SetAddress, Word);
addCyclesInMemoryAccess_x2;
if (Settings.SA1)
{
if (SetAddress == SA1.WaitByteAddress1 || SetAddress == SA1.WaitByteAddress2)
{
SA1.Executing = SA1.S9xOpcodes != NULL;
SA1.WaitCounter = 0;
}
}
#else
WRITE_WORD(SetAddress + (Address & 0xffff), Word); WRITE_WORD(SetAddress + (Address & 0xffff), Word);
addCyclesInMemoryAccess_x2; addCyclesInMemoryAccess_x2;
#endif
return; return;
} }
@ -807,7 +762,6 @@ inline void S9xSetWord (uint16 Word, uint32 Address, enum s9xwrap_t w = WRAP_NON
case CMemory::MAP_SA1RAM: case CMemory::MAP_SA1RAM:
WRITE_WORD(Memory.SRAM + (Address & 0xffff), Word); WRITE_WORD(Memory.SRAM + (Address & 0xffff), Word);
SA1.Executing = !SA1.Waiting;
addCyclesInMemoryAccess_x2; addCyclesInMemoryAccess_x2;
return; return;
@ -931,8 +885,7 @@ inline void S9xSetPCBase (uint32 Address)
Registers.PBPC = Address & 0xffffff; Registers.PBPC = Address & 0xffffff;
ICPU.ShiftedPB = Address & 0xff0000; ICPU.ShiftedPB = Address & 0xff0000;
int block; uint8 *GetAddress = Memory.Map[(int)((Address & 0xffffff) >> MEMMAP_SHIFT)];
uint8 *GetAddress = Memory.Map[block = ((Address & 0xffffff) >> MEMMAP_SHIFT)];
CPU.MemSpeed = memory_speed(Address); CPU.MemSpeed = memory_speed(Address);
CPU.MemSpeedx2 = CPU.MemSpeed << 1; CPU.MemSpeedx2 = CPU.MemSpeed << 1;

View File

@ -17,13 +17,20 @@
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja (c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso, (c) Copyright 2009 - 2018 BearOso,
OV2 OV2
(c) Copyright 2017 qwertymodo
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
BS-X C emulator code BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom, (c) Copyright 2005 - 2006 Dreamer Nom,
@ -117,6 +124,9 @@
Sound emulator code used in 1.52+ Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
S-SMP emulator code used in 1.54+
(c) Copyright 2016 byuu
SH assembler code partly based on x86 assembler code SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
@ -130,7 +140,7 @@
(c) Copyright 2006 - 2007 Shay Green (c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso (c) Copyright 2004 - 2018 BearOso
Win32 GUI code Win32 GUI code
(c) Copyright 2003 - 2006 blip, (c) Copyright 2003 - 2006 blip,
@ -138,11 +148,16 @@
Matthew Kendora, Matthew Kendora,
Nach, Nach,
nitsuja nitsuja
(c) Copyright 2009 - 2010 OV2 (c) Copyright 2009 - 2018 OV2
Mac OS GUI code Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2011 zones
Libretro port
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
@ -215,7 +230,7 @@ static uint16 get_crosshair_color (uint8);
bool8 S9xGraphicsInit (void) bool8 S9xGraphicsInit (void)
{ {
S9xInitTileRenderer(); S9xInitTileRenderer();
ZeroMemory(BlackColourMap, 256 * sizeof(uint16)); memset(BlackColourMap, 0, 256 * sizeof(uint16));
#ifdef GFX_MULTI_FORMAT #ifdef GFX_MULTI_FORMAT
if (GFX.BuildPixel == NULL) if (GFX.BuildPixel == NULL)
@ -226,9 +241,9 @@ bool8 S9xGraphicsInit (void)
GFX.InterlaceFrame = 0; GFX.InterlaceFrame = 0;
GFX.RealPPL = GFX.Pitch >> 1; GFX.RealPPL = GFX.Pitch >> 1;
IPPU.OBJChanged = TRUE; IPPU.OBJChanged = TRUE;
IPPU.DirectColourMapsNeedRebuild = TRUE;
Settings.BG_Forced = 0; Settings.BG_Forced = 0;
S9xFixColourBrightness(); S9xFixColourBrightness();
S9xBuildDirectColourMaps();
GFX.X2 = (uint16 *) malloc(sizeof(uint16) * 0x10000); GFX.X2 = (uint16 *) malloc(sizeof(uint16) * 0x10000);
GFX.ZERO = (uint16 *) malloc(sizeof(uint16) * 0x10000); GFX.ZERO = (uint16 *) malloc(sizeof(uint16) * 0x10000);
@ -245,7 +260,7 @@ bool8 S9xGraphicsInit (void)
} }
// Lookup table for color addition // Lookup table for color addition
ZeroMemory(GFX.X2, 0x10000 * sizeof(uint16)); memset(GFX.X2, 0, 0x10000 * sizeof(uint16));
for (uint32 r = 0; r <= MAX_RED; r++) for (uint32 r = 0; r <= MAX_RED; r++)
{ {
uint32 r2 = r << 1; uint32 r2 = r << 1;
@ -271,7 +286,7 @@ bool8 S9xGraphicsInit (void)
} }
// Lookup table for 1/2 color subtraction // Lookup table for 1/2 color subtraction
ZeroMemory(GFX.ZERO, 0x10000 * sizeof(uint16)); memset(GFX.ZERO, 0, 0x10000 * sizeof(uint16));
for (uint32 r = 0; r <= MAX_RED; r++) for (uint32 r = 0; r <= MAX_RED; r++)
{ {
uint32 r2 = r; uint32 r2 = r;
@ -321,15 +336,14 @@ void S9xBuildDirectColourMaps (void)
for (uint32 p = 0; p < 8; p++) for (uint32 p = 0; p < 8; p++)
for (uint32 c = 0; c < 256; c++) for (uint32 c = 0; c < 256; c++)
DirectColourMaps[p][c] = BUILD_PIXEL(IPPU.XB[((c & 7) << 2) | ((p & 1) << 1)], IPPU.XB[((c & 0x38) >> 1) | (p & 2)], IPPU.XB[((c & 0xc0) >> 3) | (p & 4)]); DirectColourMaps[p][c] = BUILD_PIXEL(IPPU.XB[((c & 7) << 2) | ((p & 1) << 1)], IPPU.XB[((c & 0x38) >> 1) | (p & 2)], IPPU.XB[((c & 0xc0) >> 3) | (p & 4)]);
IPPU.DirectColourMapsNeedRebuild = FALSE;
} }
void S9xStartScreenRefresh (void) void S9xStartScreenRefresh (void)
{ {
GFX.InterlaceFrame = !GFX.InterlaceFrame;
if (IPPU.RenderThisFrame) if (IPPU.RenderThisFrame)
{ {
GFX.InterlaceFrame = !GFX.InterlaceFrame;
if (!GFX.DoInterlace || !GFX.InterlaceFrame) if (!GFX.DoInterlace || !GFX.InterlaceFrame)
{ {
if (!S9xInitUpdate()) if (!S9xInitUpdate())
@ -361,6 +375,7 @@ void S9xStartScreenRefresh (void)
else else
#endif #endif
GFX.RealPPL = GFX.Pitch >> 1; GFX.RealPPL = GFX.Pitch >> 1;
IPPU.DoubleWidthPixels = FALSE; IPPU.DoubleWidthPixels = FALSE;
IPPU.RenderedScreenWidth = SNES_WIDTH; IPPU.RenderedScreenWidth = SNES_WIDTH;
} }
@ -386,8 +401,8 @@ void S9xStartScreenRefresh (void)
PPU.RecomputeClipWindows = TRUE; PPU.RecomputeClipWindows = TRUE;
IPPU.PreviousLine = IPPU.CurrentLine = 0; IPPU.PreviousLine = IPPU.CurrentLine = 0;
ZeroMemory(GFX.ZBuffer, GFX.ScreenSize); memset(GFX.ZBuffer, 0, GFX.ScreenSize);
ZeroMemory(GFX.SubZBuffer, GFX.ScreenSize); memset(GFX.SubZBuffer, 0, GFX.ScreenSize);
} }
if (++IPPU.FrameCount % Memory.ROMFramesPerSecond == 0) if (++IPPU.FrameCount % Memory.ROMFramesPerSecond == 0)
@ -438,7 +453,7 @@ void S9xEndScreenRefresh (void)
else else
S9xControlEOF(); S9xControlEOF();
S9xApplyCheats(); S9xUpdateCheatsInMemory ();
#ifdef DEBUGGER #ifdef DEBUGGER
if (CPU.Flags & FRAME_ADVANCE_FLAG) if (CPU.Flags & FRAME_ADVANCE_FLAG)
@ -692,7 +707,6 @@ void S9xUpdateScreen (void)
} }
else else
#endif #endif
{
// Have to back out of the regular speed hack // Have to back out of the regular speed hack
for (register uint32 y = 0; y < GFX.StartY; y++) for (register uint32 y = 0; y < GFX.StartY; y++)
{ {
@ -702,31 +716,20 @@ void S9xUpdateScreen (void)
for (register int x = 255; x >= 0; x--, p--, q -= 2) for (register int x = 255; x >= 0; x--, p--, q -= 2)
*q = *(q + 1) = *p; *q = *(q + 1) = *p;
} }
}
IPPU.DoubleWidthPixels = TRUE; IPPU.DoubleWidthPixels = TRUE;
IPPU.RenderedScreenWidth = 512; IPPU.RenderedScreenWidth = 512;
} }
if (!IPPU.DoubleHeightPixels && IPPU.Interlace) if (!IPPU.DoubleHeightPixels && IPPU.Interlace && (PPU.BGMode == 5 || PPU.BGMode == 6))
{ {
IPPU.DoubleHeightPixels = TRUE; IPPU.DoubleHeightPixels = TRUE;
IPPU.RenderedScreenHeight = PPU.ScreenHeight << 1; IPPU.RenderedScreenHeight = PPU.ScreenHeight << 1;
GFX.PPL = GFX.RealPPL << 1; GFX.PPL = GFX.RealPPL << 1;
GFX.DoInterlace = 2; GFX.DoInterlace = 2;
for (register int32 y = (int32) GFX.StartY - 1; y >= 0; y--) for (register int32 y = (int32) GFX.StartY - 2; y >= 0; y--)
memmove(GFX.Screen + y * GFX.PPL, GFX.Screen + y * GFX.RealPPL, IPPU.RenderedScreenWidth * sizeof(uint16)); memmove(GFX.Screen + (y + 1) * GFX.PPL, GFX.Screen + y * GFX.RealPPL, GFX.PPL * sizeof(uint16));
}
else if (IPPU.DoubleHeightPixels && !IPPU.Interlace)
{
for (register int32 y = 0; y < (int32) GFX.StartY; y++)
memmove(GFX.Screen + y * GFX.RealPPL, GFX.Screen + y * GFX.PPL, IPPU.RenderedScreenWidth * sizeof(uint16));
IPPU.DoubleHeightPixels = FALSE;
IPPU.RenderedScreenHeight = PPU.ScreenHeight;
GFX.PPL = GFX.RealPPL;
GFX.DoInterlace = 0;
} }
} }
@ -819,12 +822,12 @@ static void SetupOBJ (void)
if (!PPU.OAMPriorityRotation || !(PPU.OAMFlip & PPU.OAMAddr & 1)) // normal case if (!PPU.OAMPriorityRotation || !(PPU.OAMFlip & PPU.OAMAddr & 1)) // normal case
{ {
uint8 LineOBJ[SNES_HEIGHT_EXTENDED]; uint8 LineOBJ[SNES_HEIGHT_EXTENDED];
ZeroMemory(LineOBJ, sizeof(LineOBJ)); memset(LineOBJ, 0, sizeof(LineOBJ));
for (int i = 0; i < SNES_HEIGHT_EXTENDED; i++) for (int i = 0; i < SNES_HEIGHT_EXTENDED; i++)
{ {
GFX.OBJLines[i].RTOFlags = 0; GFX.OBJLines[i].RTOFlags = 0;
GFX.OBJLines[i].Tiles = 34; GFX.OBJLines[i].Tiles = Settings.MaxSpriteTilesPerLine;
for (int j = 0; j < 32; j++) for (int j = 0; j < 32; j++)
GFX.OBJLines[i].OBJ[j].Sprite = -1; GFX.OBJLines[i].OBJ[j].Sprite = -1;
} }
@ -896,7 +899,13 @@ static void SetupOBJ (void)
{ {
// First, find out which sprites are on which lines // First, find out which sprites are on which lines
uint8 OBJOnLine[SNES_HEIGHT_EXTENDED][128]; uint8 OBJOnLine[SNES_HEIGHT_EXTENDED][128];
ZeroMemory(OBJOnLine, sizeof(OBJOnLine)); // memset(OBJOnLine, 0, sizeof(OBJOnLine));
/* Hold on here, that's a lot of bytes to initialise at once!
* So we only initialise them per line, as needed. [Neb]
* Bonus: We can quickly avoid looping if a line has no OBJs.
*/
bool8 AnyOBJOnLine[SNES_HEIGHT_EXTENDED];
memset(AnyOBJOnLine, FALSE, sizeof(AnyOBJOnLine)); // better
for (S = 0; S < 128; S++) for (S = 0; S < 128; S++)
{ {
@ -930,6 +939,11 @@ static void SetupOBJ (void)
if (Y >= SNES_HEIGHT_EXTENDED) if (Y >= SNES_HEIGHT_EXTENDED)
continue; continue;
if (!AnyOBJOnLine[Y]) {
memset(OBJOnLine[Y], 0, sizeof(OBJOnLine[Y]));
AnyOBJOnLine[Y] = TRUE;
}
if (PPU.OBJ[S].VFlip) if (PPU.OBJ[S].VFlip)
// Yes, Width not Height. It so happens that the // Yes, Width not Height. It so happens that the
// sprites with H=2*W flip as two WxW sprites. // sprites with H=2*W flip as two WxW sprites.
@ -945,12 +959,14 @@ static void SetupOBJ (void)
for (int Y = 0; Y < SNES_HEIGHT_EXTENDED; Y++) for (int Y = 0; Y < SNES_HEIGHT_EXTENDED; Y++)
{ {
GFX.OBJLines[Y].RTOFlags = Y ? GFX.OBJLines[Y - 1].RTOFlags : 0; GFX.OBJLines[Y].RTOFlags = Y ? GFX.OBJLines[Y - 1].RTOFlags : 0;
GFX.OBJLines[Y].Tiles = 34; GFX.OBJLines[Y].Tiles = Settings.MaxSpriteTilesPerLine;
uint8 FirstSprite = (PPU.FirstSprite + Y) & 0x7f; uint8 FirstSprite = (PPU.FirstSprite + Y) & 0x7f;
S = FirstSprite; S = FirstSprite;
j = 0; j = 0;
if (AnyOBJOnLine[Y])
{
do do
{ {
if (OBJOnLine[Y][S]) if (OBJOnLine[Y][S])
@ -970,6 +986,7 @@ static void SetupOBJ (void)
S = (S + 1) & 0x7f; S = (S + 1) & 0x7f;
} while (S != FirstSprite); } while (S != FirstSprite);
}
if (j < 32) if (j < 32)
GFX.OBJLines[Y].OBJ[j].Sprite = -1; GFX.OBJLines[Y].OBJ[j].Sprite = -1;
@ -979,6 +996,8 @@ static void SetupOBJ (void)
IPPU.OBJChanged = FALSE; IPPU.OBJChanged = FALSE;
} }
#pragma GCC push_options
#pragma GCC optimize ("no-tree-vrp")
static void DrawOBJS (int D) static void DrawOBJS (int D)
{ {
void (*DrawTile) (uint32, uint32, uint32, uint32) = NULL; void (*DrawTile) (uint32, uint32, uint32, uint32) = NULL;
@ -1071,6 +1090,8 @@ static void DrawOBJS (int D)
} }
} }
} }
#pragma GCC pop_options
static void DrawBackground (int bg, uint8 Zh, uint8 Zl) static void DrawBackground (int bg, uint8 Zh, uint8 Zl)
{ {
@ -1329,8 +1350,8 @@ static void DrawBackgroundMosaic (int bg, uint8 Zh, uint8 Zl)
for (uint32 Y = GFX.StartY - MosaicStart; Y <= GFX.EndY; Y += PPU.Mosaic) for (uint32 Y = GFX.StartY - MosaicStart; Y <= GFX.EndY; Y += PPU.Mosaic)
{ {
uint32 Y2 = HiresInterlace ? Y * 2 : Y; uint32 Y2 = HiresInterlace ? Y * 2 : Y;
uint32 VOffset = LineData[Y].BG[bg].VOffset + (HiresInterlace ? 1 : 0); uint32 VOffset = LineData[Y + MosaicStart].BG[bg].VOffset + (HiresInterlace ? 1 : 0);
uint32 HOffset = LineData[Y].BG[bg].HOffset; uint32 HOffset = LineData[Y + MosaicStart].BG[bg].HOffset;
Lines = PPU.Mosaic - MosaicStart; Lines = PPU.Mosaic - MosaicStart;
if (Y + MosaicStart + Lines > GFX.EndY) if (Y + MosaicStart + Lines > GFX.EndY)
@ -1493,7 +1514,6 @@ static void DrawBackgroundOffset (int bg, uint8 Zh, uint8 Zl, int VOffOff)
int PixWidth = IPPU.DoubleWidthPixels ? 2 : 1; int PixWidth = IPPU.DoubleWidthPixels ? 2 : 1;
bool8 HiresInterlace = IPPU.Interlace && IPPU.DoubleWidthPixels; bool8 HiresInterlace = IPPU.Interlace && IPPU.DoubleWidthPixels;
void (*DrawTile) (uint32, uint32, uint32, uint32);
void (*DrawClippedTile) (uint32, uint32, uint32, uint32, uint32, uint32); void (*DrawClippedTile) (uint32, uint32, uint32, uint32, uint32, uint32);
for (int clip = 0; clip < GFX.Clip[bg].Count; clip++) for (int clip = 0; clip < GFX.Clip[bg].Count; clip++)
@ -1502,12 +1522,10 @@ static void DrawBackgroundOffset (int bg, uint8 Zh, uint8 Zl, int VOffOff)
if (BG.EnableMath && (GFX.Clip[bg].DrawMode[clip] & 2)) if (BG.EnableMath && (GFX.Clip[bg].DrawMode[clip] & 2))
{ {
DrawTile = GFX.DrawTileMath;
DrawClippedTile = GFX.DrawClippedTileMath; DrawClippedTile = GFX.DrawClippedTileMath;
} }
else else
{ {
DrawTile = GFX.DrawTileNomath;
DrawClippedTile = GFX.DrawClippedTileNomath; DrawClippedTile = GFX.DrawClippedTileNomath;
} }
@ -1539,8 +1557,8 @@ static void DrawBackgroundOffset (int bg, uint8 Zh, uint8 Zl, int VOffOff)
uint32 Left = GFX.Clip[bg].Left[clip]; uint32 Left = GFX.Clip[bg].Left[clip];
uint32 Right = GFX.Clip[bg].Right[clip]; uint32 Right = GFX.Clip[bg].Right[clip];
uint32 Offset = Left * PixWidth + Y * GFX.PPL; uint32 Offset = Left * PixWidth + Y * GFX.PPL;
uint32 LineHOffset = LineData[Y].BG[bg].HOffset; uint32 HScroll = LineData[Y].BG[bg].HOffset;
bool8 left_edge = (Left < (8 - (LineHOffset & 7))); bool8 left_edge = (Left < (8 - (HScroll & 7)));
uint32 Width = Right - Left; uint32 Width = Right - Left;
while (Left < Right) while (Left < Right)
@ -1551,7 +1569,7 @@ static void DrawBackgroundOffset (int bg, uint8 Zh, uint8 Zl, int VOffOff)
{ {
// SNES cannot do OPT for leftmost tile column // SNES cannot do OPT for leftmost tile column
VOffset = LineData[Y].BG[bg].VOffset; VOffset = LineData[Y].BG[bg].VOffset;
HOffset = LineHOffset; HOffset = HScroll;
left_edge = FALSE; left_edge = FALSE;
} }
else else
@ -1595,9 +1613,9 @@ static void DrawBackgroundOffset (int bg, uint8 Zh, uint8 Zl, int VOffOff)
VOffset = LineData[Y].BG[bg].VOffset; VOffset = LineData[Y].BG[bg].VOffset;
if (HCellOffset & OffsetEnableMask) if (HCellOffset & OffsetEnableMask)
HOffset = (HCellOffset & ~7) | (LineHOffset & 7); HOffset = (HCellOffset & ~7) | (HScroll & 7);
else else
HOffset = LineHOffset; HOffset = HScroll;
} }
if (HiresInterlace) if (HiresInterlace)
@ -1719,7 +1737,6 @@ static void DrawBackgroundOffsetMosaic (int bg, uint8 Zh, uint8 Zl, int VOffOff)
int Lines; int Lines;
int OffsetMask = (BG.TileSizeH == 16) ? 0x3ff : 0x1ff; int OffsetMask = (BG.TileSizeH == 16) ? 0x3ff : 0x1ff;
int OffsetShift = (BG.TileSizeV == 16) ? 4 : 3; int OffsetShift = (BG.TileSizeV == 16) ? 4 : 3;
int Offset2Mask = (BG.OffsetSizeH == 16) ? 0x3ff : 0x1ff;
int Offset2Shift = (BG.OffsetSizeV == 16) ? 4 : 3; int Offset2Shift = (BG.OffsetSizeV == 16) ? 4 : 3;
int OffsetEnableMask = 0x2000 << bg; int OffsetEnableMask = 0x2000 << bg;
int PixWidth = IPPU.DoubleWidthPixels ? 2 : 1; int PixWidth = IPPU.DoubleWidthPixels ? 2 : 1;
@ -1741,8 +1758,8 @@ static void DrawBackgroundOffsetMosaic (int bg, uint8 Zh, uint8 Zl, int VOffOff)
for (uint32 Y = GFX.StartY - MosaicStart; Y <= GFX.EndY; Y += PPU.Mosaic) for (uint32 Y = GFX.StartY - MosaicStart; Y <= GFX.EndY; Y += PPU.Mosaic)
{ {
uint32 Y2 = HiresInterlace ? Y * 2 : Y; uint32 Y2 = HiresInterlace ? Y * 2 : Y;
uint32 VOff = LineData[Y].BG[2].VOffset - 1; uint32 VOff = LineData[Y + MosaicStart].BG[2].VOffset - 1;
uint32 HOff = LineData[Y].BG[2].HOffset; uint32 HOff = LineData[Y + MosaicStart].BG[2].HOffset;
Lines = PPU.Mosaic - MosaicStart; Lines = PPU.Mosaic - MosaicStart;
if (Y + MosaicStart + Lines > GFX.EndY) if (Y + MosaicStart + Lines > GFX.EndY)
@ -1771,24 +1788,22 @@ static void DrawBackgroundOffsetMosaic (int bg, uint8 Zh, uint8 Zl, int VOffOff)
uint32 Left = GFX.Clip[bg].Left[clip]; uint32 Left = GFX.Clip[bg].Left[clip];
uint32 Right = GFX.Clip[bg].Right[clip]; uint32 Right = GFX.Clip[bg].Right[clip];
uint32 Offset = Left * PixWidth + (Y + MosaicStart) * GFX.PPL; uint32 Offset = Left * PixWidth + (Y + MosaicStart) * GFX.PPL;
uint32 LineHOffset = LineData[Y].BG[bg].HOffset; uint32 HScroll = LineData[Y + MosaicStart].BG[bg].HOffset;
bool8 left_edge = (Left < (8 - (LineHOffset & 7)));
uint32 Width = Right - Left; uint32 Width = Right - Left;
while (Left < Right) while (Left < Right)
{ {
uint32 VOffset, HOffset; uint32 VOffset, HOffset;
if (left_edge) if (Left < (8 - (HScroll & 7)))
{ {
// SNES cannot do OPT for leftmost tile column // SNES cannot do OPT for leftmost tile column
VOffset = LineData[Y].BG[bg].VOffset; VOffset = LineData[Y + MosaicStart].BG[bg].VOffset;
HOffset = LineHOffset; HOffset = HScroll;
left_edge = FALSE;
} }
else else
{ {
int HOffTile = ((HOff + Left - 1) & Offset2Mask) >> 3; int HOffTile = (((Left + (HScroll & 7)) - 8) + (HOff & ~7)) >> 3;
if (BG.OffsetSizeH == 8) if (BG.OffsetSizeH == 8)
{ {
@ -1824,12 +1839,12 @@ static void DrawBackgroundOffsetMosaic (int bg, uint8 Zh, uint8 Zl, int VOffOff)
if (VCellOffset & OffsetEnableMask) if (VCellOffset & OffsetEnableMask)
VOffset = VCellOffset + 1; VOffset = VCellOffset + 1;
else else
VOffset = LineData[Y].BG[bg].VOffset; VOffset = LineData[Y + MosaicStart].BG[bg].VOffset;
if (HCellOffset & OffsetEnableMask) if (HCellOffset & OffsetEnableMask)
HOffset = (HCellOffset & ~7) | (LineHOffset & 7); HOffset = (HCellOffset & ~7) | (HScroll & 7);
else else
HOffset = LineHOffset; HOffset = HScroll;
} }
if (HiresInterlace) if (HiresInterlace)
@ -2052,7 +2067,7 @@ static void DisplayPressedKeys (void)
static int KeyOrder[] = { 8, 10, 7, 9, 0, 6, 14, 13, 5, 1, 4, 3, 2, 11, 12 }; // < ^ > v A B Y X L R S s static int KeyOrder[] = { 8, 10, 7, 9, 0, 6, 14, 13, 5, 1, 4, 3, 2, 11, 12 }; // < ^ > v A B Y X L R S s
enum controllers controller; enum controllers controller;
int line = 1; int line = Settings.DisplayMovieFrame && S9xMovieActive() ? 2 : 1;
int8 ids[4]; int8 ids[4];
char string[255]; char string[255];
@ -2144,6 +2159,22 @@ static void DisplayPressedKeys (void)
break; break;
} }
case CTL_MACSRIFLE:
{
/*
uint8 buf[6], *p = buf;
MovieGetScope(port, buf);
int16 x = READ_WORD(p);
int16 y = READ_WORD(p + 2);
uint8 buttons = buf[4];
sprintf(string, "#%d %d: (%03d,%03d) %c%c%c%c", port, ids[0], x, y,
(buttons & 0x80) ? 'F' : ' ', (buttons & 0x40) ? 'C' : ' ',
(buttons & 0x20) ? 'T' : ' ', (buttons & 0x10) ? 'P' : ' ');
S9xDisplayString(string, line++, 1, false);
*/
break;
}
case CTL_NONE: case CTL_NONE:
{ {
sprintf(string, "#%d -", port); sprintf(string, "#%d -", port);
@ -2251,12 +2282,7 @@ void S9xDrawCrosshair (const char *crosshair, uint8 fgcolor, uint8 bgcolor, int1
fg = get_crosshair_color(fgcolor); fg = get_crosshair_color(fgcolor);
bg = get_crosshair_color(bgcolor); bg = get_crosshair_color(bgcolor);
// XXX: FIXME: why does it crash without this on Linux port? There are no out-of-bound writes without it... uint16 *s = GFX.Screen + y * (int32)GFX.RealPPL + x;
#if (defined(__unix) || defined(__linux) || defined(__sun) || defined(__DJGPP))
if (x >= 0 && y >= 0)
#endif
{
uint16 *s = GFX.Screen + y * GFX.RealPPL + x;
for (r = 0; r < 15 * rx; r++, s += GFX.RealPPL - 15 * cx) for (r = 0; r < 15 * rx; r++, s += GFX.RealPPL - 15 * cx)
{ {
@ -2290,7 +2316,6 @@ void S9xDrawCrosshair (const char *crosshair, uint8 fgcolor, uint8 bgcolor, int1
} }
} }
} }
}
#ifdef GFX_MULTI_FORMAT #ifdef GFX_MULTI_FORMAT

File diff suppressed because it is too large Load Diff

View File

@ -17,13 +17,20 @@
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja (c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso, (c) Copyright 2009 - 2018 BearOso,
OV2 OV2
(c) Copyright 2017 qwertymodo
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
BS-X C emulator code BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom, (c) Copyright 2005 - 2006 Dreamer Nom,
@ -117,6 +124,9 @@
Sound emulator code used in 1.52+ Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
S-SMP emulator code used in 1.54+
(c) Copyright 2016 byuu
SH assembler code partly based on x86 assembler code SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
@ -130,7 +140,7 @@
(c) Copyright 2006 - 2007 Shay Green (c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso (c) Copyright 2004 - 2018 BearOso
Win32 GUI code Win32 GUI code
(c) Copyright 2003 - 2006 blip, (c) Copyright 2003 - 2006 blip,
@ -138,11 +148,16 @@
Matthew Kendora, Matthew Kendora,
Nach, Nach,
nitsuja nitsuja
(c) Copyright 2009 - 2010 OV2 (c) Copyright 2009 - 2018 OV2
Mac OS GUI code Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2011 zones
Libretro port
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
@ -261,6 +276,7 @@ struct CMemory
uint32 ROMChecksum; uint32 ROMChecksum;
uint32 ROMComplementChecksum; uint32 ROMComplementChecksum;
uint32 ROMCRC32; uint32 ROMCRC32;
unsigned char ROMSHA256[32];
int32 ROMFramesPerSecond; int32 ROMFramesPerSecond;
bool8 HiROM; bool8 HiROM;
@ -278,17 +294,24 @@ struct CMemory
int ScoreHiROM (bool8, int32 romoff = 0); int ScoreHiROM (bool8, int32 romoff = 0);
int ScoreLoROM (bool8, int32 romoff = 0); int ScoreLoROM (bool8, int32 romoff = 0);
uint32 HeaderRemove (uint32, int32 &, uint8 *); uint32 HeaderRemove (uint32, uint8 *);
uint32 FileLoader (uint8 *, const char *, int32); uint32 FileLoader (uint8 *, const char *, uint32);
uint32 MemLoader (uint8 *, const char*, uint32);
bool8 LoadROMMem (const uint8 *, uint32);
bool8 LoadROM (const char *); bool8 LoadROM (const char *);
bool8 LoadROMInt (int32);
bool8 LoadMultiCartMem (const uint8 *, uint32, const uint8 *, uint32, const uint8 *, uint32);
bool8 LoadMultiCart (const char *, const char *); bool8 LoadMultiCart (const char *, const char *);
bool8 LoadSufamiTurbo (const char *, const char *); bool8 LoadMultiCartInt ();
bool8 LoadSameGame (const char *, const char *); bool8 LoadSufamiTurbo ();
bool8 LoadBSCart ();
bool8 LoadGNEXT ();
bool8 LoadSRAM (const char *); bool8 LoadSRAM (const char *);
bool8 SaveSRAM (const char *); bool8 SaveSRAM (const char *);
void ClearSRAM (bool8 onlyNonSavedSRAM = 0); void ClearSRAM (bool8 onlyNonSavedSRAM = 0);
bool8 LoadSRTC (void); bool8 LoadSRTC (void);
bool8 SaveSRTC (void); bool8 SaveSRTC (void);
bool8 SaveMPAK (const char *);
char * Safe (const char *); char * Safe (const char *);
char * SafeANK (const char *); char * SafeANK (const char *);
@ -324,10 +347,12 @@ struct CMemory
void Map_SetaDSPLoROMMap (void); void Map_SetaDSPLoROMMap (void);
void Map_SDD1LoROMMap (void); void Map_SDD1LoROMMap (void);
void Map_SA1LoROMMap (void); void Map_SA1LoROMMap (void);
void Map_BSSA1LoROMMap (void);
void Map_HiROMMap (void); void Map_HiROMMap (void);
void Map_ExtendedHiROMMap (void); void Map_ExtendedHiROMMap (void);
void Map_SameGameHiROMMap (void);
void Map_SPC7110HiROMMap (void); void Map_SPC7110HiROMMap (void);
void Map_BSCartLoROMMap(uint8);
void Map_BSCartHiROMMap(void);
uint16 checksum_calc_sum (uint8 *, uint32); uint16 checksum_calc_sum (uint8 *, uint32);
uint16 checksum_mirror_sum (uint8 *, uint32 &, uint32 mask = 0x800000); uint16 checksum_mirror_sum (uint8 *, uint32 &, uint32 mask = 0x800000);
@ -366,7 +391,7 @@ extern CMemory Memory;
extern SMulti Multi; extern SMulti Multi;
void S9xAutoSaveSRAM (void); void S9xAutoSaveSRAM (void);
bool8 LoadZip(const char *, int32 *, int32 *, uint8 *); bool8 LoadZip(const char *, uint32 *, uint8 *);
enum s9xwrap_t enum s9xwrap_t
{ {

View File

@ -17,13 +17,20 @@
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja (c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso, (c) Copyright 2009 - 2018 BearOso,
OV2 OV2
(c) Copyright 2017 qwertymodo
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
BS-X C emulator code BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom, (c) Copyright 2005 - 2006 Dreamer Nom,
@ -117,6 +124,9 @@
Sound emulator code used in 1.52+ Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
S-SMP emulator code used in 1.54+
(c) Copyright 2016 byuu
SH assembler code partly based on x86 assembler code SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
@ -130,7 +140,7 @@
(c) Copyright 2006 - 2007 Shay Green (c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso (c) Copyright 2004 - 2018 BearOso
Win32 GUI code Win32 GUI code
(c) Copyright 2003 - 2006 blip, (c) Copyright 2003 - 2006 blip,
@ -138,11 +148,16 @@
Matthew Kendora, Matthew Kendora,
Nach, Nach,
nitsuja nitsuja
(c) Copyright 2009 - 2010 OV2 (c) Copyright 2009 - 2018 OV2
Mac OS GUI code Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2011 zones
Libretro port
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
@ -204,9 +219,6 @@ static inline void S9xLatchCounters (bool force)
#ifdef DEBUGGER #ifdef DEBUGGER
missing.h_v_latch = 1; missing.h_v_latch = 1;
#endif #endif
#if 0 // #ifdef CPU_SHUTDOWN
CPU.WaitAddress = CPU.PCAtOpcodeStart;
#endif
PPU.HVBeamCounterLatched = 1; PPU.HVBeamCounterLatched = 1;
PPU.VBeamPosLatched = (uint16) CPU.V_Counter; PPU.VBeamPosLatched = (uint16) CPU.V_Counter;
@ -245,9 +257,6 @@ static inline void S9xTryGunLatch (bool force)
#ifdef DEBUGGER #ifdef DEBUGGER
missing.h_v_latch = 1; missing.h_v_latch = 1;
#endif #endif
#if 0 // #ifdef CPU_SHUTDOWN
CPU.WaitAddress = CPU.PCAtOpcodeStart;
#endif
PPU.HVBeamCounterLatched = 1; PPU.HVBeamCounterLatched = 1;
PPU.VBeamPosLatched = (uint16) PPU.GunVLatch; PPU.VBeamPosLatched = (uint16) PPU.GunVLatch;
@ -260,189 +269,105 @@ static inline void S9xTryGunLatch (bool force)
} }
} }
void S9xCheckMissingHTimerPosition (int32 hc) static int CyclesUntilNext (int hc, int vc)
{ {
if (PPU.HTimerPosition == hc) int32 total = 0;
{ int vpos = CPU.V_Counter;
if (PPU.HTimerEnabled && (!PPU.VTimerEnabled || (CPU.V_Counter == PPU.VTimerPosition)))
S9xSetIRQ(PPU_IRQ_SOURCE);
else
if (PPU.VTimerEnabled && (CPU.V_Counter == PPU.VTimerPosition))
S9xSetIRQ(PPU_IRQ_SOURCE);
}
}
void S9xCheckMissingHTimerHalt (int32 hc_from, int32 range) if (vc - vpos > 0)
{ {
if ((PPU.HTimerPosition >= hc_from) && (PPU.HTimerPosition < (hc_from + range))) // It's still in this frame */
{ // Add number of lines
if (PPU.HTimerEnabled && (!PPU.VTimerEnabled || (CPU.V_Counter == PPU.VTimerPosition))) total += (vc - vpos) * Timings.H_Max_Master;
CPU.IRQPending = 1; // If line 240 is in there and we're odd, subtract a dot
else if (vpos <= 240 && vc > 240 && Timings.InterlaceField & !IPPU.Interlace)
if (PPU.VTimerEnabled && (CPU.V_Counter == PPU.VTimerPosition)) total -= ONE_DOT_CYCLE;
CPU.IRQPending = 1;
}
}
void S9xCheckMissingHTimerRange (int32 hc_from, int32 range)
{
if ((PPU.HTimerPosition >= hc_from) && (PPU.HTimerPosition < (hc_from + range)))
{
if (PPU.HTimerEnabled && (!PPU.VTimerEnabled || (CPU.V_Counter == PPU.VTimerPosition)))
S9xSetIRQ(PPU_IRQ_SOURCE);
else
if (PPU.VTimerEnabled && (CPU.V_Counter == PPU.VTimerPosition))
S9xSetIRQ(PPU_IRQ_SOURCE);
}
}
void S9xUpdateHVTimerPosition (void)
{
if (PPU.HTimerEnabled)
{
#ifdef DEBUGGER
missing.hirq_pos = PPU.IRQHBeamPos;
#endif
if (PPU.IRQHBeamPos != 0)
{
// IRQ_read
PPU.HTimerPosition = PPU.IRQHBeamPos * ONE_DOT_CYCLE;
if (Timings.H_Max == Timings.H_Max_Master) // 1364
{
if (PPU.IRQHBeamPos > 322)
PPU.HTimerPosition += (ONE_DOT_CYCLE / 2);
if (PPU.IRQHBeamPos > 326)
PPU.HTimerPosition += (ONE_DOT_CYCLE / 2);
}
PPU.HTimerPosition += 14;
// /IRQ
PPU.HTimerPosition += 4;
// after CPU executing
PPU.HTimerPosition += 6;
} }
else else
PPU.HTimerPosition = 10 + 4 + 6; {
if (vc == vpos && (hc > CPU.Cycles))
{
return hc;
} }
else
PPU.HTimerPosition = 10 + 4 + 6;
total += (Timings.V_Max - vpos) * Timings.H_Max_Master;
if (vpos <= 240 && Timings.InterlaceField && !IPPU.Interlace)
total -= ONE_DOT_CYCLE;
total += (vc) * Timings.H_Max_Master;
if (vc > 240 && !Timings.InterlaceField && !IPPU.Interlace)
total -= ONE_DOT_CYCLE;
}
total += hc;
return total;
}
void S9xUpdateIRQPositions (bool initial)
{
PPU.HTimerPosition = PPU.IRQHBeamPos * ONE_DOT_CYCLE + Timings.IRQTriggerCycles;
PPU.HTimerPosition -= PPU.IRQHBeamPos ? 0 : ONE_DOT_CYCLE;
PPU.HTimerPosition += PPU.IRQHBeamPos > 322 ? (ONE_DOT_CYCLE / 2) : 0;
PPU.HTimerPosition += PPU.IRQHBeamPos > 326 ? (ONE_DOT_CYCLE / 2) : 0;
PPU.VTimerPosition = PPU.IRQVBeamPos; PPU.VTimerPosition = PPU.IRQVBeamPos;
if ((PPU.HTimerPosition >= Timings.H_Max) && (PPU.IRQHBeamPos < 340)) if (PPU.VTimerEnabled && (PPU.VTimerPosition >= (Timings.V_Max + (IPPU.Interlace ? 1 : 0))))
{ {
PPU.HTimerPosition -= Timings.H_Max; Timings.NextIRQTimer = 0x0fffffff;
PPU.VTimerPosition++; }
// FIXME else if (!PPU.HTimerEnabled && !PPU.VTimerEnabled)
if (PPU.VTimerPosition >= Timings.V_Max) {
PPU.VTimerPosition = 0; Timings.NextIRQTimer = 0x0fffffff;
}
else if (PPU.HTimerEnabled && !PPU.VTimerEnabled)
{
int v_pos = CPU.V_Counter;
Timings.NextIRQTimer = PPU.HTimerPosition;
if (CPU.Cycles > Timings.NextIRQTimer - Timings.IRQTriggerCycles)
{
Timings.NextIRQTimer += Timings.H_Max;
v_pos++;
} }
if (PPU.HTimerPosition < CPU.Cycles) // Check for short dot scanline
if (v_pos == 240 && Timings.InterlaceField && !IPPU.Interlace)
{ {
switch (CPU.WhichEvent) Timings.NextIRQTimer -= PPU.IRQHBeamPos <= 322 ? ONE_DOT_CYCLE / 2 : 0;
{ Timings.NextIRQTimer -= PPU.IRQHBeamPos <= 326 ? ONE_DOT_CYCLE / 2 : 0;
case HC_IRQ_1_3_EVENT:
CPU.WhichEvent = HC_HDMA_START_EVENT;
CPU.NextEvent = Timings.HDMAStart;
break;
case HC_IRQ_3_5_EVENT:
CPU.WhichEvent = HC_HCOUNTER_MAX_EVENT;
CPU.NextEvent = Timings.H_Max;
break;
case HC_IRQ_5_7_EVENT:
CPU.WhichEvent = HC_HDMA_INIT_EVENT;
CPU.NextEvent = Timings.HDMAInit;
break;
case HC_IRQ_7_9_EVENT:
CPU.WhichEvent = HC_RENDER_EVENT;
CPU.NextEvent = Timings.RenderPos;
break;
case HC_IRQ_9_A_EVENT:
CPU.WhichEvent = HC_WRAM_REFRESH_EVENT;
CPU.NextEvent = Timings.WRAMRefreshPos;
break;
case HC_IRQ_A_1_EVENT:
CPU.WhichEvent = HC_HBLANK_START_EVENT;
CPU.NextEvent = Timings.HBlankStart;
break;
} }
} }
else if (!PPU.HTimerEnabled && PPU.VTimerEnabled)
{
if (CPU.V_Counter == PPU.VTimerPosition && initial)
Timings.NextIRQTimer = CPU.Cycles + Timings.IRQTriggerCycles;
else else
if ((PPU.HTimerPosition < CPU.NextEvent) || (!(CPU.WhichEvent & 1) && (PPU.HTimerPosition == CPU.NextEvent))) Timings.NextIRQTimer = CyclesUntilNext (Timings.IRQTriggerCycles, PPU.VTimerPosition);
{
CPU.NextEvent = PPU.HTimerPosition;
switch (CPU.WhichEvent)
{
case HC_HDMA_START_EVENT:
CPU.WhichEvent = HC_IRQ_1_3_EVENT;
break;
case HC_HCOUNTER_MAX_EVENT:
CPU.WhichEvent = HC_IRQ_3_5_EVENT;
break;
case HC_HDMA_INIT_EVENT:
CPU.WhichEvent = HC_IRQ_5_7_EVENT;
break;
case HC_RENDER_EVENT:
CPU.WhichEvent = HC_IRQ_7_9_EVENT;
break;
case HC_WRAM_REFRESH_EVENT:
CPU.WhichEvent = HC_IRQ_9_A_EVENT;
break;
case HC_HBLANK_START_EVENT:
CPU.WhichEvent = HC_IRQ_A_1_EVENT;
break;
}
} }
else else
{ {
switch (CPU.WhichEvent) Timings.NextIRQTimer = CyclesUntilNext (PPU.HTimerPosition, PPU.VTimerPosition);
// Check for short dot scanline
int field = Timings.InterlaceField;
if (PPU.VTimerPosition < CPU.V_Counter ||
(PPU.VTimerPosition == CPU.V_Counter && Timings.NextIRQTimer > Timings.H_Max))
{ {
case HC_IRQ_1_3_EVENT: field = !field;
CPU.WhichEvent = HC_HDMA_START_EVENT; }
CPU.NextEvent = Timings.HDMAStart;
break;
case HC_IRQ_3_5_EVENT: if (PPU.VTimerPosition == 240 && field && !IPPU.Interlace)
CPU.WhichEvent = HC_HCOUNTER_MAX_EVENT; {
CPU.NextEvent = Timings.H_Max; Timings.NextIRQTimer -= PPU.IRQHBeamPos <= 322 ? ONE_DOT_CYCLE / 2 : 0;
break; Timings.NextIRQTimer -= PPU.IRQHBeamPos <= 326 ? ONE_DOT_CYCLE / 2 : 0;
case HC_IRQ_5_7_EVENT:
CPU.WhichEvent = HC_HDMA_INIT_EVENT;
CPU.NextEvent = Timings.HDMAInit;
break;
case HC_IRQ_7_9_EVENT:
CPU.WhichEvent = HC_RENDER_EVENT;
CPU.NextEvent = Timings.RenderPos;
break;
case HC_IRQ_9_A_EVENT:
CPU.WhichEvent = HC_WRAM_REFRESH_EVENT;
CPU.NextEvent = Timings.WRAMRefreshPos;
break;
case HC_IRQ_A_1_EVENT:
CPU.WhichEvent = HC_HBLANK_START_EVENT;
CPU.NextEvent = Timings.HBlankStart;
break;
} }
} }
#ifdef DEBUGGER #ifdef DEBUGGER
S9xTraceFormattedMessage("--- IRQ settings: H:%d V:%d (%04d, %03d)", PPU.HTimerEnabled, PPU.VTimerEnabled, PPU.HTimerPosition, PPU.VTimerPosition); S9xTraceFormattedMessage("--- IRQ Timer HC:%d VC:%d set %d cycles HTimer:%d Pos:%04d->%04d VTimer:%d Pos:%03d->%03d", CPU.Cycles, CPU.V_Counter,
Timings.NextIRQTimer, PPU.HTimerEnabled, PPU.IRQHBeamPos, PPU.HTimerPosition, PPU.VTimerEnabled, PPU.IRQVBeamPos, PPU.VTimerPosition);
#endif #endif
} }
@ -514,9 +439,9 @@ void S9xSetPPU (uint8 Byte, uint16 Address)
if (PPU.Brightness != (Byte & 0xf)) if (PPU.Brightness != (Byte & 0xf))
{ {
IPPU.ColorsChanged = TRUE; IPPU.ColorsChanged = TRUE;
IPPU.DirectColourMapsNeedRebuild = TRUE;
PPU.Brightness = Byte & 0xf; PPU.Brightness = Byte & 0xf;
S9xFixColourBrightness(); S9xFixColourBrightness();
S9xBuildDirectColourMaps();
if (PPU.Brightness > IPPU.MaxBrightness) if (PPU.Brightness > IPPU.MaxBrightness)
IPPU.MaxBrightness = PPU.Brightness; IPPU.MaxBrightness = PPU.Brightness;
} }
@ -560,7 +485,7 @@ void S9xSetPPU (uint8 Byte, uint16 Address)
case 0x2102: // OAMADDL case 0x2102: // OAMADDL
PPU.OAMAddr = ((Memory.FillRAM[0x2103] & 1) << 8) | Byte; PPU.OAMAddr = ((Memory.FillRAM[0x2103] & 1) << 8) | Byte;
PPU.OAMFlip = 2; PPU.OAMFlip = 0;
PPU.OAMReadFlip = 0; PPU.OAMReadFlip = 0;
PPU.SavedOAMAddr = PPU.OAMAddr; PPU.SavedOAMAddr = PPU.OAMAddr;
if (PPU.OAMPriorityRotation && PPU.FirstSprite != (PPU.OAMAddr >> 1)) if (PPU.OAMPriorityRotation && PPU.FirstSprite != (PPU.OAMAddr >> 1))
@ -621,7 +546,10 @@ void S9xSetPPU (uint8 Byte, uint16 Address)
PPU.BGMode = Byte & 7; PPU.BGMode = Byte & 7;
// BJ: BG3Priority only takes effect if BGMode == 1 and the bit is set // BJ: BG3Priority only takes effect if BGMode == 1 and the bit is set
PPU.BG3Priority = ((Byte & 0x0f) == 0x09); PPU.BG3Priority = ((Byte & 0x0f) == 0x09);
if (PPU.BGMode == 6 || PPU.BGMode == 5 || PPU.BGMode == 7)
IPPU.Interlace = Memory.FillRAM[0x2133] & 1; IPPU.Interlace = Memory.FillRAM[0x2133] & 1;
else
IPPU.Interlace = 0;
#ifdef DEBUGGER #ifdef DEBUGGER
missing.modes[PPU.BGMode] = 1; missing.modes[PPU.BGMode] = 1;
#endif #endif
@ -787,7 +715,7 @@ void S9xSetPPU (uint8 Byte, uint16 Address)
case 0x2116: // VMADDL case 0x2116: // VMADDL
PPU.VMA.Address &= 0xff00; PPU.VMA.Address &= 0xff00;
PPU.VMA.Address |= Byte; PPU.VMA.Address |= Byte;
#ifdef CORRECT_VRAM_READS
if (PPU.VMA.FullGraphicCount) if (PPU.VMA.FullGraphicCount)
{ {
uint32 addr = PPU.VMA.Address; uint32 addr = PPU.VMA.Address;
@ -797,15 +725,13 @@ void S9xSetPPU (uint8 Byte, uint16 Address)
} }
else else
IPPU.VRAMReadBuffer = READ_WORD(Memory.VRAM + ((PPU.VMA.Address << 1) & 0xffff)); IPPU.VRAMReadBuffer = READ_WORD(Memory.VRAM + ((PPU.VMA.Address << 1) & 0xffff));
#else
IPPU.FirstVRAMRead = TRUE;
#endif
break; break;
case 0x2117: // VMADDH case 0x2117: // VMADDH
PPU.VMA.Address &= 0x00ff; PPU.VMA.Address &= 0x00ff;
PPU.VMA.Address |= Byte << 8; PPU.VMA.Address |= Byte << 8;
#ifdef CORRECT_VRAM_READS
if (PPU.VMA.FullGraphicCount) if (PPU.VMA.FullGraphicCount)
{ {
uint32 addr = PPU.VMA.Address; uint32 addr = PPU.VMA.Address;
@ -815,22 +741,14 @@ void S9xSetPPU (uint8 Byte, uint16 Address)
} }
else else
IPPU.VRAMReadBuffer = READ_WORD(Memory.VRAM + ((PPU.VMA.Address << 1) & 0xffff)); IPPU.VRAMReadBuffer = READ_WORD(Memory.VRAM + ((PPU.VMA.Address << 1) & 0xffff));
#else
IPPU.FirstVRAMRead = TRUE;
#endif
break; break;
case 0x2118: // VMDATAL case 0x2118: // VMDATAL
#ifndef CORRECT_VRAM_READS
IPPU.FirstVRAMRead = TRUE;
#endif
REGISTER_2118(Byte); REGISTER_2118(Byte);
break; break;
case 0x2119: // VMDATAH case 0x2119: // VMDATAH
#ifndef CORRECT_VRAM_READS
IPPU.FirstVRAMRead = TRUE;
#endif
REGISTER_2119(Byte); REGISTER_2119(Byte);
break; break;
@ -1146,13 +1064,20 @@ void S9xSetPPU (uint8 Byte, uint16 Address)
#endif #endif
} }
else else
{
PPU.ScreenHeight = SNES_HEIGHT; PPU.ScreenHeight = SNES_HEIGHT;
if (IPPU.DoubleHeightPixels)
IPPU.RenderedScreenHeight = PPU.ScreenHeight << 1;
else
IPPU.RenderedScreenHeight = PPU.ScreenHeight;
}
if ((Memory.FillRAM[0x2133] ^ Byte) & 3) if ((Memory.FillRAM[0x2133] ^ Byte) & 3)
{ {
FLUSH_REDRAW(); FLUSH_REDRAW();
if ((Memory.FillRAM[0x2133] ^ Byte) & 2) if ((Memory.FillRAM[0x2133] ^ Byte) & 2)
IPPU.OBJChanged = TRUE; IPPU.OBJChanged = TRUE;
IPPU.Interlace = Byte & 1; IPPU.Interlace = Byte & 1;
IPPU.InterlaceOBJ = Byte & 2; IPPU.InterlaceOBJ = Byte & 2;
} }
@ -1259,10 +1184,9 @@ void S9xSetPPU (uint8 Byte, uint16 Address)
uint8 S9xGetPPU (uint16 Address) uint8 S9xGetPPU (uint16 Address)
{ {
// MAP_PPU: $2000-$3FFF // MAP_PPU: $2000-$3FFF
if (Settings.MSU1 && (Address & 0xfff8) == 0x2000) if (Settings.MSU1 && (Address & 0xfff8) == 0x2000)
return (S9xMSU1ReadPort(Address & 7)); return (S9xMSU1ReadPort(Address & 7));
else
if (Address < 0x2100) if (Address < 0x2100)
return (OpenBus); return (OpenBus);
@ -1337,7 +1261,7 @@ uint8 S9xGetPPU (uint16 Address)
case 0x2137: // SLHV case 0x2137: // SLHV
S9xLatchCounters(0); S9xLatchCounters(0);
return (OpenBus); return (PPU.OpenBus1);
case 0x2138: // OAMDATAREAD case 0x2138: // OAMDATAREAD
if (PPU.OAMAddr & 0x100) if (PPU.OAMAddr & 0x100)
@ -1384,7 +1308,6 @@ uint8 S9xGetPPU (uint16 Address)
return (PPU.OpenBus1 = byte); return (PPU.OpenBus1 = byte);
case 0x2139: // VMDATALREAD case 0x2139: // VMDATALREAD
#ifdef CORRECT_VRAM_READS
byte = IPPU.VRAMReadBuffer & 0xff; byte = IPPU.VRAMReadBuffer & 0xff;
if (!PPU.VMA.High) if (!PPU.VMA.High)
{ {
@ -1400,33 +1323,13 @@ uint8 S9xGetPPU (uint16 Address)
PPU.VMA.Address += PPU.VMA.Increment; PPU.VMA.Address += PPU.VMA.Increment;
} }
#else
if (IPPU.FirstVRAMRead)
byte = Memory.VRAM[(PPU.VMA.Address << 1) & 0xffff];
else
if (PPU.VMA.FullGraphicCount)
{
uint32 addr = PPU.VMA.Address - 1;
uint32 rem = addr & PPU.VMA.Mask1;
uint32 address = (addr & ~PPU.VMA.Mask1) + (rem >> PPU.VMA.Shift) + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3);
byte = Memory.VRAM[((address << 1) - 2) & 0xffff];
}
else
byte = Memory.VRAM[((PPU.VMA.Address << 1) - 2) & 0xffff];
if (!PPU.VMA.High)
{
PPU.VMA.Address += PPU.VMA.Increment;
IPPU.FirstVRAMRead = FALSE;
}
#endif
#ifdef DEBUGGER #ifdef DEBUGGER
missing.vram_read = 1; missing.vram_read = 1;
#endif #endif
return (PPU.OpenBus1 = byte); return (PPU.OpenBus1 = byte);
case 0x213a: // VMDATAHREAD case 0x213a: // VMDATAHREAD
#ifdef CORRECT_VRAM_READS
byte = (IPPU.VRAMReadBuffer >> 8) & 0xff; byte = (IPPU.VRAMReadBuffer >> 8) & 0xff;
if (PPU.VMA.High) if (PPU.VMA.High)
{ {
@ -1442,26 +1345,6 @@ uint8 S9xGetPPU (uint16 Address)
PPU.VMA.Address += PPU.VMA.Increment; PPU.VMA.Address += PPU.VMA.Increment;
} }
#else
if (IPPU.FirstVRAMRead)
byte = Memory.VRAM[((PPU.VMA.Address << 1) + 1) & 0xffff];
else
if (PPU.VMA.FullGraphicCount)
{
uint32 addr = PPU.VMA.Address - 1;
uint32 rem = addr & PPU.VMA.Mask1;
uint32 address = (addr & ~PPU.VMA.Mask1) + (rem >> PPU.VMA.Shift) + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3);
byte = Memory.VRAM[((address << 1) - 1) & 0xffff];
}
else
byte = Memory.VRAM[((PPU.VMA.Address << 1) - 1) & 0xffff];
if (PPU.VMA.High)
{
PPU.VMA.Address += PPU.VMA.Increment;
IPPU.FirstVRAMRead = FALSE;
}
#endif
#ifdef DEBUGGER #ifdef DEBUGGER
missing.vram_read = 1; missing.vram_read = 1;
#endif #endif
@ -1677,9 +1560,18 @@ void S9xSetCPU (uint8 Byte, uint16 Address)
switch (Address) switch (Address)
{ {
case 0x4200: // NMITIMEN case 0x4200: // NMITIMEN
#ifdef DEBUGGER
if (Settings.TraceHCEvent)
S9xTraceFormattedMessage("Write to 0x4200. Byte is %2x was %2x\n", Byte, Memory.FillRAM[Address]);
#endif
if (Byte == Memory.FillRAM[0x4200])
break;
if (Byte & 0x20) if (Byte & 0x20)
{ {
PPU.VTimerEnabled = TRUE; PPU.VTimerEnabled = TRUE;
#ifdef DEBUGGER #ifdef DEBUGGER
missing.virq = 1; missing.virq = 1;
missing.virq_pos = PPU.IRQVBeamPos; missing.virq_pos = PPU.IRQVBeamPos;
@ -1691,6 +1583,7 @@ void S9xSetCPU (uint8 Byte, uint16 Address)
if (Byte & 0x10) if (Byte & 0x10)
{ {
PPU.HTimerEnabled = TRUE; PPU.HTimerEnabled = TRUE;
#ifdef DEBUGGER #ifdef DEBUGGER
missing.hirq = 1; missing.hirq = 1;
missing.hirq_pos = PPU.IRQHBeamPos; missing.hirq_pos = PPU.IRQHBeamPos;
@ -1699,14 +1592,13 @@ void S9xSetCPU (uint8 Byte, uint16 Address)
else else
PPU.HTimerEnabled = FALSE; PPU.HTimerEnabled = FALSE;
S9xUpdateHVTimerPosition(); if (!(Byte & 0x10) && !(Byte & 0x20))
{
CPU.IRQLine = FALSE;
CPU.IRQTransition = FALSE;
}
// The case that IRQ will trigger in an instruction such as STA $4200. S9xUpdateIRQPositions(true);
// FIXME: not true but good enough for Snes9x, I think.
S9xCheckMissingHTimerRange(CPU.PrevCycles, CPU.Cycles - CPU.PrevCycles);
if (!(Byte & 0x30))
S9xClearIRQ(PPU_IRQ_SOURCE);
// NMI can trigger immediately during VBlank as long as NMI_read ($4210) wasn't cleard. // NMI can trigger immediately during VBlank as long as NMI_read ($4210) wasn't cleard.
if ((Byte & 0x80) && !(Memory.FillRAM[0x4200] & 0x80) && if ((Byte & 0x80) && !(Memory.FillRAM[0x4200] & 0x80) &&
@ -1714,10 +1606,20 @@ void S9xSetCPU (uint8 Byte, uint16 Address)
{ {
// FIXME: triggered at HC+=6, checked just before the final CPU cycle, // FIXME: triggered at HC+=6, checked just before the final CPU cycle,
// then, when to call S9xOpcode_NMI()? // then, when to call S9xOpcode_NMI()?
CPU.Flags |= NMI_FLAG; CPU.NMIPending = TRUE;
Timings.NMITriggerPos = CPU.Cycles + 6 + 6; Timings.NMITriggerPos = CPU.Cycles + 6 + 6;
#ifdef DEBUGGER
if (Settings.TraceHCEvent)
S9xTraceFormattedMessage("NMI Triggered on low-to-high occurring at next HC=%d\n", Timings.NMITriggerPos);
#endif
} }
#ifdef DEBUGGER
S9xTraceFormattedMessage("--- IRQ Timer Enable HTimer:%d Pos:%04d VTimer:%d Pos:%03d",
PPU.HTimerEnabled, PPU.HTimerPosition, PPU.VTimerEnabled, PPU.VTimerPosition);
#endif
break; break;
case 0x4201: // WRIO case 0x4201: // WRIO
@ -1761,7 +1663,7 @@ void S9xSetCPU (uint8 Byte, uint16 Address)
pos = PPU.IRQHBeamPos; pos = PPU.IRQHBeamPos;
PPU.IRQHBeamPos = (PPU.IRQHBeamPos & 0xff00) | Byte; PPU.IRQHBeamPos = (PPU.IRQHBeamPos & 0xff00) | Byte;
if (PPU.IRQHBeamPos != pos) if (PPU.IRQHBeamPos != pos)
S9xUpdateHVTimerPosition(); S9xUpdateIRQPositions(false);
#ifdef DEBUGGER #ifdef DEBUGGER
missing.hirq_pos = PPU.IRQHBeamPos; missing.hirq_pos = PPU.IRQHBeamPos;
#endif #endif
@ -1771,7 +1673,7 @@ void S9xSetCPU (uint8 Byte, uint16 Address)
pos = PPU.IRQHBeamPos; pos = PPU.IRQHBeamPos;
PPU.IRQHBeamPos = (PPU.IRQHBeamPos & 0xff) | ((Byte & 1) << 8); PPU.IRQHBeamPos = (PPU.IRQHBeamPos & 0xff) | ((Byte & 1) << 8);
if (PPU.IRQHBeamPos != pos) if (PPU.IRQHBeamPos != pos)
S9xUpdateHVTimerPosition(); S9xUpdateIRQPositions(false);
#ifdef DEBUGGER #ifdef DEBUGGER
missing.hirq_pos = PPU.IRQHBeamPos; missing.hirq_pos = PPU.IRQHBeamPos;
#endif #endif
@ -1781,7 +1683,7 @@ void S9xSetCPU (uint8 Byte, uint16 Address)
pos = PPU.IRQVBeamPos; pos = PPU.IRQVBeamPos;
PPU.IRQVBeamPos = (PPU.IRQVBeamPos & 0xff00) | Byte; PPU.IRQVBeamPos = (PPU.IRQVBeamPos & 0xff00) | Byte;
if (PPU.IRQVBeamPos != pos) if (PPU.IRQVBeamPos != pos)
S9xUpdateHVTimerPosition(); S9xUpdateIRQPositions(true);
#ifdef DEBUGGER #ifdef DEBUGGER
missing.virq_pos = PPU.IRQVBeamPos; missing.virq_pos = PPU.IRQVBeamPos;
#endif #endif
@ -1791,7 +1693,7 @@ void S9xSetCPU (uint8 Byte, uint16 Address)
pos = PPU.IRQVBeamPos; pos = PPU.IRQVBeamPos;
PPU.IRQVBeamPos = (PPU.IRQVBeamPos & 0xff) | ((Byte & 1) << 8); PPU.IRQVBeamPos = (PPU.IRQVBeamPos & 0xff) | ((Byte & 1) << 8);
if (PPU.IRQVBeamPos != pos) if (PPU.IRQVBeamPos != pos)
S9xUpdateHVTimerPosition(); S9xUpdateIRQPositions(true);
#ifdef DEBUGGER #ifdef DEBUGGER
missing.virq_pos = PPU.IRQVBeamPos; missing.virq_pos = PPU.IRQVBeamPos;
#endif #endif
@ -1801,8 +1703,9 @@ void S9xSetCPU (uint8 Byte, uint16 Address)
if (CPU.InDMAorHDMA) if (CPU.InDMAorHDMA)
return; return;
// XXX: Not quite right... // XXX: Not quite right...
if (Byte) if (Byte) {
CPU.Cycles += Timings.DMACPUSync; CPU.Cycles += Timings.DMACPUSync;
}
if (Byte & 0x01) if (Byte & 0x01)
S9xDoDMA(0); S9xDoDMA(0);
if (Byte & 0x02) if (Byte & 0x02)
@ -1828,8 +1731,6 @@ void S9xSetCPU (uint8 Byte, uint16 Address)
case 0x420c: // HDMAEN case 0x420c: // HDMAEN
if (CPU.InDMAorHDMA) if (CPU.InDMAorHDMA)
return; return;
if (Settings.DisableHDMA)
Byte = 0;
Memory.FillRAM[0x420c] = Byte; Memory.FillRAM[0x420c] = Byte;
// Yoshi's Island, Genjyu Ryodan, Mortal Kombat, Tales of Phantasia // Yoshi's Island, Genjyu Ryodan, Mortal Kombat, Tales of Phantasia
PPU.HDMA = Byte & ~PPU.HDMAEnded; PPU.HDMA = Byte & ~PPU.HDMAEnded;
@ -1856,17 +1757,7 @@ void S9xSetCPU (uint8 Byte, uint16 Address)
break; break;
case 0x4210: // RDNMI case 0x4210: // RDNMI
#if 0
Memory.FillRAM[0x4210] = Model->_5A22;
#endif
return;
case 0x4211: // TIMEUP case 0x4211: // TIMEUP
#if 0
S9xClearIRQ(PPU_IRQ_SOURCE);
#endif
return;
case 0x4212: // HVBJOY case 0x4212: // HVBJOY
case 0x4213: // RDIO case 0x4213: // RDIO
case 0x4214: // RDDIVL case 0x4214: // RDDIVL
@ -1982,22 +1873,22 @@ uint8 S9xGetCPU (uint16 Address)
switch (Address) switch (Address)
{ {
case 0x4210: // RDNMI case 0x4210: // RDNMI
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = CPU.PBPCAtOpcodeStart;
#endif
byte = Memory.FillRAM[0x4210]; byte = Memory.FillRAM[0x4210];
Memory.FillRAM[0x4210] = Model->_5A22; Memory.FillRAM[0x4210] = Model->_5A22;
return ((byte & 0x80) | (OpenBus & 0x70) | Model->_5A22); return ((byte & 0x80) | (OpenBus & 0x70) | Model->_5A22);
case 0x4211: // TIMEUP case 0x4211: // TIMEUP
byte = (CPU.IRQActive & PPU_IRQ_SOURCE) ? 0x80 : 0; byte = 0;
S9xClearIRQ(PPU_IRQ_SOURCE); if (CPU.IRQLine)
{
byte = 0x80;
CPU.IRQLine = FALSE;
CPU.IRQTransition = FALSE;
}
return (byte | (OpenBus & 0x7f)); return (byte | (OpenBus & 0x7f));
case 0x4212: // HVBJOY case 0x4212: // HVBJOY
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = CPU.PBPCAtOpcodeStart;
#endif
return (REGISTER_4212() | (OpenBus & 0x3e)); return (REGISTER_4212() | (OpenBus & 0x3e));
case 0x4213: // RDIO case 0x4213: // RDIO
@ -2046,6 +1937,20 @@ void S9xResetPPU (void)
PPU.M7byte = 0; PPU.M7byte = 0;
} }
void S9xResetPPUFast (void)
{
PPU.RecomputeClipWindows = TRUE;
IPPU.ColorsChanged = TRUE;
IPPU.OBJChanged = TRUE;
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);
memset(IPPU.TileCached[TILE_2BIT_EVEN], 0, MAX_2BIT_TILES);
memset(IPPU.TileCached[TILE_2BIT_ODD], 0, MAX_2BIT_TILES);
memset(IPPU.TileCached[TILE_4BIT_EVEN], 0, MAX_4BIT_TILES);
memset(IPPU.TileCached[TILE_4BIT_ODD], 0, MAX_4BIT_TILES);
}
void S9xSoftResetPPU (void) void S9xSoftResetPPU (void)
{ {
S9xControlsSoftReset(); S9xControlsSoftReset();
@ -2109,7 +2014,7 @@ void S9xSoftResetPPU (void)
PPU.OAMReadFlip = 0; PPU.OAMReadFlip = 0;
PPU.OAMTileAddress = 0; PPU.OAMTileAddress = 0;
PPU.OAMWriteRegister = 0; PPU.OAMWriteRegister = 0;
ZeroMemory(PPU.OAMData, 512 + 32); memset(PPU.OAMData, 0, 512 + 32);
PPU.FirstSprite = 0; PPU.FirstSprite = 0;
PPU.LastSprite = 127; PPU.LastSprite = 127;
@ -2183,19 +2088,15 @@ void S9xSoftResetPPU (void)
memset(&IPPU.Clip[c], 0, sizeof(struct ClipData)); memset(&IPPU.Clip[c], 0, sizeof(struct ClipData));
IPPU.ColorsChanged = TRUE; IPPU.ColorsChanged = TRUE;
IPPU.OBJChanged = TRUE; IPPU.OBJChanged = TRUE;
IPPU.DirectColourMapsNeedRebuild = TRUE; memset(IPPU.TileCached[TILE_2BIT], 0, MAX_2BIT_TILES);
ZeroMemory(IPPU.TileCached[TILE_2BIT], MAX_2BIT_TILES); memset(IPPU.TileCached[TILE_4BIT], 0, MAX_4BIT_TILES);
ZeroMemory(IPPU.TileCached[TILE_4BIT], MAX_4BIT_TILES); memset(IPPU.TileCached[TILE_8BIT], 0, MAX_8BIT_TILES);
ZeroMemory(IPPU.TileCached[TILE_8BIT], MAX_8BIT_TILES); memset(IPPU.TileCached[TILE_2BIT_EVEN], 0, MAX_2BIT_TILES);
ZeroMemory(IPPU.TileCached[TILE_2BIT_EVEN], MAX_2BIT_TILES); memset(IPPU.TileCached[TILE_2BIT_ODD], 0, MAX_2BIT_TILES);
ZeroMemory(IPPU.TileCached[TILE_2BIT_ODD], MAX_2BIT_TILES); memset(IPPU.TileCached[TILE_4BIT_EVEN], 0, MAX_4BIT_TILES);
ZeroMemory(IPPU.TileCached[TILE_4BIT_EVEN], MAX_4BIT_TILES); memset(IPPU.TileCached[TILE_4BIT_ODD], 0, MAX_4BIT_TILES);
ZeroMemory(IPPU.TileCached[TILE_4BIT_ODD], MAX_4BIT_TILES);
#ifdef CORRECT_VRAM_READS
IPPU.VRAMReadBuffer = 0; // XXX: FIXME: anything better? IPPU.VRAMReadBuffer = 0; // XXX: FIXME: anything better?
#else GFX.InterlaceFrame = 0;
IPPU.FirstVRAMRead = FALSE;
#endif
IPPU.Interlace = FALSE; IPPU.Interlace = FALSE;
IPPU.InterlaceOBJ = FALSE; IPPU.InterlaceOBJ = FALSE;
IPPU.DoubleWidthPixels = FALSE; IPPU.DoubleWidthPixels = FALSE;
@ -2216,14 +2117,16 @@ void S9xSoftResetPPU (void)
IPPU.FrameSkip = 0; IPPU.FrameSkip = 0;
S9xFixColourBrightness(); S9xFixColourBrightness();
S9xBuildDirectColourMaps();
for (int c = 0; c < 0x8000; c += 0x100) for (int c = 0; c < 0x8000; c += 0x100)
memset(&Memory.FillRAM[c], c >> 8, 0x100); memset(&Memory.FillRAM[c], c >> 8, 0x100);
ZeroMemory(&Memory.FillRAM[0x2100], 0x100); memset(&Memory.FillRAM[0x2100], 0, 0x100);
ZeroMemory(&Memory.FillRAM[0x4200], 0x100); memset(&Memory.FillRAM[0x4200], 0, 0x100);
ZeroMemory(&Memory.FillRAM[0x4000], 0x100); memset(&Memory.FillRAM[0x4000], 0, 0x100);
// For BS Suttehakkun 2... // For BS Suttehakkun 2...
ZeroMemory(&Memory.FillRAM[0x1000], 0x1000); memset(&Memory.FillRAM[0x1000], 0, 0x1000);
Memory.FillRAM[0x4201] = Memory.FillRAM[0x4213] = 0xff; Memory.FillRAM[0x4201] = Memory.FillRAM[0x4213] = 0xff;
Memory.FillRAM[0x2126] = Memory.FillRAM[0x2128] = 1;
} }

View File

@ -17,13 +17,20 @@
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja (c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso, (c) Copyright 2009 - 2018 BearOso,
OV2 OV2
(c) Copyright 2017 qwertymodo
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
BS-X C emulator code BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom, (c) Copyright 2005 - 2006 Dreamer Nom,
@ -117,6 +124,9 @@
Sound emulator code used in 1.52+ Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
S-SMP emulator code used in 1.54+
(c) Copyright 2016 byuu
SH assembler code partly based on x86 assembler code SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
@ -130,7 +140,7 @@
(c) Copyright 2006 - 2007 Shay Green (c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso (c) Copyright 2004 - 2018 BearOso
Win32 GUI code Win32 GUI code
(c) Copyright 2003 - 2006 blip, (c) Copyright 2003 - 2006 blip,
@ -138,11 +148,16 @@
Matthew Kendora, Matthew Kendora,
Nach, Nach,
nitsuja nitsuja
(c) Copyright 2009 - 2010 OV2 (c) Copyright 2009 - 2018 OV2
Mac OS GUI code Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2011 zones
Libretro port
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
@ -197,11 +212,6 @@
#define CLIP_XOR 2 #define CLIP_XOR 2
#define CLIP_XNOR 3 #define CLIP_XNOR 3
#define PPU_IRQ_SOURCE (1 << 1)
#define GSU_IRQ_SOURCE (1 << 2)
#define SA1_IRQ_SOURCE (1 << 7)
#define SA1_DMA_IRQ_SOURCE (1 << 5)
struct ClipData struct ClipData
{ {
uint8 Count; uint8 Count;
@ -215,14 +225,9 @@ struct InternalPPU
struct ClipData Clip[2][6]; struct ClipData Clip[2][6];
bool8 ColorsChanged; bool8 ColorsChanged;
bool8 OBJChanged; bool8 OBJChanged;
bool8 DirectColourMapsNeedRebuild;
uint8 *TileCache[7]; uint8 *TileCache[7];
uint8 *TileCached[7]; uint8 *TileCached[7];
#ifdef CORRECT_VRAM_READS
uint16 VRAMReadBuffer; uint16 VRAMReadBuffer;
#else
bool8 FirstVRAMRead;
#endif
bool8 Interlace; bool8 Interlace;
bool8 InterlaceOBJ; bool8 InterlaceOBJ;
bool8 PseudoHires; bool8 PseudoHires;
@ -379,15 +384,13 @@ extern struct SPPU PPU;
extern struct InternalPPU IPPU; extern struct InternalPPU IPPU;
void S9xResetPPU (void); void S9xResetPPU (void);
void S9xResetPPUFast (void);
void S9xSoftResetPPU (void); void S9xSoftResetPPU (void);
void S9xSetPPU (uint8, uint16); void S9xSetPPU (uint8, uint16);
uint8 S9xGetPPU (uint16); uint8 S9xGetPPU (uint16);
void S9xSetCPU (uint8, uint16); void S9xSetCPU (uint8, uint16);
uint8 S9xGetCPU (uint16); uint8 S9xGetCPU (uint16);
void S9xUpdateHVTimerPosition (void); void S9xUpdateIRQPositions (bool initial);
void S9xCheckMissingHTimerPosition (int32);
void S9xCheckMissingHTimerRange (int32, int32);
void S9xCheckMissingHTimerHalt (int32, int32);
void S9xFixColourBrightness (void); void S9xFixColourBrightness (void);
void S9xDoAutoJoypad (void); void S9xDoAutoJoypad (void);
@ -417,6 +420,12 @@ static inline void FLUSH_REDRAW (void)
static inline void REGISTER_2104 (uint8 Byte) static inline void REGISTER_2104 (uint8 Byte)
{ {
if (!(PPU.OAMFlip & 1))
{
PPU.OAMWriteRegister &= 0xff00;
PPU.OAMWriteRegister |= Byte;
}
if (PPU.OAMAddr & 0x100) if (PPU.OAMAddr & 0x100)
{ {
int addr = ((PPU.OAMAddr & 0x10f) << 1) + (PPU.OAMFlip & 1); int addr = ((PPU.OAMAddr & 0x10f) << 1) + (PPU.OAMFlip & 1);
@ -438,33 +447,8 @@ static inline void REGISTER_2104 (uint8 Byte)
pObj->Size = Byte & 128; pObj->Size = Byte & 128;
} }
PPU.OAMFlip ^= 1;
if (!(PPU.OAMFlip & 1))
{
++PPU.OAMAddr;
PPU.OAMAddr &= 0x1ff;
if (PPU.OAMPriorityRotation && PPU.FirstSprite != (PPU.OAMAddr >> 1))
{
PPU.FirstSprite = (PPU.OAMAddr & 0xfe) >> 1;
IPPU.OBJChanged = TRUE;
} }
} else if (PPU.OAMFlip & 1)
else
{
if (PPU.OAMPriorityRotation && (PPU.OAMAddr & 1))
IPPU.OBJChanged = TRUE;
}
}
else
if (!(PPU.OAMFlip & 1))
{
PPU.OAMWriteRegister &= 0xff00;
PPU.OAMWriteRegister |= Byte;
PPU.OAMFlip |= 1;
if (PPU.OAMPriorityRotation && (PPU.OAMAddr & 1))
IPPU.OBJChanged = TRUE;
}
else
{ {
PPU.OAMWriteRegister &= 0x00ff; PPU.OAMWriteRegister &= 0x00ff;
uint8 lowbyte = (uint8) (PPU.OAMWriteRegister); uint8 lowbyte = (uint8) (PPU.OAMWriteRegister);
@ -497,15 +481,24 @@ static inline void REGISTER_2104 (uint8 Byte)
PPU.OBJ[addr].VPos = highbyte; PPU.OBJ[addr].VPos = highbyte;
} }
} }
}
PPU.OAMFlip &= ~1; PPU.OAMFlip ^= 1;
if (!(PPU.OAMFlip & 1))
{
++PPU.OAMAddr; ++PPU.OAMAddr;
PPU.OAMAddr &= 0x1ff;
if (PPU.OAMPriorityRotation && PPU.FirstSprite != (PPU.OAMAddr >> 1)) if (PPU.OAMPriorityRotation && PPU.FirstSprite != (PPU.OAMAddr >> 1))
{ {
PPU.FirstSprite = (PPU.OAMAddr & 0xfe) >> 1; PPU.FirstSprite = (PPU.OAMAddr & 0xfe) >> 1;
IPPU.OBJChanged = TRUE; IPPU.OBJChanged = TRUE;
} }
} }
else
{
if (PPU.OAMPriorityRotation && (PPU.OAMAddr & 1))
IPPU.OBJChanged = TRUE;
}
} }
// This code is correct, however due to Snes9x's inaccurate timings, some games might be broken by this chage. :( // This code is correct, however due to Snes9x's inaccurate timings, some games might be broken by this chage. :(
@ -515,12 +508,18 @@ static inline void REGISTER_2104 (uint8 Byte)
{ \ { \
printf("Invalid VRAM acess at (%04d, %04d) blank:%d\n", CPU.Cycles, CPU.V_Counter, PPU.ForcedBlanking); \ printf("Invalid VRAM acess at (%04d, %04d) blank:%d\n", CPU.Cycles, CPU.V_Counter, PPU.ForcedBlanking); \
if (Settings.BlockInvalidVRAMAccess) \ if (Settings.BlockInvalidVRAMAccess) \
{ \
PPU.VMA.Address += !PPU.VMA.High ? PPU.VMA.Increment : 0; \
return; \ return; \
} \
} }
#else #else
#define CHECK_INBLANK() \ #define CHECK_INBLANK() \
if (Settings.BlockInvalidVRAMAccess && !PPU.ForcedBlanking && CPU.V_Counter < PPU.ScreenHeight + FIRST_VISIBLE_LINE) \ if (Settings.BlockInvalidVRAMAccess && !PPU.ForcedBlanking && CPU.V_Counter < PPU.ScreenHeight + FIRST_VISIBLE_LINE) \
return; { \
PPU.VMA.Address += !PPU.VMA.High ? PPU.VMA.Increment : 0; \
return; \
}
#endif #endif
static inline void REGISTER_2118 (uint8 Byte) static inline void REGISTER_2118 (uint8 Byte)
@ -560,10 +559,80 @@ static inline void REGISTER_2118 (uint8 Byte)
} }
} }
static inline void REGISTER_2119 (uint8 Byte) static inline void REGISTER_2118_tile (uint8 Byte)
{ {
CHECK_INBLANK(); CHECK_INBLANK();
uint32 rem = PPU.VMA.Address & PPU.VMA.Mask1;
uint32 address = (((PPU.VMA.Address & ~PPU.VMA.Mask1) + (rem >> PPU.VMA.Shift) + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3)) << 1) & 0xffff;
Memory.VRAM[address] = Byte;
IPPU.TileCached[TILE_2BIT][address >> 4] = FALSE;
IPPU.TileCached[TILE_4BIT][address >> 5] = FALSE;
IPPU.TileCached[TILE_8BIT][address >> 6] = FALSE;
IPPU.TileCached[TILE_2BIT_EVEN][address >> 4] = FALSE;
IPPU.TileCached[TILE_2BIT_EVEN][((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = FALSE;
IPPU.TileCached[TILE_2BIT_ODD] [address >> 4] = FALSE;
IPPU.TileCached[TILE_2BIT_ODD] [((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = FALSE;
IPPU.TileCached[TILE_4BIT_EVEN][address >> 5] = FALSE;
IPPU.TileCached[TILE_4BIT_EVEN][((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = FALSE;
IPPU.TileCached[TILE_4BIT_ODD] [address >> 5] = FALSE;
IPPU.TileCached[TILE_4BIT_ODD] [((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = FALSE;
if (!PPU.VMA.High)
PPU.VMA.Address += PPU.VMA.Increment;
}
static inline void REGISTER_2118_linear (uint8 Byte)
{
CHECK_INBLANK();
uint32 address;
Memory.VRAM[address = (PPU.VMA.Address << 1) & 0xffff] = Byte;
IPPU.TileCached[TILE_2BIT][address >> 4] = FALSE;
IPPU.TileCached[TILE_4BIT][address >> 5] = FALSE;
IPPU.TileCached[TILE_8BIT][address >> 6] = FALSE;
IPPU.TileCached[TILE_2BIT_EVEN][address >> 4] = FALSE;
IPPU.TileCached[TILE_2BIT_EVEN][((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = FALSE;
IPPU.TileCached[TILE_2BIT_ODD] [address >> 4] = FALSE;
IPPU.TileCached[TILE_2BIT_ODD] [((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = FALSE;
IPPU.TileCached[TILE_4BIT_EVEN][address >> 5] = FALSE;
IPPU.TileCached[TILE_4BIT_EVEN][((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = FALSE;
IPPU.TileCached[TILE_4BIT_ODD] [address >> 5] = FALSE;
IPPU.TileCached[TILE_4BIT_ODD] [((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = FALSE;
if (!PPU.VMA.High)
PPU.VMA.Address += PPU.VMA.Increment;
}
#undef CHECK_INBLANK
#ifdef DEBUGGER
#define CHECK_INBLANK() \
if (!PPU.ForcedBlanking && CPU.V_Counter < PPU.ScreenHeight + FIRST_VISIBLE_LINE) \
{ \
printf("Invalid VRAM acess at (%04d, %04d) blank:%d\n", CPU.Cycles, CPU.V_Counter, PPU.ForcedBlanking); \
if (Settings.BlockInvalidVRAMAccess) \
{ \
PPU.VMA.Address += PPU.VMA.High ? PPU.VMA.Increment : 0; \
return; \
} \
}
#else
#define CHECK_INBLANK() \
if (Settings.BlockInvalidVRAMAccess && !PPU.ForcedBlanking && CPU.V_Counter < PPU.ScreenHeight + FIRST_VISIBLE_LINE) \
{ \
PPU.VMA.Address += PPU.VMA.High ? PPU.VMA.Increment : 0; \
return; \
}
#endif
static inline void REGISTER_2119 (uint8 Byte)
{
CHECK_INBLANK();
uint32 address; uint32 address;
if (PPU.VMA.FullGraphicCount) if (PPU.VMA.FullGraphicCount)
@ -597,31 +666,6 @@ static inline void REGISTER_2119 (uint8 Byte)
} }
} }
static inline void REGISTER_2118_tile (uint8 Byte)
{
CHECK_INBLANK();
uint32 rem = PPU.VMA.Address & PPU.VMA.Mask1;
uint32 address = (((PPU.VMA.Address & ~PPU.VMA.Mask1) + (rem >> PPU.VMA.Shift) + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3)) << 1) & 0xffff;
Memory.VRAM[address] = Byte;
IPPU.TileCached[TILE_2BIT][address >> 4] = FALSE;
IPPU.TileCached[TILE_4BIT][address >> 5] = FALSE;
IPPU.TileCached[TILE_8BIT][address >> 6] = FALSE;
IPPU.TileCached[TILE_2BIT_EVEN][address >> 4] = FALSE;
IPPU.TileCached[TILE_2BIT_EVEN][((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = FALSE;
IPPU.TileCached[TILE_2BIT_ODD] [address >> 4] = FALSE;
IPPU.TileCached[TILE_2BIT_ODD] [((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = FALSE;
IPPU.TileCached[TILE_4BIT_EVEN][address >> 5] = FALSE;
IPPU.TileCached[TILE_4BIT_EVEN][((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = FALSE;
IPPU.TileCached[TILE_4BIT_ODD] [address >> 5] = FALSE;
IPPU.TileCached[TILE_4BIT_ODD] [((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = FALSE;
if (!PPU.VMA.High)
PPU.VMA.Address += PPU.VMA.Increment;
}
static inline void REGISTER_2119_tile (uint8 Byte) static inline void REGISTER_2119_tile (uint8 Byte)
{ {
CHECK_INBLANK(); CHECK_INBLANK();
@ -647,30 +691,6 @@ static inline void REGISTER_2119_tile (uint8 Byte)
PPU.VMA.Address += PPU.VMA.Increment; PPU.VMA.Address += PPU.VMA.Increment;
} }
static inline void REGISTER_2118_linear (uint8 Byte)
{
CHECK_INBLANK();
uint32 address;
Memory.VRAM[address = (PPU.VMA.Address << 1) & 0xffff] = Byte;
IPPU.TileCached[TILE_2BIT][address >> 4] = FALSE;
IPPU.TileCached[TILE_4BIT][address >> 5] = FALSE;
IPPU.TileCached[TILE_8BIT][address >> 6] = FALSE;
IPPU.TileCached[TILE_2BIT_EVEN][address >> 4] = FALSE;
IPPU.TileCached[TILE_2BIT_EVEN][((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = FALSE;
IPPU.TileCached[TILE_2BIT_ODD] [address >> 4] = FALSE;
IPPU.TileCached[TILE_2BIT_ODD] [((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = FALSE;
IPPU.TileCached[TILE_4BIT_EVEN][address >> 5] = FALSE;
IPPU.TileCached[TILE_4BIT_EVEN][((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = FALSE;
IPPU.TileCached[TILE_4BIT_ODD] [address >> 5] = FALSE;
IPPU.TileCached[TILE_4BIT_ODD] [((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = FALSE;
if (!PPU.VMA.High)
PPU.VMA.Address += PPU.VMA.Increment;
}
static inline void REGISTER_2119_linear (uint8 Byte) static inline void REGISTER_2119_linear (uint8 Byte)
{ {
CHECK_INBLANK(); CHECK_INBLANK();

View File

@ -1,353 +0,0 @@
/***********************************************************************************
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
(c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
Jerremy Koot (jkoot@snes9x.com)
(c) Copyright 2002 - 2004 Matthew Kendora
(c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
(c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
(c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
(c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
Kris Bleakley (codeviolation@hotmail.com)
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso,
OV2
BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom,
zones
C4 x86 assembler and some C emulation code
(c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
Nach,
zsKnight (zsknight@zsnes.com)
C4 C++ code
(c) Copyright 2003 - 2006 Brad Jorsch,
Nach
DSP-1 emulator code
(c) Copyright 1998 - 2006 _Demo_,
Andreas Naive (andreasnaive@gmail.com),
Gary Henderson,
Ivar (ivar@snes9x.com),
John Weidman,
Kris Bleakley,
Matthew Kendora,
Nach,
neviksti (neviksti@hotmail.com)
DSP-2 emulator code
(c) Copyright 2003 John Weidman,
Kris Bleakley,
Lord Nightmare (lord_nightmare@users.sourceforge.net),
Matthew Kendora,
neviksti
DSP-3 emulator code
(c) Copyright 2003 - 2006 John Weidman,
Kris Bleakley,
Lancer,
z80 gaiden
DSP-4 emulator code
(c) Copyright 2004 - 2006 Dreamer Nom,
John Weidman,
Kris Bleakley,
Nach,
z80 gaiden
OBC1 emulator code
(c) Copyright 2001 - 2004 zsKnight,
pagefault (pagefault@zsnes.com),
Kris Bleakley
Ported from x86 assembler to C by sanmaiwashi
SPC7110 and RTC C++ emulator code used in 1.39-1.51
(c) Copyright 2002 Matthew Kendora with research by
zsKnight,
John Weidman,
Dark Force
SPC7110 and RTC C++ emulator code used in 1.52+
(c) Copyright 2009 byuu,
neviksti
S-DD1 C emulator code
(c) Copyright 2003 Brad Jorsch with research by
Andreas Naive,
John Weidman
S-RTC C emulator code
(c) Copyright 2001 - 2006 byuu,
John Weidman
ST010 C++ emulator code
(c) Copyright 2003 Feather,
John Weidman,
Kris Bleakley,
Matthew Kendora
Super FX x86 assembler emulator code
(c) Copyright 1998 - 2003 _Demo_,
pagefault,
zsKnight
Super FX C emulator code
(c) Copyright 1997 - 1999 Ivar,
Gary Henderson,
John Weidman
Sound emulator code used in 1.5-1.51
(c) Copyright 1998 - 2003 Brad Martin
(c) Copyright 1998 - 2006 Charles Bilyue'
Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
2xSaI filter
(c) Copyright 1999 - 2001 Derek Liauw Kie Fa
HQ2x, HQ3x, HQ4x filters
(c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
NTSC filter
(c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso
Win32 GUI code
(c) Copyright 2003 - 2006 blip,
funkyass,
Matthew Kendora,
Nach,
nitsuja
(c) Copyright 2009 - 2010 OV2
Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones
Specific ports contains the works of other authors. See headers in
individual files.
Snes9x homepage: http://www.snes9x.com/
Permission to use, copy, modify and/or 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 or it's derivatives.
Snes9x is freeware for PERSONAL USE only. Commercial users should
seek permission of the copyright holders first. Commercial use includes,
but is not limited to, charging money for Snes9x or software derived from
Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
using Snes9x as a promotion for your commercial product.
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.
***********************************************************************************/
// Abstract the details of reading from zip files versus FILE *'s.
#include <string>
#ifdef UNZIP_SUPPORT
#include "unzip.h"
#endif
#include "snes9x.h"
#include "reader.h"
// Generic constructor/destructor
Reader::Reader (void)
{
return;
}
Reader::~Reader (void)
{
return;
}
// Generic getline function, based on gets. Reimlpement if you can do better.
char * Reader::getline (void)
{
bool eof;
std::string ret;
ret = getline(eof);
if (ret.size() == 0 && eof)
return (NULL);
return (strdup(ret.c_str()));
}
std::string Reader::getline (bool &eof)
{
char buf[1024];
std::string ret;
eof = false;
ret.clear();
do
{
if (gets(buf, sizeof(buf)) == NULL)
{
eof = true;
break;
}
ret.append(buf);
}
while (*ret.rbegin() != '\n');
return (ret);
}
// snes9x.h STREAM reader
fReader::fReader (STREAM f)
{
fp = f;
}
fReader::~fReader (void)
{
return;
}
int fReader::get_char (void)
{
return (GETC_STREAM(fp));
}
char * fReader::gets (char *buf, size_t len)
{
return (GETS_STREAM(buf, len, fp));
}
size_t fReader::read (char *buf, size_t len)
{
return (READ_STREAM(buf, len, fp));
}
// unzip reader
#ifdef UNZIP_SUPPORT
unzReader::unzReader (unzFile &v)
{
file = v;
head = NULL;
numbytes = 0;
}
unzReader::~unzReader (void)
{
return;
}
int unzReader::get_char (void)
{
unsigned char c;
if (numbytes <= 0)
{
numbytes = unzReadCurrentFile(file, buffer, unz_BUFFSIZ);
if (numbytes <= 0)
return (EOF);
head = buffer;
}
c = *head;
head++;
numbytes--;
return ((int) c);
}
char * unzReader::gets (char *buf, size_t len)
{
size_t i;
int c;
for (i = 0; i < len - 1; i++)
{
c = get_char();
if (c == EOF)
{
if (i == 0)
return (NULL);
break;
}
buf[i] = (char) c;
if (buf[i] == '\n')
break;
}
buf[i] = '\0';
return (buf);
}
size_t unzReader::read (char *buf, size_t len)
{
if (len == 0)
return (len);
if (len <= numbytes)
{
memcpy(buf, head, len);
numbytes -= len;
head += len;
return (len);
}
size_t numread = 0;
if (numbytes > 0)
{
memcpy(buf, head, numbytes);
numread += numbytes;
head = NULL;
numbytes = 0;
}
int l = unzReadCurrentFile(file, buf + numread, len - numread);
if (l > 0)
numread += l;
return (numread);
}
#endif

View File

@ -1,228 +0,0 @@
/***********************************************************************************
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
(c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
Jerremy Koot (jkoot@snes9x.com)
(c) Copyright 2002 - 2004 Matthew Kendora
(c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
(c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
(c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
(c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
Kris Bleakley (codeviolation@hotmail.com)
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso,
OV2
BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom,
zones
C4 x86 assembler and some C emulation code
(c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
Nach,
zsKnight (zsknight@zsnes.com)
C4 C++ code
(c) Copyright 2003 - 2006 Brad Jorsch,
Nach
DSP-1 emulator code
(c) Copyright 1998 - 2006 _Demo_,
Andreas Naive (andreasnaive@gmail.com),
Gary Henderson,
Ivar (ivar@snes9x.com),
John Weidman,
Kris Bleakley,
Matthew Kendora,
Nach,
neviksti (neviksti@hotmail.com)
DSP-2 emulator code
(c) Copyright 2003 John Weidman,
Kris Bleakley,
Lord Nightmare (lord_nightmare@users.sourceforge.net),
Matthew Kendora,
neviksti
DSP-3 emulator code
(c) Copyright 2003 - 2006 John Weidman,
Kris Bleakley,
Lancer,
z80 gaiden
DSP-4 emulator code
(c) Copyright 2004 - 2006 Dreamer Nom,
John Weidman,
Kris Bleakley,
Nach,
z80 gaiden
OBC1 emulator code
(c) Copyright 2001 - 2004 zsKnight,
pagefault (pagefault@zsnes.com),
Kris Bleakley
Ported from x86 assembler to C by sanmaiwashi
SPC7110 and RTC C++ emulator code used in 1.39-1.51
(c) Copyright 2002 Matthew Kendora with research by
zsKnight,
John Weidman,
Dark Force
SPC7110 and RTC C++ emulator code used in 1.52+
(c) Copyright 2009 byuu,
neviksti
S-DD1 C emulator code
(c) Copyright 2003 Brad Jorsch with research by
Andreas Naive,
John Weidman
S-RTC C emulator code
(c) Copyright 2001 - 2006 byuu,
John Weidman
ST010 C++ emulator code
(c) Copyright 2003 Feather,
John Weidman,
Kris Bleakley,
Matthew Kendora
Super FX x86 assembler emulator code
(c) Copyright 1998 - 2003 _Demo_,
pagefault,
zsKnight
Super FX C emulator code
(c) Copyright 1997 - 1999 Ivar,
Gary Henderson,
John Weidman
Sound emulator code used in 1.5-1.51
(c) Copyright 1998 - 2003 Brad Martin
(c) Copyright 1998 - 2006 Charles Bilyue'
Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
2xSaI filter
(c) Copyright 1999 - 2001 Derek Liauw Kie Fa
HQ2x, HQ3x, HQ4x filters
(c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
NTSC filter
(c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso
Win32 GUI code
(c) Copyright 2003 - 2006 blip,
funkyass,
Matthew Kendora,
Nach,
nitsuja
(c) Copyright 2009 - 2010 OV2
Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones
Specific ports contains the works of other authors. See headers in
individual files.
Snes9x homepage: http://www.snes9x.com/
Permission to use, copy, modify and/or 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 or it's derivatives.
Snes9x is freeware for PERSONAL USE only. Commercial users should
seek permission of the copyright holders first. Commercial use includes,
but is not limited to, charging money for Snes9x or software derived from
Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
using Snes9x as a promotion for your commercial product.
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.
***********************************************************************************/
#ifndef _READER_H_
#define _READER_H_
class Reader
{
public:
Reader (void);
virtual ~Reader (void);
virtual int get_char (void) = 0;
virtual char * gets (char *, size_t) = 0;
virtual char * getline (void); // free() when done
virtual std::string getline (bool &);
virtual size_t read (char *, size_t) = 0;
};
class fReader : public Reader
{
public:
fReader (STREAM);
virtual ~fReader (void);
virtual int get_char (void);
virtual char * gets (char *, size_t);
virtual size_t read (char *, size_t);
private:
STREAM fp;
};
#ifdef UNZIP_SUPPORT
#define unz_BUFFSIZ 1024
class unzReader : public Reader
{
public:
unzReader (unzFile &);
virtual ~unzReader (void);
virtual int get_char (void);
virtual char * gets (char *, size_t);
virtual size_t read (char *, size_t);
private:
unzFile file;
char buffer[unz_BUFFSIZ];
char *head;
size_t numbytes;
};
#endif
#endif

View File

@ -17,13 +17,20 @@
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja (c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso, (c) Copyright 2009 - 2018 BearOso,
OV2 OV2
(c) Copyright 2017 qwertymodo
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
BS-X C emulator code BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom, (c) Copyright 2005 - 2006 Dreamer Nom,
@ -117,6 +124,9 @@
Sound emulator code used in 1.52+ Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
S-SMP emulator code used in 1.54+
(c) Copyright 2016 byuu
SH assembler code partly based on x86 assembler code SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
@ -130,7 +140,7 @@
(c) Copyright 2006 - 2007 Shay Green (c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso (c) Copyright 2004 - 2018 BearOso
Win32 GUI code Win32 GUI code
(c) Copyright 2003 - 2006 blip, (c) Copyright 2003 - 2006 blip,
@ -138,11 +148,16 @@
Matthew Kendora, Matthew Kendora,
Nach, Nach,
nitsuja nitsuja
(c) Copyright 2009 - 2010 OV2 (c) Copyright 2009 - 2018 OV2
Mac OS GUI code Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2011 zones
Libretro port
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
@ -180,7 +195,6 @@
uint8 SA1OpenBus; uint8 SA1OpenBus;
static void S9xSA1Reset (void);
static void S9xSA1SetBWRAMMemMap (uint8); static void S9xSA1SetBWRAMMemMap (uint8);
static void S9xSetSA1MemMap (uint32, uint8); static void S9xSetSA1MemMap (uint32, uint8);
static void S9xSA1CharConv2 (void); static void S9xSA1CharConv2 (void);
@ -190,31 +204,37 @@ static void S9xSA1ReadVariableLengthData (bool8, bool8);
void S9xSA1Init (void) void S9xSA1Init (void)
{ {
SA1.IRQActive = FALSE; SA1.Cycles = 0;
SA1.WaitingForInterrupt = FALSE; SA1.PrevCycles = 0;
SA1.Waiting = FALSE;
SA1.Flags = 0; SA1.Flags = 0;
SA1.Executing = FALSE; SA1.WaitingForInterrupt = FALSE;
memset(&Memory.FillRAM[0x2200], 0, 0x200); memset(&Memory.FillRAM[0x2200], 0, 0x200);
Memory.FillRAM[0x2200] = 0x20; Memory.FillRAM[0x2200] = 0x20;
Memory.FillRAM[0x2220] = 0x00; Memory.FillRAM[0x2220] = 0x00;
Memory.FillRAM[0x2221] = 0x01; Memory.FillRAM[0x2221] = 0x01;
Memory.FillRAM[0x2222] = 0x02; Memory.FillRAM[0x2222] = 0x02;
Memory.FillRAM[0x2223] = 0x03; Memory.FillRAM[0x2223] = 0x03;
Memory.FillRAM[0x2228] = 0xff; Memory.FillRAM[0x2228] = 0x0f;
SA1.in_char_dma = FALSE;
SA1.TimerIRQLastState = FALSE;
SA1.HTimerIRQPos = 0;
SA1.VTimerIRQPos = 0;
SA1.HCounter = 0;
SA1.VCounter = 0;
SA1.PrevHCounter = 0;
SA1.arithmetic_op = 0;
SA1.op1 = 0; SA1.op1 = 0;
SA1.op2 = 0; SA1.op2 = 0;
SA1.arithmetic_op = 0;
SA1.sum = 0; SA1.sum = 0;
SA1.overflow = FALSE; SA1.overflow = FALSE;
SA1.S9xOpcodes = NULL; SA1.VirtualBitmapFormat = 0;
} SA1.variable_bit_pos = 0;
static void S9xSA1Reset (void)
{
SA1Registers.PBPC = 0; SA1Registers.PBPC = 0;
SA1Registers.PB = 0; SA1Registers.PB = 0;
SA1Registers.PCw = Memory.FillRAM[0x2203] | (Memory.FillRAM[0x2204] << 8); SA1Registers.PCw = 0;
SA1Registers.D.W = 0; SA1Registers.D.W = 0;
SA1Registers.DB = 0; SA1Registers.DB = 0;
SA1Registers.SH = 1; SA1Registers.SH = 1;
@ -228,17 +248,20 @@ static void S9xSA1Reset (void)
SA1SetFlags(MemoryFlag | IndexFlag | IRQ | Emulation); SA1SetFlags(MemoryFlag | IndexFlag | IRQ | Emulation);
SA1ClearFlags(Decimal); SA1ClearFlags(Decimal);
SA1.WaitingForInterrupt = FALSE; SA1.MemSpeed = SLOW_ONE_CYCLE;
SA1.PCBase = NULL; SA1.MemSpeedx2 = SLOW_ONE_CYCLE * 2;
S9xSA1SetPCBase(SA1Registers.PBPC);
SA1.S9xOpcodes = S9xSA1OpcodesM1X1; SA1.S9xOpcodes = S9xSA1OpcodesM1X1;
SA1.S9xOpLengths = S9xOpLengthsM1X1; SA1.S9xOpLengths = S9xOpLengthsM1X1;
S9xSA1SetPCBase(SA1Registers.PBPC);
S9xSA1UnpackStatus(); S9xSA1UnpackStatus();
S9xSA1FixCycles(); S9xSA1FixCycles();
SA1.Executing = TRUE;
SA1.BWRAM = Memory.SRAM; SA1.BWRAM = Memory.SRAM;
Memory.FillRAM[0x2225] = 0;
CPU.IRQExternal = FALSE;
} }
static void S9xSA1SetBWRAMMemMap (uint8 val) static void S9xSA1SetBWRAMMemMap (uint8 val)
@ -280,23 +303,6 @@ void S9xSA1PostLoadState (void)
SA1.VirtualBitmapFormat = (Memory.FillRAM[0x223f] & 0x80) ? 2 : 4; SA1.VirtualBitmapFormat = (Memory.FillRAM[0x223f] & 0x80) ? 2 : 4;
Memory.BWRAM = Memory.SRAM + (Memory.FillRAM[0x2224] & 7) * 0x2000; Memory.BWRAM = Memory.SRAM + (Memory.FillRAM[0x2224] & 7) * 0x2000;
S9xSA1SetBWRAMMemMap(Memory.FillRAM[0x2225]); S9xSA1SetBWRAMMemMap(Memory.FillRAM[0x2225]);
SA1.Waiting = (Memory.FillRAM[0x2200] & 0x60) != 0;
SA1.Executing = !SA1.Waiting;
}
void S9xSA1ExecuteDuringSleep (void)
{
#if 0
if (SA1.Executing)
{
while (CPU.Cycles < CPU.NextEvent)
{
S9xSA1MainLoop();
CPU.Cycles += TWO_CYCLES * 2;
}
}
#endif
} }
static void S9xSetSA1MemMap (uint32 which1, uint8 map) static void S9xSetSA1MemMap (uint32 which1, uint8 map)
@ -309,14 +315,43 @@ static void S9xSetSA1MemMap (uint32 which1, uint8 map)
for (int c = 0; c < 0x100; c += 16) for (int c = 0; c < 0x100; c += 16)
{ {
uint8 *block = &Memory.ROM[(map & 7) * 0x100000 + (c << 12)]; uint8 *block;
if (Multi.cartType != 5)
block = &Memory.ROM[(map & 7) * 0x100000 + (c << 12)];
else
{
if ((map & 7) < 4)
block = Memory.ROM + Multi.cartOffsetA + ((map & 7) * 0x100000 + (c << 12));
else
block = Memory.ROM + Multi.cartOffsetB + (((map & 7) - 4) * 0x100000 + (c << 12));
}
for (int i = c; i < c + 16; i++) for (int i = c; i < c + 16; i++)
Memory.Map[start + i] = SA1.Map[start + i] = block; Memory.Map[start + i] = SA1.Map[start + i] = block;
} }
for (int c = 0; c < 0x200; c += 16) for (int c = 0; c < 0x200; c += 16)
{ {
uint8 *block = &Memory.ROM[(map & 7) * 0x100000 + (c << 11) - 0x8000]; // conversion to int is needed here - map is promoted but which1 is not
int32 offset;
uint8 *block;
if (Multi.cartType != 5)
{
offset = (((map & 0x80) ? map : which1) & 7) * 0x100000 + (c << 11) - 0x8000;
block = &Memory.ROM[offset];
}
else
{
if ((map & 7) < 4)
{
offset = (((map & 0x80) ? map : which1) & 7) * 0x100000 + (c << 11) - 0x8000;
block = Memory.ROM + Multi.cartOffsetA + offset;
}
else
{
offset = (((map & 0x80) ? (map - 4) : which1) & 7) * 0x100000 + (c << 11) - 0x8000;
block = Memory.ROM + Multi.cartOffsetB + offset;
}
}
for (int i = c + 8; i < c + 16; i++) for (int i = c + 8; i < c + 16; i++)
Memory.Map[start2 + i] = SA1.Map[start2 + i] = block; Memory.Map[start2 + i] = SA1.Map[start2 + i] = block;
} }
@ -326,31 +361,48 @@ uint8 S9xGetSA1 (uint32 address)
{ {
switch (address) switch (address)
{ {
case 0x2300: case 0x2300: // S-CPU flag
return ((uint8) ((Memory.FillRAM[0x2209] & 0x5f) | (CPU.IRQActive & (SA1_IRQ_SOURCE | SA1_DMA_IRQ_SOURCE)))); return ((Memory.FillRAM[0x2209] & 0x5f) | (Memory.FillRAM[0x2300] & 0xa0));
case 0x2301: case 0x2301: // SA-1 flag
return ((Memory.FillRAM[0x2200] & 0xf) | (Memory.FillRAM[0x2301] & 0xf0)); return ((Memory.FillRAM[0x2200] & 0x0f) | (Memory.FillRAM[0x2301] & 0xf0));
case 0x2306: case 0x2302: // H counter (L)
SA1.HTimerIRQPos = SA1.HCounter / ONE_DOT_CYCLE;
SA1.VTimerIRQPos = SA1.VCounter;
return ((uint8) SA1.HTimerIRQPos);
case 0x2303: // H counter (H)
return ((uint8) (SA1.HTimerIRQPos >> 8));
case 0x2304: // V counter (L)
return ((uint8) SA1.VTimerIRQPos);
case 0x2305: // V counter (H)
return ((uint8) (SA1.VTimerIRQPos >> 8));
case 0x2306: // arithmetic result (LLL)
return ((uint8) SA1.sum); return ((uint8) SA1.sum);
case 0x2307: case 0x2307: // arithmetic result (LLH)
return ((uint8) (SA1.sum >> 8)); return ((uint8) (SA1.sum >> 8));
case 0x2308: case 0x2308: // arithmetic result (LHL)
return ((uint8) (SA1.sum >> 16)); return ((uint8) (SA1.sum >> 16));
case 0x2309: case 0x2309: // arithmetic result (LLH)
return ((uint8) (SA1.sum >> 24)); return ((uint8) (SA1.sum >> 24));
case 0x230a: case 0x230a: // arithmetic result (HLL)
return ((uint8) (SA1.sum >> 32)); return ((uint8) (SA1.sum >> 32));
case 0x230c: case 0x230b: // arithmetic overflow
return (SA1.overflow ? 0x80 : 0);
case 0x230c: // variable-length data read port (L)
return (Memory.FillRAM[0x230c]); return (Memory.FillRAM[0x230c]);
case 0x230d: case 0x230d: // variable-length data read port (H)
{ {
uint8 byte = Memory.FillRAM[0x230d]; uint8 byte = Memory.FillRAM[0x230d];
@ -360,8 +412,10 @@ uint8 S9xGetSA1 (uint32 address)
return (byte); return (byte);
} }
case 0x230e: // version code register
return (0x01);
default: default:
//printf("R: %04x\n", address);
break; break;
} }
@ -372,337 +426,279 @@ void S9xSetSA1 (uint8 byte, uint32 address)
{ {
switch (address) switch (address)
{ {
case 0x2200: case 0x2200: // SA-1 control
SA1.Waiting = (byte & 0x60) != 0; #ifdef DEBUGGER
//SA1.Executing = !SA1.Waiting && SA1.S9xOpcodes; if (byte & 0x60)
printf("SA-1 sleep\n");
#endif
if (!(byte & 0x20) && (Memory.FillRAM[0x2200] & 0x20)) // SA-1 reset
S9xSA1Reset(); if (!(byte & 0x80) && (Memory.FillRAM[0x2200] & 0x20))
{
#ifdef DEBUGGER
printf("SA-1 reset\n");
#endif
SA1Registers.PBPC = 0;
SA1Registers.PB = 0;
SA1Registers.PCw = Memory.FillRAM[0x2203] | (Memory.FillRAM[0x2204] << 8);
S9xSA1SetPCBase(SA1Registers.PBPC);
}
// SA-1 IRQ control
if (byte & 0x80) if (byte & 0x80)
{ {
Memory.FillRAM[0x2301] |= 0x80; Memory.FillRAM[0x2301] |= 0x80;
if (Memory.FillRAM[0x220a] & 0x80) if (Memory.FillRAM[0x220a] & 0x80)
{ Memory.FillRAM[0x220b] &= ~0x80;
SA1.Flags |= IRQ_FLAG;
SA1.IRQActive |= SNES_IRQ_SOURCE;
SA1.Executing = !SA1.Waiting && SA1.S9xOpcodes;
}
} }
// SA-1 NMI control
if (byte & 0x10) if (byte & 0x10)
{ {
Memory.FillRAM[0x2301] |= 0x10; Memory.FillRAM[0x2301] |= 0x10;
if (Memory.FillRAM[0x220a] & 0x10) if (Memory.FillRAM[0x220a] & 0x10)
{ Memory.FillRAM[0x220b] &= ~0x10;
SA1.Flags |= NMI_FLAG;
SA1.Executing = !SA1.Waiting && SA1.S9xOpcodes;
}
} }
break; break;
case 0x2201: case 0x2201: // S-CPU interrupt enable
// S-CPU IRQ enable
if (((byte ^ Memory.FillRAM[0x2201]) & 0x80) && (Memory.FillRAM[0x2300] & byte & 0x80)) if (((byte ^ Memory.FillRAM[0x2201]) & 0x80) && (Memory.FillRAM[0x2300] & byte & 0x80))
S9xSetIRQ(SA1_IRQ_SOURCE); {
Memory.FillRAM[0x2202] &= ~0x80;
CPU.IRQExternal = TRUE;
}
// S-CPU CHDMA IRQ enable
if (((byte ^ Memory.FillRAM[0x2201]) & 0x20) && (Memory.FillRAM[0x2300] & byte & 0x20)) if (((byte ^ Memory.FillRAM[0x2201]) & 0x20) && (Memory.FillRAM[0x2300] & byte & 0x20))
S9xSetIRQ(SA1_DMA_IRQ_SOURCE); {
Memory.FillRAM[0x2202] &= ~0x20;
CPU.IRQExternal = TRUE;
}
break; break;
case 0x2202: case 0x2202: // S-CPU interrupt clear
// S-CPU IRQ clear
if (byte & 0x80) if (byte & 0x80)
{
Memory.FillRAM[0x2300] &= ~0x80; Memory.FillRAM[0x2300] &= ~0x80;
S9xClearIRQ(SA1_IRQ_SOURCE);
}
// S-CPU CHDMA IRQ clear
if (byte & 0x20) if (byte & 0x20)
{
Memory.FillRAM[0x2300] &= ~0x20; Memory.FillRAM[0x2300] &= ~0x20;
S9xClearIRQ(SA1_DMA_IRQ_SOURCE);
} if (!(Memory.FillRAM[0x2300] & 0xa0))
CPU.IRQExternal = FALSE;
break; break;
case 0x2203: case 0x2203: // SA-1 reset vector (L)
//printf("SA1 reset vector: %04x\n", byte | (Memory.FillRAM[0x2204] << 8)); case 0x2204: // SA-1 reset vector (H)
case 0x2205: // SA-1 NMI vector (L)
case 0x2206: // SA-1 NMI vector (H)
case 0x2207: // SA-1 IRQ vector (L)
case 0x2208: // SA-1 IRQ vector (H)
break; break;
case 0x2204: case 0x2209: // S-CPU control
//printf("SA1 reset vector: %04x\n", (byte << 8) | Memory.FillRAM[0x2203]); // 0x40: S-CPU IRQ overwrite
break; // 0x20: S-CPU NMI overwrite
case 0x2205:
//printf("SA1 NMI vector: %04x\n", byte | (Memory.FillRAM[0x2206] << 8));
break;
case 0x2206:
//printf("SA1 NMI vector: %04x\n", (byte << 8) | Memory.FillRAM[0x2205]);
break;
case 0x2207:
//printf("SA1 IRQ vector: %04x\n", byte | (Memory.FillRAM[0x2208] << 8));
break;
case 0x2208:
//printf("SA1 IRQ vector: %04x\n", (byte << 8) | Memory.FillRAM[0x2207]);
break;
case 0x2209:
Memory.FillRAM[0x2209] = byte;
// S-CPU IRQ control
if (byte & 0x80) if (byte & 0x80)
{
Memory.FillRAM[0x2300] |= 0x80; Memory.FillRAM[0x2300] |= 0x80;
if (Memory.FillRAM[0x2201] & 0x80)
if (byte & Memory.FillRAM[0x2201] & 0x80) {
S9xSetIRQ(SA1_IRQ_SOURCE); Memory.FillRAM[0x2202] &= ~0x80;
CPU.IRQExternal = TRUE;
}
}
break; break;
case 0x220a: case 0x220a: // SA-1 interrupt enable
// SA-1 IRQ enable
if (((byte ^ Memory.FillRAM[0x220a]) & 0x80) && (Memory.FillRAM[0x2301] & byte & 0x80)) if (((byte ^ Memory.FillRAM[0x220a]) & 0x80) && (Memory.FillRAM[0x2301] & byte & 0x80))
{ Memory.FillRAM[0x220b] &= ~0x80;
SA1.Flags |= IRQ_FLAG;
SA1.IRQActive |= SNES_IRQ_SOURCE;
//SA1.Executing = !SA1.Waiting;
}
// SA-1 timer IRQ enable
if (((byte ^ Memory.FillRAM[0x220a]) & 0x40) && (Memory.FillRAM[0x2301] & byte & 0x40)) if (((byte ^ Memory.FillRAM[0x220a]) & 0x40) && (Memory.FillRAM[0x2301] & byte & 0x40))
{ Memory.FillRAM[0x220b] &= ~0x40;
SA1.Flags |= IRQ_FLAG;
SA1.IRQActive |= TIMER_IRQ_SOURCE;
//SA1.Executing = !SA1.Waiting;
}
// SA-1 DMA IRQ enable
if (((byte ^ Memory.FillRAM[0x220a]) & 0x20) && (Memory.FillRAM[0x2301] & byte & 0x20)) if (((byte ^ Memory.FillRAM[0x220a]) & 0x20) && (Memory.FillRAM[0x2301] & byte & 0x20))
{ Memory.FillRAM[0x220b] &= ~0x20;
SA1.Flags |= IRQ_FLAG;
SA1.IRQActive |= DMA_IRQ_SOURCE;
//SA1.Executing = !SA1.Waiting;
}
// SA-1 NMI enable
if (((byte ^ Memory.FillRAM[0x220a]) & 0x10) && (Memory.FillRAM[0x2301] & byte & 0x10)) if (((byte ^ Memory.FillRAM[0x220a]) & 0x10) && (Memory.FillRAM[0x2301] & byte & 0x10))
{ Memory.FillRAM[0x220b] &= ~0x10;
SA1.Flags |= NMI_FLAG;
//SA1.Executing = !SA1.Waiting;
}
break; break;
case 0x220b: case 0x220b: // SA-1 interrupt clear
// SA-1 IRQ clear
if (byte & 0x80) if (byte & 0x80)
{
SA1.IRQActive &= ~SNES_IRQ_SOURCE;
Memory.FillRAM[0x2301] &= ~0x80; Memory.FillRAM[0x2301] &= ~0x80;
}
// SA-1 timer IRQ clear
if (byte & 0x40) if (byte & 0x40)
{
SA1.IRQActive &= ~TIMER_IRQ_SOURCE;
Memory.FillRAM[0x2301] &= ~0x40; Memory.FillRAM[0x2301] &= ~0x40;
}
// SA-1 DMA IRQ clear
if (byte & 0x20) if (byte & 0x20)
{
SA1.IRQActive &= ~DMA_IRQ_SOURCE;
Memory.FillRAM[0x2301] &= ~0x20; Memory.FillRAM[0x2301] &= ~0x20;
}
// SA-1 NMI clear
if (byte & 0x10) if (byte & 0x10)
Memory.FillRAM[0x2301] &= ~0x10; Memory.FillRAM[0x2301] &= ~0x10;
if (!SA1.IRQActive)
SA1.Flags &= ~IRQ_FLAG;
break; break;
case 0x220c: case 0x220c: // S-CPU NMI vector (L)
//printf("SNES NMI vector: %04x\n", byte | (Memory.FillRAM[0x220d] << 8)); case 0x220d: // S-CPU NMI vector (H)
case 0x220e: // S-CPU IRQ vector (L)
case 0x220f: // S-CPU IRQ vector (H)
break; break;
case 0x220d: case 0x2210: // SA-1 timer control
//printf("SNES NMI vector: %04x\n", (byte << 8) | Memory.FillRAM[0x220c]); // 0x80: mode (linear / HV)
break; // 0x02: V timer enable
// 0x01: H timer enable
case 0x220e: #ifdef DEBUGGER
//printf("SNES IRQ vector: %04x\n", byte | (Memory.FillRAM[0x220f] << 8)); printf("SA-1 timer control write:%02x\n", byte);
break;
case 0x220f:
//printf("SNES IRQ vector: %04x\n", (byte << 8) | Memory.FillRAM[0x220e]);
break;
case 0x2210:
#if 0
printf("Timer %s\n", (byte & 0x80) ? "linear" : "HV");
printf("Timer H-IRQ %s\n", (byte & 1) ? "enabled" : "disabled");
printf("Timer V-IRQ %s\n", (byte & 2) ? "enabled" : "disabled");
#endif #endif
break; break;
case 0x2211: case 0x2211: // SA-1 timer reset
//printf("Timer reset\n"); SA1.HCounter = 0;
SA1.VCounter = 0;
break; break;
case 0x2212: case 0x2212: // SA-1 H-timer (L)
//printf("H-Timer %04x\n", byte | (Memory.FillRAM[0x2213] << 8)); SA1.HTimerIRQPos = byte | (Memory.FillRAM[0x2213] << 8);
break; break;
case 0x2213: case 0x2213: // SA-1 H-timer (H)
//printf("H-Timer %04x\n", (byte << 8) | Memory.FillRAM[0x2212]); SA1.HTimerIRQPos = (byte << 8) | Memory.FillRAM[0x2212];
break; break;
case 0x2214: case 0x2214: // SA-1 V-timer (L)
//printf("V-Timer %04x\n", byte | (Memory.FillRAM[0x2215] << 8)); SA1.VTimerIRQPos = byte | (Memory.FillRAM[0x2215] << 8);
break; break;
case 0x2215: case 0x2215: // SA-1 V-timer (H)
//printf("V-Timer %04x\n", (byte << 8) | Memory.FillRAM[0x2214]); SA1.VTimerIRQPos = (byte << 8) | Memory.FillRAM[0x2214];
break; break;
case 0x2220: case 0x2220: // MMC bank C
case 0x2221: case 0x2221: // MMC bank D
case 0x2222: case 0x2222: // MMC bank E
case 0x2223: case 0x2223: // MMC bank F
//printf("MMC: %02x\n", byte);
S9xSetSA1MemMap(address - 0x2220, byte); S9xSetSA1MemMap(address - 0x2220, byte);
break; break;
case 0x2224: case 0x2224: // S-CPU BW-RAM mapping
//printf("BWRAM image SNES %02x -> 0x6000\n", byte);
Memory.BWRAM = Memory.SRAM + (byte & 7) * 0x2000; Memory.BWRAM = Memory.SRAM + (byte & 7) * 0x2000;
break; break;
case 0x2225: case 0x2225: // SA-1 BW-RAM mapping
//printf("BWRAM image SA1 %02x -> 0x6000 (%02x)\n", byte, Memory.FillRAM[0x2225]);
if (byte != Memory.FillRAM[0x2225]) if (byte != Memory.FillRAM[0x2225])
S9xSA1SetBWRAMMemMap(byte); S9xSA1SetBWRAMMemMap(byte);
break; break;
case 0x2226: case 0x2226: // S-CPU BW-RAM write enable
//printf("BW-RAM SNES write %s\n", (byte & 0x80) ? "enabled" : "disabled"); case 0x2227: // SA-1 BW-RAM write enable
case 0x2228: // BW-RAM write-protected area
case 0x2229: // S-CPU I-RAM write protection
case 0x222a: // SA-1 I-RAM write protection
break; break;
case 0x2227: case 0x2230: // DMA control
//printf("BW-RAM SA1 write %s\n", (byte & 0x80) ? "enabled" : "disabled"); // 0x80: enable
// 0x40: priority (DMA / SA-1)
// 0x20: character conversion / normal
// 0x10: BW-RAM -> I-RAM / SA-1 -> I-RAM
// 0x04: destinatin (BW-RAM / I-RAM)
// 0x03: source
break; break;
case 0x2228: case 0x2231: // character conversion DMA parameters
//printf("BW-RAM write protect area %02x\n", byte); // 0x80: CHDEND (complete / incomplete)
break; // 0x03: color mode
// (byte >> 2) & 7: virtual VRAM width
case 0x2229:
//printf("I-RAM SNES write protect area %02x\n", byte);
break;
case 0x222a:
//printf("I-RAM SA1 write protect area %02x\n", byte);
break;
case 0x2230:
#if 0
printf("SA1 DMA %s\n", (byte & 0x80) ? "enabled" : "disabled");
printf("DMA priority %s\n", (byte & 0x40) ? "DMA" : "SA1");
printf("DMA %s\n", (byte & 0x20) ? "char conv" : "normal");
printf("DMA type %s\n", (byte & 0x10) ? "BW-RAM -> I-RAM" : "SA1 -> I-RAM");
printf("DMA distination %s\n", (byte & 4) ? "BW-RAM" : "I-RAM");
printf("DMA source %s\n", DMAsource[byte & 3]);
#endif
break;
case 0x2231:
if (byte & 0x80) if (byte & 0x80)
SA1.in_char_dma = FALSE; SA1.in_char_dma = FALSE;
#if 0
printf("CHDEND %s\n", (byte & 0x80) ? "complete" : "incomplete");
printf("DMA colour mode %d\n", byte & 3);
printf("virtual VRAM width %d\n", (byte >> 2) & 7);
#endif
break; break;
case 0x2232: case 0x2232: // DMA source start address (LL)
case 0x2233: case 0x2233: // DMA source start address (LH)
case 0x2234: case 0x2234: // DMA source start address (HL)
Memory.FillRAM[address] = byte;
#if 0
printf("DMA source start %06x\n", Memory.FillRAM[0x2232] | (Memory.FillRAM[0x2233] << 8) | (Memory.FillRAM[0x2234] << 16));
#endif
break; break;
case 0x2235: case 0x2235: // DMA destination start address (LL)
Memory.FillRAM[0x2235] = byte;
break; break;
case 0x2236: case 0x2236: // DMA destination start address (LH)
Memory.FillRAM[0x2236] = byte; Memory.FillRAM[0x2236] = byte;
if ((Memory.FillRAM[0x2230] & 0xa4) == 0x80) // Normal DMA to I-RAM if ((Memory.FillRAM[0x2230] & 0xa4) == 0x80) // Normal DMA to I-RAM
S9xSA1DMA(); S9xSA1DMA();
else else
if ((Memory.FillRAM[0x2230] & 0xb0) == 0xb0) if ((Memory.FillRAM[0x2230] & 0xb0) == 0xb0) // CC1
{ {
SA1.in_char_dma = TRUE;
Memory.FillRAM[0x2300] |= 0x20; Memory.FillRAM[0x2300] |= 0x20;
if (Memory.FillRAM[0x2201] & 0x20) if (Memory.FillRAM[0x2201] & 0x20)
S9xSetIRQ(SA1_DMA_IRQ_SOURCE); {
SA1.in_char_dma = TRUE; Memory.FillRAM[0x2202] &= ~0x20;
CPU.IRQExternal = TRUE;
}
} }
break; break;
case 0x2237: case 0x2237: // DMA destination start address (HL)
Memory.FillRAM[0x2237] = byte; Memory.FillRAM[0x2237] = byte;
if ((Memory.FillRAM[0x2230] & 0xa4) == 0x84) // Normal DMA to BW-RAM if ((Memory.FillRAM[0x2230] & 0xa4) == 0x84) // Normal DMA to BW-RAM
S9xSA1DMA(); S9xSA1DMA();
#if 0
printf("DMA dest address %06x\n", Memory.FillRAM[0x2235] | (Memory.FillRAM[0x2236] << 8) | (Memory.FillRAM[0x2237] << 16));
#endif
break; break;
case 0x2238: case 0x2238: // DMA terminal counter (L)
case 0x2239: case 0x2239: // DMA terminal counter (H)
Memory.FillRAM[address] = byte;
#if 0
printf("DMA length %04x\n", Memory.FillRAM[0x2238] | (Memory.FillRAM[0x2239] << 8));
#endif
break; break;
case 0x223f: case 0x223f: // BW-RAM bitmap format
//printf("virtual VRAM depth %d\n", (byte & 0x80) ? 2 : 4);
SA1.VirtualBitmapFormat = (byte & 0x80) ? 2 : 4; SA1.VirtualBitmapFormat = (byte & 0x80) ? 2 : 4;
break; break;
case 0x2240: case 0x2240: // bitmap register 0
case 0x2241: case 0x2241: // bitmap register 1
case 0x2242: case 0x2242: // bitmap register 2
case 0x2243: case 0x2243: // bitmap register 3
case 0x2244: case 0x2244: // bitmap register 4
case 0x2245: case 0x2245: // bitmap register 5
case 0x2246: case 0x2246: // bitmap register 6
case 0x2247: case 0x2247: // bitmap register 7
case 0x2248: case 0x2248: // bitmap register 8
case 0x2249: case 0x2249: // bitmap register 9
case 0x224a: case 0x224a: // bitmap register A
case 0x224b: case 0x224b: // bitmap register B
case 0x224c: case 0x224c: // bitmap register C
case 0x224d: case 0x224d: // bitmap register D
case 0x224e: case 0x224e: // bitmap register E
#if 0
if (!(SA1.Flags & TRACE_FLAG))
{
TraceSA1();
Trace();
}
#endif
Memory.FillRAM[address] = byte;
break; break;
case 0x224f: case 0x224f: // bitmap register F
Memory.FillRAM[0x224f] = byte; Memory.FillRAM[0x224f] = byte;
if ((Memory.FillRAM[0x2230] & 0xb0) == 0xa0) // Char conversion 2 DMA enabled if ((Memory.FillRAM[0x2230] & 0xb0) == 0xa0) // CC2
{ {
memmove(&Memory.ROM[CMemory::MAX_ROM_SIZE - 0x10000] + SA1.in_char_dma * 16, &Memory.FillRAM[0x2240], 16); memmove(&Memory.ROM[CMemory::MAX_ROM_SIZE - 0x10000] + SA1.in_char_dma * 16, &Memory.FillRAM[0x2240], 16);
SA1.in_char_dma = (SA1.in_char_dma + 1) & 7; SA1.in_char_dma = (SA1.in_char_dma + 1) & 7;
@ -712,58 +708,69 @@ void S9xSetSA1 (uint8 byte, uint32 address)
break; break;
case 0x2250: case 0x2250: // arithmetic control
if (byte & 2) if (byte & 2)
SA1.sum = 0; SA1.sum = 0;
SA1.arithmetic_op = byte & 3; SA1.arithmetic_op = byte & 3;
break; break;
case 0x2251: case 0x2251: // multiplicand / dividend (L)
SA1.op1 = (SA1.op1 & 0xff00) | byte; SA1.op1 = (SA1.op1 & 0xff00) | byte;
break; break;
case 0x2252: case 0x2252: // multiplicand / dividend (H)
SA1.op1 = (SA1.op1 & 0xff) | (byte << 8); SA1.op1 = (SA1.op1 & 0x00ff) | (byte << 8);
break; break;
case 0x2253: case 0x2253: // multiplier / divisor (L)
SA1.op2 = (SA1.op2 & 0xff00) | byte; SA1.op2 = (SA1.op2 & 0xff00) | byte;
break; break;
case 0x2254: case 0x2254: // multiplier / divisor (H)
SA1.op2 = (SA1.op2 & 0xff) | (byte << 8); SA1.op2 = (SA1.op2 & 0x00ff) | (byte << 8);
switch (SA1.arithmetic_op) switch (SA1.arithmetic_op)
{ {
case 0: // multiply case 0: // signed multiplication
SA1.sum = SA1.op1 * SA1.op2; SA1.sum = (int16) SA1.op1 * (int16) SA1.op2;
SA1.op2 = 0;
break; break;
case 1: // divide case 1: // unsigned division
if (SA1.op2 == 0) if (SA1.op2 == 0)
SA1.sum = SA1.op1 << 16; SA1.sum = 0;
else else
SA1.sum = (SA1.op1 / (int) ((uint16) SA1.op2)) | ((SA1.op1 % (int) ((uint16) SA1.op2)) << 16); {
int16 dividend = (int16) SA1.op1;
uint16 divisor = (uint16) SA1.op2;
uint16 remainder = (dividend >= 0) ? dividend % divisor : (dividend % divisor) + divisor;
uint16 quotient = (dividend - remainder) / divisor;
SA1.sum = (remainder << 16) | quotient;
}
SA1.op1 = 0;
SA1.op2 = 0;
break; break;
case 2: // cumulative sum case 2: // cumulative sum
default: default:
SA1.sum += SA1.op1 * SA1.op2; SA1.sum += (int16) SA1.op1 * (int16) SA1.op2;
if (SA1.sum & ((int64) 0xffffff << 32)) SA1.overflow = (SA1.sum >= (1ULL << 40));
SA1.overflow = TRUE; SA1.sum &= (1ULL << 40) - 1;
SA1.op2 = 0;
break; break;
} }
break; break;
case 0x2258: // Variable bit-field length/auto inc/start. case 0x2258: // variable bit-field length / auto inc / start
Memory.FillRAM[0x2258] = byte; Memory.FillRAM[0x2258] = byte;
S9xSA1ReadVariableLengthData(TRUE, FALSE); S9xSA1ReadVariableLengthData(TRUE, FALSE);
return; return;
case 0x2259: // Variable bit-field start address case 0x2259: // variable bit-field start address (LL)
case 0x225a: case 0x225a: // variable bit-field start address (LH)
case 0x225b: case 0x225b: // variable bit-field start address (HL)
Memory.FillRAM[address] = byte; Memory.FillRAM[address] = byte;
// XXX: ??? // XXX: ???
SA1.variable_bit_pos = 0; SA1.variable_bit_pos = 0;
@ -771,7 +778,6 @@ void S9xSetSA1 (uint8 byte, uint32 address)
return; return;
default: default:
//printf("W: %02x->%04x\n", byte, address);
break; break;
} }
@ -890,14 +896,11 @@ static void S9xSA1DMA (void)
} }
memmove(d, s, len); memmove(d, s, len);
Memory.FillRAM[0x2301] |= 0x20;
// SA-1 DMA IRQ control
Memory.FillRAM[0x2301] |= 0x20;
if (Memory.FillRAM[0x220a] & 0x20) if (Memory.FillRAM[0x220a] & 0x20)
{ Memory.FillRAM[0x220b] &= ~0x20;
SA1.Flags |= IRQ_FLAG;
SA1.IRQActive |= DMA_IRQ_SOURCE;
//SA1.Executing = !SA1.Waiting;
}
} }
static void S9xSA1ReadVariableLengthData (bool8 inc, bool8 no_shift) static void S9xSA1ReadVariableLengthData (bool8 inc, bool8 no_shift)
@ -1096,6 +1099,10 @@ void S9xSA1SetPCBase (uint32 address)
SA1Registers.PBPC = address & 0xffffff; SA1Registers.PBPC = address & 0xffffff;
SA1.ShiftedPB = address & 0xff0000; SA1.ShiftedPB = address & 0xff0000;
// FIXME
SA1.MemSpeed = memory_speed(address);
SA1.MemSpeedx2 = SA1.MemSpeed << 1;
uint8 *GetAddress = SA1.Map[(address & 0xffffff) >> MEMMAP_SHIFT]; uint8 *GetAddress = SA1.Map[(address & 0xffffff) >> MEMMAP_SHIFT];
if (GetAddress >= (uint8 *) CMemory::MAP_LAST) if (GetAddress >= (uint8 *) CMemory::MAP_LAST)
@ -1133,4 +1140,3 @@ void S9xSA1SetPCBase (uint32 address)
return; return;
} }
} }

View File

@ -17,13 +17,20 @@
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja (c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso, (c) Copyright 2009 - 2018 BearOso,
OV2 OV2
(c) Copyright 2017 qwertymodo
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
BS-X C emulator code BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom, (c) Copyright 2005 - 2006 Dreamer Nom,
@ -117,6 +124,9 @@
Sound emulator code used in 1.52+ Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
S-SMP emulator code used in 1.54+
(c) Copyright 2016 byuu
SH assembler code partly based on x86 assembler code SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
@ -130,7 +140,7 @@
(c) Copyright 2006 - 2007 Shay Green (c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso (c) Copyright 2004 - 2018 BearOso
Win32 GUI code Win32 GUI code
(c) Copyright 2003 - 2006 blip, (c) Copyright 2003 - 2006 blip,
@ -138,11 +148,16 @@
Matthew Kendora, Matthew Kendora,
Nach, Nach,
nitsuja nitsuja
(c) Copyright 2009 - 2010 OV2 (c) Copyright 2009 - 2018 OV2
Mac OS GUI code Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2011 zones
Libretro port
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
@ -198,32 +213,33 @@ struct SSA1
uint8 _Zero; uint8 _Zero;
uint8 _Negative; uint8 _Negative;
uint8 _Overflow; uint8 _Overflow;
bool8 CPUExecuting;
uint32 ShiftedPB; uint32 ShiftedPB;
uint32 ShiftedDB; uint32 ShiftedDB;
uint32 Flags; uint32 Flags;
int32 Cycles;
int32 PrevCycles;
uint8 *PCBase; uint8 *PCBase;
bool8 IRQActive;
bool8 Waiting;
bool8 WaitingForInterrupt; bool8 WaitingForInterrupt;
uint32 WaitAddress;
uint32 WaitCounter;
uint32 PBPCAtOpcodeStart;
uint8 *WaitByteAddress1;
uint8 *WaitByteAddress2;
uint8 *Map[MEMMAP_NUM_BLOCKS]; uint8 *Map[MEMMAP_NUM_BLOCKS];
uint8 *WriteMap[MEMMAP_NUM_BLOCKS]; uint8 *WriteMap[MEMMAP_NUM_BLOCKS];
uint8 *BWRAM; uint8 *BWRAM;
bool8 Executing;
bool8 overflow;
bool8 in_char_dma; bool8 in_char_dma;
int16 op1; bool8 TimerIRQLastState;
int16 op2; uint16 HTimerIRQPos;
uint16 VTimerIRQPos;
int16 HCounter;
int16 VCounter;
int16 PrevHCounter;
int32 MemSpeed;
int32 MemSpeedx2;
int32 arithmetic_op; int32 arithmetic_op;
int64 sum; uint16 op1;
uint16 op2;
uint64 sum;
bool8 overflow;
uint8 VirtualBitmapFormat; uint8 VirtualBitmapFormat;
uint8 variable_bit_pos; uint8 variable_bit_pos;
}; };
@ -263,13 +279,8 @@ uint8 S9xGetSA1 (uint32);
void S9xSetSA1 (uint8, uint32); void S9xSetSA1 (uint8, uint32);
void S9xSA1Init (void); void S9xSA1Init (void);
void S9xSA1MainLoop (void); void S9xSA1MainLoop (void);
void S9xSA1ExecuteDuringSleep (void);
void S9xSA1PostLoadState (void); void S9xSA1PostLoadState (void);
#define SNES_IRQ_SOURCE (1 << 7)
#define TIMER_IRQ_SOURCE (1 << 6)
#define DMA_IRQ_SOURCE (1 << 5)
static inline void S9xSA1UnpackStatus (void) static inline void S9xSA1UnpackStatus (void)
{ {
SA1._Zero = (SA1Registers.PL & Zero) == 0; SA1._Zero = (SA1Registers.PL & Zero) == 0;

View File

@ -17,13 +17,20 @@
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja (c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso, (c) Copyright 2009 - 2018 BearOso,
OV2 OV2
(c) Copyright 2017 qwertymodo
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
BS-X C emulator code BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom, (c) Copyright 2005 - 2006 Dreamer Nom,
@ -117,6 +124,9 @@
Sound emulator code used in 1.52+ Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
S-SMP emulator code used in 1.54+
(c) Copyright 2016 byuu
SH assembler code partly based on x86 assembler code SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
@ -130,7 +140,7 @@
(c) Copyright 2006 - 2007 Shay Green (c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso (c) Copyright 2004 - 2018 BearOso
Win32 GUI code Win32 GUI code
(c) Copyright 2003 - 2006 blip, (c) Copyright 2003 - 2006 blip,
@ -138,11 +148,16 @@
Matthew Kendora, Matthew Kendora,
Nach, Nach,
nitsuja nitsuja
(c) Copyright 2009 - 2010 OV2 (c) Copyright 2009 - 2018 OV2
Mac OS GUI code Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2011 zones
Libretro port
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
@ -221,20 +236,27 @@
#define StackRelative SA1StackRelative #define StackRelative SA1StackRelative
#define StackRelativeIndirectIndexed SA1StackRelativeIndirectIndexed #define StackRelativeIndirectIndexed SA1StackRelativeIndirectIndexed
//#undef CPU_SHUTDOWN
#define SA1_OPCODES #define SA1_OPCODES
#include "cpuops.cpp" #include "cpuops.cpp"
static void S9xSA1UpdateTimer (void);
void S9xSA1MainLoop (void) void S9xSA1MainLoop (void)
{ {
if (SA1.Flags & NMI_FLAG) if (Memory.FillRAM[0x2200] & 0x60)
{ {
if (Memory.FillRAM[0x2200] & 0x10) SA1.Cycles += 6; // FIXME
S9xSA1UpdateTimer();
return;
}
// SA-1 NMI
if ((Memory.FillRAM[0x2200] & 0x10) && !(Memory.FillRAM[0x220b] & 0x10))
{ {
SA1.Flags &= ~NMI_FLAG;
Memory.FillRAM[0x2301] |= 0x10; Memory.FillRAM[0x2301] |= 0x10;
Memory.FillRAM[0x220b] |= 0x10;
if (SA1.WaitingForInterrupt) if (SA1.WaitingForInterrupt)
{ {
@ -244,36 +266,59 @@ void S9xSA1MainLoop (void)
S9xSA1Opcode_NMI(); S9xSA1Opcode_NMI();
} }
} else
if (!SA1CheckFlag(IRQ))
{
// SA-1 Timer IRQ
if ((Memory.FillRAM[0x220a] & 0x40) && !(Memory.FillRAM[0x220b] & 0x40))
{
Memory.FillRAM[0x2301] |= 0x40;
if (SA1.Flags & IRQ_FLAG)
{
if (SA1.IRQActive)
{
if (SA1.WaitingForInterrupt) if (SA1.WaitingForInterrupt)
{ {
SA1.WaitingForInterrupt = FALSE; SA1.WaitingForInterrupt = FALSE;
SA1Registers.PCw++; SA1Registers.PCw++;
} }
if (!SA1CheckFlag(IRQ))
S9xSA1Opcode_IRQ(); S9xSA1Opcode_IRQ();
} }
else else
SA1.Flags &= ~IRQ_FLAG; // SA-1 DMA IRQ
if ((Memory.FillRAM[0x220a] & 0x20) && !(Memory.FillRAM[0x220b] & 0x20))
{
Memory.FillRAM[0x2301] |= 0x20;
if (SA1.WaitingForInterrupt)
{
SA1.WaitingForInterrupt = FALSE;
SA1Registers.PCw++;
} }
for (int i = 0; i < 3 && SA1.Executing; i++) S9xSA1Opcode_IRQ();
}
else
// SA-1 IRQ
if ((Memory.FillRAM[0x2200] & 0x80) && !(Memory.FillRAM[0x220b] & 0x80))
{
Memory.FillRAM[0x2301] |= 0x80;
if (SA1.WaitingForInterrupt)
{
SA1.WaitingForInterrupt = FALSE;
SA1Registers.PCw++;
}
S9xSA1Opcode_IRQ();
}
}
for (int i = 0; i < 5 && !(Memory.FillRAM[0x2200] & 0x60); i++)
{ {
#ifdef DEBUGGER #ifdef DEBUGGER
if (SA1.Flags & TRACE_FLAG) if (SA1.Flags & TRACE_FLAG)
S9xSA1Trace(); S9xSA1Trace();
#endif #endif
#ifdef CPU_SHUTDOWN
SA1.PBPCAtOpcodeStart = SA1Registers.PBPC;
#endif
register uint8 Op; register uint8 Op;
register struct SOpcodes *Opcodes; register struct SOpcodes *Opcodes;
@ -299,5 +344,71 @@ void S9xSA1MainLoop (void)
Registers.PCw++; Registers.PCw++;
(*Opcodes[Op].S9xOpcode)(); (*Opcodes[Op].S9xOpcode)();
} }
S9xSA1UpdateTimer();
} }
static void S9xSA1UpdateTimer (void) // FIXME
{
SA1.PrevHCounter = SA1.HCounter;
if (Memory.FillRAM[0x2210] & 0x80)
{
SA1.HCounter += (SA1.Cycles - SA1.PrevCycles);
if (SA1.HCounter >= 0x800)
{
SA1.HCounter -= 0x800;
SA1.PrevHCounter -= 0x800;
if (++SA1.VCounter >= 0x200)
SA1.VCounter = 0;
}
}
else
{
SA1.HCounter += (SA1.Cycles - SA1.PrevCycles);
if (SA1.HCounter >= Timings.H_Max_Master)
{
SA1.HCounter -= Timings.H_Max_Master;
SA1.PrevHCounter -= Timings.H_Max_Master;
if (++SA1.VCounter >= Timings.V_Max_Master)
SA1.VCounter = 0;
}
}
if (SA1.Cycles >= Timings.H_Max_Master)
SA1.Cycles -= Timings.H_Max_Master;
SA1.PrevCycles = SA1.Cycles;
bool8 thisIRQ = Memory.FillRAM[0x2210] & 0x03;
if (Memory.FillRAM[0x2210] & 0x01)
{
if (SA1.PrevHCounter >= SA1.HTimerIRQPos * ONE_DOT_CYCLE || SA1.HCounter < SA1.HTimerIRQPos * ONE_DOT_CYCLE)
thisIRQ = FALSE;
}
if (Memory.FillRAM[0x2210] & 0x02)
{
if (SA1.VCounter != SA1.VTimerIRQPos * ONE_DOT_CYCLE)
thisIRQ = FALSE;
}
// SA-1 Timer IRQ control
if (!SA1.TimerIRQLastState && thisIRQ)
{
Memory.FillRAM[0x2301] |= 0x40;
if (Memory.FillRAM[0x220a] & 0x40)
{
Memory.FillRAM[0x220b] &= ~0x40;
#ifdef DEBUGGER
S9xTraceFormattedMessage("--- SA-1 Timer IRQ triggered prev HC:%04d curr HC:%04d HTimer:%d Pos:%04d VTimer:%d Pos:%03d",
SA1.PrevHCounter, SA1.HCounter,
(Memory.FillRAM[0x2210] & 0x01) ? 1 : 0, SA1.HTimerIRQPos * ONE_DOT_CYCLE,
(Memory.FillRAM[0x2210] & 0x02) ? 1 : 0, SA1.VTimerIRQPos);
#endif
}
}
SA1.TimerIRQLastState = thisIRQ;
}

View File

@ -17,13 +17,20 @@
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja (c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso, (c) Copyright 2009 - 2018 BearOso,
OV2 OV2
(c) Copyright 2017 qwertymodo
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
BS-X C emulator code BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom, (c) Copyright 2005 - 2006 Dreamer Nom,
@ -117,6 +124,9 @@
Sound emulator code used in 1.52+ Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
S-SMP emulator code used in 1.54+
(c) Copyright 2016 byuu
SH assembler code partly based on x86 assembler code SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
@ -130,7 +140,7 @@
(c) Copyright 2006 - 2007 Shay Green (c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso (c) Copyright 2004 - 2018 BearOso
Win32 GUI code Win32 GUI code
(c) Copyright 2003 - 2006 blip, (c) Copyright 2003 - 2006 blip,
@ -138,14 +148,16 @@
Matthew Kendora, Matthew Kendora,
Nach, Nach,
nitsuja nitsuja
(c) Copyright 2009 - 2010 OV2 (c) Copyright 2009 - 2018 OV2
Mac OS GUI code Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2011 zones
MSU-1 code Libretro port
(c) Copyright 2016 qwertymodo (c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
@ -345,7 +357,7 @@ struct SnapshotScreenshotInfo
static struct Obsolete static struct Obsolete
{ {
uint8 reserved; uint8 CPU_IRQActive;
} Obsolete; } Obsolete;
#define STRUCT struct SCPUState #define STRUCT struct SCPUState
@ -356,7 +368,7 @@ static FreezeData SnapCPU[] =
INT_ENTRY(6, PrevCycles), INT_ENTRY(6, PrevCycles),
INT_ENTRY(6, V_Counter), INT_ENTRY(6, V_Counter),
INT_ENTRY(6, Flags), INT_ENTRY(6, Flags),
INT_ENTRY(6, IRQActive), OBSOLETE_INT_ENTRY(6, 7, CPU_IRQActive),
INT_ENTRY(6, IRQPending), INT_ENTRY(6, IRQPending),
INT_ENTRY(6, MemSpeed), INT_ENTRY(6, MemSpeed),
INT_ENTRY(6, MemSpeedx2), INT_ENTRY(6, MemSpeedx2),
@ -369,9 +381,14 @@ static FreezeData SnapCPU[] =
INT_ENTRY(6, WhichEvent), INT_ENTRY(6, WhichEvent),
INT_ENTRY(6, NextEvent), INT_ENTRY(6, NextEvent),
INT_ENTRY(6, WaitingForInterrupt), INT_ENTRY(6, WaitingForInterrupt),
INT_ENTRY(6, WaitAddress), DELETED_INT_ENTRY(6, 7, WaitAddress, 4),
INT_ENTRY(6, WaitCounter), DELETED_INT_ENTRY(6, 7, WaitCounter, 4),
INT_ENTRY(6, PBPCAtOpcodeStart) DELETED_INT_ENTRY(6, 7, PBPCAtOpcodeStart, 4),
INT_ENTRY(7, NMIPending),
INT_ENTRY(7, IRQLine),
INT_ENTRY(7, IRQTransition),
INT_ENTRY(7, IRQLastState),
INT_ENTRY(7, IRQExternal)
}; };
#undef STRUCT #undef STRUCT
@ -578,8 +595,10 @@ static FreezeData SnapTimings[] =
INT_ENTRY(6, InterlaceField), INT_ENTRY(6, InterlaceField),
INT_ENTRY(6, DMACPUSync), INT_ENTRY(6, DMACPUSync),
INT_ENTRY(6, NMIDMADelay), INT_ENTRY(6, NMIDMADelay),
INT_ENTRY(6, IRQPendCount), INT_ENTRY(6, IRQFlagChanging),
INT_ENTRY(6, APUSpeedup) INT_ENTRY(6, APUSpeedup),
INT_ENTRY(7, IRQTriggerCycles),
INT_ENTRY(7, APUAllowTimeOverflow)
}; };
#undef STRUCT #undef STRUCT
@ -648,17 +667,17 @@ static FreezeData SnapFX[] =
static FreezeData SnapSA1[] = static FreezeData SnapSA1[] =
{ {
INT_ENTRY(6, CPUExecuting), DELETED_INT_ENTRY(6, 7, CPUExecuting, 1),
INT_ENTRY(6, ShiftedPB), INT_ENTRY(6, ShiftedPB),
INT_ENTRY(6, ShiftedDB), INT_ENTRY(6, ShiftedDB),
INT_ENTRY(6, Flags), INT_ENTRY(6, Flags),
INT_ENTRY(6, IRQActive), DELETED_INT_ENTRY(6, 7, IRQActive, 1),
INT_ENTRY(6, Waiting), DELETED_INT_ENTRY(6, 7, Waiting, 1),
INT_ENTRY(6, WaitingForInterrupt), INT_ENTRY(6, WaitingForInterrupt),
INT_ENTRY(6, WaitAddress), DELETED_INT_ENTRY(6, 7, WaitAddress, 4),
INT_ENTRY(6, WaitCounter), DELETED_INT_ENTRY(6, 7, WaitCounter, 4),
INT_ENTRY(6, PBPCAtOpcodeStart), DELETED_INT_ENTRY(6, 7, PBPCAtOpcodeStart, 4),
INT_ENTRY(6, Executing), DELETED_INT_ENTRY(6, 7, Executing, 1),
INT_ENTRY(6, overflow), INT_ENTRY(6, overflow),
INT_ENTRY(6, in_char_dma), INT_ENTRY(6, in_char_dma),
INT_ENTRY(6, op1), INT_ENTRY(6, op1),
@ -666,7 +685,17 @@ static FreezeData SnapSA1[] =
INT_ENTRY(6, arithmetic_op), INT_ENTRY(6, arithmetic_op),
INT_ENTRY(6, sum), INT_ENTRY(6, sum),
INT_ENTRY(6, VirtualBitmapFormat), INT_ENTRY(6, VirtualBitmapFormat),
INT_ENTRY(6, variable_bit_pos) INT_ENTRY(6, variable_bit_pos),
INT_ENTRY(7, Cycles),
INT_ENTRY(7, PrevCycles),
INT_ENTRY(7, TimerIRQLastState),
INT_ENTRY(7, HTimerIRQPos),
INT_ENTRY(7, VTimerIRQPos),
INT_ENTRY(7, HCounter),
INT_ENTRY(7, VCounter),
INT_ENTRY(7, PrevHCounter),
INT_ENTRY(7, MemSpeed),
INT_ENTRY(7, MemSpeedx2)
}; };
#undef STRUCT #undef STRUCT
@ -1113,16 +1142,16 @@ static FreezeData SnapBSX[] =
static FreezeData SnapMSU1[] = static FreezeData SnapMSU1[] =
{ {
INT_ENTRY(7, MSU1_STATUS), INT_ENTRY(9, MSU1_STATUS),
INT_ENTRY(7, MSU1_DATA_SEEK), INT_ENTRY(9, MSU1_DATA_SEEK),
INT_ENTRY(7, MSU1_DATA_POS), INT_ENTRY(9, MSU1_DATA_POS),
INT_ENTRY(7, MSU1_TRACK_SEEK), INT_ENTRY(9, MSU1_TRACK_SEEK),
INT_ENTRY(7, MSU1_CURRENT_TRACK), INT_ENTRY(9, MSU1_CURRENT_TRACK),
INT_ENTRY(7, MSU1_RESUME_TRACK), INT_ENTRY(9, MSU1_RESUME_TRACK),
INT_ENTRY(7, MSU1_VOLUME), INT_ENTRY(9, MSU1_VOLUME),
INT_ENTRY(7, MSU1_CONTROL), INT_ENTRY(9, MSU1_CONTROL),
INT_ENTRY(7, MSU1_AUDIO_POS), INT_ENTRY(9, MSU1_AUDIO_POS),
INT_ENTRY(7, MSU1_RESUME_POS) INT_ENTRY(9, MSU1_RESUME_POS)
}; };
#undef STRUCT #undef STRUCT
@ -1151,6 +1180,8 @@ static int UnfreezeStructCopy (STREAM, const char *, uint8 **, FreezeData *, int
static void UnfreezeStructFromCopy (void *, FreezeData *, int, uint8 *, int); static void UnfreezeStructFromCopy (void *, FreezeData *, int, uint8 *, int);
static void FreezeBlock (STREAM, const char *, uint8 *, int); static void FreezeBlock (STREAM, const char *, uint8 *, int);
static void FreezeStruct (STREAM, const char *, void *, FreezeData *, int); static void FreezeStruct (STREAM, const char *, void *, FreezeData *, int);
static bool CheckBlockName(STREAM stream, const char *name, int &len);
static void SkipBlockWithName(STREAM stream, const char *name);
void S9xResetSaveTimer (bool8 dontsave) void S9xResetSaveTimer (bool8 dontsave)
@ -1163,7 +1194,7 @@ void S9xResetSaveTimer (bool8 dontsave)
char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[_MAX_FNAME + 1], ext[_MAX_EXT + 1]; char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[_MAX_FNAME + 1], ext[_MAX_EXT + 1];
_splitpath(Memory.ROMFilename, drive, dir, def, ext); _splitpath(Memory.ROMFilename, drive, dir, def, ext);
sprintf(filename, "%s%s%s.%.*s", S9xGetDirectory(SNAPSHOT_DIR), SLASH_STR, def, _MAX_EXT - 1, "oops"); snprintf(filename, PATH_MAX + 1, "%s%s%s.%.*s", S9xGetDirectory(SNAPSHOT_DIR), SLASH_STR, def, _MAX_EXT - 1, "oops");
S9xMessage(S9X_INFO, S9X_FREEZE_FILE_INFO, SAVE_INFO_OOPS); S9xMessage(S9X_INFO, S9X_FREEZE_FILE_INFO, SAVE_INFO_OOPS);
S9xFreezeGame(filename); S9xFreezeGame(filename);
} }
@ -1171,6 +1202,21 @@ void S9xResetSaveTimer (bool8 dontsave)
t = time(NULL); t = time(NULL);
} }
uint32 S9xFreezeSize()
{
nulStream stream;
S9xFreezeToStream(&stream);
return stream.size();
}
bool8 S9xFreezeGameMem (uint8 *buf, uint32 bufSize)
{
memStream mStream(buf, bufSize);
S9xFreezeToStream(&mStream);
return (TRUE);
}
bool8 S9xFreezeGame (const char *filename) bool8 S9xFreezeGame (const char *filename)
{ {
STREAM stream = NULL; STREAM stream = NULL;
@ -1196,6 +1242,14 @@ bool8 S9xFreezeGame (const char *filename)
return (FALSE); return (FALSE);
} }
int S9xUnfreezeGameMem (const uint8 *buf, uint32 bufSize)
{
memStream stream(buf, bufSize);
int result = S9xUnfreezeFromStream(&stream);
return result;
}
bool8 S9xUnfreezeGame (const char *filename) bool8 S9xUnfreezeGame (const char *filename)
{ {
STREAM stream = NULL; STREAM stream = NULL;
@ -1270,11 +1324,9 @@ bool8 S9xUnfreezeGame (const char *filename)
void S9xFreezeToStream (STREAM stream) void S9xFreezeToStream (STREAM stream)
{ {
char buffer[1024]; char buffer[8192];
uint8 *soundsnapshot = new uint8[SPC_SAVE_STATE_BLOCK_SIZE]; uint8 *soundsnapshot = new uint8[SPC_SAVE_STATE_BLOCK_SIZE];
S9xSetSoundMute(TRUE);
sprintf(buffer, "%s:%04d\n", SNAPSHOT_MAGIC, SNAPSHOT_VERSION); sprintf(buffer, "%s:%04d\n", SNAPSHOT_MAGIC, SNAPSHOT_VERSION);
WRITE_STREAM(buffer, strlen(buffer), stream); WRITE_STREAM(buffer, strlen(buffer), stream);
@ -1413,19 +1465,19 @@ void S9xFreezeToStream (STREAM stream)
} }
} }
S9xSetSoundMute(FALSE);
delete [] soundsnapshot; delete [] soundsnapshot;
} }
int S9xUnfreezeFromStream (STREAM stream) int S9xUnfreezeFromStream (STREAM stream)
{ {
const bool8 fast = Settings.FastSavestates;
int result = SUCCESS; int result = SUCCESS;
int version, len; int version, len;
char buffer[PATH_MAX + 1]; char buffer[PATH_MAX + 1];
len = strlen(SNAPSHOT_MAGIC) + 1 + 4 + 1; len = strlen(SNAPSHOT_MAGIC) + 1 + 4 + 1;
if (READ_STREAM(buffer, len, stream) != len) if (READ_STREAM(buffer, len, stream) != (unsigned int ) len)
return (WRONG_FORMAT); return (WRONG_FORMAT);
if (strncmp(buffer, SNAPSHOT_MAGIC, strlen(SNAPSHOT_MAGIC)) != 0) if (strncmp(buffer, SNAPSHOT_MAGIC, strlen(SNAPSHOT_MAGIC)) != 0)
@ -1486,18 +1538,30 @@ int S9xUnfreezeFromStream (STREAM stream)
if (result != SUCCESS) if (result != SUCCESS)
break; break;
if (fast)
result = UnfreezeBlock(stream, "VRA", Memory.VRAM, 0x10000);
else
result = UnfreezeBlockCopy(stream, "VRA", &local_vram, 0x10000); result = UnfreezeBlockCopy(stream, "VRA", &local_vram, 0x10000);
if (result != SUCCESS) if (result != SUCCESS)
break; break;
if (fast)
result = UnfreezeBlock(stream, "RAM", Memory.RAM, 0x20000);
else
result = UnfreezeBlockCopy(stream, "RAM", &local_ram, 0x20000); result = UnfreezeBlockCopy(stream, "RAM", &local_ram, 0x20000);
if (result != SUCCESS) if (result != SUCCESS)
break; break;
if (fast)
result = UnfreezeBlock(stream, "SRA", Memory.SRAM, 0x20000);
else
result = UnfreezeBlockCopy (stream, "SRA", &local_sram, 0x20000); result = UnfreezeBlockCopy (stream, "SRA", &local_sram, 0x20000);
if (result != SUCCESS) if (result != SUCCESS)
break; break;
if (fast)
result = UnfreezeBlock(stream, "FIL", Memory.FillRAM, 0x8000);
else
result = UnfreezeBlockCopy(stream, "FIL", &local_fillram, 0x8000); result = UnfreezeBlockCopy(stream, "FIL", &local_fillram, 0x8000);
if (result != SUCCESS) if (result != SUCCESS)
break; break;
@ -1538,9 +1602,19 @@ int S9xUnfreezeFromStream (STREAM stream)
if (result != SUCCESS && Settings.DSP == 4) if (result != SUCCESS && Settings.DSP == 4)
break; break;
if (Settings.C4)
{
if (fast)
result = UnfreezeBlock(stream, "CX4", Memory.C4RAM, 8192);
else
result = UnfreezeBlockCopy(stream, "CX4", &local_cx4_data, 8192); result = UnfreezeBlockCopy(stream, "CX4", &local_cx4_data, 8192);
if (result != SUCCESS && Settings.C4) if (result != SUCCESS)
break; break;
}
else
{
SkipBlockWithName(stream, "CX4");
}
result = UnfreezeStructCopy(stream, "ST0", &local_st010, SnapST010, COUNT(SnapST010), version); result = UnfreezeStructCopy(stream, "ST0", &local_st010, SnapST010, COUNT(SnapST010), version);
if (result != SUCCESS && Settings.SETA == ST_010) if (result != SUCCESS && Settings.SETA == ST_010)
@ -1550,9 +1624,19 @@ int S9xUnfreezeFromStream (STREAM stream)
if (result != SUCCESS && Settings.OBC1) if (result != SUCCESS && Settings.OBC1)
break; break;
if (Settings.OBC1)
{
if (fast)
result = UnfreezeBlock(stream, "OBM", Memory.OBC1RAM, 8192);
else
result = UnfreezeBlockCopy(stream, "OBM", &local_obc1_data, 8192); result = UnfreezeBlockCopy(stream, "OBM", &local_obc1_data, 8192);
if (result != SUCCESS && Settings.OBC1) if (result != SUCCESS)
break; break;
}
else
{
SkipBlockWithName(stream, "OBM");
}
result = UnfreezeStructCopy(stream, "S71", &local_spc7110, SnapSPC7110Snap, COUNT(SnapSPC7110Snap), version); result = UnfreezeStructCopy(stream, "S71", &local_spc7110, SnapSPC7110Snap, COUNT(SnapSPC7110Snap), version);
if (result != SUCCESS && Settings.SPC7110) if (result != SUCCESS && Settings.SPC7110)
@ -1615,9 +1699,15 @@ int S9xUnfreezeFromStream (STREAM stream)
uint32 old_flags = CPU.Flags; uint32 old_flags = CPU.Flags;
uint32 sa1_old_flags = SA1.Flags; uint32 sa1_old_flags = SA1.Flags;
S9xSetSoundMute(TRUE); if (fast)
{
S9xResetPPUFast();
}
else
{
//Do not call this if you have written directly to "Memory." arrays
S9xReset(); S9xReset();
}
UnfreezeStructFromCopy(&CPU, SnapCPU, COUNT(SnapCPU), local_cpu, version); UnfreezeStructFromCopy(&CPU, SnapCPU, COUNT(SnapCPU), local_cpu, version);
@ -1628,12 +1718,16 @@ int S9xUnfreezeFromStream (STREAM stream)
struct SDMASnapshot dma_snap; struct SDMASnapshot dma_snap;
UnfreezeStructFromCopy(&dma_snap, SnapDMA, COUNT(SnapDMA), local_dma, version); UnfreezeStructFromCopy(&dma_snap, SnapDMA, COUNT(SnapDMA), local_dma, version);
if (local_vram)
memcpy(Memory.VRAM, local_vram, 0x10000); memcpy(Memory.VRAM, local_vram, 0x10000);
if (local_ram)
memcpy(Memory.RAM, local_ram, 0x20000); memcpy(Memory.RAM, local_ram, 0x20000);
if (local_sram)
memcpy(Memory.SRAM, local_sram, 0x20000); memcpy(Memory.SRAM, local_sram, 0x20000);
if (local_fillram)
memcpy(Memory.FillRAM, local_fillram, 0x8000); memcpy(Memory.FillRAM, local_fillram, 0x8000);
S9xAPULoadState(local_apu_sound); S9xAPULoadState(local_apu_sound);
@ -1691,11 +1785,46 @@ int S9xUnfreezeFromStream (STREAM stream)
if (local_msu1_data) if (local_msu1_data)
UnfreezeStructFromCopy(&MSU1, SnapMSU1, COUNT(SnapMSU1), local_msu1_data, version); UnfreezeStructFromCopy(&MSU1, SnapMSU1, COUNT(SnapMSU1), local_msu1_data, version);
if (version < SNAPSHOT_VERSION_IRQ)
{
printf("Converting old snapshot version %d to %d\n...", version, SNAPSHOT_VERSION);
CPU.NMIPending = (CPU.Flags & (1 << 7)) ? TRUE : FALSE;
CPU.IRQLine = (CPU.Flags & (1 << 11)) ? TRUE : FALSE;
CPU.IRQTransition = FALSE;
CPU.IRQLastState = FALSE;
CPU.IRQExternal = (Obsolete.CPU_IRQActive & ~(1 << 1)) ? TRUE : FALSE;
switch (CPU.WhichEvent)
{
case 12: case 1: CPU.WhichEvent = 1; break;
case 2: case 3: CPU.WhichEvent = 2; break;
case 4: case 5: CPU.WhichEvent = 3; break;
case 6: case 7: CPU.WhichEvent = 4; break;
case 8: case 9: CPU.WhichEvent = 5; break;
case 10: case 11: CPU.WhichEvent = 6; break;
}
if (local_sa1) // FIXME
{
SA1.Cycles = SA1.PrevCycles = 0;
SA1.TimerIRQLastState = FALSE;
SA1.HTimerIRQPos = Memory.FillRAM[0x2212] | (Memory.FillRAM[0x2213] << 8);
SA1.VTimerIRQPos = Memory.FillRAM[0x2214] | (Memory.FillRAM[0x2215] << 8);
SA1.HCounter = 0;
SA1.VCounter = 0;
SA1.PrevHCounter = 0;
SA1.MemSpeed = SLOW_ONE_CYCLE;
SA1.MemSpeedx2 = SLOW_ONE_CYCLE * 2;
}
}
CPU.Flags |= old_flags & (DEBUG_MODE_FLAG | TRACE_FLAG | SINGLE_STEP_FLAG | FRAME_ADVANCE_FLAG); CPU.Flags |= old_flags & (DEBUG_MODE_FLAG | TRACE_FLAG | SINGLE_STEP_FLAG | FRAME_ADVANCE_FLAG);
ICPU.ShiftedPB = Registers.PB << 16; ICPU.ShiftedPB = Registers.PB << 16;
ICPU.ShiftedDB = Registers.DB << 16; ICPU.ShiftedDB = Registers.DB << 16;
S9xSetPCBase(Registers.PBPC); S9xSetPCBase(Registers.PBPC);
S9xUnpackStatus(); S9xUnpackStatus();
S9xUpdateIRQPositions(false);
S9xFixCycles(); S9xFixCycles();
for (int d = 0; d < 8; d++) for (int d = 0; d < 8; d++)
@ -1705,6 +1834,7 @@ int S9xUnfreezeFromStream (STREAM stream)
CPU.HDMARanInDMA = 0; CPU.HDMARanInDMA = 0;
S9xFixColourBrightness(); S9xFixColourBrightness();
S9xBuildDirectColourMaps();
IPPU.ColorsChanged = TRUE; IPPU.ColorsChanged = TRUE;
IPPU.OBJChanged = TRUE; IPPU.OBJChanged = TRUE;
IPPU.RenderThisFrame = TRUE; IPPU.RenderThisFrame = TRUE;
@ -1807,11 +1937,9 @@ int S9xUnfreezeFromStream (STREAM stream)
else else
{ {
// couldn't load graphics, so black out the screen instead // couldn't load graphics, so black out the screen instead
//for (uint32 y = 0; y < (uint32) (IMAGE_HEIGHT); y++) for (uint32 y = 0; y < (uint32) (IMAGE_HEIGHT); y++)
// memset(GFX.Screen + y * GFX.RealPPL, 0, GFX.RealPPL * 2); memset(GFX.Screen + y * GFX.RealPPL, 0, GFX.RealPPL * 2);
} }
S9xSetSoundMute(FALSE);
} }
if (local_cpu) delete [] local_cpu; if (local_cpu) delete [] local_cpu;
@ -2007,6 +2135,51 @@ static void FreezeBlock (STREAM stream, const char *name, uint8 *block, int size
WRITE_STREAM(block, size, stream); WRITE_STREAM(block, size, stream);
} }
static bool CheckBlockName(STREAM stream, const char *name, int &len)
{
char buffer[16];
len = 0;
long rewind = FIND_STREAM(stream);
size_t l = READ_STREAM(buffer, 11, stream);
buffer[l] = 0;
REVERT_STREAM(stream, FIND_STREAM(stream) - l, 0);
if (buffer[4] == '-')
{
len = (((unsigned char)buffer[6]) << 24)
| (((unsigned char)buffer[7]) << 16)
| (((unsigned char)buffer[8]) << 8)
| (((unsigned char)buffer[9]) << 0);
}
else
len = atoi(buffer + 4);
if (l != 11 || strncmp(buffer, name, 3) != 0 || buffer[3] != ':')
{
return false;
}
if (len <= 0)
{
return false;
}
return true;
}
static void SkipBlockWithName(STREAM stream, const char *name)
{
int len;
bool matchesName = CheckBlockName(stream, name, len);
if (matchesName)
{
long rewind = FIND_STREAM(stream);
rewind += len + 11;
REVERT_STREAM(stream, rewind, 0);
}
}
static int UnfreezeBlock (STREAM stream, const char *name, uint8 *block, int size) static int UnfreezeBlock (STREAM stream, const char *name, uint8 *block, int size)
{ {
char buffer[20]; char buffer[20];
@ -2019,7 +2192,9 @@ static int UnfreezeBlock (STREAM stream, const char *name, uint8 *block, int siz
if (l != 11 || strncmp(buffer, name, 3) != 0 || buffer[3] != ':') if (l != 11 || strncmp(buffer, name, 3) != 0 || buffer[3] != ':')
{ {
err: err:
#ifdef DEBUGGER
fprintf(stdout, "absent: %s(%d); next: '%.11s'\n", name, size, buffer); fprintf(stdout, "absent: %s(%d); next: '%.11s'\n", name, size, buffer);
#endif
REVERT_STREAM(stream, FIND_STREAM(stream) - l, 0); REVERT_STREAM(stream, FIND_STREAM(stream) - l, 0);
return (WRONG_FORMAT); return (WRONG_FORMAT);
} }
@ -2043,9 +2218,12 @@ static int UnfreezeBlock (STREAM stream, const char *name, uint8 *block, int siz
len = size; len = size;
} }
ZeroMemory(block, size); if (!Settings.FastSavestates)
{
memset(block, 0, size);
}
if (READ_STREAM(block, len, stream) != len) if (READ_STREAM(block, len, stream) != (unsigned int) len)
{ {
REVERT_STREAM(stream, rewind, 0); REVERT_STREAM(stream, rewind, 0);
return (WRONG_FORMAT); return (WRONG_FORMAT);
@ -2070,6 +2248,13 @@ static int UnfreezeBlockCopy (STREAM stream, const char *name, uint8 **block, in
{ {
int result; int result;
//check name first to avoid memory allocation
int blockLength;
if (!CheckBlockName(stream, name, blockLength))
{
return 0;
}
*block = new uint8[size]; *block = new uint8[size];
result = UnfreezeBlock(stream, name, *block, size); result = UnfreezeBlock(stream, name, *block, size);
@ -2257,28 +2442,3 @@ static void UnfreezeStructFromCopy (void *sbase, FreezeData *fields, int num_fie
} }
} }
} }
bool8 S9xSPCDump (const char *filename)
{
FILE *fs;
uint8 buf[SNES_SPC::spc_file_size];
size_t ignore;
fs = fopen(filename, "wb");
if (!fs)
return (FALSE);
S9xSetSoundMute(TRUE);
spc_core->init_header(buf);
spc_core->save_spc(buf);
ignore = fwrite(buf, SNES_SPC::spc_file_size, 1, fs);
fclose(fs);
S9xSetSoundMute(FALSE);
return (TRUE);
}

View File

@ -17,13 +17,20 @@
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja (c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso, (c) Copyright 2009 - 2018 BearOso,
OV2 OV2
(c) Copyright 2017 qwertymodo
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
BS-X C emulator code BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom, (c) Copyright 2005 - 2006 Dreamer Nom,
@ -117,6 +124,9 @@
Sound emulator code used in 1.52+ Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
S-SMP emulator code used in 1.54+
(c) Copyright 2016 byuu
SH assembler code partly based on x86 assembler code SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
@ -130,7 +140,7 @@
(c) Copyright 2006 - 2007 Shay Green (c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso (c) Copyright 2004 - 2018 BearOso
Win32 GUI code Win32 GUI code
(c) Copyright 2003 - 2006 blip, (c) Copyright 2003 - 2006 blip,
@ -138,14 +148,16 @@
Matthew Kendora, Matthew Kendora,
Nach, Nach,
nitsuja nitsuja
(c) Copyright 2009 - 2010 OV2 (c) Copyright 2009 - 2018 OV2
Mac OS GUI code Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2011 zones
MSU-1 code Libretro port
(c) Copyright 2016 qwertymodo (c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
@ -181,8 +193,12 @@
#ifndef _SNAPSHOT_H_ #ifndef _SNAPSHOT_H_
#define _SNAPSHOT_H_ #define _SNAPSHOT_H_
#include "snes9x.h"
#define SNAPSHOT_MAGIC "#!s9xsnp" #define SNAPSHOT_MAGIC "#!s9xsnp"
#define SNAPSHOT_VERSION 7 #define SNAPSHOT_VERSION_IRQ 7
#define SNAPSHOT_VERSION_BAPU 8
#define SNAPSHOT_VERSION 10
#define SUCCESS 1 #define SUCCESS 1
#define WRONG_FORMAT (-1) #define WRONG_FORMAT (-1)
@ -194,9 +210,11 @@
void S9xResetSaveTimer (bool8); void S9xResetSaveTimer (bool8);
bool8 S9xFreezeGame (const char *); bool8 S9xFreezeGame (const char *);
uint32 S9xFreezeSize (void);
bool8 S9xFreezeGameMem (uint8 *,uint32);
bool8 S9xUnfreezeGame (const char *); bool8 S9xUnfreezeGame (const char *);
int S9xUnfreezeGameMem (const uint8 *,uint32);
void S9xFreezeToStream (STREAM); void S9xFreezeToStream (STREAM);
int S9xUnfreezeFromStream (STREAM); int S9xUnfreezeFromStream (STREAM);
bool8 S9xSPCDump (const char *);
#endif #endif

View File

@ -17,13 +17,20 @@
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja (c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso, (c) Copyright 2009 - 2018 BearOso,
OV2 OV2
(c) Copyright 2017 qwertymodo
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
BS-X C emulator code BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom, (c) Copyright 2005 - 2006 Dreamer Nom,
@ -117,6 +124,9 @@
Sound emulator code used in 1.52+ Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
S-SMP emulator code used in 1.54+
(c) Copyright 2016 byuu
SH assembler code partly based on x86 assembler code SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
@ -130,7 +140,7 @@
(c) Copyright 2006 - 2007 Shay Green (c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso (c) Copyright 2004 - 2018 BearOso
Win32 GUI code Win32 GUI code
(c) Copyright 2003 - 2006 blip, (c) Copyright 2003 - 2006 blip,
@ -138,11 +148,16 @@
Matthew Kendora, Matthew Kendora,
Nach, Nach,
nitsuja nitsuja
(c) Copyright 2009 - 2010 OV2 (c) Copyright 2009 - 2018 OV2
Mac OS GUI code Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2011 zones
Libretro port
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
@ -190,29 +205,42 @@
#ifdef ZLIB #ifdef ZLIB
#include <zlib.h> #include <zlib.h>
#define STREAM gzFile #define FSTREAM gzFile
#define READ_STREAM(p, l, s) gzread(s, p, l) #define READ_FSTREAM(p, l, s) gzread(s, p, l)
#define WRITE_STREAM(p, l, s) gzwrite(s, p, l) #define WRITE_FSTREAM(p, l, s) gzwrite(s, p, l)
#define GETS_STREAM(p, l, s) gzgets(s, p, l) #define GETS_FSTREAM(p, l, s) gzgets(s, p, l)
#define GETC_STREAM(s) gzgetc(s) #define GETC_FSTREAM(s) gzgetc(s)
#define OPEN_STREAM(f, m) gzopen(f, m) #define OPEN_FSTREAM(f, m) gzopen(f, m)
#define REOPEN_STREAM(f, m) gzdopen(f, m) #define REOPEN_FSTREAM(f, m) gzdopen(f, m)
#define FIND_STREAM(f) gztell(f) #define FIND_FSTREAM(f) gztell(f)
#define REVERT_STREAM(f, o, s) gzseek(f, o, s) #define REVERT_FSTREAM(s, o, p) gzseek(s, o, p)
#define CLOSE_STREAM(s) gzclose(s) #define CLOSE_FSTREAM(s) gzclose(s)
#else #else
#define STREAM FILE * #define FSTREAM FILE *
#define READ_STREAM(p, l, s) fread(p, 1, l, s) #define READ_FSTREAM(p, l, s) fread(p, 1, l, s)
#define WRITE_STREAM(p, l, s) fwrite(p, 1, l, s) #define WRITE_FSTREAM(p, l, s) fwrite(p, 1, l, s)
#define GETS_STREAM(p, l, s) fgets(p, l, s) #define GETS_FSTREAM(p, l, s) fgets(p, l, s)
#define GETC_STREAM(s) fgetc(s) #define GETC_FSTREAM(s) fgetc(s)
#define OPEN_STREAM(f, m) fopen(f, m) #define OPEN_FSTREAM(f, m) fopen(f, m)
#define REOPEN_STREAM(f, m) fdopen(f, m) #define REOPEN_FSTREAM(f, m) fdopen(f, m)
#define FIND_STREAM(f) ftell(f) #define FIND_FSTREAM(s) ftell(s)
#define REVERT_STREAM(f, o, s) fseek(f, o, s) #define REVERT_FSTREAM(s, o, p) fseek(s, o, p)
#define CLOSE_STREAM(s) fclose(s) #define CLOSE_FSTREAM(s) fclose(s)
#endif #endif
#include "stream.h"
#define STREAM Stream *
#define READ_STREAM(p, l, s) s->read(p,l)
#define WRITE_STREAM(p, l, s) s->write(p,l)
#define GETS_STREAM(p, l, s) s->gets(p,l)
#define GETC_STREAM(s) s->get_char()
#define OPEN_STREAM(f, m) openStreamFromFSTREAM(f, m)
#define REOPEN_STREAM(f, m) reopenStreamFromFd(f, m)
#define FIND_STREAM(s) s->pos()
#define REVERT_STREAM(s, o, p) s->revert(p, o)
#define CLOSE_STREAM(s) s->closeStream()
#define SNES_WIDTH 256 #define SNES_WIDTH 256
#define SNES_HEIGHT 224 #define SNES_HEIGHT 224
#define SNES_HEIGHT_EXTENDED 239 #define SNES_HEIGHT_EXTENDED 239
@ -228,9 +256,15 @@
#define SNES_MAX_PAL_VCOUNTER 312 #define SNES_MAX_PAL_VCOUNTER 312
#define SNES_HCOUNTER_MAX 341 #define SNES_HCOUNTER_MAX 341
#ifndef ALLOW_CPU_OVERCLOCK
#define ONE_CYCLE 6 #define ONE_CYCLE 6
#define SLOW_ONE_CYCLE 8 #define SLOW_ONE_CYCLE 8
#define TWO_CYCLES 12 #define TWO_CYCLES 12
#else
#define ONE_CYCLE (Settings.OneClockCycle)
#define SLOW_ONE_CYCLE (Settings.OneSlowClockCycle)
#define TWO_CYCLES (Settings.TwoClockCycles)
#endif
#define ONE_DOT_CYCLE 4 #define ONE_DOT_CYCLE 4
#define SNES_CYCLES_PER_SCANLINE (SNES_HCOUNTER_MAX * ONE_DOT_CYCLE) #define SNES_CYCLES_PER_SCANLINE (SNES_HCOUNTER_MAX * ONE_DOT_CYCLE)
@ -263,8 +297,6 @@
#define TRACE_FLAG (1 << 1) // debugger #define TRACE_FLAG (1 << 1) // debugger
#define SINGLE_STEP_FLAG (1 << 2) // debugger #define SINGLE_STEP_FLAG (1 << 2) // debugger
#define BREAK_FLAG (1 << 3) // debugger #define BREAK_FLAG (1 << 3) // debugger
#define NMI_FLAG (1 << 7) // CPU
#define IRQ_FLAG (1 << 11) // CPU
#define SCAN_KEYS_FLAG (1 << 4) // CPU #define SCAN_KEYS_FLAG (1 << 4) // CPU
#define HALTED_FLAG (1 << 12) // APU #define HALTED_FLAG (1 << 12) // APU
#define FRAME_ADVANCE_FLAG (1 << 9) #define FRAME_ADVANCE_FLAG (1 << 9)
@ -274,12 +306,16 @@
struct SCPUState struct SCPUState
{ {
uint32 Flags;
int32 Cycles; int32 Cycles;
int32 PrevCycles; int32 PrevCycles;
int32 V_Counter; int32 V_Counter;
uint32 Flags;
uint8 *PCBase; uint8 *PCBase;
bool8 IRQActive; bool8 NMIPending;
bool8 IRQLine;
bool8 IRQTransition;
bool8 IRQLastState;
bool8 IRQExternal;
int32 IRQPending; int32 IRQPending;
int32 MemSpeed; int32 MemSpeed;
int32 MemSpeedx2; int32 MemSpeedx2;
@ -293,9 +329,6 @@ struct SCPUState
uint8 WhichEvent; uint8 WhichEvent;
int32 NextEvent; int32 NextEvent;
bool8 WaitingForInterrupt; bool8 WaitingForInterrupt;
uint32 WaitAddress;
uint32 WaitCounter;
uint32 PBPCAtOpcodeStart;
uint32 AutoSaveTimer; uint32 AutoSaveTimer;
bool8 SRAMModified; bool8 SRAMModified;
}; };
@ -303,17 +336,18 @@ struct SCPUState
enum enum
{ {
HC_HBLANK_START_EVENT = 1, HC_HBLANK_START_EVENT = 1,
HC_IRQ_1_3_EVENT = 2, HC_HDMA_START_EVENT = 2,
HC_HDMA_START_EVENT = 3, HC_HCOUNTER_MAX_EVENT = 3,
HC_IRQ_3_5_EVENT = 4, HC_HDMA_INIT_EVENT = 4,
HC_HCOUNTER_MAX_EVENT = 5, HC_RENDER_EVENT = 5,
HC_IRQ_5_7_EVENT = 6, HC_WRAM_REFRESH_EVENT = 6
HC_HDMA_INIT_EVENT = 7, };
HC_IRQ_7_9_EVENT = 8,
HC_RENDER_EVENT = 9, enum
HC_IRQ_9_A_EVENT = 10, {
HC_WRAM_REFRESH_EVENT = 11, IRQ_NONE = 0,
HC_IRQ_A_1_EVENT = 12 IRQ_SET_FLAG = 1,
IRQ_CLEAR_FLAG = 2
}; };
struct STimings struct STimings
@ -327,12 +361,14 @@ struct STimings
int32 HDMAInit; int32 HDMAInit;
int32 HDMAStart; int32 HDMAStart;
int32 NMITriggerPos; int32 NMITriggerPos;
int32 NextIRQTimer;
int32 IRQTriggerCycles;
int32 WRAMRefreshPos; int32 WRAMRefreshPos;
int32 RenderPos; int32 RenderPos;
bool8 InterlaceField; bool8 InterlaceField;
int32 DMACPUSync; // The cycles to synchronize DMA and CPU. Snes9x cannot emulate correctly. int32 DMACPUSync; // The cycles to synchronize DMA and CPU. Snes9x cannot emulate correctly.
int32 NMIDMADelay; // The delay of NMI trigger after DMA transfers. Snes9x cannot emulate correctly. int32 NMIDMADelay; // The delay of NMI trigger after DMA transfers. Snes9x cannot emulate correctly.
int32 IRQPendCount; // This value is just a hack, because Snes9x cannot emulate any events in an opcode. int32 IRQFlagChanging; // This value is just a hack.
int32 APUSpeedup; int32 APUSpeedup;
bool8 APUAllowTimeOverflow; bool8 APUAllowTimeOverflow;
}; };
@ -345,6 +381,7 @@ struct SSettings
bool8 TraceUnknownRegisters; bool8 TraceUnknownRegisters;
bool8 TraceDSP; bool8 TraceDSP;
bool8 TraceHCEvent; bool8 TraceHCEvent;
bool8 TraceSMP;
bool8 SuperFX; bool8 SuperFX;
uint8 DSP; uint8 DSP;
@ -364,6 +401,7 @@ struct SSettings
bool8 SuperScopeMaster; bool8 SuperScopeMaster;
bool8 JustifierMaster; bool8 JustifierMaster;
bool8 MultiPlayer5Master; bool8 MultiPlayer5Master;
bool8 MacsRifleMaster;
bool8 ForceLoROM; bool8 ForceLoROM;
bool8 ForceHiROM; bool8 ForceHiROM;
@ -400,18 +438,15 @@ struct SSettings
bool8 AutoDisplayMessages; bool8 AutoDisplayMessages;
uint32 InitialInfoStringTimeout; uint32 InitialInfoStringTimeout;
uint16 DisplayColor; uint16 DisplayColor;
bool8 BilinearFilter;
bool8 Multi; bool8 Multi;
char CartAName[PATH_MAX + 1]; char CartAName[PATH_MAX + 1];
char CartBName[PATH_MAX + 1]; char CartBName[PATH_MAX + 1];
bool8 DisableGameSpecificHacks; bool8 DisableGameSpecificHacks;
bool8 ShutdownMaster;
bool8 Shutdown;
bool8 BlockInvalidVRAMAccessMaster; bool8 BlockInvalidVRAMAccessMaster;
bool8 BlockInvalidVRAMAccess; bool8 BlockInvalidVRAMAccess;
bool8 DisableIRQ;
bool8 DisableHDMA;
int32 HDMATimingHack; int32 HDMATimingHack;
bool8 ForcedPause; bool8 ForcedPause;
@ -424,6 +459,7 @@ struct SSettings
bool8 TurboMode; bool8 TurboMode;
uint32 HighSpeedSeek; uint32 HighSpeedSeek;
bool8 FrameAdvance; bool8 FrameAdvance;
bool8 Rewinding;
bool8 NetPlay; bool8 NetPlay;
bool8 NetPlayServer; bool8 NetPlayServer;
@ -439,15 +475,23 @@ struct SSettings
bool8 TakeScreenshot; bool8 TakeScreenshot;
int8 StretchScreenshots; int8 StretchScreenshots;
bool8 SnapshotScreenshots; bool8 SnapshotScreenshots;
char InitialSnapshotFilename[PATH_MAX + 1];
bool8 FastSavestates;
bool8 ApplyCheats; bool8 ApplyCheats;
bool8 NoPatch; bool8 NoPatch;
bool8 IgnorePatchChecksum;
int32 AutoSaveDelay; int32 AutoSaveDelay;
bool8 DontSaveOopsSnapshot; bool8 DontSaveOopsSnapshot;
bool8 UpAndDown; bool8 UpAndDown;
bool8 OpenGLEnable; bool8 OpenGLEnable;
float SuperFXSpeedPerLine;
uint32 SuperFXClockMultiplier;
int OneClockCycle;
int OneSlowClockCycle;
int TwoClockCycles;
int MaxSpriteTilesPerLine;
}; };
struct SSNESGameFixes struct SSNESGameFixes

View File

@ -17,13 +17,20 @@
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja (c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso, (c) Copyright 2009 - 2018 BearOso,
OV2 OV2
(c) Copyright 2017 qwertymodo
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
BS-X C emulator code BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom, (c) Copyright 2005 - 2006 Dreamer Nom,
@ -117,6 +124,9 @@
Sound emulator code used in 1.52+ Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
S-SMP emulator code used in 1.54+
(c) Copyright 2016 byuu
SH assembler code partly based on x86 assembler code SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
@ -130,7 +140,7 @@
(c) Copyright 2006 - 2007 Shay Green (c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso (c) Copyright 2004 - 2018 BearOso
Win32 GUI code Win32 GUI code
(c) Copyright 2003 - 2006 blip, (c) Copyright 2003 - 2006 blip,
@ -138,11 +148,16 @@
Matthew Kendora, Matthew Kendora,
Nach, Nach,
nitsuja nitsuja
(c) Copyright 2009 - 2010 OV2 (c) Copyright 2009 - 2018 OV2
Mac OS GUI code Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2011 zones
Libretro port
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
Daniel De Matteis
(Under no circumstances will commercial rights be given)
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
@ -474,7 +489,6 @@ static uint8 ConvertTile4h_even (uint8 *pCache, uint32 TileAddr, uint32 Tile)
#undef DOBIT #undef DOBIT
// First-level include: Get all the renderers. // First-level include: Get all the renderers.
#include "tile.cpp" #include "tile.cpp"
// Functions to select which converter and renderer to use. // Functions to select which converter and renderer to use.
@ -697,13 +711,11 @@ void S9xSelectTileConverter (int depth, bool8 hires, bool8 sub, bool8 mosaic)
} }
#define IS_BLANK_TILE() \ #define IS_BLANK_TILE() \
(BG.Buffered[TileNumber] == BLANK_TILE) ( ( (Tile & H_FLIP) ? BG.BufferedFlip[TileNumber] : BG.Buffered[TileNumber]) == BLANK_TILE)
#define SELECT_PALETTE() \ #define SELECT_PALETTE() \
if (BG.DirectColourMode) \ if (BG.DirectColourMode) \
{ \ { \
if (IPPU.DirectColourMapsNeedRebuild) \
S9xBuildDirectColourMaps(); \
GFX.RealScreenColors = DirectColourMaps[(Tile >> 10) & 7]; \ GFX.RealScreenColors = DirectColourMaps[(Tile >> 10) & 7]; \
} \ } \
else \ else \
@ -749,6 +761,7 @@ void S9xSelectTileConverter (int depth, bool8 hires, bool8 sub, bool8 mosaic)
if (!(Tile & (V_FLIP | H_FLIP))) \ if (!(Tile & (V_FLIP | H_FLIP))) \
{ \ { \
bp = pCache + BPSTART; \ bp = pCache + BPSTART; \
OFFSET_IN_LINE; \
for (l = LineCount; l > 0; l--, bp += 8 * PITCH, Offset += GFX.PPL) \ for (l = LineCount; l > 0; l--, bp += 8 * PITCH, Offset += GFX.PPL) \
{ \ { \
DRAW_PIXEL(0, Pix = bp[0]); \ DRAW_PIXEL(0, Pix = bp[0]); \
@ -765,6 +778,7 @@ void S9xSelectTileConverter (int depth, bool8 hires, bool8 sub, bool8 mosaic)
if (!(Tile & V_FLIP)) \ if (!(Tile & V_FLIP)) \
{ \ { \
bp = pCache + BPSTART; \ bp = pCache + BPSTART; \
OFFSET_IN_LINE; \
for (l = LineCount; l > 0; l--, bp += 8 * PITCH, Offset += GFX.PPL) \ for (l = LineCount; l > 0; l--, bp += 8 * PITCH, Offset += GFX.PPL) \
{ \ { \
DRAW_PIXEL(0, Pix = bp[7]); \ DRAW_PIXEL(0, Pix = bp[7]); \
@ -781,6 +795,7 @@ void S9xSelectTileConverter (int depth, bool8 hires, bool8 sub, bool8 mosaic)
if (!(Tile & H_FLIP)) \ if (!(Tile & H_FLIP)) \
{ \ { \
bp = pCache + 56 - BPSTART; \ bp = pCache + 56 - BPSTART; \
OFFSET_IN_LINE; \
for (l = LineCount; l > 0; l--, bp -= 8 * PITCH, Offset += GFX.PPL) \ for (l = LineCount; l > 0; l--, bp -= 8 * PITCH, Offset += GFX.PPL) \
{ \ { \
DRAW_PIXEL(0, Pix = bp[0]); \ DRAW_PIXEL(0, Pix = bp[0]); \
@ -796,6 +811,7 @@ void S9xSelectTileConverter (int depth, bool8 hires, bool8 sub, bool8 mosaic)
else \ else \
{ \ { \
bp = pCache + 56 - BPSTART; \ bp = pCache + 56 - BPSTART; \
OFFSET_IN_LINE; \
for (l = LineCount; l > 0; l--, bp -= 8 * PITCH, Offset += GFX.PPL) \ for (l = LineCount; l > 0; l--, bp -= 8 * PITCH, Offset += GFX.PPL) \
{ \ { \
DRAW_PIXEL(0, Pix = bp[7]); \ DRAW_PIXEL(0, Pix = bp[7]); \
@ -840,18 +856,19 @@ void S9xSelectTileConverter (int depth, bool8 hires, bool8 sub, bool8 mosaic)
if (!(Tile & (V_FLIP | H_FLIP))) \ if (!(Tile & (V_FLIP | H_FLIP))) \
{ \ { \
bp = pCache + BPSTART; \ bp = pCache + BPSTART; \
OFFSET_IN_LINE; \
for (l = LineCount; l > 0; l--, bp += 8 * PITCH, Offset += GFX.PPL) \ for (l = LineCount; l > 0; l--, bp += 8 * PITCH, Offset += GFX.PPL) \
{ \ { \
w = Width; \ w = Width; \
switch (StartPixel) \ switch (StartPixel) \
{ \ { \
case 0: DRAW_PIXEL(0, Pix = bp[0]); if (!--w) break; \ case 0: DRAW_PIXEL(0, Pix = bp[0]); if (!--w) break; /* Fall through */ \
case 1: DRAW_PIXEL(1, Pix = bp[1]); if (!--w) break; \ case 1: DRAW_PIXEL(1, Pix = bp[1]); if (!--w) break; /* Fall through */ \
case 2: DRAW_PIXEL(2, Pix = bp[2]); if (!--w) break; \ case 2: DRAW_PIXEL(2, Pix = bp[2]); if (!--w) break; /* Fall through */ \
case 3: DRAW_PIXEL(3, Pix = bp[3]); if (!--w) break; \ case 3: DRAW_PIXEL(3, Pix = bp[3]); if (!--w) break; /* Fall through */ \
case 4: DRAW_PIXEL(4, Pix = bp[4]); if (!--w) break; \ case 4: DRAW_PIXEL(4, Pix = bp[4]); if (!--w) break; /* Fall through */ \
case 5: DRAW_PIXEL(5, Pix = bp[5]); if (!--w) break; \ case 5: DRAW_PIXEL(5, Pix = bp[5]); if (!--w) break; /* Fall through */ \
case 6: DRAW_PIXEL(6, Pix = bp[6]); if (!--w) break; \ case 6: DRAW_PIXEL(6, Pix = bp[6]); if (!--w) break; /* Fall through */ \
case 7: DRAW_PIXEL(7, Pix = bp[7]); break; \ case 7: DRAW_PIXEL(7, Pix = bp[7]); break; \
} \ } \
} \ } \
@ -860,18 +877,19 @@ void S9xSelectTileConverter (int depth, bool8 hires, bool8 sub, bool8 mosaic)
if (!(Tile & V_FLIP)) \ if (!(Tile & V_FLIP)) \
{ \ { \
bp = pCache + BPSTART; \ bp = pCache + BPSTART; \
OFFSET_IN_LINE; \
for (l = LineCount; l > 0; l--, bp += 8 * PITCH, Offset += GFX.PPL) \ for (l = LineCount; l > 0; l--, bp += 8 * PITCH, Offset += GFX.PPL) \
{ \ { \
w = Width; \ w = Width; \
switch (StartPixel) \ switch (StartPixel) \
{ \ { \
case 0: DRAW_PIXEL(0, Pix = bp[7]); if (!--w) break; \ case 0: DRAW_PIXEL(0, Pix = bp[7]); if (!--w) break; /* Fall through */ \
case 1: DRAW_PIXEL(1, Pix = bp[6]); if (!--w) break; \ case 1: DRAW_PIXEL(1, Pix = bp[6]); if (!--w) break; /* Fall through */ \
case 2: DRAW_PIXEL(2, Pix = bp[5]); if (!--w) break; \ case 2: DRAW_PIXEL(2, Pix = bp[5]); if (!--w) break; /* Fall through */ \
case 3: DRAW_PIXEL(3, Pix = bp[4]); if (!--w) break; \ case 3: DRAW_PIXEL(3, Pix = bp[4]); if (!--w) break; /* Fall through */ \
case 4: DRAW_PIXEL(4, Pix = bp[3]); if (!--w) break; \ case 4: DRAW_PIXEL(4, Pix = bp[3]); if (!--w) break; /* Fall through */ \
case 5: DRAW_PIXEL(5, Pix = bp[2]); if (!--w) break; \ case 5: DRAW_PIXEL(5, Pix = bp[2]); if (!--w) break; /* Fall through */ \
case 6: DRAW_PIXEL(6, Pix = bp[1]); if (!--w) break; \ case 6: DRAW_PIXEL(6, Pix = bp[1]); if (!--w) break; /* Fall through */ \
case 7: DRAW_PIXEL(7, Pix = bp[0]); break; \ case 7: DRAW_PIXEL(7, Pix = bp[0]); break; \
} \ } \
} \ } \
@ -880,18 +898,19 @@ void S9xSelectTileConverter (int depth, bool8 hires, bool8 sub, bool8 mosaic)
if (!(Tile & H_FLIP)) \ if (!(Tile & H_FLIP)) \
{ \ { \
bp = pCache + 56 - BPSTART; \ bp = pCache + 56 - BPSTART; \
OFFSET_IN_LINE; \
for (l = LineCount; l > 0; l--, bp -= 8 * PITCH, Offset += GFX.PPL) \ for (l = LineCount; l > 0; l--, bp -= 8 * PITCH, Offset += GFX.PPL) \
{ \ { \
w = Width; \ w = Width; \
switch (StartPixel) \ switch (StartPixel) \
{ \ { \
case 0: DRAW_PIXEL(0, Pix = bp[0]); if (!--w) break; \ case 0: DRAW_PIXEL(0, Pix = bp[0]); if (!--w) break; /* Fall through */ \
case 1: DRAW_PIXEL(1, Pix = bp[1]); if (!--w) break; \ case 1: DRAW_PIXEL(1, Pix = bp[1]); if (!--w) break; /* Fall through */ \
case 2: DRAW_PIXEL(2, Pix = bp[2]); if (!--w) break; \ case 2: DRAW_PIXEL(2, Pix = bp[2]); if (!--w) break; /* Fall through */ \
case 3: DRAW_PIXEL(3, Pix = bp[3]); if (!--w) break; \ case 3: DRAW_PIXEL(3, Pix = bp[3]); if (!--w) break; /* Fall through */ \
case 4: DRAW_PIXEL(4, Pix = bp[4]); if (!--w) break; \ case 4: DRAW_PIXEL(4, Pix = bp[4]); if (!--w) break; /* Fall through */ \
case 5: DRAW_PIXEL(5, Pix = bp[5]); if (!--w) break; \ case 5: DRAW_PIXEL(5, Pix = bp[5]); if (!--w) break; /* Fall through */ \
case 6: DRAW_PIXEL(6, Pix = bp[6]); if (!--w) break; \ case 6: DRAW_PIXEL(6, Pix = bp[6]); if (!--w) break; /* Fall through */ \
case 7: DRAW_PIXEL(7, Pix = bp[7]); break; \ case 7: DRAW_PIXEL(7, Pix = bp[7]); break; \
} \ } \
} \ } \
@ -899,18 +918,19 @@ void S9xSelectTileConverter (int depth, bool8 hires, bool8 sub, bool8 mosaic)
else \ else \
{ \ { \
bp = pCache + 56 - BPSTART; \ bp = pCache + 56 - BPSTART; \
OFFSET_IN_LINE; \
for (l = LineCount; l > 0; l--, bp -= 8 * PITCH, Offset += GFX.PPL) \ for (l = LineCount; l > 0; l--, bp -= 8 * PITCH, Offset += GFX.PPL) \
{ \ { \
w = Width; \ w = Width; \
switch (StartPixel) \ switch (StartPixel) \
{ \ { \
case 0: DRAW_PIXEL(0, Pix = bp[7]); if (!--w) break; \ case 0: DRAW_PIXEL(0, Pix = bp[7]); if (!--w) break; /* Fall through */ \
case 1: DRAW_PIXEL(1, Pix = bp[6]); if (!--w) break; \ case 1: DRAW_PIXEL(1, Pix = bp[6]); if (!--w) break; /* Fall through */ \
case 2: DRAW_PIXEL(2, Pix = bp[5]); if (!--w) break; \ case 2: DRAW_PIXEL(2, Pix = bp[5]); if (!--w) break; /* Fall through */ \
case 3: DRAW_PIXEL(3, Pix = bp[4]); if (!--w) break; \ case 3: DRAW_PIXEL(3, Pix = bp[4]); if (!--w) break; /* Fall through */ \
case 4: DRAW_PIXEL(4, Pix = bp[3]); if (!--w) break; \ case 4: DRAW_PIXEL(4, Pix = bp[3]); if (!--w) break; /* Fall through */ \
case 5: DRAW_PIXEL(5, Pix = bp[2]); if (!--w) break; \ case 5: DRAW_PIXEL(5, Pix = bp[2]); if (!--w) break; /* Fall through */ \
case 6: DRAW_PIXEL(6, Pix = bp[1]); if (!--w) break; \ case 6: DRAW_PIXEL(6, Pix = bp[1]); if (!--w) break; /* Fall through */ \
case 7: DRAW_PIXEL(7, Pix = bp[0]); break; \ case 7: DRAW_PIXEL(7, Pix = bp[0]); break; \
} \ } \
} \ } \
@ -955,6 +975,7 @@ void S9xSelectTileConverter (int depth, bool8 hires, bool8 sub, bool8 mosaic)
\ \
if (Pix) \ if (Pix) \
{ \ { \
OFFSET_IN_LINE; \
for (l = LineCount; l > 0; l--, Offset += GFX.PPL) \ for (l = LineCount; l > 0; l--, Offset += GFX.PPL) \
{ \ { \
for (w = Width - 1; w >= 0; w--) \ for (w = Width - 1; w >= 0; w--) \
@ -991,6 +1012,7 @@ void S9xSelectTileConverter (int depth, bool8 hires, bool8 sub, bool8 mosaic)
GFX.RealScreenColors = IPPU.ScreenColors; \ GFX.RealScreenColors = IPPU.ScreenColors; \
GFX.ScreenColors = GFX.ClipColors ? BlackColourMap : GFX.RealScreenColors; \ GFX.ScreenColors = GFX.ClipColors ? BlackColourMap : GFX.RealScreenColors; \
\ \
OFFSET_IN_LINE; \
for (l = GFX.StartY; l <= GFX.EndY; l++, Offset += GFX.PPL) \ for (l = GFX.StartY; l <= GFX.EndY; l++, Offset += GFX.PPL) \
{ \ { \
for (x = Left; x < Right; x++) \ for (x = Left; x < Right; x++) \
@ -1036,8 +1058,6 @@ extern struct SLineMatrixData LineMatrixData[240];
\ \
if (DCMODE) \ if (DCMODE) \
{ \ { \
if (IPPU.DirectColourMapsNeedRebuild) \
S9xBuildDirectColourMaps(); \
GFX.RealScreenColors = DirectColourMaps[0]; \ GFX.RealScreenColors = DirectColourMaps[0]; \
} \ } \
else \ else \
@ -1051,6 +1071,7 @@ extern struct SLineMatrixData LineMatrixData[240];
uint32 Offset = GFX.StartY * GFX.PPL; \ uint32 Offset = GFX.StartY * GFX.PPL; \
struct SLineMatrixData *l = &LineMatrixData[GFX.StartY]; \ struct SLineMatrixData *l = &LineMatrixData[GFX.StartY]; \
\ \
OFFSET_IN_LINE; \
for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Offset += GFX.PPL, l++) \ for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Offset += GFX.PPL, l++) \
{ \ { \
int yy, starty; \ int yy, starty; \
@ -1133,8 +1154,6 @@ extern struct SLineMatrixData LineMatrixData[240];
\ \
if (DCMODE) \ if (DCMODE) \
{ \ { \
if (IPPU.DirectColourMapsNeedRebuild) \
S9xBuildDirectColourMaps(); \
GFX.RealScreenColors = DirectColourMaps[0]; \ GFX.RealScreenColors = DirectColourMaps[0]; \
} \ } \
else \ else \
@ -1166,6 +1185,7 @@ extern struct SLineMatrixData LineMatrixData[240];
uint32 Offset = StartY * GFX.PPL; \ uint32 Offset = StartY * GFX.PPL; \
struct SLineMatrixData *l = &LineMatrixData[StartY]; \ struct SLineMatrixData *l = &LineMatrixData[StartY]; \
\ \
OFFSET_IN_LINE; \
for (uint32 Line = StartY; Line <= GFX.EndY; Line += VMosaic, Offset += VMosaic * GFX.PPL, l += VMosaic) \ for (uint32 Line = StartY; Line <= GFX.EndY; Line += VMosaic, Offset += VMosaic * GFX.PPL, l += VMosaic) \
{ \ { \
if (Line + VMosaic > GFX.EndY) \ if (Line + VMosaic > GFX.EndY) \
@ -1341,6 +1361,7 @@ extern struct SLineMatrixData LineMatrixData[240];
// The 1x1 pixel plotter, for speedhacking modes. // The 1x1 pixel plotter, for speedhacking modes.
#define OFFSET_IN_LINE
#define DRAW_PIXEL(N, M) \ #define DRAW_PIXEL(N, M) \
if (Z1 > GFX.DB[Offset + N] && (M)) \ if (Z1 > GFX.DB[Offset + N] && (M)) \
{ \ { \
@ -1375,6 +1396,7 @@ extern struct SLineMatrixData LineMatrixData[240];
#undef NAME2 #undef NAME2
#undef DRAW_PIXEL #undef DRAW_PIXEL
#undef OFFSET_IN_LINE
// Hires pixel plotter, this combines the main and subscreen pixels as appropriate to render hires or pseudo-hires images. // Hires pixel plotter, this combines the main and subscreen pixels as appropriate to render hires or pseudo-hires images.
// Use it only on the main screen, subscreen should use Normal2x1 instead. // Use it only on the main screen, subscreen should use Normal2x1 instead.
@ -1388,11 +1410,16 @@ extern struct SLineMatrixData LineMatrixData[240];
#define DRAW_PIXEL_H2x1(N, M) \ #define DRAW_PIXEL_H2x1(N, M) \
if (Z1 > GFX.DB[Offset + 2 * N] && (M)) \ if (Z1 > GFX.DB[Offset + 2 * N] && (M)) \
{ \ { \
GFX.S[Offset + 2 * N] = MATH((GFX.ClipColors ? 0 : GFX.SubScreen[Offset + 2 * N]), GFX.RealScreenColors[Pix], GFX.SubZBuffer[Offset + 2 * N]); \
GFX.S[Offset + 2 * N + 1] = MATH(GFX.ScreenColors[Pix], GFX.SubScreen[Offset + 2 * N], GFX.SubZBuffer[Offset + 2 * N]); \ GFX.S[Offset + 2 * N + 1] = MATH(GFX.ScreenColors[Pix], GFX.SubScreen[Offset + 2 * N], GFX.SubZBuffer[Offset + 2 * N]); \
if ((OffsetInLine + 2 * N ) != (SNES_WIDTH - 1) << 1) \
GFX.S[Offset + 2 * N + 2] = MATH((GFX.ClipColors ? 0 : GFX.SubScreen[Offset + 2 * N + 2]), GFX.RealScreenColors[Pix], GFX.SubZBuffer[Offset + 2 * N]); \
if ((OffsetInLine + 2 * N) == 0) \
GFX.S[Offset + 2 * N] = MATH((GFX.ClipColors ? 0 : GFX.SubScreen[Offset + 2 * N]), GFX.RealScreenColors[Pix], GFX.SubZBuffer[Offset + 2 * N]); \
GFX.DB[Offset + 2 * N] = GFX.DB[Offset + 2 * N + 1] = Z2; \ GFX.DB[Offset + 2 * N] = GFX.DB[Offset + 2 * N + 1] = Z2; \
} }
#define OFFSET_IN_LINE \
uint32 OffsetInLine = Offset % GFX.RealPPL;
#define DRAW_PIXEL(N, M) DRAW_PIXEL_H2x1(N, M) #define DRAW_PIXEL(N, M) DRAW_PIXEL_H2x1(N, M)
#define NAME2 Hires #define NAME2 Hires
@ -1402,6 +1429,7 @@ extern struct SLineMatrixData LineMatrixData[240];
#undef NAME2 #undef NAME2
#undef DRAW_PIXEL #undef DRAW_PIXEL
#undef OFFSET_IN_LINE
// Interlace: Only draw every other line, so we'll redefine BPSTART and PITCH to do so. // Interlace: Only draw every other line, so we'll redefine BPSTART and PITCH to do so.
// Otherwise, it's the same as Normal2x1/Hires2x1. // Otherwise, it's the same as Normal2x1/Hires2x1.
@ -1414,6 +1442,7 @@ extern struct SLineMatrixData LineMatrixData[240];
#ifndef NO_INTERLACE #ifndef NO_INTERLACE
#define OFFSET_IN_LINE
#define DRAW_PIXEL(N, M) DRAW_PIXEL_N2x1(N, M) #define DRAW_PIXEL(N, M) DRAW_PIXEL_N2x1(N, M)
#define NAME2 Interlace #define NAME2 Interlace
@ -1423,7 +1452,10 @@ extern struct SLineMatrixData LineMatrixData[240];
#undef NAME2 #undef NAME2
#undef DRAW_PIXEL #undef DRAW_PIXEL
#undef OFFSET_IN_LINE
#define OFFSET_IN_LINE \
uint32 OffsetInLine = Offset % GFX.RealPPL;
#define DRAW_PIXEL(N, M) DRAW_PIXEL_H2x1(N, M) #define DRAW_PIXEL(N, M) DRAW_PIXEL_H2x1(N, M)
#define NAME2 HiresInterlace #define NAME2 HiresInterlace
@ -1433,6 +1465,7 @@ extern struct SLineMatrixData LineMatrixData[240];
#undef NAME2 #undef NAME2
#undef DRAW_PIXEL #undef DRAW_PIXEL
#undef OFFSET_IN_LINE
#endif #endif

View File

@ -518,13 +518,7 @@ int main(int argc, char *argv[])
BrowserLoadFile(); BrowserLoadFile();
} }
switch (GCSettings.sfxOverclock) Settings.SuperFXClockMultiplier = GCSettings.superFxSpeed;
{
case 0: Settings.SuperFXSpeedPerLine = 0.417 * 10.5e6; break;
case 1: Settings.SuperFXSpeedPerLine = 0.417 * 40.5e6; break;
case 2: Settings.SuperFXSpeedPerLine = 0.417 * 60.5e6; break;
S9xResetSuperFX();
}
while (1) // main loop while (1) // main loop
{ {

View File

@ -121,7 +121,7 @@ struct SGCSettings{
int language; int language;
int PreviewImage; int PreviewImage;
int sfxOverclock; int superFxSpeed;
}; };
void ExitApp(); void ExitApp();