mirror of
https://github.com/AppleWin/AppleWin.git
synced 2025-02-05 17:30:45 +00:00
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:
parent
717c5cba84
commit
498f01edde
@ -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);
|
||||
}
|
||||
|
@ -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 );
|
||||
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user