psx - straighten out setting of discs when loading savestates, and avoid doing likely desyncing operations in CDC module when loading savestates and setting the appropriate disc. fixes #381

This commit is contained in:
zeromus 2015-02-01 04:55:09 +00:00
parent 62d781b960
commit 91c130a07a
7 changed files with 108 additions and 32 deletions

View File

@ -524,6 +524,20 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
return new System.Drawing.Size(VirtualWidth, VirtualHeight);
}
void PokeDisc()
{
if (CurrentDiscIndexMounted == 0)
{
currentDiscInterface = null;
OctoshockDll.shock_PokeDisc(psx, IntPtr.Zero);
}
else
{
currentDiscInterface = discInterfaces[CurrentDiscIndexMounted - 1];
OctoshockDll.shock_PokeDisc(psx, currentDiscInterface.OctoshockHandle);
}
}
void FrameAdvance_PrepDiscState()
{
//reminder: if this is the beginning of time, we can begin with the disc ejected or inserted.
@ -834,6 +848,7 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
Frame = s.ExtraData.Frame;
CurrentTrayOpen = s.ExtraData.CurrentDiscEjected;
CurrentDiscIndexMounted = s.ExtraData.CurrentDiscIndexMounted;
PokeDisc();
}
byte[] savebuff;
@ -899,8 +914,7 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
Frame = reader.ReadInt32();
CurrentTrayOpen = reader.ReadBoolean();
CurrentDiscIndexMounted = reader.ReadInt32();
//TODO - need a method to sneak the required disc, without having to do a proper eject sequence
PokeDisc();
}
}

View File

@ -211,6 +211,9 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
[DllImport(dd, CallingConvention = cc)]
public static extern int shock_SetDisc(IntPtr psx, IntPtr disc);
[DllImport(dd, CallingConvention = cc)]
public static extern int shock_PokeDisc(IntPtr psx, IntPtr disc);
[DllImport(dd, CallingConvention = cc)]
public static extern int shock_CloseTray(IntPtr psx);

Binary file not shown.

View File

@ -62,6 +62,7 @@ PS_CDC::PS_CDC() : DMABuffer(4096)
{
IsPSXDisc = false;
Cur_disc = NULL;
Open_disc = NULL;
DriveStatus = DS_STOPPED;
PendingCommandPhase = 0;
@ -90,33 +91,58 @@ void PS_CDC::DMForceStop(void)
SectorsRead = 0;
}
void PS_CDC::SetDisc(bool tray_open, ShockDiscRef *disc, const char *disc_id)
void PS_CDC::OpenTray()
{
if(tray_open)
disc = NULL;
//effectively a NOP at t=0
DMForceStop();
Cur_disc = disc;
IsPSXDisc = false;
memset(DiscID, 0, sizeof(DiscID));
//zero 31-jan-2015 - psxtech says that what this is used for is actually a 'was open' flag which gets cleared after the status gets polled.
//so lets set it here, and rename it later if we're sure.
DiscChanged = true;
}
if(!Cur_disc)
{
DMForceStop();
}
else
{
HeaderBufValid = false;
DiscStartupDelay = (int64)1000 * 33868800 / 1000;
DiscChanged = true;
void PS_CDC::CloseTray(bool poke)
{
//switch pending (open) disc to current disc
Cur_disc = Open_disc;
Open_disc = NULL;
char disc_id[5];
strncpy(disc_id,(char*)Open_DiscID,4);
Open_DiscID[0] = 0;
Cur_disc->ReadTOC((ShockTOC*)&toc,(ShockTOCTrack*)toc.tracks);
//prepare analysis if disc: leave in empty state
IsPSXDisc = false;
memset(DiscID, 0, sizeof(DiscID));
if(disc_id)
{
strncpy((char *)DiscID, disc_id, 4);
IsPSXDisc = true;
}
}
//stuff to always happen, even when poking:
if(Cur_disc)
{
Cur_disc->ReadTOC((ShockTOC*)&toc,(ShockTOCTrack*)toc.tracks);
//complete analysis
if(disc_id)
{
strncpy((char *)DiscID, disc_id, 4);
IsPSXDisc = true;
}
}
//stuff to happen when not poking (reset CDC state)
if(Cur_disc && !poke)
{
HeaderBufValid = false;
DiscStartupDelay = (int64)1000 * 33868800 / 1000;
}
}
void PS_CDC::SetDisc(ShockDiscRef *disc, const char *disc_id, bool poke)
{
Open_disc = disc;
strncpy((char*)Open_DiscID,disc_id,4);
if(poke)
CloseTray(true);
}
int32 PS_CDC::CalcNextEvent(void)

View File

@ -26,7 +26,9 @@ class PS_CDC
template<bool isReader>void SyncState(EW::NewState *ns);
void SetDisc(bool tray_open, ShockDiscRef *disc, const char disc_id[4]);
void OpenTray();
void SetDisc(ShockDiscRef *disc, const char disc_id[4], bool poke);
void CloseTray(bool poke);
void Power(void);
void ResetTS(void);
@ -47,6 +49,10 @@ class PS_CDC
private:
CDIF *Cur_CDIF;
ShockDiscRef* Cur_disc;
ShockDiscRef* Open_disc; //the disc that's in the tray, while the tray is open. pending, kind of. used because Cur_disc != NULL is used as a tray-closed marker in the CDC code
uint8 Open_DiscID[4]; //same thing
bool DiscChanged;
int32 DiscStartupDelay;

View File

@ -1285,8 +1285,7 @@ EW_EXPORT s32 shock_Create(void** psx, s32 region, void* firmware512k)
s_ShockState.power = false;
s_ShockState.eject = false;
//set tray closed with no disc
CDC->SetDisc(false,NULL,"");
//do we need to do anything particualr with the CDC disc/tray state? survey says... no.
return SHOCK_OK;
}
@ -1896,15 +1895,41 @@ EW_EXPORT s32 shock_SetDisc(void* psx, ShockDiscRef* disc)
if(ret != SHOCK_OK) return ret;
}
s_CurrDiscInfo = info;
s_CurrDisc = disc;
CDC->SetDisc(s_CurrDisc,s_CurrDiscInfo.id, false);
return SHOCK_OK;
}
EW_EXPORT s32 shock_PokeDisc(void* psx, ShockDiscRef* disc)
{
//TODO HACKS! DONT COPY/PASTE SO MUCH! REFACTOR DISC ID STUFF!
//let's talk about why this function is needed. well, let's paste an old comment on the subject:
//heres a comment from some old savestating code. something to keep in mind (maybe or maybe not a surprise depending on your point of view)
//"Call SetDisc() BEFORE we load CDC state, since SetDisc() has emulation side effects. We might want to clean this up in the future."
//I'm not really sure I like how SetDisc works, so I'm glad this was brought to our attention
//TODO - non-psx disc is legal here. should pass null ID to CDC setdisc
//analyze disc so we dont have to annoyingly manage it from client
//TODO - so junky
ShockDiscInfo info;
strcpy(info.id,"\0\0\0\0");
info.region = REGION_NONE;
if(disc != NULL)
{
s32 ret = shock_AnalyzeDisc(disc,&info);
if(ret != SHOCK_OK) return ret;
}
s_CurrDiscInfo = info;
s_CurrDisc = disc;
//set the disc to the CDC, but since its necessarily open to insert, this is false
CDC->SetDisc(true,s_CurrDisc,s_CurrDiscInfo.id);
CDC->SetDisc(s_CurrDisc,s_CurrDiscInfo.id,true);
return SHOCK_OK;
}
@ -1913,7 +1938,7 @@ EW_EXPORT s32 shock_OpenTray(void* psx)
{
if(s_ShockState.eject) return SHOCK_NOCANDO;
s_ShockState.eject = true;
CDC->SetDisc(true,s_CurrDisc,s_CurrDiscInfo.id);
CDC->OpenTray();
return SHOCK_OK;
}
@ -1921,7 +1946,7 @@ EW_EXPORT s32 shock_CloseTray(void* psx)
{
if(!s_ShockState.eject) return SHOCK_NOCANDO;
s_ShockState.eject = false;
CDC->SetDisc(false,s_CurrDisc,s_CurrDiscInfo.id);
CDC->CloseTray(false);
return SHOCK_OK;
}
@ -2106,7 +2131,6 @@ static s32 AnalyzeDiscEx(ShockDiscRef* disc, ShockDiscInfo* info)
uint8 buf[2048];
uint8 fbuf[2048 + 1];
unsigned ipos, opos;
int i;
//clear it out in case of error
info->region = REGION_NONE;

View File

@ -343,6 +343,9 @@ EW_EXPORT s32 shock_OpenTray(void* psx);
//Sets the disc in the tray. Returns SHOCK_NOCANDO if it's closed. You can pass NULL to remove a disc from the tray
EW_EXPORT s32 shock_SetDisc(void* psx, ShockDiscRef* disc);
//POKES the disc in the tray, for use after loading a state. Does not affect any of the internal emulation parameters
EW_EXPORT s32 shock_PokeDisc(void* psx, ShockDiscRef* disc);
//Closes the disc tray. Returns SHOCK_NOCANDO if already closed.
EW_EXPORT s32 shock_CloseTray(void* psx);