New save-state (.aws) v2:

Added card save/load for:
. Phasor (#260)
. CP/M (#260)
. 80 column card:
  . aux memory now saved separately from main memory
  . extended memory (RAMworks) (#260)

Mockingboard & Phasor:
. Full AY8910 internal state now preserved.
  . needed for eg. envelope, ay_change[], etc
  . also Phasor player only updates AY regs that have changed

Other:
. On restore error, then PostMessage(WM_USER_RESTART), so that emulator not left in intermediate state
. Fix: Start Dir wasn't set when drag & dropping an image onto a drive icon or double-clicking an image file
This commit is contained in:
tomcw 2015-04-11 22:24:54 +01:00
parent 717c5cba84
commit 498f01edde
18 changed files with 972 additions and 177 deletions

View File

@ -114,12 +114,17 @@ static int rstereopos, rchan1pos, rchan2pos, rchan3pos;
double CAY8910::m_fCurrentCLK_AY8910 = 0.0;
CAY8910::CAY8910() :
// Init the statics that were in sound_ay_overlay()
rng(1),
noise_toggle(0),
env_first(1), env_rev(0), env_counter(15)
void CAY8910::init(void)
{
// Init the statics that were in sound_ay_overlay()
rng = 1;
noise_toggle = 0;
env_first = 1; env_rev = 0; env_counter = 15;
}
CAY8910::CAY8910(void)
{
init();
m_fCurrentCLK_AY8910 = g_fCurrentCLK6502;
};
@ -731,6 +736,8 @@ void CAY8910::sound_ay_reset( void )
{
int f;
init(); // AppleWin:TC
/* recalculate timings based on new machines ay clock */
sound_ay_init();
@ -940,6 +947,157 @@ sound_beeper( int is_tape, int on )
}
#endif
// disable warning C4200: zero-sized array in struct/union
#pragma warning(disable: 4200)
struct SS_AY8910
{
unsigned int ay_tone_tick[3], ay_tone_high[3], ay_noise_tick;
unsigned int ay_tone_subcycles, ay_env_subcycles;
unsigned int ay_env_internal_tick, ay_env_tick;
unsigned int ay_tick_incr;
unsigned int ay_tone_period[3], ay_noise_period, ay_env_period;
BYTE sound_ay_registers[16];
int rng;
int noise_toggle;
int env_first, env_rev, env_counter;
int ay_change_count;
void* ay_change[0]; // real type is ay_change_tag (but this is private)
};
UINT CAY8910::GetSnapshot(const HANDLE hFile)
{
const UINT uAYChangeLength = ay_change_count * sizeof(ay_change_tag);
const UINT uAYTotalLength = sizeof(SS_AY8910) + uAYChangeLength;
if (hFile == NULL)
return uAYTotalLength;
//
SS_AY8910 ay_state;
memcpy(ay_state.ay_tone_tick, ay_tone_tick, sizeof(ay_tone_tick));
memcpy(ay_state.ay_tone_high, ay_tone_high, sizeof(ay_tone_high));
ay_state.ay_noise_tick = ay_noise_tick;
ay_state.ay_tone_subcycles = ay_tone_subcycles;
ay_state.ay_env_subcycles = ay_env_subcycles;
ay_state.ay_env_internal_tick = ay_env_internal_tick;
ay_state.ay_env_tick = ay_env_tick;
ay_state.ay_tick_incr = ay_tick_incr;
memcpy(ay_state.ay_tone_period, ay_tone_period, sizeof(ay_tone_period));
ay_state.ay_noise_period = ay_noise_period;
ay_state.ay_env_period = ay_env_period;
memcpy(ay_state.sound_ay_registers, sound_ay_registers, sizeof(sound_ay_registers));
ay_state.rng = rng;
ay_state.noise_toggle = noise_toggle;
ay_state.env_first = env_first;
ay_state.env_rev = env_rev;
ay_state.env_counter = env_counter;
ay_state.ay_change_count = ay_change_count;
//
DWORD dwBytesWritten;
BOOL bRes = WriteFile( hFile,
&ay_state,
sizeof(SS_AY8910),
&dwBytesWritten,
NULL);
if(!bRes || (dwBytesWritten != sizeof(SS_AY8910)))
{
//dwError = GetLastError();
throw std::string("Save error: AY8910");
}
//
if (uAYChangeLength)
{
DWORD dwBytesWritten2;
BOOL bRes2 = WriteFile( hFile,
ay_change,
uAYChangeLength,
&dwBytesWritten2,
NULL);
if(!bRes2 || (dwBytesWritten2 != uAYChangeLength))
{
//dwError = GetLastError();
throw std::string("Save error: AY8910");
}
}
return uAYTotalLength;
}
UINT CAY8910::SetSnapshot(const HANDLE hFile)
{
SS_AY8910 ay_state;
DWORD dwBytesRead;
BOOL bRes = ReadFile( hFile,
&ay_state,
sizeof(SS_AY8910),
&dwBytesRead,
NULL);
if (dwBytesRead != sizeof(SS_AY8910))
throw std::string("Card: file corrupt");
if (ay_state.ay_change_count > AY_CHANGE_MAX)
throw std::string("Card: file corrupt");
//
memcpy(ay_tone_tick, ay_state.ay_tone_tick, sizeof(ay_tone_tick));
memcpy(ay_tone_high, ay_state.ay_tone_high, sizeof(ay_tone_high));
ay_noise_tick = ay_state.ay_noise_tick;
ay_tone_subcycles = ay_state.ay_tone_subcycles;
ay_env_subcycles = ay_state.ay_env_subcycles;
ay_env_internal_tick = ay_state.ay_env_internal_tick;
ay_env_tick = ay_state.ay_env_tick;
ay_tick_incr = ay_state.ay_tick_incr;
memcpy(ay_tone_period, ay_state.ay_tone_period, sizeof(ay_tone_period));
ay_noise_period = ay_state.ay_noise_period;
ay_env_period = ay_state.ay_env_period;
memcpy(sound_ay_registers, ay_state.sound_ay_registers, sizeof(sound_ay_registers));
rng = ay_state.rng;
noise_toggle = ay_state.noise_toggle;
env_first = ay_state.env_first;
env_rev = ay_state.env_rev;
env_counter = ay_state.env_counter;
ay_change_count = ay_state.ay_change_count;
//
const UINT uLength = ay_change_count * sizeof(ay_change_tag);
if (uLength)
{
DWORD dwBytesRead2;
BOOL bRes = ReadFile( hFile,
ay_change,
uLength,
&dwBytesRead2,
NULL);
if (dwBytesRead2 != uLength)
throw std::string("Card: file corrupt");
}
return dwBytesRead+uLength;
}
///////////////////////////////////////////////////////////////////////////////
// AY8910 interface
@ -996,8 +1154,24 @@ void AY8910_InitClock(int nClock)
BYTE* AY8910_GetRegsPtr(UINT uChip)
{
if(uChip >= MAX_8910)
if (uChip >= MAX_8910)
return NULL;
return g_AY8910[uChip].GetAYRegsPtr();
}
UINT AY8910_GetSnapshot(const HANDLE hFile, UINT uChip)
{
if (uChip >= MAX_8910)
return 0;
return g_AY8910[uChip].GetSnapshot(hFile);
}
UINT AY8910_SetSnapshot(const HANDLE hFile, UINT uChip)
{
if (uChip >= MAX_8910)
return 0;
return g_AY8910[uChip].SetSnapshot(hFile);
}

View File

@ -17,6 +17,9 @@ BYTE* AY8910_GetRegsPtr(UINT uChip);
void AY8910UpdateSetCycles();
UINT AY8910_GetSnapshot(const HANDLE hFile, UINT uChip);
UINT AY8910_SetSnapshot(const HANDLE hFile, UINT uChip);
//-------------------------------------
// FUSE stuff
@ -43,8 +46,12 @@ public:
void sound_frame( void );
BYTE* GetAYRegsPtr( void ) { return &sound_ay_registers[0]; }
static void SetCLK( double CLK ) { m_fCurrentCLK_AY8910 = CLK; }
void ClearAYChangeCount( void ) { ay_change_count = 0; }
UINT GetSnapshot(const HANDLE hFile);
UINT SetSnapshot(const HANDLE hFile);
private:
void init( void );
void sound_end( void );
void sound_ay_overlay( void );

View File

@ -494,11 +494,6 @@ void LoadConfiguration(void)
if(REGLOAD(TEXT(REGVALUE_SLOT5), &dwTmp))
g_Slot5 = (SS_CARDTYPE) dwTmp;
if (g_Slot4 == CT_MockingboardC || g_Slot4 == CT_Phasor)
MB_SetSoundcardType(g_Slot4);
else
MB_SetSoundcardType(CT_Empty);
//
char szFilename[MAX_PATH] = {0};

View File

@ -15,6 +15,7 @@ public:
m_bEnableHDD = HD_CardIsEnabled();
m_bEnableTheFreezesF8Rom = bEnableTheFreezesF8Rom;
memset(&m_Slot, 0, sizeof(m_Slot));
m_SlotAux = CT_Empty;
m_Slot[4] = g_Slot4;
m_Slot[5] = g_Slot5;
}
@ -47,6 +48,7 @@ public:
eApple2Type m_Apple2Type;
SS_CARDTYPE m_Slot[NUM_SLOTS]; // 0..7
SS_CARDTYPE m_SlotAux;
BOOL m_bEnhanceDisk;
bool m_bEnableHDD;
UINT m_bEnableTheFreezesF8Rom;

View File

@ -2434,7 +2434,7 @@ void DrawMemory ( int line, int iMemDump )
DEVICE_e eDevice = pMD->eDevice;
MemoryView_e iView = pMD->eView;
SS_CARD_MOCKINGBOARD SS_MB;
SS_CARD_MOCKINGBOARD_v1 SS_MB;
if ((eDevice == DEV_SY6522) || (eDevice == DEV_AY8910))
MB_GetSnapshot_v1(&SS_MB, 4+(nAddr>>1)); // Slot4 or Slot5

View File

@ -117,6 +117,7 @@ static bool IsDriveValid( const int iDrive );
static void ReadTrack (int drive);
static void RemoveDisk (int drive);
static void WriteTrack (int drive);
static LPCTSTR DiskGetFullPathName(const int iDrive);
//===========================================================================
@ -195,6 +196,17 @@ void Disk_SaveLastDiskImage(const int iDrive)
RegSaveString(TEXT(REG_PREFS), REGVALUE_PREF_LAST_DISK_1, TRUE, pFileName);
else
RegSaveString(TEXT(REG_PREFS), REGVALUE_PREF_LAST_DISK_2, TRUE, pFileName);
//
char szPathName[MAX_PATH];
strcpy(szPathName, DiskGetFullPathName(iDrive));
if (_tcsrchr(szPathName, TEXT('\\')))
{
char* pPathEnd = _tcsrchr(szPathName, TEXT('\\'))+1;
*pPathEnd = 0;
RegSaveString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_START_DIR), 1, szPathName);
}
}
//===========================================================================
@ -847,9 +859,6 @@ static bool DiskSelectImage(const int iDrive, LPCSTR pszFilename)
ImageError_e Error = DiskInsert(iDrive, filename, ofn.Flags & OFN_READONLY, IMAGE_CREATE);
if (Error == eIMAGE_ERROR_NONE)
{
filename[ofn.nFileOffset] = 0;
if (_tcsicmp(directory, filename))
RegSaveString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_START_DIR), 1, filename);
bRes = true;
}
else

View File

@ -218,6 +218,17 @@ static void HD_SaveLastDiskImage(const int iDrive)
RegSaveString(TEXT(REG_PREFS), REGVALUE_PREF_LAST_HARDDISK_1, TRUE, pFileName);
else
RegSaveString(TEXT(REG_PREFS), REGVALUE_PREF_LAST_HARDDISK_2, TRUE, pFileName);
//
char szPathName[MAX_PATH];
strcpy(szPathName, HD_GetFullPathName(iDrive));
if (_tcsrchr(szPathName, TEXT('\\')))
{
char* pPathEnd = _tcsrchr(szPathName, TEXT('\\'))+1;
*pPathEnd = 0;
RegSaveString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_HDV_START_DIR), 1, szPathName);
}
}
//===========================================================================
@ -407,9 +418,6 @@ static bool HD_SelectImage(const int iDrive, LPCSTR pszFilename)
if (HD_Insert(iDrive, filename))
{
filename[ofn.nFileOffset] = 0;
if (_tcsicmp(directory, filename))
RegSaveString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_HDV_START_DIR), 1, filename);
bRes = true;
}
else

View File

@ -170,7 +170,7 @@ iofunction IORead[256];
iofunction IOWrite[256];
static LPVOID SlotParameters[NUM_SLOTS];
static BOOL lastwriteram = 0;
static BOOL lastwriteram = 0; // NB. redundant - only used in MemSetPaging(), where it's forced to 1
LPBYTE mem = NULL;
@ -194,7 +194,8 @@ static BOOL Pravets8charmode = 0;
static CNoSlotClock g_NoSlotClock;
#ifdef RAMWORKS
UINT g_uMaxExPages = 1; // user requested ram pages
UINT g_uMaxExPages = 1; // user requested ram pages
UINT g_uActiveBank = 0; // 0 = memaux
static LPBYTE RWpages[128]; // pointers to RW memory banks
#endif
@ -694,11 +695,6 @@ static void InitIoHandlers()
//
IO_SELECT = 0;
IO_SELECT_InternalROM = 0;
g_eExpansionRomType = eExpRomNull;
g_uPeripheralRomSlot = 0;
for (i=0; i<NUM_SLOTS; i++)
{
g_SlotInfo[i].bHasCard = false;
@ -1028,6 +1024,7 @@ static LPBYTE MemGetPtrBANK1(const WORD offset, const LPBYTE pMemBase)
if ((offset & 0xF000) != 0xC000) // Requesting RAM at physical addr $Cxxx (ie. 4K RAM BANK1)
return NULL;
// fixme: Need to extend for RAMWORKS / RWpages (when pMemBase == memaux)
const BYTE bank1page = (offset >> 8) & 0xF;
return (memshadow[0xD0+bank1page] == pMemBase+(0xC0+bank1page)*256)
? mem+offset+0x1000 // Return ptr to $Dxxx address - 'mem' has (a potentially dirty) 4K RAM BANK1 mapped in at $D000
@ -1146,7 +1143,9 @@ void MemInitialize()
#ifdef RAMWORKS
// allocate memory for RAMWorks III - up to 8MB
RWpages[0] = memaux;
g_uActiveBank = 0;
RWpages[g_uActiveBank] = memaux;
UINT i = 1;
while ((i < g_uMaxExPages) && (RWpages[i] = (LPBYTE) VirtualAlloc(NULL,_6502_MEM_END+1,MEM_COMMIT,PAGE_READWRITE)))
i++;
@ -1340,9 +1339,16 @@ void MemReset()
// INITIALIZE THE RAM IMAGES
ZeroMemory(memaux ,0x10000);
ZeroMemory(memmain,0x10000);
// Init the I/O ROM vars
IO_SELECT = 0;
IO_SELECT_InternalROM = 0;
g_eExpansionRomType = eExpRomNull;
g_uPeripheralRomSlot = 0;
//
int iByte;
// Memory is pseudo-initialized across various models of Apple ][ //e //c
@ -1453,7 +1459,7 @@ void MemReset()
// - "BeachParty-PoacherWars-DaytonDinger-BombsAway.dsk"
// - "Dung Beetles, Ms. PacMan, Pooyan, Star Cruiser, Star Thief, Invas. Force.dsk"
memmain[ 0x620B ] = 0x0;
// https://github.com/AppleWin/AppleWin/issues/222
// MIP_PAGE_ADDRESS_LOW
// "Copy II+ v5.0.dsk"
@ -1474,7 +1480,7 @@ void MemReset()
CpuInitialize();
//Sets Caps Lock = false (Pravets 8A/C only)
z80_reset();
z80_reset(); // NB. Also called above in CpuInitialize()
}
//===========================================================================
@ -1589,7 +1595,8 @@ BYTE __stdcall MemSetPaging(WORD programcounter, WORD address, BYTE write, BYTE
case 0x73: // Ramworks III set aux page number
if ((value < g_uMaxExPages) && RWpages[value])
{
memaux = RWpages[value];
g_uActiveBank = value;
memaux = RWpages[g_uActiveBank];
UpdatePaging(0); // Initialize=0
}
break;
@ -1679,7 +1686,7 @@ void MemSetSnapshot_v1(const DWORD MemMode, const BOOL LastWriteRam, const BYTE*
//
modechanging = 0;
// NB. MemUpdatePaging(TRUE) called at end of Snapshot_LoadState_v1()
UpdatePaging(1); // Initialize=1
}
@ -1689,11 +1696,14 @@ void MemGetSnapshot(SS_BaseMemory_v2& Memory)
{
Memory.dwMemMode = memmode;
Memory.bLastWriteRam = lastwriteram;
Memory.IO_SELECT = IO_SELECT;
Memory.IO_SELECT_InternalROM = IO_SELECT_InternalROM;
Memory.ExpansionRomType = g_eExpansionRomType;
Memory.PeripheralRomSlot = g_uPeripheralRomSlot;
for(DWORD dwOffset = 0x0000; dwOffset < 0x10000; dwOffset+=0x100)
{
memcpy(Memory.MemMain+dwOffset, MemGetMainPtr((WORD)dwOffset), 0x100);
memcpy(Memory.MemAux+dwOffset, MemGetAuxPtr((WORD)dwOffset), 0x100);
}
}
@ -1701,14 +1711,132 @@ void MemSetSnapshot(const SS_BaseMemory_v2& Memory)
{
SetMemMode(Memory.dwMemMode);
lastwriteram = Memory.bLastWriteRam;
IO_SELECT = Memory.IO_SELECT;
IO_SELECT_InternalROM = Memory.IO_SELECT_InternalROM;
g_eExpansionRomType = (eExpansionRomType) Memory.ExpansionRomType;
g_uPeripheralRomSlot = Memory.PeripheralRomSlot;
memcpy(memmain, Memory.MemMain, nMemMainSize);
memcpy(memaux, Memory.MemAux, nMemAuxSize);
memset(memdirty, 0, 0x100);
//
modechanging = 0;
UpdatePaging(1); // Initialize=1
// NB. MemUpdatePaging(TRUE) called at end of Snapshot_LoadState_v2()
UpdatePaging(1); // Initialize=1 (Still needed, even with call to MemUpdatePaging() - why?)
}
//
// disable warning C4200: zero-sized array in struct/union
#pragma warning(disable: 4200)
struct SS_CARD_80COL_AUX_MEMORY
{
SS_CARD_HDR Hdr;
UINT NumBanks;
UINT ActiveBank;
BYTE MemAux[0];
};
void MemGetSnapshotAux(const HANDLE hFile)
{
if (IS_APPLE2)
{
return; // No Aux slot for AppleII
}
if (IS_APPLE2C)
{
_ASSERT(g_uMaxExPages == 1);
}
const UINT uSize = sizeof(SS_CARD_80COL_AUX_MEMORY) + g_uMaxExPages*(_6502_MEM_END+1);
SS_CARD_80COL_AUX_MEMORY* const pSS = (SS_CARD_80COL_AUX_MEMORY*) new BYTE [uSize];
pSS->Hdr.UnitHdr.hdr.v2.Length = uSize;
pSS->Hdr.UnitHdr.hdr.v2.Type = UT_Card;
pSS->Hdr.UnitHdr.hdr.v2.Version = 1;
pSS->Hdr.Slot = kSLOT_AUX;
pSS->Hdr.Type = g_uMaxExPages == 0 ? CT_80Col :
g_uMaxExPages == 1 ? CT_Extended80Col :
CT_RamWorksIII;
pSS->ActiveBank = g_uActiveBank;
pSS->NumBanks = g_uMaxExPages;
for(UINT uBank = 1; uBank <= g_uMaxExPages; uBank++)
{
memcpy(pSS->MemAux+(uBank-1)*(_6502_MEM_END+1), MemGetBankPtr(uBank), _6502_MEM_END+1);
}
//
DWORD dwBytesWritten;
BOOL bRes = WriteFile( hFile,
pSS,
pSS->Hdr.UnitHdr.hdr.v2.Length,
&dwBytesWritten,
NULL);
delete [] pSS;
if(!bRes || (dwBytesWritten != uSize))
{
//dwError = GetLastError();
throw std::string("Save error: 80COL_AUX_MEMORY card");
}
}
void MemSetSnapshotAux(const HANDLE hFile)
{
SS_CARD_80COL_AUX_MEMORY Card;
DWORD dwBytesRead;
BOOL bRes = ReadFile( hFile,
&Card,
sizeof(Card),
&dwBytesRead,
NULL);
if (dwBytesRead != sizeof(Card))
throw std::string("Card: file corrupt");
if (Card.Hdr.Slot != kSLOT_AUX)
throw std::string("Card: wrong slot");
if (Card.Hdr.UnitHdr.hdr.v2.Version > 1)
throw std::string("Card: wrong version");
if (Card.Hdr.UnitHdr.hdr.v2.Length < sizeof(SS_CARD_80COL_AUX_MEMORY))
throw std::string("Card: unit size mismatch");
g_uActiveBank = Card.ActiveBank;
g_uMaxExPages = Card.NumBanks;
for(UINT uBank = 1; uBank <= g_uMaxExPages; uBank++)
{
LPBYTE pBank = MemGetBankPtr(uBank);
if (!pBank)
{
// todo: alloc
_ASSERT(pBank);
break;
}
bRes = ReadFile( hFile,
pBank,
_6502_MEM_END+1,
&dwBytesRead,
NULL);
if (dwBytesRead != _6502_MEM_END+1)
throw std::string("Card: file corrupt");
}
memaux = RWpages[g_uActiveBank];
// NB. MemUpdatePaging(TRUE) called at end of Snapshot_LoadState_v2()
}

View File

@ -56,6 +56,8 @@ LPVOID MemGetSlotParameters (UINT uSlot);
void MemSetSnapshot_v1(const DWORD MemMode, const BOOL LastWriteRam, const BYTE* const pMemMain, const BYTE* const pMemAux);
void MemGetSnapshot(struct SS_BaseMemory_v2& Memory);
void MemSetSnapshot(const struct SS_BaseMemory_v2& Memory);
void MemGetSnapshotAux(const HANDLE hFile);
void MemSetSnapshotAux(const HANDLE hFile);
BYTE __stdcall IO_Null(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles);

View File

@ -116,14 +116,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#define Phasor_SY6522A_Offset (1<<Phasor_SY6522A_CS)
#define Phasor_SY6522B_Offset (1<<Phasor_SY6522B_CS)
typedef struct
struct SY6522_AY8910
{
SY6522 sy6522;
BYTE nAY8910Number;
BYTE nAYCurrentRegister;
BYTE nTimerStatus;
SSI263A SpeechChip;
} SY6522_AY8910;
};
// IFR & IER:
@ -178,6 +178,7 @@ static bool g_bMBAvailable = false;
static SS_CARDTYPE g_SoundcardType = CT_Empty; // Use CT_Empty to mean: no soundcard
static bool g_bPhasorEnable = false;
static BYTE g_nPhasorMode = 0; // 0=Mockingboard emulation, 1=Phasor native
static UINT g_PhasorClockScaleFactor = 1; // for save-state only
//-------------------------------------
@ -999,6 +1000,13 @@ static DWORD WINAPI SSI263Thread(LPVOID lpParameter)
//-----------------------------------------------------------------------------
// Warning! Data-race!
// . SSI263Thread() can asynchronously set /g_nCurrentActivePhoneme/ to -1
// . I have seen it on a call to Play(0,0,0)
// . eg. could occur between [1] and [2]
// - presumably after Stop(), wait for: g_bStopPhoneme == false OR for g_nCurrentActivePhoneme == -1
// - NB. sample could finish between: if (g_nCurrentActivePhoneme >= 0) and g_bStopPhoneme = true
static void SSI263_Play(unsigned int nPhoneme)
{
#if 1
@ -1013,6 +1021,8 @@ static void SSI263_Play(unsigned int nPhoneme)
g_nCurrentActivePhoneme = nPhoneme;
// [1]
hr = SSI263Voice[g_nCurrentActivePhoneme].lpDSBvoice->SetCurrentPosition(0);
if(FAILED(hr))
return;
@ -1022,6 +1032,8 @@ static void SSI263_Play(unsigned int nPhoneme)
return;
SSI263Voice[g_nCurrentActivePhoneme].bActive = true;
// [2]
#else
HRESULT hr;
bool bPause;
@ -1373,7 +1385,8 @@ void MB_Initialize()
// NB. Called when /g_fCurrentCLK6502/ changes
void MB_Reinitialize()
{
AY8910_InitClock((int)g_fCurrentCLK6502);
AY8910_InitClock((int)g_fCurrentCLK6502); // todo: account for g_PhasorClockScaleFactor?
// NB. Other calls to AY8910_InitClock() use the constant CLK_6502
}
//-----------------------------------------------------------------------------
@ -1405,9 +1418,10 @@ static void ResetState()
//g_bMBAvailable = false;
//g_SoundcardType = CT_Empty;
//g_bPhasorEnable = false;
// g_SoundcardType = CT_Empty; // Don't uncomment, else _ASSERT will fire in MB_Read() after an F2->MB_Reset()
// g_bPhasorEnable = false;
g_nPhasorMode = 0;
g_PhasorClockScaleFactor = 1;
}
void MB_Reset()
@ -1555,9 +1569,9 @@ static BYTE __stdcall PhasorIO(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, UL
if(g_nPhasorMode < 2)
g_nPhasorMode = nAddr & 1;
double fCLK = (nAddr & 4) ? CLK_6502*2 : CLK_6502;
g_PhasorClockScaleFactor = (nAddr & 4) ? 2 : 1;
AY8910_InitClock((int)fCLK);
AY8910_InitClock((int)(CLK_6502 * g_PhasorClockScaleFactor));
return MemReadFloatingBus(nCyclesLeft);
}
@ -1764,9 +1778,9 @@ void MB_SetVolume(DWORD dwVolume, DWORD dwVolumeMax)
//===========================================================================
// Called by debugger - Debugger_Display.cpp
void MB_GetSnapshot_v1(SS_CARD_MOCKINGBOARD* const pSS, const DWORD dwSlot)
void MB_GetSnapshot_v1(SS_CARD_MOCKINGBOARD_v1* const pSS, const DWORD dwSlot)
{
pSS->Hdr.UnitHdr.hdr.v2.Length = sizeof(SS_CARD_MOCKINGBOARD);
pSS->Hdr.UnitHdr.hdr.v2.Length = sizeof(SS_CARD_MOCKINGBOARD_v1);
pSS->Hdr.UnitHdr.hdr.v2.Type = UT_Card;
pSS->Hdr.UnitHdr.hdr.v2.Version = 1;
@ -1777,19 +1791,22 @@ void MB_GetSnapshot_v1(SS_CARD_MOCKINGBOARD* const pSS, const DWORD dwSlot)
UINT nDeviceNum = nMbCardNum*2;
SY6522_AY8910* pMB = &g_MB[nDeviceNum];
for(UINT i=0; i<MB_UNITS_PER_CARD; i++)
for(UINT i=0; i<MB_UNITS_PER_CARD_v1; i++)
{
memcpy(&pSS->Unit[i].RegsSY6522, &pMB->sy6522, sizeof(SY6522));
memcpy(&pSS->Unit[i].RegsAY8910, AY8910_GetRegsPtr(nDeviceNum), 16);
memcpy(&pSS->Unit[i].RegsSSI263, &pMB->SpeechChip, sizeof(SSI263A));
pSS->Unit[i].nAYCurrentRegister = pMB->nAYCurrentRegister;
pSS->Unit[i].bTimer1IrqPending = false;
pSS->Unit[i].bTimer2IrqPending = false;
pSS->Unit[i].bSpeechIrqPending = false;
nDeviceNum++;
pMB++;
}
}
int MB_SetSnapshot_v1(const SS_CARD_MOCKINGBOARD* const pSS, const DWORD /*dwSlot*/)
int MB_SetSnapshot_v1(const SS_CARD_MOCKINGBOARD_v1* const pSS, const DWORD /*dwSlot*/)
{
if(pSS->Hdr.UnitHdr.hdr.v1.dwVersion != MAKE_VERSION(1,0,0,0))
return -1;
@ -1801,7 +1818,7 @@ int MB_SetSnapshot_v1(const SS_CARD_MOCKINGBOARD* const pSS, const DWORD /*dwSlo
g_nSSI263Device = 0;
g_nCurrentActivePhoneme = -1;
for(UINT i=0; i<MB_UNITS_PER_CARD; i++)
for(UINT i=0; i<MB_UNITS_PER_CARD_v1; i++)
{
memcpy(&pMB->sy6522, &pSS->Unit[i].RegsSY6522, sizeof(SY6522));
memcpy(AY8910_GetRegsPtr(nDeviceNum), &pSS->Unit[i].RegsAY8910, 16);
@ -1837,86 +1854,134 @@ int MB_SetSnapshot_v1(const SS_CARD_MOCKINGBOARD* const pSS, const DWORD /*dwSlo
//===========================================================================
static UINT DoWriteFile(const HANDLE hFile, const void* const pData, const UINT Length)
{
DWORD dwBytesWritten;
BOOL bRes = WriteFile( hFile,
pData,
Length,
&dwBytesWritten,
NULL);
if(!bRes || (dwBytesWritten != Length))
{
//dwError = GetLastError();
throw std::string("Card: save error");
}
return dwBytesWritten;
}
static UINT DoReadFile(const HANDLE hFile, void* const pData, const UINT Length)
{
DWORD dwBytesRead;
BOOL bRes = ReadFile( hFile,
pData,
Length,
&dwBytesRead,
NULL);
if (dwBytesRead != Length)
throw std::string("Card: file corrupt");
return dwBytesRead;
}
//===========================================================================
struct Mockingboard_Unit
{
SY6522 RegsSY6522;
SSI263A RegsSSI263;
BYTE AYCurrentRegister;
bool bTimer1IrqPending;
bool bTimer2IrqPending;
bool bSpeechIrqPending;
// SS_AY8910 AY8910; // Internal state of AY8910
};
const UINT NUM_MB_UNITS = 2;
struct SS_CARD_MOCKINGBOARD
{
SS_CARD_HDR Hdr;
Mockingboard_Unit Unit[NUM_MB_UNITS];
};
void MB_GetSnapshot(const HANDLE hFile, const UINT uSlot)
{
SS_CARD_MOCKINGBOARD CardMockingboardC;
SS_CARD_MOCKINGBOARD Card;
SS_CARD_MOCKINGBOARD* const pSS = &CardMockingboardC;
Card.Hdr.UnitHdr.hdr.v2.Length = sizeof(SS_CARD_MOCKINGBOARD);
Card.Hdr.UnitHdr.hdr.v2.Type = UT_Card;
Card.Hdr.UnitHdr.hdr.v2.Version = 1;
pSS->Hdr.UnitHdr.hdr.v2.Length = sizeof(SS_CARD_MOCKINGBOARD);
pSS->Hdr.UnitHdr.hdr.v2.Type = UT_Card;
pSS->Hdr.UnitHdr.hdr.v2.Version = 1;
Card.Hdr.Slot = uSlot; // fixme: object should be just 1 Mockingboard card & it will know its slot
Card.Hdr.Type = CT_MockingboardC;
pSS->Hdr.Slot = uSlot; // fixme: object should be just 1 Mockingboard card & it will know its slot
pSS->Hdr.Type = CT_MockingboardC;
const UINT nMbCardNum = uSlot - SLOT4;
Card.Hdr.UnitHdr.hdr.v2.Length += AY8910_GetSnapshot(NULL, nMbCardNum*2+0);
Card.Hdr.UnitHdr.hdr.v2.Length += AY8910_GetSnapshot(NULL, nMbCardNum*2+1);
UINT uTotalWriteSize = DoWriteFile(hFile, &Card, (UINT)&Card.Unit-(UINT)&Card);
//
UINT nMbCardNum = uSlot - SLOT4;
UINT nDeviceNum = nMbCardNum*2;
SY6522_AY8910* pMB = &g_MB[nDeviceNum];
for(UINT i=0; i<MB_UNITS_PER_CARD; i++)
for(UINT i=0; i<NUM_MB_UNITS; i++)
{
memcpy(&pSS->Unit[i].RegsSY6522, &pMB->sy6522, sizeof(SY6522));
memcpy(&pSS->Unit[i].RegsAY8910, AY8910_GetRegsPtr(nDeviceNum), 16);
memcpy(&pSS->Unit[i].RegsSSI263, &pMB->SpeechChip, sizeof(SSI263A));
pSS->Unit[i].nAYCurrentRegister = pMB->nAYCurrentRegister;
memcpy(&Card.Unit[i].RegsSY6522, &pMB->sy6522, sizeof(SY6522));
memcpy(&Card.Unit[i].RegsSSI263, &pMB->SpeechChip, sizeof(SSI263A));
Card.Unit[i].AYCurrentRegister = pMB->nAYCurrentRegister;
Card.Unit[i].bTimer1IrqPending = false;
Card.Unit[i].bTimer2IrqPending = false;
Card.Unit[i].bSpeechIrqPending = false;
uTotalWriteSize += DoWriteFile(hFile, &Card.Unit[i], sizeof(Card.Unit[0]));
uTotalWriteSize += AY8910_GetSnapshot(hFile, nDeviceNum);
nDeviceNum++;
pMB++;
}
//
DWORD dwBytesWritten;
BOOL bRes = WriteFile( hFile,
&CardMockingboardC,
CardMockingboardC.Hdr.UnitHdr.hdr.v2.Length,
&dwBytesWritten,
NULL);
if(!bRes || (dwBytesWritten != CardMockingboardC.Hdr.UnitHdr.hdr.v2.Length))
{
//dwError = GetLastError();
throw std::string("Save error: Mockingboard");
}
_ASSERT(uTotalWriteSize == Card.Hdr.UnitHdr.hdr.v2.Length);
if (uTotalWriteSize != Card.Hdr.UnitHdr.hdr.v2.Length)
throw std::string("Card: unit size mismatch");
}
void MB_SetSnapshot(const HANDLE hFile)
{
SS_CARD_MOCKINGBOARD CardMockingboardC;
SS_CARD_MOCKINGBOARD Card;
DWORD dwBytesRead;
BOOL bRes = ReadFile( hFile,
&CardMockingboardC,
sizeof(CardMockingboardC),
&dwBytesRead,
NULL);
UINT uTotalReadSize = DoReadFile(hFile, &Card, (UINT)&Card.Unit-(UINT)&Card);
if (dwBytesRead != sizeof(CardMockingboardC))
throw std::string("Card: file corrupt");
if (CardMockingboardC.Hdr.Slot != 4 && CardMockingboardC.Hdr.Slot != 5) // fixme
if (Card.Hdr.Slot != 4 && Card.Hdr.Slot != 5) // fixme
throw std::string("Card: wrong slot");
if (CardMockingboardC.Hdr.UnitHdr.hdr.v2.Version > 1)
if (Card.Hdr.UnitHdr.hdr.v2.Version > 1)
throw std::string("Card: wrong version");
if (CardMockingboardC.Hdr.UnitHdr.hdr.v2.Length != sizeof(SS_CARD_MOCKINGBOARD))
if (Card.Hdr.UnitHdr.hdr.v2.Length <= sizeof(SS_CARD_MOCKINGBOARD))
throw std::string("Card: unit size mismatch");
UINT nMbCardNum = CardMockingboardC.Hdr.Slot - SLOT4;
AY8910UpdateSetCycles();
const UINT nMbCardNum = Card.Hdr.Slot - SLOT4;
UINT nDeviceNum = nMbCardNum*2;
SY6522_AY8910* pMB = &g_MB[nDeviceNum];
g_nSSI263Device = 0;
g_nCurrentActivePhoneme = -1;
for(UINT i=0; i<MB_UNITS_PER_CARD; i++)
for(UINT i=0; i<NUM_MB_UNITS; i++)
{
memcpy(&pMB->sy6522, &CardMockingboardC.Unit[i].RegsSY6522, sizeof(SY6522));
memcpy(AY8910_GetRegsPtr(nDeviceNum), &CardMockingboardC.Unit[i].RegsAY8910, 16);
memcpy(&pMB->SpeechChip, &CardMockingboardC.Unit[i].RegsSSI263, sizeof(SSI263A));
pMB->nAYCurrentRegister = CardMockingboardC.Unit[i].nAYCurrentRegister;
uTotalReadSize += DoReadFile(hFile, &Card.Unit[i], sizeof(Card.Unit[0]));
memcpy(&pMB->sy6522, &Card.Unit[i].RegsSY6522, sizeof(SY6522));
memcpy(&pMB->SpeechChip, &Card.Unit[i].RegsSSI263, sizeof(SSI263A));
pMB->nAYCurrentRegister = Card.Unit[i].AYCurrentRegister;
StartTimer(pMB); // Attempt to start timer
@ -1938,7 +2003,163 @@ void MB_SetSnapshot(const HANDLE hFile)
}
}
uTotalReadSize += AY8910_SetSnapshot(hFile, nDeviceNum);
nDeviceNum++;
pMB++;
}
_ASSERT(uTotalReadSize == Card.Hdr.UnitHdr.hdr.v2.Length);
if (uTotalReadSize != Card.Hdr.UnitHdr.hdr.v2.Length)
throw std::string("Card: unit size mismatch");
AY8910_InitClock((int)CLK_6502);
// Setup in MB_InitializeIO() -> MB_SetSoundcardType()
g_SoundcardType = CT_Empty;
g_bPhasorEnable = false;
}
//===========================================================================
struct Phasor_Unit
{
SY6522 RegsSY6522;
SSI263A RegsSSI263;
BYTE AYCurrentRegister;
bool bTimer1IrqPending;
bool bTimer2IrqPending;
bool bSpeechIrqPending;
// SS_AY8910 AY8910[2]; // Internal state of AY8910
};
const UINT NUM_PHASOR_UNITS = 2;
struct SS_CARD_PHASOR
{
SS_CARD_HDR Hdr;
UINT ClockScaleFactor;
UINT Mode;
Phasor_Unit Unit[NUM_PHASOR_UNITS];
};
void Phasor_GetSnapshot(const HANDLE hFile)
{
SS_CARD_PHASOR Card;
Card.Hdr.UnitHdr.hdr.v2.Length = sizeof(SS_CARD_PHASOR);
Card.Hdr.UnitHdr.hdr.v2.Type = UT_Card;
Card.Hdr.UnitHdr.hdr.v2.Version = 1;
const UINT uSlot = 4; // fixme
Card.Hdr.Slot = uSlot; // fixme: object should just be Phasor card & it will know its slot
Card.Hdr.Type = CT_Phasor;
Card.ClockScaleFactor = g_PhasorClockScaleFactor;
Card.Mode = g_nPhasorMode;
for (UINT i=0; i<4; i++)
Card.Hdr.UnitHdr.hdr.v2.Length += AY8910_GetSnapshot(NULL, i);
UINT uTotalWriteSize = DoWriteFile(hFile, &Card, (UINT)&Card.Unit-(UINT)&Card);
//
UINT nDeviceNum = 0;
SY6522_AY8910* pMB = &g_MB[0]; // fixme: Phasor uses MB's slot4(2x6522), slot4(2xSSI263), but slot4+5(4xAY8910)
for(UINT i=0; i<NUM_PHASOR_UNITS; i++)
{
memcpy(&Card.Unit[i].RegsSY6522, &pMB->sy6522, sizeof(SY6522));
memcpy(&Card.Unit[i].RegsSSI263, &pMB->SpeechChip, sizeof(SSI263A));
Card.Unit[i].AYCurrentRegister = pMB->nAYCurrentRegister;
Card.Unit[i].bTimer1IrqPending = false;
Card.Unit[i].bTimer2IrqPending = false;
Card.Unit[i].bSpeechIrqPending = false;
uTotalWriteSize += DoWriteFile(hFile, &Card.Unit[i], sizeof(Card.Unit[0]));
uTotalWriteSize += AY8910_GetSnapshot(hFile, nDeviceNum+0);
uTotalWriteSize += AY8910_GetSnapshot(hFile, nDeviceNum+1);
nDeviceNum += 2;
pMB++;
}
_ASSERT(uTotalWriteSize == Card.Hdr.UnitHdr.hdr.v2.Length);
if (uTotalWriteSize != Card.Hdr.UnitHdr.hdr.v2.Length)
throw std::string("Card: unit size mismatch");
}
void Phasor_SetSnapshot(const HANDLE hFile)
{
SS_CARD_PHASOR Card;
UINT uTotalReadSize = DoReadFile(hFile, &Card, (UINT)&Card.Unit-(UINT)&Card);
if (Card.Hdr.Slot != 4) // fixme
throw std::string("Card: wrong slot");
if (Card.Hdr.UnitHdr.hdr.v2.Version > 1)
throw std::string("Card: wrong version");
if (Card.Hdr.UnitHdr.hdr.v2.Length <= sizeof(SS_CARD_PHASOR))
throw std::string("Card: unit size mismatch");
g_PhasorClockScaleFactor = Card.ClockScaleFactor;
g_nPhasorMode = Card.Mode;
AY8910UpdateSetCycles();
UINT nDeviceNum = 0;
SY6522_AY8910* pMB = &g_MB[0];
g_nSSI263Device = 0;
g_nCurrentActivePhoneme = -1;
for(UINT i=0; i<NUM_PHASOR_UNITS; i++)
{
uTotalReadSize += DoReadFile(hFile, &Card.Unit[i], sizeof(Card.Unit[0]));
memcpy(&pMB->sy6522, &Card.Unit[i].RegsSY6522, sizeof(SY6522));
memcpy(&pMB->SpeechChip, &Card.Unit[i].RegsSSI263, sizeof(SSI263A));
pMB->nAYCurrentRegister = Card.Unit[i].AYCurrentRegister;
StartTimer(pMB); // Attempt to start timer
//
// Crude - currently only support a single speech chip
// FIX THIS:
// . Speech chip could be Votrax instead
// . Is this IRQ compatible with Phasor?
if(pMB->SpeechChip.DurationPhonome)
{
g_nSSI263Device = nDeviceNum;
if((pMB->SpeechChip.CurrentMode != MODE_IRQ_DISABLED) && (pMB->sy6522.PCR == 0x0C) && (pMB->sy6522.IER & IxR_PERIPHERAL))
{
pMB->sy6522.IFR |= IxR_PERIPHERAL;
UpdateIFR(pMB);
pMB->SpeechChip.CurrentMode |= 1; // Set SSI263's D7 pin
}
}
//
uTotalReadSize += AY8910_SetSnapshot(hFile, nDeviceNum+0);
uTotalReadSize += AY8910_SetSnapshot(hFile, nDeviceNum+1);
nDeviceNum += 2;
pMB++;
}
_ASSERT(uTotalReadSize == Card.Hdr.UnitHdr.hdr.v2.Length);
if (uTotalReadSize != Card.Hdr.UnitHdr.hdr.v2.Length)
throw std::string("Card: unit size mismatch");
AY8910_InitClock((int)(CLK_6502 * g_PhasorClockScaleFactor));
// Setup in MB_InitializeIO() -> MB_SetSoundcardType()
g_SoundcardType = CT_Empty;
g_bPhasorEnable = false;
}

View File

@ -23,7 +23,10 @@ bool MB_IsActive();
DWORD MB_GetVolume();
void MB_SetVolume(DWORD dwVolume, DWORD dwVolumeMax);
void MB_GetSnapshot_v1(struct SS_CARD_MOCKINGBOARD* const pSS, const DWORD dwSlot); // For debugger
int MB_SetSnapshot_v1(const struct SS_CARD_MOCKINGBOARD* const pSS, const DWORD dwSlot);
void MB_GetSnapshot_v1(struct SS_CARD_MOCKINGBOARD_v1* const pSS, const DWORD dwSlot); // For debugger
int MB_SetSnapshot_v1(const struct SS_CARD_MOCKINGBOARD_v1* const pSS, const DWORD dwSlot);
void MB_GetSnapshot(const HANDLE hFile, const UINT uSlot);
void MB_SetSnapshot(const HANDLE hFile);
void Phasor_GetSnapshot(const HANDLE hFile);
void Phasor_SetSnapshot(const HANDLE hFile);

View File

@ -44,6 +44,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "SerialComms.h"
#include "Speaker.h"
#include "Video.h"
#include "z80emu.h"
#include "Configuration\Config.h"
#include "Configuration\IPropertySheet.h"
@ -211,6 +212,8 @@ static void Snapshot_LoadState_v1() // .aws v1.0.0.1, up to (and including) Appl
MB_ICONEXCLAMATION | MB_SETFOREGROUND);
SetCurrentImageDir(strOldImageDir.c_str());
PostMessage(g_hFrameWindow, WM_USER_RESTART, 0, 0); // Power-cycle VM (undoing all the new state just loaded)
}
delete [] pSS;
@ -270,17 +273,16 @@ static void Snapshot_LoadState_FileHdr(SS_FILE_HDR& Hdr)
static void LoadUnitApple2(DWORD Length, DWORD Version)
{
SS_APPLE2_Unit_v2 Apple2Unit;
if (Version != UNIT_APPLE2_VER)
throw std::string("Apple2: Version mismatch");
if (Length != sizeof(Apple2Unit))
if (Length != sizeof(SS_APPLE2_Unit_v2))
throw std::string("Apple2: Length mismatch");
if (SetFilePointer(m_hFile, -(LONG)sizeof(Apple2Unit.UnitHdr), NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
if (SetFilePointer(m_hFile, -(LONG)sizeof(SS_UNIT_HDR), NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
throw std::string("Apple2: file corrupt");
SS_APPLE2_Unit_v2 Apple2Unit;
DWORD dwBytesRead;
BOOL bRes = ReadFile( m_hFile,
&Apple2Unit,
@ -335,6 +337,21 @@ static void LoadCardHDD(void)
m_ConfigNew.m_bEnableHDD = true;
}
static void LoadCardPhasor(void)
{
Phasor_SetSnapshot(m_hFile);
}
static void LoadCardZ80(void)
{
Z80_SetSnapshot(m_hFile);
}
static void LoadCard80ColAuxMem(void)
{
MemSetSnapshotAux(m_hFile);
}
//===
static void LoadUnitCard(DWORD Length, DWORD Version)
@ -391,10 +408,15 @@ static void LoadUnitCard(DWORD Length, DWORD Version)
LoadCardMouseInterface();
break;
case CT_Z80:
throw std::string("Card: todo");
LoadCardZ80();
break;
case CT_Phasor:
throw std::string("Card: todo");
LoadCardPhasor();
break;
case CT_80Col:
case CT_Extended80Col:
case CT_RamWorksIII:
LoadCard80ColAuxMem();
break;
default:
//throw std::string("Card: unsupported");
@ -404,7 +426,12 @@ static void LoadUnitCard(DWORD Length, DWORD Version)
}
if (bIsCardSupported)
m_ConfigNew.m_Slot[Card.Slot] = (SS_CARDTYPE) Card.Type;
{
if (Card.Slot <= 7)
m_ConfigNew.m_Slot[Card.Slot] = (SS_CARDTYPE) Card.Type;
else
m_ConfigNew.m_SlotAux = (SS_CARDTYPE) Card.Type;
}
}
static void LoadUnitConfig(DWORD Length, DWORD Version)
@ -432,7 +459,6 @@ static void LoadUnitConfig(DWORD Length, DWORD Version)
// todo:
//m_ConfigNew.m_bEnhanceDisk;
//m_ConfigNew.m_bEnableHDD;
}
static void Snapshot_LoadState_v2(DWORD dwVersion)
@ -447,14 +473,18 @@ static void Snapshot_LoadState_v2(DWORD dwVersion)
ConfigOld.m_Slot[2] = CT_SSC; // fixme
ConfigOld.m_Slot[6] = CT_Disk2; // fixme
ConfigOld.m_Slot[7] = ConfigOld.m_bEnableHDD ? CT_GenericHDD : CT_Empty; // fixme
//ConfigOld.m_SlotAux = ?; // fixme
for (UINT i=0; i<NUM_SLOTS; i++)
m_ConfigNew.m_Slot[i] = CT_Empty;
m_ConfigNew.m_SlotAux = CT_Empty;
MemReset();
// fixme: Apple type may change - assume ths can be removed?
if (!IS_APPLE2)
MemResetPaging();
// fixme-end
DiskReset();
KeybReset();
@ -520,6 +550,8 @@ static void Snapshot_LoadState_v2(DWORD dwVersion)
szMessage.c_str(),
TEXT("Load State"),
MB_ICONEXCLAMATION | MB_SETFOREGROUND);
PostMessage(g_hFrameWindow, WM_USER_RESTART, 0, 0); // Power-cycle VM (undoing all the new state just loaded)
}
CloseHandle(m_hFile);
@ -575,19 +607,19 @@ void Snapshot_SaveState()
//
APPLEWIN_SNAPSHOT_v2 AppleSnapshotv2;
APPLEWIN_SNAPSHOT_v2 AppleSnapshot;
AppleSnapshotv2.Hdr.dwTag = AW_SS_TAG;
AppleSnapshotv2.Hdr.dwVersion = MAKE_VERSION(2,0,0,0);
AppleSnapshotv2.Hdr.dwChecksum = 0; // TO DO
AppleSnapshot.Hdr.dwTag = AW_SS_TAG;
AppleSnapshot.Hdr.dwVersion = MAKE_VERSION(2,0,0,0);
AppleSnapshot.Hdr.dwChecksum = 0; // TO DO
SS_APPLE2_Unit_v2& Apple2Unit = AppleSnapshotv2.Apple2Unit;
SS_APPLE2_Unit_v2& Apple2Unit = AppleSnapshot.Apple2Unit;
//
// Apple2 unit
//
Apple2Unit.UnitHdr.hdr.v2.Length = sizeof(SS_APPLE2_Unit_v2);
Apple2Unit.UnitHdr.hdr.v2.Length = sizeof(Apple2Unit);
Apple2Unit.UnitHdr.hdr.v2.Type = UT_Apple2;
Apple2Unit.UnitHdr.hdr.v2.Version = UNIT_APPLE2_VER;
@ -602,12 +634,12 @@ void Snapshot_SaveState()
DWORD dwBytesWritten;
BOOL bRes = WriteFile( m_hFile,
&AppleSnapshotv2,
sizeof(APPLEWIN_SNAPSHOT_v2),
&AppleSnapshot,
sizeof(AppleSnapshot),
&dwBytesWritten,
NULL);
if(!bRes || (dwBytesWritten != sizeof(APPLEWIN_SNAPSHOT_v2)))
if(!bRes || (dwBytesWritten != sizeof(AppleSnapshot)))
{
//dwError = GetLastError();
throw std::string("Save error");
@ -615,18 +647,29 @@ void Snapshot_SaveState()
//
MemGetSnapshotAux(m_hFile);
Printer_GetSnapshot(m_hFile);
sg_SSC.GetSnapshot(m_hFile);
sg_Mouse.GetSnapshot(m_hFile);
if (g_Slot4 == CT_Z80)
Z80_GetSnapshot(m_hFile, 4);
if (g_Slot5 == CT_Z80)
Z80_GetSnapshot(m_hFile, 5);
if (g_Slot4 == CT_MockingboardC)
MB_GetSnapshot(m_hFile, 4);
if (g_Slot5 == CT_MockingboardC)
MB_GetSnapshot(m_hFile, 5);
if (g_Slot4 == CT_Phasor)
Phasor_GetSnapshot(m_hFile);
DiskGetSnapshot(m_hFile);
HD_GetSnapshot(m_hFile);

View File

@ -46,6 +46,9 @@ enum SS_UNIT_TYPE
const UINT nMemMainSize = 64*1024;
const UINT nMemAuxSize = 64*1024;
const UINT kSLOT_LANG = 0;
const UINT kSLOT_AUX = 8;
struct SS_CARD_HDR
{
SS_UNIT_HDR UnitHdr;
@ -67,6 +70,9 @@ enum SS_CARDTYPE
CT_Phasor, // Soundcard
CT_Echo, // Soundcard
CT_SAM, // Soundcard: Software Automated Mouth
CT_80Col, // 80 column card (no memory)
CT_Extended80Col, // Extended 80-col card (64K)
CT_RamWorksIII, // RamWorksIII (up to 8MB)
};
/////////////////////////////////////////////////////////////////////////////////
@ -75,3 +81,55 @@ struct SS_CARD_EMPTY
{
SS_CARD_HDR Hdr;
};
/////////////////////////////////////////////////////////////////////////////////
struct IWORD
{
union
{
struct
{
BYTE l;
BYTE h;
};
USHORT w;
};
};
struct SY6522
{
BYTE ORB; // $00 - Port B
BYTE ORA; // $01 - Port A (with handshaking)
BYTE DDRB; // $02 - Data Direction Register B
BYTE DDRA; // $03 - Data Direction Register A
//
// $04 - Read counter (L) / Write latch (L)
// $05 - Read / Write & initiate count (H)
// $06 - Read / Write & latch (L)
// $07 - Read / Write & latch (H)
// $08 - Read counter (L) / Write latch (L)
// $09 - Read counter (H) / Write latch (H)
IWORD TIMER1_COUNTER;
IWORD TIMER1_LATCH;
IWORD TIMER2_COUNTER;
IWORD TIMER2_LATCH;
//
BYTE SERIAL_SHIFT; // $0A
BYTE ACR; // $0B - Auxiliary Control Register
BYTE PCR; // $0C - Peripheral Control Register
BYTE IFR; // $0D - Interrupt Flag Register
BYTE IER; // $0E - Interrupt Enable Register
BYTE ORA_NO_HS; // $0F - Port A (without handshaking)
};
struct SSI263A
{
BYTE DurationPhonome;
BYTE Inflection; // I10..I3
BYTE RateInflection;
BYTE CtrlArtAmp;
BYTE FilterFreq;
//
BYTE CurrentMode; // b7:6=Mode; b0=D7 pin (for IRQ)
};

View File

@ -110,57 +110,7 @@ struct SS_CARD_DISK2
/////////////////////////////////////////////////////////////////////////////////
struct IWORD
{
union
{
struct
{
BYTE l;
BYTE h;
};
USHORT w;
};
};
struct SY6522
{
BYTE ORB; // $00 - Port B
BYTE ORA; // $01 - Port A (with handshaking)
BYTE DDRB; // $02 - Data Direction Register B
BYTE DDRA; // $03 - Data Direction Register A
//
// $04 - Read counter (L) / Write latch (L)
// $05 - Read / Write & initiate count (H)
// $06 - Read / Write & latch (L)
// $07 - Read / Write & latch (H)
// $08 - Read counter (L) / Write latch (L)
// $09 - Read counter (H) / Write latch (H)
IWORD TIMER1_COUNTER;
IWORD TIMER1_LATCH;
IWORD TIMER2_COUNTER;
IWORD TIMER2_LATCH;
//
BYTE SERIAL_SHIFT; // $0A
BYTE ACR; // $0B - Auxiliary Control Register
BYTE PCR; // $0C - Peripheral Control Register
BYTE IFR; // $0D - Interrupt Flag Register
BYTE IER; // $0E - Interrupt Enable Register
BYTE ORA_NO_HS; // $0F - Port A (without handshaking)
};
struct SSI263A
{
BYTE DurationPhonome;
BYTE Inflection; // I10..I3
BYTE RateInflection;
BYTE CtrlArtAmp;
BYTE FilterFreq;
//
BYTE CurrentMode; // b7:6=Mode; b0=D7 pin (for IRQ)
};
struct MB_Unit
struct MB_Unit_v1
{
SY6522 RegsSY6522;
BYTE RegsAY8910[16];
@ -171,12 +121,12 @@ struct MB_Unit
bool bSpeechIrqPending;
};
const UINT MB_UNITS_PER_CARD = 2;
const UINT MB_UNITS_PER_CARD_v1 = 2;
struct SS_CARD_MOCKINGBOARD
struct SS_CARD_MOCKINGBOARD_v1
{
SS_CARD_HDR Hdr;
MB_Unit Unit[MB_UNITS_PER_CARD];
MB_Unit_v1 Unit[MB_UNITS_PER_CARD_v1];
};
/////////////////////////////////////////////////////////////////////////////////
@ -185,13 +135,13 @@ struct APPLEWIN_SNAPSHOT_v1
{
SS_FILE_HDR Hdr;
SS_APPLE2_Unit Apple2Unit;
SS_CARD_EMPTY Empty1; // Slot1
SS_CARD_EMPTY Empty2; // Slot2
SS_CARD_EMPTY Empty3; // Slot3
SS_CARD_MOCKINGBOARD Mockingboard1; // Slot4
SS_CARD_MOCKINGBOARD Mockingboard2; // Slot5
SS_CARD_DISK2 Disk2; // Slot6
SS_CARD_EMPTY Empty7; // Slot7
SS_CARD_EMPTY Empty1; // Slot1
SS_CARD_EMPTY Empty2; // Slot2
SS_CARD_EMPTY Empty3; // Slot3
SS_CARD_MOCKINGBOARD_v1 Mockingboard1; // Slot4
SS_CARD_MOCKINGBOARD_v1 Mockingboard2; // Slot5
SS_CARD_DISK2 Disk2; // Slot6
SS_CARD_EMPTY Empty7; // Slot7
};
const UINT kSnapshotSize_v1 = 145400; // Const size for v1
const UINT kSnapshotSize_v1 = 145400; // Const size for v1

View File

@ -46,8 +46,11 @@ struct SS_BaseMemory_v2
{
DWORD dwMemMode;
BOOL bLastWriteRam;
BYTE IO_SELECT;
BYTE IO_SELECT_InternalROM;
UINT ExpansionRomType;
UINT PeripheralRomSlot;
BYTE MemMain[nMemMainSize];
BYTE MemAux[nMemAuxSize];
};
struct SS_APPLE2_Unit_v2
@ -72,7 +75,7 @@ struct APPLEWIN_SNAPSHOT_v2
{
SS_FILE_HDR Hdr;
SS_APPLE2_Unit_v2 Apple2Unit;
// SS_CARD_EMPTY[7] Slots; // Slot 0..7 (0=language card for Apple][)
// SS_CARD_EMPTY[8] Slots; // Slot 0..7 (0=language card for Apple][)
// SS_CARD_EMPTY AuxSlot; // Apple//e auxiliary slot (including optional RAMworks memory)
// SS_APPLEWIN_CONFIG AppleWinCfg;
};

View File

@ -86,16 +86,20 @@ static BYTE reg_f2 = 0;
static BYTE reg_h2 = 0;
static BYTE reg_l2 = 0;
#if 0 // [AppleWin-TC] Not used
static int dma_request = 0;
#endif
static BYTE *z80_bank_base;
static int z80_bank_limit;
#if 0 // [AppleWin-TC] Not used
void z80_trigger_dma(void)
{
dma_request = 1;
}
#endif
void z80_reset(void)
{
@ -162,11 +166,11 @@ void z80_reset(void)
/* ------------------------------------------------------------------------- */
#if 0 // [AppleWin-TC]
static unsigned int z80_last_opcode_info;
#define LAST_OPCODE_INFO z80_last_opcode_info
#if 0 // [AppleWin-TC]
/* Remember the number of the last opcode. By default, the opcode does not
delay interrupt and does not change the I flag. */
#define SET_LAST_OPCODE(x) \
@ -463,6 +467,9 @@ static void export_registers(void)
/* ------------------------------------------------------------------------- */
// [AppleWin-TC] Z80 IRQs not supported
#if 0
/* Interrupt handling. */
#define DO_INTERRUPT(int_kind) \
@ -533,6 +540,7 @@ static void export_registers(void)
} \
} \
} while (0)
#endif
/* ------------------------------------------------------------------------- */
@ -6422,3 +6430,181 @@ void z80_WRMEM(WORD Addr, BYTE Value)
}
CpuWrite( addr, Value, ConvertZ80TStatesTo6502Cycles(maincpu_clk) );
}
//===========================================================================
struct Z80_Unit
{
BYTE reg_a;
BYTE reg_b;
BYTE reg_c;
BYTE reg_d;
BYTE reg_e;
BYTE reg_f;
BYTE reg_h;
BYTE reg_l;
BYTE reg_ixh;
BYTE reg_ixl;
BYTE reg_iyh;
BYTE reg_iyl;
WORD reg_sp;
DWORD z80_reg_pc;
BYTE reg_i;
BYTE reg_r;
BYTE iff1;
BYTE iff2;
BYTE im_mode;
BYTE reg_a2;
BYTE reg_b2;
BYTE reg_c2;
BYTE reg_d2;
BYTE reg_e2;
BYTE reg_f2;
BYTE reg_h2;
BYTE reg_l2;
};
struct SS_CARD_Z80
{
SS_CARD_HDR Hdr;
Z80_Unit Unit;
UINT Active;
};
void Z80_GetSnapshot(const HANDLE hFile, const UINT uZ80Slot)
{
SS_CARD_Z80 Card;
SS_CARD_Z80* const pSS = &Card;
pSS->Hdr.UnitHdr.hdr.v2.Length = sizeof(SS_CARD_Z80);
pSS->Hdr.UnitHdr.hdr.v2.Type = UT_Card;
pSS->Hdr.UnitHdr.hdr.v2.Version = 1;
pSS->Hdr.Slot = uZ80Slot; // fixme: object should know its slot
pSS->Hdr.Type = CT_Z80;
pSS->Unit.reg_a = reg_a;
pSS->Unit.reg_b = reg_b;
pSS->Unit.reg_c = reg_c;
pSS->Unit.reg_d = reg_d;
pSS->Unit.reg_e = reg_e;
pSS->Unit.reg_f = reg_f;
pSS->Unit.reg_h = reg_h;
pSS->Unit.reg_l = reg_l;
pSS->Unit.reg_ixh = reg_ixh;
pSS->Unit.reg_ixl = reg_ixl;
pSS->Unit.reg_iyh = reg_iyh;
pSS->Unit.reg_iyl = reg_iyl;
pSS->Unit.reg_sp = reg_sp;
pSS->Unit.z80_reg_pc = z80_reg_pc;
pSS->Unit.reg_i = reg_i;
pSS->Unit.reg_r = reg_r;
pSS->Unit.iff1 = iff1;
pSS->Unit.iff2 = iff2;
pSS->Unit.im_mode = im_mode;
pSS->Unit.reg_a2 = reg_a2;
pSS->Unit.reg_b2 = reg_b2;
pSS->Unit.reg_c2 = reg_c2;
pSS->Unit.reg_d2 = reg_d2;
pSS->Unit.reg_e2 = reg_e2;
pSS->Unit.reg_f2 = reg_f2;
pSS->Unit.reg_h2 = reg_h2;
pSS->Unit.reg_l2 = reg_l2;
// SoftCard SW & HW details: http://apple2info.net/images/f/f0/SC-SWHW.pdf
// . SoftCard uses the Apple II's DMA circuit to pause the 6502 (no CLK to 6502)
// . But: "In Apple II DMA, the 6502 CPU will die after approximately 15 clocks because it depends on the clock to refresh its internal registers."
// ref: Apple Tech Note: https://archive.org/stream/IIe_2523004_RDY_Line/IIe_2523004_RDY_Line_djvu.txt
// NB. Not for 65C02 which is a static processor.
// . SoftCard controls the 6502's RDY line to periodically allow only 1 memory fetch by 6502 (ie. the opcode fetch)
//
// So save /g_ActiveCPU/ to SS_CARD_Z80 (so RDY is like IRQ & NMI signals, ie. saved struct of the producer's card)
//
// NB. Save-state only occurs when message pump runs:
// . ie. at end of 1ms emulation burst
// Either 6502 or Z80 could be active.
//
pSS->Active = g_ActiveCPU == CPU_Z80 ? 1 : 0;
//
DWORD dwBytesWritten;
BOOL bRes = WriteFile( hFile,
&Card,
Card.Hdr.UnitHdr.hdr.v2.Length,
&dwBytesWritten,
NULL);
if(!bRes || (dwBytesWritten != Card.Hdr.UnitHdr.hdr.v2.Length))
{
//dwError = GetLastError();
throw std::string("Save error: Z80");
}
}
void Z80_SetSnapshot(const HANDLE hFile)
{
SS_CARD_Z80 Card;
DWORD dwBytesRead;
BOOL bRes = ReadFile( hFile,
&Card,
sizeof(Card),
&dwBytesRead,
NULL);
if (dwBytesRead != sizeof(Card))
throw std::string("Card: file corrupt");
if (Card.Hdr.Slot != 4 && Card.Hdr.Slot != 5) // fixme
throw std::string("Card: wrong slot");
if (Card.Hdr.UnitHdr.hdr.v2.Version > 1)
throw std::string("Card: wrong version");
if (Card.Hdr.UnitHdr.hdr.v2.Length != sizeof(SS_CARD_Z80))
throw std::string("Card: unit size mismatch");
SS_CARD_Z80* pSS = &Card;
reg_a = pSS->Unit.reg_a;
reg_b = pSS->Unit.reg_b;
reg_c = pSS->Unit.reg_c;
reg_d = pSS->Unit.reg_d;
reg_e = pSS->Unit.reg_e;
reg_f = pSS->Unit.reg_f;
reg_h = pSS->Unit.reg_h;
reg_l = pSS->Unit.reg_l;
reg_ixh = pSS->Unit.reg_ixh;
reg_ixl = pSS->Unit.reg_ixl;
reg_iyh = pSS->Unit.reg_iyh;
reg_iyl = pSS->Unit.reg_iyl;
reg_sp = pSS->Unit.reg_sp;
z80_reg_pc = pSS->Unit.z80_reg_pc;
reg_i = pSS->Unit.reg_i;
reg_r = pSS->Unit.reg_r;
iff1 = pSS->Unit.iff1;
iff2 = pSS->Unit.iff2;
im_mode = pSS->Unit.im_mode;
reg_a2 = pSS->Unit.reg_a2;
reg_b2 = pSS->Unit.reg_b2;
reg_c2 = pSS->Unit.reg_c2;
reg_d2 = pSS->Unit.reg_d2;
reg_e2 = pSS->Unit.reg_e2;
reg_f2 = pSS->Unit.reg_f2;
reg_h2 = pSS->Unit.reg_h2;
reg_l2 = pSS->Unit.reg_l2;
export_registers();
if (pSS->Active)
g_ActiveCPU = CPU_Z80; // Support MS SoftCard in multiple slots (only one Z80 can be active at any one time)
}

View File

@ -46,6 +46,7 @@ typedef struct z80_regs_s {
WORD reg_hl2;
} z80_regs_t;
#if 0 // [AppleWin-TC]: unused, so comment out
#define Z80_REGS_GET_AF(reg_ptr) ((reg_ptr)->reg_af)
#define Z80_REGS_GET_BC(reg_ptr) ((reg_ptr)->reg_bc)
#define Z80_REGS_GET_DE(reg_ptr) ((reg_ptr)->reg_de)
@ -75,6 +76,7 @@ typedef struct z80_regs_s {
#define Z80_REGS_SET_BC2(reg_ptr, val) ((reg_ptr)->reg_bc2 = (val))
#define Z80_REGS_SET_DE2(reg_ptr, val) ((reg_ptr)->reg_de2 = (val))
#define Z80_REGS_SET_HL2(reg_ptr, val) ((reg_ptr)->reg_hl2 = (val))
#endif
#endif

View File

@ -14,3 +14,7 @@
// Protótipos
void ConfigureSoftcard(LPBYTE pCxRomPeripheral, UINT uSlot);
// NB. These are in z80.cpp:
void Z80_GetSnapshot(const HANDLE hFile, const UINT uZ80Slot);
void Z80_SetSnapshot(const HANDLE hFile);