diff --git a/AppleWinExpress2013.vcxproj b/AppleWinExpress2013.vcxproj index 95b86697..6d0c6dba 100644 --- a/AppleWinExpress2013.vcxproj +++ b/AppleWinExpress2013.vcxproj @@ -76,16 +76,19 @@ + + + + - @@ -97,6 +100,7 @@ + @@ -107,7 +111,7 @@ - + @@ -126,6 +130,7 @@ + @@ -152,6 +157,7 @@ + @@ -191,6 +197,7 @@ NotUsing + NotUsing @@ -237,6 +244,9 @@ {9b32a6e7-1237-4f36-8903-a3fd51df9c4e} + + {0212e0df-06da-4080-bd1d-f3b01599f70f} + @@ -343,9 +353,9 @@ Use Level3 Disabled - WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;%(PreprocessorDefinitions) + WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;YAML_DECLARE_STATIC;%(PreprocessorDefinitions) true - source\cpu;source\emulator;source\debugger;zlib;zip_lib;%(AdditionalIncludeDirectories) + source\cpu;source\emulator;source\debugger;zlib;zip_lib;libyaml\include;%(AdditionalIncludeDirectories) MultiThreadedDebug @@ -354,15 +364,22 @@ htmlhelp.lib;comctl32.lib;ddraw.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;Advapi32.lib;shell32.lib;Comdlg32.lib;ole32.lib;wsock32.lib;%(AdditionalDependencies) "type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df' language='*'" + + echo Performing unit-test: TestCPU6502 +.\Debug\TestCPU6502.exe + + + Performing unit-test: TestCPU6502 + Use Level3 Disabled - WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;NO_DIRECT_X;%(PreprocessorDefinitions) + WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;NO_DIRECT_X;YAML_DECLARE_STATIC;%(PreprocessorDefinitions) true - source\cpu;source\emulator;source\debugger;zlib;zip_lib;%(AdditionalIncludeDirectories) + source\cpu;source\emulator;source\debugger;zlib;zip_lib;libyaml\include;%(AdditionalIncludeDirectories) MultiThreadedDebug @@ -371,6 +388,13 @@ htmlhelp.lib;comctl32.lib;ddraw.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;Advapi32.lib;shell32.lib;Comdlg32.lib;ole32.lib;wsock32.lib;%(AdditionalDependencies) "type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df' language='*'" + + echo Performing unit-test: TestCPU6502 +.\Debug\TestCPU6502.exe + + + Performing unit-test: TestCPU6502 + @@ -379,9 +403,9 @@ MaxSpeed true true - WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;%(PreprocessorDefinitions) + WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;YAML_DECLARE_STATIC;%(PreprocessorDefinitions) true - source\cpu;source\emulator;source\debugger;zlib;zip_lib;%(AdditionalIncludeDirectories) + source\cpu;source\emulator;source\debugger;zlib;zip_lib;libyaml\include;%(AdditionalIncludeDirectories) MultiThreaded Speed @@ -394,6 +418,13 @@ UseLinkTimeCodeGeneration "type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df' language='*'" + + echo Performing unit-test: TestCPU6502 +.\Release\TestCPU6502.exe + + + Performing unit-test: TestCPU6502 + @@ -402,9 +433,9 @@ MaxSpeed true true - WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;NO_DIRECT_X;%(PreprocessorDefinitions) + WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;NO_DIRECT_X;YAML_DECLARE_STATIC;%(PreprocessorDefinitions) true - source\cpu;source\emulator;source\debugger;zlib;zip_lib;%(AdditionalIncludeDirectories) + source\cpu;source\emulator;source\debugger;zlib;zip_lib;libyaml\include;%(AdditionalIncludeDirectories) MultiThreaded Speed @@ -417,6 +448,13 @@ UseLinkTimeCodeGeneration "type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df' language='*'" + + echo Performing unit-test: TestCPU6502 +.\Release\TestCPU6502.exe + + + Performing unit-test: TestCPU6502 + diff --git a/AppleWinExpress2013.vcxproj.filters b/AppleWinExpress2013.vcxproj.filters index 6b8315a3..c9b778eb 100644 --- a/AppleWinExpress2013.vcxproj.filters +++ b/AppleWinExpress2013.vcxproj.filters @@ -172,6 +172,15 @@ Source Files\Video + + Source Files\Model + + + Source Files\Emulator + + + Source Files\Emulator + @@ -372,9 +381,6 @@ Source Files - - Source Files\_Headers - Source Files\Emulator @@ -423,6 +429,21 @@ Source Files\Video + + Source Files\Model + + + Source Files\Emulator + + + Source Files\Emulator + + + Source Files\_Headers + + + Source Files\_Headers + @@ -591,9 +612,6 @@ Docs - - Docs - Docs @@ -603,6 +621,7 @@ Docs + @@ -644,6 +663,9 @@ {b5c6889e-727d-4339-96c8-e4284e1d6e0f} + + {15b450e4-f89f-4d80-9c44-48b32f33f3e3} + diff --git a/ApplewinExpress9.00.vcproj b/ApplewinExpress9.00.vcproj index 27e7e9f1..5542a063 100644 --- a/ApplewinExpress9.00.vcproj +++ b/ApplewinExpress9.00.vcproj @@ -26,6 +26,8 @@ > + + + + @@ -734,6 +746,14 @@ RelativePath=".\source\Tape.h" > + + + + @@ -755,11 +775,15 @@ > + + @@ -959,6 +983,18 @@ > + + + + + + > 8) & 0xf; + period = (USHORT) yamlLoadHelper.LoadUint(SS_YAML_KEY_REG_TONE1_PERIOD); + sound_ay_registers[2] = period & 0xff; + sound_ay_registers[3] = (period >> 8) & 0xf; + period = (USHORT) yamlLoadHelper.LoadUint(SS_YAML_KEY_REG_TONE2_PERIOD); + sound_ay_registers[4] = period & 0xff; + sound_ay_registers[5] = (period >> 8) & 0xf; + sound_ay_registers[6] = yamlLoadHelper.LoadUint(SS_YAML_KEY_REG_NOISE_PERIOD); + sound_ay_registers[7] = yamlLoadHelper.LoadUint(SS_YAML_KEY_REG_MIXER); + sound_ay_registers[8] = yamlLoadHelper.LoadUint(SS_YAML_KEY_REG_VOL0); + sound_ay_registers[9] = yamlLoadHelper.LoadUint(SS_YAML_KEY_REG_VOL1); + sound_ay_registers[10] = yamlLoadHelper.LoadUint(SS_YAML_KEY_REG_VOL2); + period = (USHORT) yamlLoadHelper.LoadUint(SS_YAML_KEY_REG_ENV_PERIOD); + sound_ay_registers[11] = period & 0xff; + sound_ay_registers[12] = period >> 8; + sound_ay_registers[13] = yamlLoadHelper.LoadUint(SS_YAML_KEY_REG_ENV_SHAPE); + sound_ay_registers[14] = yamlLoadHelper.LoadUint(SS_YAML_KEY_REG_PORTA); + sound_ay_registers[15] = yamlLoadHelper.LoadUint(SS_YAML_KEY_REG_PORTB); + + yamlLoadHelper.PopMap(); + + ay_change_count = 0; + if (yamlLoadHelper.GetSubMap(SS_YAML_KEY_CHANGE)) + { + while(1) + { + char szIndex[7]; + sprintf_s(szIndex, sizeof(szIndex), "0x%04X", ay_change_count); + + bool bFound; + std::string value = yamlLoadHelper.LoadString_NoThrow(szIndex, bFound); + if (!bFound) + break; // done + + if(4 != sscanf_s(value.c_str(), SS_YAML_VALUE_CHANGE_FORMAT, + &ay_change[ay_change_count].tstates, + &ay_change[ay_change_count].ofs, + &ay_change[ay_change_count].reg, + &ay_change[ay_change_count].val)) + throw std::string("Card: AY8910: Failed to scanf change list"); + + ay_change_count++; + if (ay_change_count > AY_CHANGE_MAX) + throw std::string("Card: AY8910: Too many changes"); + } + + yamlLoadHelper.PopMap(); + } + + yamlLoadHelper.PopMap(); + + return true; +} + /////////////////////////////////////////////////////////////////////////////// // AY8910 interface @@ -996,8 +1190,25 @@ 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_SaveSnapshot(YamlSaveHelper& yamlSaveHelper, UINT uChip, std::string& suffix) +{ + if (uChip >= MAX_8910) + return 0; + + g_AY8910[uChip].SaveSnapshot(yamlSaveHelper, suffix); + return 1; +} + +UINT AY8910_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT uChip, std::string& suffix) +{ + if (uChip >= MAX_8910) + return 0; + + return g_AY8910[uChip].LoadSnapshot(yamlLoadHelper, suffix) ? 1 : 0; +} diff --git a/source/AY8910.h b/source/AY8910.h index 59a53359..31ad9a15 100644 --- a/source/AY8910.h +++ b/source/AY8910.h @@ -17,6 +17,9 @@ BYTE* AY8910_GetRegsPtr(UINT uChip); void AY8910UpdateSetCycles(); +UINT AY8910_SaveSnapshot(class YamlSaveHelper& yamlSaveHelper, UINT uChip, std::string& suffix); +UINT AY8910_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT uChip, std::string& suffix); + //------------------------------------- // FUSE stuff @@ -43,8 +46,11 @@ public: void sound_frame( void ); BYTE* GetAYRegsPtr( void ) { return &sound_ay_registers[0]; } static void SetCLK( double CLK ) { m_fCurrentCLK_AY8910 = CLK; } + void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper, std::string& suffix); + bool LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, std::string& suffix); private: + void init( void ); void sound_end( void ); void sound_ay_overlay( void ); diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 76a0b3e6..c49a6e0a 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -57,6 +57,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Configuration\PropertySheet.h" #include "Tfe\Tfe.h" +static UINT16 g_AppleWinVersion[4] = {0}; char VERSIONSTRING[16] = "xx.yy.zz.ww"; TCHAR *g_pAppTitle = TITLE_APPLE_2E_ENHANCED; @@ -65,9 +66,6 @@ eApple2Type g_Apple2Type = A2TYPE_APPLE2EENHANCED; bool g_bFullSpeed = false; -//Pravets 8A/C variables -bool P8CAPS_ON = false; -bool P8Shift = false; //================================================= // Win32 @@ -102,8 +100,6 @@ CMouseInterface sg_Mouse; SS_CARDTYPE g_Slot4 = CT_Empty; SS_CARDTYPE g_Slot5 = CT_Empty; -eCPU g_ActiveCPU = CPU_6502; - HANDLE g_hCustomRomF8 = INVALID_HANDLE_VALUE; // Cmd-line specified custom ROM at $F800..$FFFF static bool g_bCustomRomF8Failed = false; // Set if custom ROM file failed @@ -114,6 +110,22 @@ CSpeech g_Speech; //=========================================================================== +eApple2Type GetApple2Type(void) +{ + return g_Apple2Type; +} + +void SetApple2Type(eApple2Type type) +{ + g_Apple2Type = type; + SetMainCpuDefault(type); +} + +const UINT16* GetAppleWinVersion(void) +{ + return &g_AppleWinVersion[0]; +} + bool GetLoadedSaveStateFlag(void) { return g_bLoadedSaveState; @@ -371,20 +383,39 @@ static void LoadConfigOldJoystick(const UINT uJoyNum) break; } - joytype[uJoyNum] = uNewJoyType; + JoySetJoyType(uJoyNum, uNewJoyType); +} + +//Sets the character set for the Apple model/clone +void SetCharsetType(void) +{ + switch ( GetApple2Type() ) + { + case A2TYPE_APPLE2: g_nCharsetType = 0; break; + case A2TYPE_APPLE2PLUS: g_nCharsetType = 0; break; + case A2TYPE_APPLE2E: g_nCharsetType = 0; break; + case A2TYPE_APPLE2EENHANCED:g_nCharsetType = 0; break; + case A2TYPE_PRAVETS82: g_nCharsetType = 1; break; + case A2TYPE_PRAVETS8A: g_nCharsetType = 2; break; + case A2TYPE_PRAVETS8M: g_nCharsetType = 3; break; //This charset has a very small difference with the PRAVETS82 one an probably has some misplaced characters. Still the Pravets82 charset is used, because setting charset to 3 results in some problems. + default: + _ASSERT(0); + g_nCharsetType = 0; + } } //Reads configuration from the registry entries void LoadConfiguration(void) { DWORD dwComputerType; + eApple2Type apple2Type = A2TYPE_APPLE2EENHANCED; if (REGLOAD(TEXT(REGVALUE_APPLE2_TYPE), &dwComputerType)) { if ((dwComputerType >= A2TYPE_MAX) || (dwComputerType >= A2TYPE_UNDEFINED && dwComputerType < A2TYPE_CLONE)) dwComputerType = A2TYPE_APPLE2EENHANCED; - g_Apple2Type = (eApple2Type) dwComputerType; + apple2Type = (eApple2Type) dwComputerType; } else // Support older AppleWin registry entries { @@ -392,27 +423,42 @@ void LoadConfiguration(void) switch (dwComputerType) { // NB. No A2TYPE_APPLE2E (this is correct) - case 0: g_Apple2Type = A2TYPE_APPLE2; - case 1: g_Apple2Type = A2TYPE_APPLE2PLUS; - case 2: g_Apple2Type = A2TYPE_APPLE2EENHANCED; - default: g_Apple2Type = A2TYPE_APPLE2EENHANCED; + case 0: apple2Type = A2TYPE_APPLE2; break; + case 1: apple2Type = A2TYPE_APPLE2PLUS; break; + case 2: apple2Type = A2TYPE_APPLE2EENHANCED; break; + default: apple2Type = A2TYPE_APPLE2EENHANCED; } } - switch (g_Apple2Type) //Sets the character set for the Apple model/clone + SetApple2Type(apple2Type); + SetCharsetType(); + + // + + DWORD dwCpuType; + eCpuType cpu = CPU_65C02; + + if (REGLOAD(TEXT(REGVALUE_CPU_TYPE), &dwCpuType)) { - case A2TYPE_APPLE2: g_nCharsetType = 0; break; - case A2TYPE_APPLE2PLUS: g_nCharsetType = 0; break; - case A2TYPE_APPLE2E: g_nCharsetType = 0; break; - case A2TYPE_APPLE2EENHANCED:g_nCharsetType = 0; break; - case A2TYPE_PRAVETS82: g_nCharsetType = 1; break; - case A2TYPE_PRAVETS8A: g_nCharsetType = 2; break; - case A2TYPE_PRAVETS8M: g_nCharsetType = 3; break; //This charset has a very small difference with the PRAVETS82 one an probably has some misplaced characters. Still the Pravets82 charset is used, because setting charset to 3 results in some problems. + if (dwCpuType != CPU_6502 && dwCpuType != CPU_65C02) + dwCpuType = CPU_65C02; + + cpu = (eCpuType) dwCpuType; } - if (!REGLOAD(TEXT(REGVALUE_JOYSTICK0_EMU_TYPE), &joytype[JN_JOYSTICK0])) + SetMainCpu(cpu); + + // + + DWORD dwJoyType; + if (REGLOAD(TEXT(REGVALUE_JOYSTICK0_EMU_TYPE), &dwJoyType)) + JoySetJoyType(JN_JOYSTICK0, dwJoyType); + else LoadConfigOldJoystick(JN_JOYSTICK0); - if (!REGLOAD(TEXT(REGVALUE_JOYSTICK1_EMU_TYPE), &joytype[JN_JOYSTICK1])) + + if (REGLOAD(TEXT(REGVALUE_JOYSTICK1_EMU_TYPE), &dwJoyType)) + JoySetJoyType(JN_JOYSTICK1, dwJoyType); + else LoadConfigOldJoystick(JN_JOYSTICK1); REGLOAD(TEXT("Sound Emulation") ,&soundtype); @@ -469,12 +515,6 @@ void LoadConfiguration(void) if(REGLOAD(TEXT(REGVALUE_HDD_ENABLED), &dwTmp)) HD_SetEnabled(dwTmp ? true : false); - char szHDVPathname[MAX_PATH] = {0}; - if(RegLoadString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_LAST_HARDDISK_1), 1, szHDVPathname, sizeof(szHDVPathname))) - HD_InsertDisk(HARDDISK_1, szHDVPathname); - if(RegLoadString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_LAST_HARDDISK_2), 1, szHDVPathname, sizeof(szHDVPathname))) - HD_InsertDisk(HARDDISK_2, szHDVPathname); - if(REGLOAD(TEXT(REGVALUE_PDL_XTRIM), &dwTmp)) JoySetTrim((short)dwTmp, true); if(REGLOAD(TEXT(REGVALUE_PDL_YTRIM), &dwTmp)) @@ -500,15 +540,20 @@ 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}; + RegLoadString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_HDV_START_DIR), 1, szFilename, MAX_PATH); + if (szFilename[0] == 0) + GetCurrentDirectory(sizeof(szFilename), szFilename); + SetCurrentImageDir(szFilename); + + HD_LoadLastDiskImage(HARDDISK_1); + HD_LoadLastDiskImage(HARDDISK_2); + + // + // Current/Starting Dir is the "root" of where the user keeps his disk images RegLoadString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_START_DIR), 1, szFilename, MAX_PATH); if (szFilename[0] == 0) @@ -550,7 +595,7 @@ bool SetCurrentImageDir(const char* pszImageDir) strcpy(g_sCurrentDir, pszImageDir); int nLen = strlen( g_sCurrentDir ); - if( g_sCurrentDir[ nLen - 1 ] != '\\' ) + if ((nLen > 0) && (g_sCurrentDir[ nLen - 1 ] != '\\')) { g_sCurrentDir[ nLen + 0 ] = '\\'; g_sCurrentDir[ nLen + 1 ] = 0; @@ -739,10 +784,12 @@ static int DoDiskInsert(const int nDrive, LPCSTR szFileName) int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) { + bool bShutdown = false; bool bSetFullScreen = false; bool bBoot = false; LPSTR szImageName_drive1 = NULL; LPSTR szImageName_drive2 = NULL; + LPSTR szSnapshotName = NULL; const std::string strCmdLine(lpCmdLine); // Keep a copy for log ouput while (*lpCmdLine) @@ -774,6 +821,12 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) lpNextArg = GetNextArg(lpNextArg); szImageName_drive2 = lpCmdLine; } + else if (strcmp(lpCmdLine, "-load-state") == 0) + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + szSnapshotName = lpCmdLine; + } else if (strcmp(lpCmdLine, "-f") == 0) { bSetFullScreen = true; @@ -811,8 +864,8 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) lpCmdLine = GetCurrArg(lpNextArg); lpNextArg = GetNextArg(lpNextArg); g_uMaxExPages = atoi(lpCmdLine); - if (g_uMaxExPages > 127) - g_uMaxExPages = 128; + if (g_uMaxExPages > kMaxExMemoryBanks) + g_uMaxExPages = kMaxExMemoryBanks; else if (g_uMaxExPages < 1) g_uMaxExPages = 1; } @@ -905,11 +958,11 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) // Construct version string from fixed file info block - unsigned long major = pFixedFileInfo->dwFileVersionMS >> 16; - unsigned long minor = pFixedFileInfo->dwFileVersionMS & 0xffff; - unsigned long fix = pFixedFileInfo->dwFileVersionLS >> 16; - unsigned long fix_minor = pFixedFileInfo->dwFileVersionLS & 0xffff; - sprintf(VERSIONSTRING, "%d.%d.%d.%d", major, minor, fix, fix_minor); // potential buffer overflow + unsigned long major = g_AppleWinVersion[0] = pFixedFileInfo->dwFileVersionMS >> 16; + unsigned long minor = g_AppleWinVersion[1] = pFixedFileInfo->dwFileVersionMS & 0xffff; + unsigned long fix = g_AppleWinVersion[2] = pFixedFileInfo->dwFileVersionLS >> 16; + unsigned long fix_minor = g_AppleWinVersion[3] = pFixedFileInfo->dwFileVersionLS & 0xffff; + sprintf(VERSIONSTRING, "%d.%d.%d.%d", major, minor, fix, fix_minor); // potential buffer overflow } } @@ -955,7 +1008,7 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) DiskInitialize(); LogFileOutput("Init: DiskInitialize()\n"); - int nError = 0; // TODO: Show error MsgBox if we get a DiskInsert error + int nError = 0; // TODO: Show error MsgBox if we get a DiskInsert error if (szImageName_drive1) { nError = DoDiskInsert(DRIVE_1, szImageName_drive1); @@ -1003,7 +1056,7 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) if (bShowAboutDlg) { if (!AboutDlg()) - PostMessage(g_hFrameWindow, WM_DESTROY, 0, 0); // Close everything down + bShutdown = true; // Close everything down else RegSaveString(TEXT(REG_CONFIG), TEXT(REGVALUE_VERSION), 1, VERSIONSTRING); // Only save version after user accepts license } @@ -1019,31 +1072,57 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) if (!bSysClkOK) { MessageBox(g_hFrameWindow, "DirectX failed to create SystemClock instance", TEXT("AppleWin Error"), MB_OK); - PostMessage(g_hFrameWindow, WM_DESTROY, 0, 0); // Close everything down + bShutdown = true; } if (g_bCustomRomF8Failed) { MessageBox(g_hFrameWindow, "Failed to load custom F8 rom (not found or not exactly 2KB)", TEXT("AppleWin Error"), MB_OK); - PostMessage(g_hFrameWindow, WM_DESTROY, 0, 0); // Close everything down + bShutdown = true; } tfe_init(); LogFileOutput("Main: tfe_init()\n"); - Snapshot_Startup(); // Do this after everything has been init'ed - LogFileOutput("Main: Snapshot_Startup()\n"); - - if (bSetFullScreen) + if (szSnapshotName) { - PostMessage(g_hFrameWindow, WM_USER_FULLSCREEN, 0, 0); - bSetFullScreen = false; + // Override value just loaded from Registry by LoadConfiguration() + // . NB. Registry value is not updated with this cmd-line value + Snapshot_SetFilename(szSnapshotName); + Snapshot_LoadState(); + bBoot = true; +#if _DEBUG && 0 // Debug/test: Save a duplicate of the save-state file in tmp folder + std::string saveName = std::string("tmp\\") + std::string(szSnapshotName); + Snapshot_SetFilename(saveName); + g_bSaveStateOnExit = true; + bShutdown = true; +#endif + szSnapshotName = NULL; + } + else + { + Snapshot_Startup(); // Do this after everything has been init'ed + LogFileOutput("Main: Snapshot_Startup()\n"); } - if (bBoot) + if (bShutdown) { - PostMessage(g_hFrameWindow, WM_USER_BOOT, 0, 0); - bBoot = false; + PostMessage(g_hFrameWindow, WM_DESTROY, 0, 0); // Close everything down + // NB. If shutting down, then don't post any other messages (GH#286) + } + else + { + if (bSetFullScreen) + { + PostMessage(g_hFrameWindow, WM_USER_FULLSCREEN, 0, 0); + bSetFullScreen = false; + } + + if (bBoot) + { + PostMessage(g_hFrameWindow, WM_USER_BOOT, 0, 0); + bBoot = false; + } } // ENTER THE MAIN MESSAGE LOOP diff --git a/source/Applewin.h b/source/Applewin.h index 24f19fd2..b57efcde 100644 --- a/source/Applewin.h +++ b/source/Applewin.h @@ -1,23 +1,23 @@ #pragma once -#include "Structs.h" +#include "SaveState_Structs_common.h" #include "Common.h" void SetCurrentCLK6502(); bool SetCurrentImageDir(const char* pszImageDir); +void SetCharsetType(void); - +extern const UINT16* GetAppleWinVersion(void); extern char VERSIONSTRING[]; // Constructed in WinMain() extern TCHAR *g_pAppTitle; extern eApple2Type g_Apple2Type; +eApple2Type GetApple2Type(void); +void SetApple2Type(eApple2Type type); extern bool g_bFullSpeed; -//Pravets 8A/C only variables -extern bool P8CAPS_ON; -extern bool P8Shift; //=========================================== // Win32 @@ -49,9 +49,6 @@ extern SS_CARDTYPE g_Slot5; // Mockingboard, Z80, in slot5 extern HANDLE g_hCustomRomF8; // NULL if no custom rom -enum eCPU {CPU_6502=1, CPU_Z80}; -extern eCPU g_ActiveCPU; - #ifdef USE_SPEECH_API class CSpeech; extern CSpeech g_Speech; diff --git a/source/CPU.cpp b/source/CPU.cpp index faf45fbf..daacf9fc 100644 --- a/source/CPU.cpp +++ b/source/CPU.cpp @@ -63,7 +63,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // What about these: // . 65C02: STZ?, TRB?, TSB? -// . Answer: TRB & TSB don't have affected adressing modes +// . Answer: TRB & TSB don't have affected addressing modes // . STZ probably doesn't add a cycle since otherwise it would be slower than STA which doesn't make sense. // // NB. 'Zero-page indexed' opcodes wrap back to zero-page. @@ -103,6 +103,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Z80VICE\z80mem.h" #include "Debugger\Debug.h" +#include "YamlHelper.h" // 6502 Accumulator Bit Flags #define AF_SIGN 0x80 @@ -148,6 +149,53 @@ static volatile UINT32 g_bmIRQ = 0; static volatile UINT32 g_bmNMI = 0; static volatile BOOL g_bNmiFlank = FALSE; // Positive going flank on NMI line +// + +static eCpuType g_MainCPU = CPU_65C02; +static eCpuType g_ActiveCPU = CPU_65C02; + +eCpuType GetMainCpu(void) +{ + return g_MainCPU; +} + +void SetMainCpu(eCpuType cpu) +{ + _ASSERT(cpu != CPU_Z80); + if (cpu == CPU_Z80) + return; + + g_MainCPU = cpu; +} + +static bool IsCpu65C02(eApple2Type apple2Type) +{ + // NB. All Pravets clones are 6502 (GH#307) + return (apple2Type == A2TYPE_APPLE2EENHANCED) || (apple2Type & A2TYPE_APPLE2C); +} + +eCpuType ProbeMainCpuDefault(eApple2Type apple2Type) +{ + return IsCpu65C02(apple2Type) ? CPU_65C02 : CPU_6502; +} + +void SetMainCpuDefault(eApple2Type apple2Type) +{ + SetMainCpu( ProbeMainCpuDefault(apple2Type) ); +} + +eCpuType GetActiveCpu(void) +{ + return g_ActiveCPU; +} + +void SetActiveCpu(eCpuType cpu) +{ + g_ActiveCPU = cpu; +} + +// + #include "cpu/cpu_general.inl" #include "cpu/cpu_instructions.inl" @@ -409,8 +457,8 @@ static __forceinline void CheckInterruptSources(ULONG uExecutedCycles) static DWORD InternalCpuExecute (DWORD uTotalCycles) { - if (IS_APPLE2 || (g_Apple2Type == A2TYPE_APPLE2E)) - return Cpu6502(uTotalCycles); // Apple ][, ][+, //e + if (GetMainCpu() == CPU_6502) + return Cpu6502(uTotalCycles); // Apple ][, ][+, //e, Clones else return Cpu65C02(uTotalCycles); // Enhanced Apple //e } @@ -639,36 +687,83 @@ void CpuReset() regs.bJammed = 0; - g_ActiveCPU = CPU_6502; + SetActiveCpu( GetMainCpu() ); z80_reset(); } //=========================================================================== -DWORD CpuGetSnapshot(SS_CPU6502* pSS) +void CpuSetSnapshot_v1(const BYTE A, const BYTE X, const BYTE Y, const BYTE P, const BYTE SP, const USHORT PC, const unsigned __int64 CumulativeCycles) { - pSS->A = regs.a; - pSS->X = regs.x; - pSS->Y = regs.y; - pSS->P = regs.ps | AF_RESERVED | AF_BREAK; - pSS->S = (BYTE) (regs.sp & 0xff); - pSS->PC = regs.pc; - pSS->g_nCumulativeCycles = g_nCumulativeCycles; + regs.a = A; + regs.x = X; + regs.y = Y; + regs.ps = P | (AF_RESERVED | AF_BREAK); + regs.sp = ((USHORT)SP) | 0x100; + regs.pc = PC; - return 0; -} - -DWORD CpuSetSnapshot(SS_CPU6502* pSS) -{ - regs.a = pSS->A; - regs.x = pSS->X; - regs.y = pSS->Y; - regs.ps = pSS->P | AF_RESERVED | AF_BREAK; - regs.sp = (USHORT)pSS->S | 0x100; - regs.pc = pSS->PC; CpuIrqReset(); CpuNmiReset(); - g_nCumulativeCycles = pSS->g_nCumulativeCycles; - - return 0; + g_nCumulativeCycles = CumulativeCycles; +} + +// + +#define SS_YAML_KEY_CPU_TYPE "Type" +#define SS_YAML_KEY_REGA "A" +#define SS_YAML_KEY_REGX "X" +#define SS_YAML_KEY_REGY "Y" +#define SS_YAML_KEY_REGP "P" +#define SS_YAML_KEY_REGS "S" +#define SS_YAML_KEY_REGPC "PC" +#define SS_YAML_KEY_CUMULATIVECYCLES "Cumulative Cycles" + +#define SS_YAML_VALUE_6502 "6502" +#define SS_YAML_VALUE_65C02 "65C02" + +static std::string CpuGetSnapshotStructName(void) +{ + static const std::string name("CPU"); + return name; +} + +void CpuSaveSnapshot(YamlSaveHelper& yamlSaveHelper) +{ + regs.ps |= (AF_RESERVED | AF_BREAK); + + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", CpuGetSnapshotStructName().c_str()); + yamlSaveHelper.SaveString(SS_YAML_KEY_CPU_TYPE, GetMainCpu() == CPU_6502 ? SS_YAML_VALUE_6502 : SS_YAML_VALUE_65C02); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGA, regs.a); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGX, regs.x); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGY, regs.y); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGP, regs.ps); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGS, (BYTE) regs.sp); + yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_REGPC, regs.pc); + yamlSaveHelper.SaveHexUint64(SS_YAML_KEY_CUMULATIVECYCLES, g_nCumulativeCycles); +} + +void CpuLoadSnapshot(YamlLoadHelper& yamlLoadHelper) +{ + if (!yamlLoadHelper.GetSubMap(CpuGetSnapshotStructName())) + return; + + std::string cpuType = yamlLoadHelper.LoadString(SS_YAML_KEY_CPU_TYPE); + eCpuType cpu; + if (cpuType == SS_YAML_VALUE_6502) cpu = CPU_6502; + else if (cpuType == SS_YAML_VALUE_65C02) cpu = CPU_65C02; + else throw std::string("Load: Unknown main CPU type"); + SetMainCpu(cpu); + + regs.a = (BYTE) yamlLoadHelper.LoadUint(SS_YAML_KEY_REGA); + regs.x = (BYTE) yamlLoadHelper.LoadUint(SS_YAML_KEY_REGX); + regs.y = (BYTE) yamlLoadHelper.LoadUint(SS_YAML_KEY_REGY); + regs.ps = (BYTE) yamlLoadHelper.LoadUint(SS_YAML_KEY_REGP) | (AF_RESERVED | AF_BREAK); + regs.sp = (USHORT) ((yamlLoadHelper.LoadUint(SS_YAML_KEY_REGS) & 0xff) | 0x100); + regs.pc = (USHORT) yamlLoadHelper.LoadUint(SS_YAML_KEY_REGPC); + + CpuIrqReset(); + CpuNmiReset(); + g_nCumulativeCycles = yamlLoadHelper.LoadUint64(SS_YAML_KEY_CUMULATIVECYCLES); + + yamlLoadHelper.PopMap(); } diff --git a/source/CPU.h b/source/CPU.h index 58c5d886..5086e9e1 100644 --- a/source/CPU.h +++ b/source/CPU.h @@ -1,6 +1,7 @@ #pragma once -typedef struct _regsrec { +struct regsrec +{ BYTE a; // accumulator BYTE x; // index X BYTE y; // index Y @@ -8,7 +9,7 @@ typedef struct _regsrec { WORD pc; // program counter WORD sp; // stack pointer BYTE bJammed; // CPU has crashed (NMOS 6502 only) -} regsrec, *regsptr; +}; extern regsrec regs; extern unsigned __int64 g_nCumulativeCycles; @@ -26,10 +27,20 @@ void CpuNmiReset(); void CpuNmiAssert(eIRQSRC Device); void CpuNmiDeassert(eIRQSRC Device); void CpuReset (); -DWORD CpuGetSnapshot(SS_CPU6502* pSS); -DWORD CpuSetSnapshot(SS_CPU6502* pSS); +void CpuSetSnapshot_v1(const BYTE A, const BYTE X, const BYTE Y, const BYTE P, const BYTE SP, const USHORT PC, const unsigned __int64 CumulativeCycles); +void CpuSaveSnapshot(class YamlSaveHelper& yamlSaveHelper); +void CpuLoadSnapshot(class YamlLoadHelper& yamlLoadHelper); BYTE CpuRead(USHORT addr, ULONG uExecutedCycles); void CpuWrite(USHORT addr, BYTE a, ULONG uExecutedCycles); DWORD CpuGetEmulationTime_ms(void); + +enum eCpuType {CPU_6502=1, CPU_65C02, CPU_Z80}; // Don't change! Persisted to Registry + +eCpuType GetMainCpu(void); +void SetMainCpu(eCpuType cpu); +eCpuType ProbeMainCpuDefault(eApple2Type apple2Type); +void SetMainCpuDefault(eApple2Type apple2Type); +eCpuType GetActiveCpu(void); +void SetActiveCpu(eCpuType cpu); diff --git a/source/CPU/cpu6502.h b/source/CPU/cpu6502.h index 3645242e..b2a25e67 100644 --- a/source/CPU/cpu6502.h +++ b/source/CPU/cpu6502.h @@ -35,7 +35,6 @@ static DWORD Cpu6502 (DWORD uTotalCycles) WORD val; AF_TO_EF ULONG uExecutedCycles = 0; - BOOL bSlowerOnPagecross = 0; // Set if opcode writes to memory (eg. ASL, STA) WORD base; g_bDebugBreakpointHit = 0; @@ -49,275 +48,276 @@ static DWORD Cpu6502 (DWORD uTotalCycles) ULONG uPreviousCycles = uExecutedCycles; // NTSC_END - if (g_ActiveCPU == CPU_Z80) + if (GetActiveCpu() == CPU_Z80) { const UINT uZ80Cycles = z80_mainloop(uTotalCycles, uExecutedCycles); CYC(uZ80Cycles) } else { - if (!Fetch(iOpcode, uExecutedCycles)) - break; + if (!Fetch(iOpcode, uExecutedCycles)) + break; #define $ INV // INV = Invalid -> Debugger Break - switch (iOpcode) - { - case 0x00: BRK CYC(7) break; - case 0x01: idx ORA CYC(6) break; - case 0x02: $ HLT CYC(2) break; - case 0x03: $ idx ASO CYC(8) break; - case 0x04: $ ZPG NOP CYC(3) break; - case 0x05: ZPG ORA CYC(3) break; - case 0x06: ZPG ASLn CYC(5) break; - case 0x07: $ ZPG ASO CYC(5) break; // invalid - case 0x08: PHP CYC(3) break; - case 0x09: IMM ORA CYC(2) break; - case 0x0A: asl CYC(2) break; - case 0x0B: $ IMM ANC CYC(2) break; // invald - case 0x0C: $ abx NOP CYC(4) break; - case 0x0D: ABS ORA CYC(4) break; - case 0x0E: ABS ASLn CYC(6) break; - case 0x0F: $ ABS ASO CYC(6) break; // invalid - case 0x10: REL BPL CYC(2) break; - case 0x11: idy ORA CYC(5) break; - case 0x12: $ HLT CYC(2) break; - case 0x13: $ idy ASO CYC(8) break; // invalid - case 0x14: $ zpx NOP CYC(4) break; - case 0x15: zpx ORA CYC(4) break; - case 0x16: zpx ASLn CYC(6) break; - case 0x17: $ zpx ASO CYC(6) break; // invalid - case 0x18: CLC CYC(2) break; - case 0x19: aby ORA CYC(4) break; - case 0x1A: $ NOP CYC(2) break; - case 0x1B: $ aby ASO CYC(7) break; // invalid - case 0x1C: $ abx NOP CYC(4) break; - case 0x1D: abx ORA CYC(4) break; - case 0x1E: abx ASLn CYC(6) break; - case 0x1F: $ abx ASO CYC(7) break; // invalid - case 0x20: ABS JSR CYC(6) break; - case 0x21: idx AND CYC(6) break; - case 0x22: $ HLT CYC(2) break; - case 0x23: $ idx RLA CYC(8) break; - case 0x24: ZPG BIT CYC(3) break; - case 0x25: ZPG AND CYC(3) break; - case 0x26: ZPG ROLn CYC(5) break; - case 0x27: $ ZPG RLA CYC(5) break; - case 0x28: PLP CYC(4) break; - case 0x29: IMM AND CYC(2) break; - case 0x2A: rol CYC(2) break; - case 0x2B: $ IMM ANC CYC(2) break; // invalid - case 0x2C: ABS BIT CYC(4) break; - case 0x2D: ABS AND CYC(2) break; - case 0x2E: ABS ROLn CYC(6) break; - case 0x2F: $ ABS RLA CYC(6) break; - case 0x30: REL BMI CYC(2) break; - case 0x31: idy AND CYC(5) break; - case 0x32: $ HLT CYC(2) break; - case 0x33: $ idy RLA CYC(8) break; // invalid - case 0x34: $ zpx NOP CYC(4) break; - case 0x35: zpx AND CYC(4) break; - case 0x36: zpx ROLn CYC(6) break; - case 0x37: $ zpx RLA CYC(6) break; - case 0x38: SEC CYC(2) break; - case 0x39: aby AND CYC(4) break; - case 0x3A: $ NOP CYC(2) break; - case 0x3B: $ aby RLA CYC(7) break; // invalid - case 0x3C: $ abx NOP CYC(4) break; - case 0x3D: abx AND CYC(4) break; - case 0x3E: abx ROLn CYC(6) break; - case 0x3F: $ abx RLA CYC(7) break; // invalid - case 0x40: RTI CYC(6) DoIrqProfiling(uExecutedCycles); break; - case 0x41: idx EOR CYC(6) break; - case 0x42: $ HLT CYC(2) break; - case 0x43: $ idx LSE CYC(8) break; // invalid - case 0x44: $ ZPG NOP CYC(3) break; - case 0x45: ZPG EOR CYC(3) break; - case 0x46: ZPG LSRn CYC(5) break; - case 0x47: $ ZPG LSE CYC(5) break; // invalid - case 0x48: PHA CYC(3) break; - case 0x49: IMM EOR CYC(2) break; - case 0x4A: lsr CYC(2) break; - case 0x4B: $ IMM ALR CYC(2) break; // invalid - case 0x4C: ABS JMP CYC(3) break; - case 0x4D: ABS EOR CYC(4) break; - case 0x4E: ABS LSRn CYC(6) break; - case 0x4F: $ ABS LSE CYC(6) break; - case 0x50: REL BVC CYC(2) break; - case 0x51: idy EOR CYC(5) break; - case 0x52: $ HLT CYC(2) break; - case 0x53: $ idy LSE CYC(8) break; - case 0x54: $ zpx NOP CYC(4) break; - case 0x55: zpx EOR CYC(4) break; - case 0x56: zpx LSRn CYC(6) break; - case 0x57: $ zpx LSE CYC(6) break; // invalid - case 0x58: CLI CYC(2) break; - case 0x59: aby EOR CYC(4) break; - case 0x5A: $ NOP CYC(2) break; - case 0x5B: $ aby LSE CYC(7) break; // invalid - case 0x5C: $ abx NOP CYC(4) break; - case 0x5D: abx EOR CYC(4) break; - case 0x5E: abx LSRn CYC(6) break; - case 0x5F: $ abx LSE CYC(7) break; - case 0x60: RTS CYC(6) break; - case 0x61: idx ADCn CYC(6) break; - case 0x62: $ HLT CYC(2) break; - case 0x63: $ idx RRA CYC(8) break; // invalid - case 0x64: $ ZPG NOP CYC(3) break; - case 0x65: ZPG ADCn CYC(3) break; - case 0x66: ZPG RORn CYC(5) break; - case 0x67: $ ZPG RRA CYC(5) break; - case 0x68: PLA CYC(4) break; - case 0x69: IMM ADCn CYC(2) break; - case 0x6A: ror CYC(2) break; - case 0x6B: $ IMM ARR CYC(2) break; // invalid - case 0x6C: IABSNMOS JMP CYC(6) break; - case 0x6D: ABS ADCn CYC(4) break; - case 0x6E: ABS RORn CYC(6) break; - case 0x6F: $ ABS RRA CYC(6) break; // invalid - case 0x70: REL BVS CYC(2) break; - case 0x71: idy ADCn CYC(5) break; - case 0x72: $ HLT CYC(2) break; - case 0x73: $ idy RRA CYC(8) break; // invalid - case 0x74: $ zpx NOP CYC(4) break; - case 0x75: zpx ADCn CYC(4) break; - case 0x76: zpx RORn CYC(6) break; - case 0x77: $ zpx RRA CYC(6) break; // invalid - case 0x78: SEI CYC(2) break; - case 0x79: aby ADCn CYC(4) break; - case 0x7A: $ NOP CYC(2) break; - case 0x7B: $ aby RRA CYC(7) break; // invalid - case 0x7C: $ abx NOP CYC(4) break; - case 0x7D: abx ADCn CYC(4) break; - case 0x7E: abx RORn CYC(6) break; - case 0x7F: $ abx RRA CYC(7) break; // invalid - case 0x80: $ IMM NOP CYC(2) break; - case 0x81: idx STA CYC(6) break; - case 0x82: $ IMM NOP CYC(2) break; - case 0x83: $ idx AXS CYC(6) break; // invalid - case 0x84: ZPG STY CYC(3) break; - case 0x85: ZPG STA CYC(3) break; - case 0x86: ZPG STX CYC(3) break; - case 0x87: $ ZPG AXS CYC(3) break; // invalid - case 0x88: DEY CYC(2) break; - case 0x89: $ IMM NOP CYC(2) break; - case 0x8A: TXA CYC(2) break; - case 0x8B: $ IMM XAA CYC(2) break; // invalid - case 0x8C: ABS STY CYC(4) break; - case 0x8D: ABS STA CYC(4) break; - case 0x8E: ABS STX CYC(4) break; - case 0x8F: $ ABS AXS CYC(4) break; // invalid - case 0x90: REL BCC CYC(2) break; - case 0x91: idy STA CYC(6) break; - case 0x92: $ HLT CYC(2) break; - case 0x93: $ idy AXA CYC(6) break; // invalid - case 0x94: zpx STY CYC(4) break; - case 0x95: zpx STA CYC(4) break; - case 0x96: zpy STX CYC(4) break; - case 0x97: $ zpy AXS CYC(4) break; // invalid - case 0x98: TYA CYC(2) break; - case 0x99: aby STA CYC(5) break; - case 0x9A: TXS CYC(2) break; - case 0x9B: $ aby TAS CYC(5) break; // invalid - case 0x9C: $ abx SAY CYC(5) break; // invalid - case 0x9D: abx STA CYC(5) break; - case 0x9E: $ aby XAS CYC(5) break; - case 0x9F: $ aby AXA CYC(5) break; - case 0xA0: IMM LDY CYC(2) break; - case 0xA1: idx LDA CYC(6) break; - case 0xA2: IMM LDX CYC(2) break; - case 0xA3: $ idx LAX CYC(6) break; // invalid - case 0xA4: ZPG LDY CYC(3) break; - case 0xA5: ZPG LDA CYC(3) break; - case 0xA6: ZPG LDX CYC(3) break; - case 0xA7: $ ZPG LAX CYC(3) break; // invalid - case 0xA8: TAY CYC(2) break; - case 0xA9: IMM LDA CYC(2) break; - case 0xAA: TAX CYC(2) break; - case 0xAB: $ IMM OAL CYC(2) break; // invalid - case 0xAC: ABS LDY CYC(4) break; - case 0xAD: ABS LDA CYC(4) break; - case 0xAE: ABS LDX CYC(4) break; - case 0xAF: $ ABS LAX CYC(4) break; // invalid - case 0xB0: REL BCS CYC(2) break; - case 0xB1: idy LDA CYC(5) break; - case 0xB2: $ HLT CYC(2) break; - case 0xB3: $ idy LAX CYC(5) break; - case 0xB4: zpx LDY CYC(4) break; - case 0xB5: zpx LDA CYC(4) break; - case 0xB6: zpy LDX CYC(4) break; - case 0xB7: $ zpy LAX CYC(4) break; // invalid - case 0xB8: CLV CYC(2) break; - case 0xB9: aby LDA CYC(4) break; - case 0xBA: TSX CYC(2) break; - case 0xBB: $ aby LAS CYC(4) break; // invalid - case 0xBC: abx LDY CYC(4) break; - case 0xBD: abx LDA CYC(4) break; - case 0xBE: aby LDX CYC(4) break; - case 0xBF: $ aby LAX CYC(4) break; // invalid - case 0xC0: IMM CPY CYC(2) break; - case 0xC1: idx CMP CYC(6) break; - case 0xC2: $ IMM NOP CYC(2) break; - case 0xC3: $ idx DCM CYC(8) break; // invalid - case 0xC4: ZPG CPY CYC(3) break; - case 0xC5: ZPG CMP CYC(3) break; - case 0xC6: ZPG DECn CYC(5) break; - case 0xC7: $ ZPG DCM CYC(5) break; // invalid - case 0xC8: INY CYC(2) break; - case 0xC9: IMM CMP CYC(2) break; - case 0xCA: DEX CYC(2) break; - case 0xCB: $ IMM SAX CYC(2) break; // invalid - case 0xCC: ABS CPY CYC(4) break; - case 0xCD: ABS CMP CYC(4) break; - case 0xCE: ABS DECn CYC(5) break; - case 0xCF: $ ABS DCM CYC(6) break; // invalid - case 0xD0: REL BNE CYC(2) break; - case 0xD1: idy CMP CYC(5) break; - case 0xD2: $ HLT CYC(2) break; - case 0xD3: $ idy DCM CYC(8) break; // invalid - case 0xD4: $ zpx NOP CYC(4) break; - case 0xD5: zpx CMP CYC(4) break; - case 0xD6: zpx DECn CYC(6) break; - case 0xD7: $ zpx DCM CYC(6) break; // invalid - case 0xD8: CLD CYC(2) break; - case 0xD9: aby CMP CYC(4) break; - case 0xDA: $ NOP CYC(2) break; - case 0xDB: $ aby DCM CYC(7) break; // invalid - case 0xDC: $ abx NOP CYC(4) break; - case 0xDD: abx CMP CYC(4) break; - case 0xDE: abx DECn CYC(6) break; - case 0xDF: $ abx DCM CYC(7) break; // invalid - case 0xE0: IMM CPX CYC(2) break; - case 0xE1: idx SBCn CYC(6) break; - case 0xE2: $ IMM NOP CYC(2) break; - case 0xE3: $ idx INS CYC(8) break; // invalid - case 0xE4: ZPG CPX CYC(3) break; - case 0xE5: ZPG SBCn CYC(3) break; - case 0xE6: ZPG INCn CYC(5) break; - case 0xE7: $ ZPG INS CYC(5) break; // invalid - case 0xE8: INX CYC(2) break; - case 0xE9: IMM SBCn CYC(2) break; - case 0xEA: NOP CYC(2) break; - case 0xEB: $ IMM SBCn CYC(2) break; - case 0xEC: ABS CPX CYC(4) break; - case 0xED: ABS SBCn CYC(4) break; - case 0xEE: ABS INCn CYC(6) break; - case 0xEF: $ ABS INS CYC(6) break; // invalid - case 0xF0: REL BEQ CYC(2) break; - case 0xF1: idy SBCn CYC(5) break; - case 0xF2: $ HLT CYC(2) break; - case 0xF3: $ idy INS CYC(8) break; // invalid - case 0xF4: $ zpx NOP CYC(4) break; - case 0xF5: zpx SBCn CYC(4) break; - case 0xF6: zpx INCn CYC(6) break; - case 0xF7: $ zpx INS CYC(6) break; // invalid - case 0xF8: SED CYC(2) break; - case 0xF9: aby SBCn CYC(4) break; - case 0xFA: $ NOP CYC(2) break; - case 0xFB: $ aby INS CYC(7) break; - case 0xFC: $ abx NOP CYC(4) break; - case 0xFD: abx SBCn CYC(4) break; - case 0xFE: abx INCn CYC(6) break; - case 0xFF: $ abx INS CYC(7) break; - } + switch (iOpcode) + { + case 0x00: BRK CYC(7) break; + case 0x01: idx ORA CYC(6) break; + case 0x02: $ HLT CYC(2) break; + case 0x03: $ idx ASO CYC(8) break; + case 0x04: $ ZPG NOP CYC(3) break; + case 0x05: ZPG ORA CYC(3) break; + case 0x06: ZPG ASLn CYC(5) break; + case 0x07: $ ZPG ASO CYC(5) break; + case 0x08: PHP CYC(3) break; + case 0x09: IMM ORA CYC(2) break; + case 0x0A: asl CYC(2) break; + case 0x0B: $ IMM ANC CYC(2) break; + case 0x0C: $ ABSX_OPT NOP CYC(4) break; + case 0x0D: ABS ORA CYC(4) break; + case 0x0E: ABS ASLn CYC(6) break; + case 0x0F: $ ABS ASO CYC(6) break; + case 0x10: REL BPL CYC(2) break; + case 0x11: INDY_OPT ORA CYC(5) break; + case 0x12: $ HLT CYC(2) break; + case 0x13: $ INDY_CONST ASO CYC(8) break; + case 0x14: $ zpx NOP CYC(4) break; + case 0x15: zpx ORA CYC(4) break; + case 0x16: zpx ASLn CYC(6) break; + case 0x17: $ zpx ASO CYC(6) break; + case 0x18: CLC CYC(2) break; + case 0x19: ABSY_OPT ORA CYC(4) break; + case 0x1A: $ NOP CYC(2) break; + case 0x1B: $ ABSY_CONST ASO CYC(7) break; + case 0x1C: $ ABSX_OPT NOP CYC(4) break; + case 0x1D: ABSX_OPT ORA CYC(4) break; + case 0x1E: ABSX_CONST ASLn CYC(7) break; + case 0x1F: $ ABSX_CONST ASO CYC(7) break; + case 0x20: ABS JSR CYC(6) break; + case 0x21: idx AND CYC(6) break; + case 0x22: $ HLT CYC(2) break; + case 0x23: $ idx RLA CYC(8) break; + case 0x24: ZPG BIT CYC(3) break; + case 0x25: ZPG AND CYC(3) break; + case 0x26: ZPG ROLn CYC(5) break; + case 0x27: $ ZPG RLA CYC(5) break; + case 0x28: PLP CYC(4) break; + case 0x29: IMM AND CYC(2) break; + case 0x2A: rol CYC(2) break; + case 0x2B: $ IMM ANC CYC(2) break; + case 0x2C: ABS BIT CYC(4) break; + case 0x2D: ABS AND CYC(4) break; + case 0x2E: ABS ROLn CYC(6) break; + case 0x2F: $ ABS RLA CYC(6) break; + case 0x30: REL BMI CYC(2) break; + case 0x31: INDY_OPT AND CYC(5) break; + case 0x32: $ HLT CYC(2) break; + case 0x33: $ INDY_CONST RLA CYC(8) break; + case 0x34: $ zpx NOP CYC(4) break; + case 0x35: zpx AND CYC(4) break; + case 0x36: zpx ROLn CYC(6) break; + case 0x37: $ zpx RLA CYC(6) break; + case 0x38: SEC CYC(2) break; + case 0x39: ABSY_OPT AND CYC(4) break; + case 0x3A: $ NOP CYC(2) break; + case 0x3B: $ ABSY_CONST RLA CYC(7) break; + case 0x3C: $ ABSX_OPT NOP CYC(4) break; + case 0x3D: ABSX_OPT AND CYC(4) break; + case 0x3E: ABSX_CONST ROLn CYC(6) break; + case 0x3F: $ ABSX_CONST RLA CYC(7) break; + case 0x40: RTI CYC(6) DoIrqProfiling(uExecutedCycles); break; + case 0x41: idx EOR CYC(6) break; + case 0x42: $ HLT CYC(2) break; + case 0x43: $ idx LSE CYC(8) break; + case 0x44: $ ZPG NOP CYC(3) break; + case 0x45: ZPG EOR CYC(3) break; + case 0x46: ZPG LSRn CYC(5) break; + case 0x47: $ ZPG LSE CYC(5) break; + case 0x48: PHA CYC(3) break; + case 0x49: IMM EOR CYC(2) break; + case 0x4A: lsr CYC(2) break; + case 0x4B: $ IMM ALR CYC(2) break; + case 0x4C: ABS JMP CYC(3) break; + case 0x4D: ABS EOR CYC(4) break; + case 0x4E: ABS LSRn CYC(6) break; + case 0x4F: $ ABS LSE CYC(6) break; + case 0x50: REL BVC CYC(2) break; + case 0x51: INDY_OPT EOR CYC(5) break; + case 0x52: $ HLT CYC(2) break; + case 0x53: $ INDY_CONST LSE CYC(8) break; + case 0x54: $ zpx NOP CYC(4) break; + case 0x55: zpx EOR CYC(4) break; + case 0x56: zpx LSRn CYC(6) break; + case 0x57: $ zpx LSE CYC(6) break; + case 0x58: CLI CYC(2) break; + case 0x59: ABSY_OPT EOR CYC(4) break; + case 0x5A: $ NOP CYC(2) break; + case 0x5B: $ ABSY_CONST LSE CYC(7) break; + case 0x5C: $ ABSX_OPT NOP CYC(4) break; + case 0x5D: ABSX_OPT EOR CYC(4) break; + case 0x5E: ABSX_CONST LSRn CYC(6) break; + case 0x5F: $ ABSX_CONST LSE CYC(7) break; + case 0x60: RTS CYC(6) break; + case 0x61: idx ADCn CYC(6) break; + case 0x62: $ HLT CYC(2) break; + case 0x63: $ idx RRA CYC(8) break; + case 0x64: $ ZPG NOP CYC(3) break; + case 0x65: ZPG ADCn CYC(3) break; + case 0x66: ZPG RORn CYC(5) break; + case 0x67: $ ZPG RRA CYC(5) break; + case 0x68: PLA CYC(4) break; + case 0x69: IMM ADCn CYC(2) break; + case 0x6A: ror CYC(2) break; + case 0x6B: $ IMM ARR CYC(2) break; + case 0x6C: IABS_NMOS JMP CYC(5) break; // GH#264 + case 0x6D: ABS ADCn CYC(4) break; + case 0x6E: ABS RORn CYC(6) break; + case 0x6F: $ ABS RRA CYC(6) break; + case 0x70: REL BVS CYC(2) break; + case 0x71: INDY_OPT ADCn CYC(5) break; + case 0x72: $ HLT CYC(2) break; + case 0x73: $ INDY_CONST RRA CYC(8) break; + case 0x74: $ zpx NOP CYC(4) break; + case 0x75: zpx ADCn CYC(4) break; + case 0x76: zpx RORn CYC(6) break; + case 0x77: $ zpx RRA CYC(6) break; + case 0x78: SEI CYC(2) break; + case 0x79: ABSY_OPT ADCn CYC(4) break; + case 0x7A: $ NOP CYC(2) break; + case 0x7B: $ ABSY_CONST RRA CYC(7) break; + case 0x7C: $ ABSX_OPT NOP CYC(4) break; + case 0x7D: ABSX_OPT ADCn CYC(4) break; + case 0x7E: ABSX_CONST RORn CYC(6) break; + case 0x7F: $ ABSX_CONST RRA CYC(7) break; + case 0x80: $ IMM NOP CYC(2) break; + case 0x81: idx STA CYC(6) break; + case 0x82: $ IMM NOP CYC(2) break; + case 0x83: $ idx AXS CYC(6) break; + case 0x84: ZPG STY CYC(3) break; + case 0x85: ZPG STA CYC(3) break; + case 0x86: ZPG STX CYC(3) break; + case 0x87: $ ZPG AXS CYC(3) break; + case 0x88: DEY CYC(2) break; + case 0x89: $ IMM NOP CYC(2) break; + case 0x8A: TXA CYC(2) break; + case 0x8B: $ IMM XAA CYC(2) break; + case 0x8C: ABS STY CYC(4) break; + case 0x8D: ABS STA CYC(4) break; + case 0x8E: ABS STX CYC(4) break; + case 0x8F: $ ABS AXS CYC(4) break; + case 0x90: REL BCC CYC(2) break; + case 0x91: INDY_CONST STA CYC(6) break; + case 0x92: $ HLT CYC(2) break; + case 0x93: $ INDY_CONST AXA CYC(6) break; + case 0x94: zpx STY CYC(4) break; + case 0x95: zpx STA CYC(4) break; + case 0x96: zpy STX CYC(4) break; + case 0x97: $ zpy AXS CYC(4) break; + case 0x98: TYA CYC(2) break; + case 0x99: ABSY_CONST STA CYC(5) break; + case 0x9A: TXS CYC(2) break; + case 0x9B: $ ABSY_CONST TAS CYC(5) break; + case 0x9C: $ ABSX_CONST SAY CYC(5) break; + case 0x9D: ABSX_CONST STA CYC(5) break; + case 0x9E: $ ABSY_CONST XAS CYC(5) break; + case 0x9F: $ ABSY_CONST AXA CYC(5) break; + case 0xA0: IMM LDY CYC(2) break; + case 0xA1: idx LDA CYC(6) break; + case 0xA2: IMM LDX CYC(2) break; + case 0xA3: $ idx LAX CYC(6) break; + case 0xA4: ZPG LDY CYC(3) break; + case 0xA5: ZPG LDA CYC(3) break; + case 0xA6: ZPG LDX CYC(3) break; + case 0xA7: $ ZPG LAX CYC(3) break; + case 0xA8: TAY CYC(2) break; + case 0xA9: IMM LDA CYC(2) break; + case 0xAA: TAX CYC(2) break; + case 0xAB: $ IMM OAL CYC(2) break; + case 0xAC: ABS LDY CYC(4) break; + case 0xAD: ABS LDA CYC(4) break; + case 0xAE: ABS LDX CYC(4) break; + case 0xAF: $ ABS LAX CYC(4) break; + case 0xB0: REL BCS CYC(2) break; + case 0xB1: INDY_OPT LDA CYC(5) break; + case 0xB2: $ HLT CYC(2) break; + case 0xB3: $ INDY_OPT LAX CYC(5) break; + case 0xB4: zpx LDY CYC(4) break; + case 0xB5: zpx LDA CYC(4) break; + case 0xB6: zpy LDX CYC(4) break; + case 0xB7: $ zpy LAX CYC(4) break; + case 0xB8: CLV CYC(2) break; + case 0xB9: ABSY_OPT LDA CYC(4) break; + case 0xBA: TSX CYC(2) break; + case 0xBB: $ ABSY_OPT LAS CYC(4) break; + case 0xBC: ABSX_OPT LDY CYC(4) break; + case 0xBD: ABSX_OPT LDA CYC(4) break; + case 0xBE: ABSY_OPT LDX CYC(4) break; + case 0xBF: $ ABSY_OPT LAX CYC(4) break; + case 0xC0: IMM CPY CYC(2) break; + case 0xC1: idx CMP CYC(6) break; + case 0xC2: $ IMM NOP CYC(2) break; + case 0xC3: $ idx DCM CYC(8) break; + case 0xC4: ZPG CPY CYC(3) break; + case 0xC5: ZPG CMP CYC(3) break; + case 0xC6: ZPG DEC CYC(5) break; + case 0xC7: $ ZPG DCM CYC(5) break; + case 0xC8: INY CYC(2) break; + case 0xC9: IMM CMP CYC(2) break; + case 0xCA: DEX CYC(2) break; + case 0xCB: $ IMM SAX CYC(2) break; + case 0xCC: ABS CPY CYC(4) break; + case 0xCD: ABS CMP CYC(4) break; + case 0xCE: ABS DEC CYC(6) break; + case 0xCF: $ ABS DCM CYC(6) break; + case 0xD0: REL BNE CYC(2) break; + case 0xD1: INDY_OPT CMP CYC(5) break; + case 0xD2: $ HLT CYC(2) break; + case 0xD3: $ INDY_CONST DCM CYC(8) break; + case 0xD4: $ zpx NOP CYC(4) break; + case 0xD5: zpx CMP CYC(4) break; + case 0xD6: zpx DEC CYC(6) break; + case 0xD7: $ zpx DCM CYC(6) break; + case 0xD8: CLD CYC(2) break; + case 0xD9: ABSY_OPT CMP CYC(4) break; + case 0xDA: $ NOP CYC(2) break; + case 0xDB: $ ABSY_CONST DCM CYC(7) break; + case 0xDC: $ ABSX_OPT NOP CYC(4) break; + case 0xDD: ABSX_OPT CMP CYC(4) break; + case 0xDE: ABSX_CONST DEC CYC(7) break; + case 0xDF: $ ABSX_CONST DCM CYC(7) break; + case 0xE0: IMM CPX CYC(2) break; + case 0xE1: idx SBCn CYC(6) break; + case 0xE2: $ IMM NOP CYC(2) break; + case 0xE3: $ idx INS CYC(8) break; + case 0xE4: ZPG CPX CYC(3) break; + case 0xE5: ZPG SBCn CYC(3) break; + case 0xE6: ZPG INC CYC(5) break; + case 0xE7: $ ZPG INS CYC(5) break; + case 0xE8: INX CYC(2) break; + case 0xE9: IMM SBCn CYC(2) break; + case 0xEA: NOP CYC(2) break; + case 0xEB: $ IMM SBCn CYC(2) break; + case 0xEC: ABS CPX CYC(4) break; + case 0xED: ABS SBCn CYC(4) break; + case 0xEE: ABS INC CYC(6) break; + case 0xEF: $ ABS INS CYC(6) break; + case 0xF0: REL BEQ CYC(2) break; + case 0xF1: INDY_OPT SBCn CYC(5) break; + case 0xF2: $ HLT CYC(2) break; + case 0xF3: $ INDY_CONST INS CYC(8) break; + case 0xF4: $ zpx NOP CYC(4) break; + case 0xF5: zpx SBCn CYC(4) break; + case 0xF6: zpx INC CYC(6) break; + case 0xF7: $ zpx INS CYC(6) break; + case 0xF8: SED CYC(2) break; + case 0xF9: ABSY_OPT SBCn CYC(4) break; + case 0xFA: $ NOP CYC(2) break; + case 0xFB: $ ABSY_CONST INS CYC(7) break; + case 0xFC: $ ABSX_OPT NOP CYC(4) break; + case 0xFD: ABSX_OPT SBCn CYC(4) break; + case 0xFE: ABSX_CONST INC CYC(7) break; + case 0xFF: $ ABSX_CONST INS CYC(7) break; + } +#undef $ } // NTSC_BEGIN diff --git a/source/CPU/cpu65C02.h b/source/CPU/cpu65C02.h index a85e3c04..d9ad28c5 100644 --- a/source/CPU/cpu65C02.h +++ b/source/CPU/cpu65C02.h @@ -38,7 +38,6 @@ static DWORD Cpu65C02 (DWORD uTotalCycles) WORD val; AF_TO_EF ULONG uExecutedCycles = 0; - BOOL bSlowerOnPagecross = 0; // Set if opcode writes to memory (eg. ASL, STA) WORD base; g_bDebugBreakpointHit = 0; @@ -52,7 +51,7 @@ static DWORD Cpu65C02 (DWORD uTotalCycles) ULONG uPreviousCycles = uExecutedCycles; // NTSC_END - if (g_ActiveCPU == CPU_Z80) + if (GetActiveCpu() == CPU_Z80) { const UINT uZ80Cycles = z80_mainloop(uTotalCycles, uExecutedCycles); CYC(uZ80Cycles) } @@ -61,265 +60,265 @@ static DWORD Cpu65C02 (DWORD uTotalCycles) if (!Fetch(iOpcode, uExecutedCycles)) break; +#define $ INV // INV = Invalid -> Debugger Break switch (iOpcode) { -#define $ INV // INV = Invalid -> Debugger Break - case 0x00: BRK CYC(7) break; - case 0x01: idx ORA CYC(6) break; - case 0x02: $ IMM NOP CYC(2) break; - case 0x03: $ NOP CYC(2) break; - case 0x04: ZPG TSB CYC(5) break; - case 0x05: ZPG ORA CYC(3) break; - case 0x06: ZPG ASLc CYC(5) break; - case 0x07: $ NOP CYC(2) break; - case 0x08: PHP CYC(3) break; - case 0x09: IMM ORA CYC(2) break; - case 0x0A: asl CYC(2) break; - case 0x0B: $ NOP CYC(2) break; - case 0x0C: ABS TSB CYC(6) break; - case 0x0D: ABS ORA CYC(4) break; - case 0x0E: ABS ASLc CYC(6) break; - case 0x0F: $ NOP CYC(2) break; - case 0x10: REL BPL CYC(2) break; - case 0x11: idy ORA CYC(5) break; - case 0x12: izp ORA CYC(5) break; - case 0x13: $ NOP CYC(2) break; - case 0x14: ZPG TRB CYC(5) break; - case 0x15: zpx ORA CYC(4) break; - case 0x16: zpx ASLc CYC(6) break; - case 0x17: $ NOP CYC(2) break; - case 0x18: CLC CYC(2) break; - case 0x19: aby ORA CYC(4) break; - case 0x1A: INA CYC(2) break; - case 0x1B: $ NOP CYC(2) break; - case 0x1C: ABS TRB CYC(6) break; - case 0x1D: abx ORA CYC(4) break; - case 0x1E: abx ASLc CYC(6) break; - case 0x1F: $ NOP CYC(2) break; - case 0x20: ABS JSR CYC(6) break; - case 0x21: idx AND CYC(6) break; - case 0x22: $ IMM NOP CYC(2) break; - case 0x23: $ NOP CYC(2) break; - case 0x24: ZPG BIT CYC(3) break; - case 0x25: ZPG AND CYC(3) break; - case 0x26: ZPG ROLc CYC(5) break; - case 0x27: $ NOP CYC(2) break; - case 0x28: PLP CYC(4) break; - case 0x29: IMM AND CYC(2) break; - case 0x2A: rol CYC(2) break; - case 0x2B: $ NOP CYC(2) break; - case 0x2C: ABS BIT CYC(4) break; - case 0x2D: ABS AND CYC(2) break; - case 0x2E: ABS ROLc CYC(6) break; - case 0x2F: $ NOP CYC(2) break; - case 0x30: REL BMI CYC(2) break; - case 0x31: idy AND CYC(5) break; - case 0x32: izp AND CYC(5) break; - case 0x33: $ NOP CYC(2) break; - case 0x34: zpx BIT CYC(4) break; - case 0x35: zpx AND CYC(4) break; - case 0x36: zpx ROLc CYC(6) break; - case 0x37: $ NOP CYC(2) break; - case 0x38: SEC CYC(2) break; - case 0x39: aby AND CYC(4) break; - case 0x3A: DEA CYC(2) break; - case 0x3B: $ NOP CYC(2) break; - case 0x3C: abx BIT CYC(4) break; - case 0x3D: abx AND CYC(4) break; - case 0x3E: abx ROLc CYC(6) break; - case 0x3F: $ NOP CYC(2) break; - case 0x40: RTI CYC(6) DoIrqProfiling(uExecutedCycles); break; - case 0x41: idx EOR CYC(6) break; - case 0x42: $ IMM NOP CYC(2) break; - case 0x43: $ NOP CYC(2) break; - case 0x44: $ ZPG NOP CYC(3) break; - case 0x45: ZPG EOR CYC(3) break; - case 0x46: ZPG LSRc CYC(5) break; - case 0x47: $ NOP CYC(2) break; - case 0x48: PHA CYC(3) break; - case 0x49: IMM EOR CYC(2) break; - case 0x4A: lsr CYC(2) break; - case 0x4B: $ NOP CYC(2) break; - case 0x4C: ABS JMP CYC(3) break; - case 0x4D: ABS EOR CYC(4) break; - case 0x4E: ABS LSRc CYC(6) break; - case 0x4F: $ NOP CYC(2) break; - case 0x50: REL BVC CYC(2) break; - case 0x51: idy EOR CYC(5) break; - case 0x52: izp EOR CYC(5) break; - case 0x53: $ NOP CYC(2) break; - case 0x54: $ zpx NOP CYC(4) break; - case 0x55: zpx EOR CYC(4) break; - case 0x56: zpx LSRc CYC(6) break; - case 0x57: $ NOP CYC(2) break; - case 0x58: CLI CYC(2) break; - case 0x59: aby EOR CYC(4) break; - case 0x5A: PHY CYC(3) break; - case 0x5B: $ NOP CYC(2) break; - case 0x5C: $ abx NOP CYC(8) break; - case 0x5D: abx EOR CYC(4) break; - case 0x5E: abx LSRc CYC(6) break; - case 0x5F: $ NOP CYC(2) break; - case 0x60: RTS CYC(6) break; - case 0x61: idx ADCc CYC(6) break; - case 0x62: $ IMM NOP CYC(2) break; - case 0x63: $ NOP CYC(2) break; - case 0x64: ZPG STZ CYC(3) break; - case 0x65: ZPG ADCc CYC(3) break; - case 0x66: ZPG RORc CYC(5) break; - case 0x67: $ NOP CYC(2) break; - case 0x68: PLA CYC(4) break; - case 0x69: IMM ADCc CYC(2) break; - case 0x6A: ror CYC(2) break; - case 0x6B: $ NOP CYC(2) break; - case 0x6C: IABSCMOS JMP CYC(6) break; - case 0x6D: ABS ADCc CYC(4) break; - case 0x6E: ABS RORc CYC(6) break; - case 0x6F: $ NOP CYC(2) break; - case 0x70: REL BVS CYC(2) break; - case 0x71: idy ADCc CYC(5) break; - case 0x72: izp ADCc CYC(5) break; - case 0x73: $ NOP CYC(2) break; - case 0x74: zpx STZ CYC(4) break; - case 0x75: zpx ADCc CYC(4) break; - case 0x76: zpx RORc CYC(6) break; - case 0x77: $ NOP CYC(2) break; - case 0x78: SEI CYC(2) break; - case 0x79: aby ADCc CYC(4) break; - case 0x7A: PLY CYC(4) break; - case 0x7B: $ NOP CYC(2) break; - case 0x7C: IABSX JMP CYC(6) break; // - case 0x7D: abx ADCc CYC(4) break; - case 0x7E: abx RORc CYC(6) break; - case 0x7F: $ NOP CYC(2) break; - case 0x80: REL BRA CYC(2) break; - case 0x81: idx STA CYC(6) break; - case 0x82: $ IMM NOP CYC(2) break; - case 0x83: $ NOP CYC(2) break; - case 0x84: ZPG STY CYC(3) break; - case 0x85: ZPG STA CYC(3) break; - case 0x86: ZPG STX CYC(3) break; - case 0x87: $ NOP CYC(2) break; - case 0x88: DEY CYC(2) break; - case 0x89: IMM BITI CYC(2) break; - case 0x8A: TXA CYC(2) break; - case 0x8B: $ NOP CYC(2) break; - case 0x8C: ABS STY CYC(4) break; - case 0x8D: ABS STA CYC(4) break; - case 0x8E: ABS STX CYC(4) break; - case 0x8F: $ NOP CYC(2) break; - case 0x90: REL BCC CYC(2) break; - case 0x91: idy STA CYC(6) break; - case 0x92: izp STA CYC(5) break; - case 0x93: $ NOP CYC(2) break; - case 0x94: zpx STY CYC(4) break; - case 0x95: zpx STA CYC(4) break; - case 0x96: zpy STX CYC(4) break; - case 0x97: $ NOP CYC(2) break; - case 0x98: TYA CYC(2) break; - case 0x99: aby STA CYC(5) break; - case 0x9A: TXS CYC(2) break; - case 0x9B: $ NOP CYC(2) break; - case 0x9C: ABS STZ CYC(4) break; - case 0x9D: abx STA CYC(5) break; - case 0x9E: abx STZ CYC(5) break; - case 0x9F: $ NOP CYC(2) break; - case 0xA0: IMM LDY CYC(2) break; - case 0xA1: idx LDA CYC(6) break; - case 0xA2: IMM LDX CYC(2) break; - case 0xA3: $ NOP CYC(2) break; - case 0xA4: ZPG LDY CYC(3) break; - case 0xA5: ZPG LDA CYC(3) break; - case 0xA6: ZPG LDX CYC(3) break; - case 0xA7: $ NOP CYC(2) break; - case 0xA8: TAY CYC(2) break; - case 0xA9: IMM LDA CYC(2) break; - case 0xAA: TAX CYC(2) break; - case 0xAB: $ NOP CYC(2) break; - case 0xAC: ABS LDY CYC(4) break; - case 0xAD: ABS LDA CYC(4) break; - case 0xAE: ABS LDX CYC(4) break; - case 0xAF: $ NOP CYC(2) break; - case 0xB0: REL BCS CYC(2) break; - case 0xB1: idy LDA CYC(5) break; - case 0xB2: izp LDA CYC(5) break; - case 0xB3: $ NOP CYC(2) break; - case 0xB4: zpx LDY CYC(4) break; - case 0xB5: zpx LDA CYC(4) break; - case 0xB6: zpy LDX CYC(4) break; - case 0xB7: $ NOP CYC(2) break; - case 0xB8: CLV CYC(2) break; - case 0xB9: aby LDA CYC(4) break; - case 0xBA: TSX CYC(2) break; - case 0xBB: $ NOP CYC(2) break; - case 0xBC: abx LDY CYC(4) break; - case 0xBD: abx LDA CYC(4) break; - case 0xBE: aby LDX CYC(4) break; - case 0xBF: $ NOP CYC(2) break; - case 0xC0: IMM CPY CYC(2) break; - case 0xC1: idx CMP CYC(6) break; - case 0xC2: $ IMM NOP CYC(2) break; - case 0xC3: $ NOP CYC(2) break; - case 0xC4: ZPG CPY CYC(3) break; - case 0xC5: ZPG CMP CYC(3) break; - case 0xC6: ZPG DECc CYC(5) break; - case 0xC7: $ NOP CYC(2) break; - case 0xC8: INY CYC(2) break; - case 0xC9: IMM CMP CYC(2) break; - case 0xCA: DEX CYC(2) break; - case 0xCB: $ NOP CYC(2) break; - case 0xCC: ABS CPY CYC(4) break; - case 0xCD: ABS CMP CYC(4) break; - case 0xCE: ABS DECc CYC(5) break; - case 0xCF: $ NOP CYC(2) break; - case 0xD0: REL BNE CYC(2) break; - case 0xD1: idy CMP CYC(5) break; - case 0xD2: izp CMP CYC(5) break; - case 0xD3: $ NOP CYC(2) break; - case 0xD4: $ zpx NOP CYC(4) break; - case 0xD5: zpx CMP CYC(4) break; - case 0xD6: zpx DECc CYC(6) break; - case 0xD7: $ NOP CYC(2) break; - case 0xD8: CLD CYC(2) break; - case 0xD9: aby CMP CYC(4) break; - case 0xDA: PHX CYC(3) break; - case 0xDB: $ NOP CYC(2) break; - case 0xDC: $ abx NOP CYC(4) break; - case 0xDD: abx CMP CYC(4) break; - case 0xDE: abx DECc CYC(6) break; - case 0xDF: $ NOP CYC(2) break; - case 0xE0: IMM CPX CYC(2) break; - case 0xE1: idx SBCc CYC(6) break; - case 0xE2: $ IMM NOP CYC(2) break; - case 0xE3: $ NOP CYC(2) break; - case 0xE4: ZPG CPX CYC(3) break; - case 0xE5: ZPG SBCc CYC(3) break; - case 0xE6: ZPG INCc CYC(5) break; - case 0xE7: $ NOP CYC(2) break; - case 0xE8: INX CYC(2) break; - case 0xE9: IMM SBCc CYC(2) break; - case 0xEA: NOP CYC(2) break; - case 0xEB: $ NOP CYC(2) break; - case 0xEC: ABS CPX CYC(4) break; - case 0xED: ABS SBCc CYC(4) break; - case 0xEE: ABS INCc CYC(6) break; - case 0xEF: $ NOP CYC(2) break; - case 0xF0: REL BEQ CYC(2) break; - case 0xF1: idy SBCc CYC(5) break; - case 0xF2: izp SBCc CYC(5) break; - case 0xF3: $ NOP CYC(2) break; - case 0xF4: $ zpx NOP CYC(4) break; - case 0xF5: zpx SBCc CYC(4) break; - case 0xF6: zpx INCc CYC(6) break; - case 0xF7: $ NOP CYC(2) break; - case 0xF8: SED CYC(2) break; - case 0xF9: aby SBCc CYC(4) break; - case 0xFA: PLX CYC(4) break; - case 0xFB: $ NOP CYC(2) break; - case 0xFC: $ abx NOP CYC(4) break; - case 0xFD: abx SBCc CYC(4) break; - case 0xFE: abx INCc CYC(6) break; - case 0xFF: $ NOP CYC(2) break; + case 0x00: BRK CYC(7) break; + case 0x01: idx ORA CYC(6) break; + case 0x02: $ IMM NOP CYC(2) break; + case 0x03: $ NOP CYC(1) break; + case 0x04: ZPG TSB CYC(5) break; + case 0x05: ZPG ORA CYC(3) break; + case 0x06: ZPG ASLc CYC(5) break; + case 0x07: $ NOP CYC(1) break; + case 0x08: PHP CYC(3) break; + case 0x09: IMM ORA CYC(2) break; + case 0x0A: asl CYC(2) break; + case 0x0B: $ NOP CYC(1) break; + case 0x0C: ABS TSB CYC(6) break; + case 0x0D: ABS ORA CYC(4) break; + case 0x0E: ABS ASLc CYC(6) break; + case 0x0F: $ NOP CYC(1) break; + case 0x10: REL BPL CYC(2) break; + case 0x11: INDY_OPT ORA CYC(5) break; + case 0x12: izp ORA CYC(5) break; + case 0x13: $ NOP CYC(1) break; + case 0x14: ZPG TRB CYC(5) break; + case 0x15: zpx ORA CYC(4) break; + case 0x16: zpx ASLc CYC(6) break; + case 0x17: $ NOP CYC(1) break; + case 0x18: CLC CYC(2) break; + case 0x19: ABSY_OPT ORA CYC(4) break; + case 0x1A: INA CYC(2) break; + case 0x1B: $ NOP CYC(1) break; + case 0x1C: ABS TRB CYC(6) break; + case 0x1D: ABSX_OPT ORA CYC(4) break; + case 0x1E: ABSX_OPT ASLc CYC(6) break; + case 0x1F: $ NOP CYC(1) break; + case 0x20: ABS JSR CYC(6) break; + case 0x21: idx AND CYC(6) break; + case 0x22: $ IMM NOP CYC(2) break; + case 0x23: $ NOP CYC(1) break; + case 0x24: ZPG BIT CYC(3) break; + case 0x25: ZPG AND CYC(3) break; + case 0x26: ZPG ROLc CYC(5) break; + case 0x27: $ NOP CYC(1) break; + case 0x28: PLP CYC(4) break; + case 0x29: IMM AND CYC(2) break; + case 0x2A: rol CYC(2) break; + case 0x2B: $ NOP CYC(1) break; + case 0x2C: ABS BIT CYC(4) break; + case 0x2D: ABS AND CYC(4) break; + case 0x2E: ABS ROLc CYC(6) break; + case 0x2F: $ NOP CYC(1) break; + case 0x30: REL BMI CYC(2) break; + case 0x31: INDY_OPT AND CYC(5) break; + case 0x32: izp AND CYC(5) break; + case 0x33: $ NOP CYC(1) break; + case 0x34: zpx BIT CYC(4) break; + case 0x35: zpx AND CYC(4) break; + case 0x36: zpx ROLc CYC(6) break; + case 0x37: $ NOP CYC(1) break; + case 0x38: SEC CYC(2) break; + case 0x39: ABSY_OPT AND CYC(4) break; + case 0x3A: DEA CYC(2) break; + case 0x3B: $ NOP CYC(1) break; + case 0x3C: ABSX_OPT BIT CYC(4) break; + case 0x3D: ABSX_OPT AND CYC(4) break; + case 0x3E: ABSX_OPT ROLc CYC(6) break; + case 0x3F: $ NOP CYC(1) break; + case 0x40: RTI CYC(6) DoIrqProfiling(uExecutedCycles); break; + case 0x41: idx EOR CYC(6) break; + case 0x42: $ IMM NOP CYC(2) break; + case 0x43: $ NOP CYC(1) break; + case 0x44: $ ZPG NOP CYC(3) break; + case 0x45: ZPG EOR CYC(3) break; + case 0x46: ZPG LSRc CYC(5) break; + case 0x47: $ NOP CYC(1) break; + case 0x48: PHA CYC(3) break; + case 0x49: IMM EOR CYC(2) break; + case 0x4A: lsr CYC(2) break; + case 0x4B: $ NOP CYC(1) break; + case 0x4C: ABS JMP CYC(3) break; + case 0x4D: ABS EOR CYC(4) break; + case 0x4E: ABS LSRc CYC(6) break; + case 0x4F: $ NOP CYC(1) break; + case 0x50: REL BVC CYC(2) break; + case 0x51: INDY_OPT EOR CYC(5) break; + case 0x52: izp EOR CYC(5) break; + case 0x53: $ NOP CYC(1) break; + case 0x54: $ zpx NOP CYC(4) break; + case 0x55: zpx EOR CYC(4) break; + case 0x56: zpx LSRc CYC(6) break; + case 0x57: $ NOP CYC(1) break; + case 0x58: CLI CYC(2) break; + case 0x59: ABSY_OPT EOR CYC(4) break; + case 0x5A: PHY CYC(3) break; + case 0x5B: $ NOP CYC(1) break; + case 0x5C: $ ABS NOP CYC(8) break; + case 0x5D: ABSX_OPT EOR CYC(4) break; + case 0x5E: ABSX_OPT LSRc CYC(6) break; + case 0x5F: $ NOP CYC(1) break; + case 0x60: RTS CYC(6) break; + case 0x61: idx ADCc CYC(6) break; + case 0x62: $ IMM NOP CYC(2) break; + case 0x63: $ NOP CYC(1) break; + case 0x64: ZPG STZ CYC(3) break; + case 0x65: ZPG ADCc CYC(3) break; + case 0x66: ZPG RORc CYC(5) break; + case 0x67: $ NOP CYC(1) break; + case 0x68: PLA CYC(4) break; + case 0x69: IMM ADCc CYC(2) break; + case 0x6A: ror CYC(2) break; + case 0x6B: $ NOP CYC(1) break; + case 0x6C: IABS_CMOS JMP CYC(6) break; + case 0x6D: ABS ADCc CYC(4) break; + case 0x6E: ABS RORc CYC(6) break; + case 0x6F: $ NOP CYC(1) break; + case 0x70: REL BVS CYC(2) break; + case 0x71: INDY_OPT ADCc CYC(5) break; + case 0x72: izp ADCc CYC(5) break; + case 0x73: $ NOP CYC(1) break; + case 0x74: zpx STZ CYC(4) break; + case 0x75: zpx ADCc CYC(4) break; + case 0x76: zpx RORc CYC(6) break; + case 0x77: $ NOP CYC(1) break; + case 0x78: SEI CYC(2) break; + case 0x79: ABSY_OPT ADCc CYC(4) break; + case 0x7A: PLY CYC(4) break; + case 0x7B: $ NOP CYC(1) break; + case 0x7C: IABSX JMP CYC(6) break; + case 0x7D: ABSX_OPT ADCc CYC(4) break; + case 0x7E: ABSX_OPT RORc CYC(6) break; + case 0x7F: $ NOP CYC(1) break; + case 0x80: REL BRA CYC(2) break; + case 0x81: idx STA CYC(6) break; + case 0x82: $ IMM NOP CYC(2) break; + case 0x83: $ NOP CYC(1) break; + case 0x84: ZPG STY CYC(3) break; + case 0x85: ZPG STA CYC(3) break; + case 0x86: ZPG STX CYC(3) break; + case 0x87: $ NOP CYC(1) break; + case 0x88: DEY CYC(2) break; + case 0x89: IMM BITI CYC(2) break; + case 0x8A: TXA CYC(2) break; + case 0x8B: $ NOP CYC(1) break; + case 0x8C: ABS STY CYC(4) break; + case 0x8D: ABS STA CYC(4) break; + case 0x8E: ABS STX CYC(4) break; + case 0x8F: $ NOP CYC(1) break; + case 0x90: REL BCC CYC(2) break; + case 0x91: INDY_CONST STA CYC(6) break; + case 0x92: izp STA CYC(5) break; + case 0x93: $ NOP CYC(1) break; + case 0x94: zpx STY CYC(4) break; + case 0x95: zpx STA CYC(4) break; + case 0x96: zpy STX CYC(4) break; + case 0x97: $ NOP CYC(1) break; + case 0x98: TYA CYC(2) break; + case 0x99: ABSY_CONST STA CYC(5) break; + case 0x9A: TXS CYC(2) break; + case 0x9B: $ NOP CYC(1) break; + case 0x9C: ABS STZ CYC(4) break; + case 0x9D: ABSX_CONST STA CYC(5) break; + case 0x9E: ABSX_CONST STZ CYC(5) break; + case 0x9F: $ NOP CYC(1) break; + case 0xA0: IMM LDY CYC(2) break; + case 0xA1: idx LDA CYC(6) break; + case 0xA2: IMM LDX CYC(2) break; + case 0xA3: $ NOP CYC(1) break; + case 0xA4: ZPG LDY CYC(3) break; + case 0xA5: ZPG LDA CYC(3) break; + case 0xA6: ZPG LDX CYC(3) break; + case 0xA7: $ NOP CYC(1) break; + case 0xA8: TAY CYC(2) break; + case 0xA9: IMM LDA CYC(2) break; + case 0xAA: TAX CYC(2) break; + case 0xAB: $ NOP CYC(1) break; + case 0xAC: ABS LDY CYC(4) break; + case 0xAD: ABS LDA CYC(4) break; + case 0xAE: ABS LDX CYC(4) break; + case 0xAF: $ NOP CYC(1) break; + case 0xB0: REL BCS CYC(2) break; + case 0xB1: INDY_OPT LDA CYC(5) break; + case 0xB2: izp LDA CYC(5) break; + case 0xB3: $ NOP CYC(1) break; + case 0xB4: zpx LDY CYC(4) break; + case 0xB5: zpx LDA CYC(4) break; + case 0xB6: zpy LDX CYC(4) break; + case 0xB7: $ NOP CYC(1) break; + case 0xB8: CLV CYC(2) break; + case 0xB9: ABSY_OPT LDA CYC(4) break; + case 0xBA: TSX CYC(2) break; + case 0xBB: $ NOP CYC(1) break; + case 0xBC: ABSX_OPT LDY CYC(4) break; + case 0xBD: ABSX_OPT LDA CYC(4) break; + case 0xBE: ABSY_OPT LDX CYC(4) break; + case 0xBF: $ NOP CYC(1) break; + case 0xC0: IMM CPY CYC(2) break; + case 0xC1: idx CMP CYC(6) break; + case 0xC2: $ IMM NOP CYC(2) break; + case 0xC3: $ NOP CYC(1) break; + case 0xC4: ZPG CPY CYC(3) break; + case 0xC5: ZPG CMP CYC(3) break; + case 0xC6: ZPG DEC CYC(5) break; + case 0xC7: $ NOP CYC(1) break; + case 0xC8: INY CYC(2) break; + case 0xC9: IMM CMP CYC(2) break; + case 0xCA: DEX CYC(2) break; + case 0xCB: $ NOP CYC(1) break; + case 0xCC: ABS CPY CYC(4) break; + case 0xCD: ABS CMP CYC(4) break; + case 0xCE: ABS DEC CYC(6) break; + case 0xCF: $ NOP CYC(1) break; + case 0xD0: REL BNE CYC(2) break; + case 0xD1: INDY_OPT CMP CYC(5) break; + case 0xD2: izp CMP CYC(5) break; + case 0xD3: $ NOP CYC(1) break; + case 0xD4: $ zpx NOP CYC(4) break; + case 0xD5: zpx CMP CYC(4) break; + case 0xD6: zpx DEC CYC(6) break; + case 0xD7: $ NOP CYC(1) break; + case 0xD8: CLD CYC(2) break; + case 0xD9: ABSY_OPT CMP CYC(4) break; + case 0xDA: PHX CYC(3) break; + case 0xDB: $ NOP CYC(1) break; + case 0xDC: $ ABS LDD CYC(4) break; + case 0xDD: ABSX_OPT CMP CYC(4) break; + case 0xDE: ABSX_CONST DEC CYC(7) break; + case 0xDF: $ NOP CYC(1) break; + case 0xE0: IMM CPX CYC(2) break; + case 0xE1: idx SBCc CYC(6) break; + case 0xE2: $ IMM NOP CYC(2) break; + case 0xE3: $ NOP CYC(1) break; + case 0xE4: ZPG CPX CYC(3) break; + case 0xE5: ZPG SBCc CYC(3) break; + case 0xE6: ZPG INC CYC(5) break; + case 0xE7: $ NOP CYC(1) break; + case 0xE8: INX CYC(2) break; + case 0xE9: IMM SBCc CYC(2) break; + case 0xEA: NOP CYC(2) break; + case 0xEB: $ NOP CYC(1) break; + case 0xEC: ABS CPX CYC(4) break; + case 0xED: ABS SBCc CYC(4) break; + case 0xEE: ABS INC CYC(6) break; + case 0xEF: $ NOP CYC(1) break; + case 0xF0: REL BEQ CYC(2) break; + case 0xF1: INDY_OPT SBCc CYC(5) break; + case 0xF2: izp SBCc CYC(5) break; + case 0xF3: $ NOP CYC(1) break; + case 0xF4: $ zpx NOP CYC(4) break; + case 0xF5: zpx SBCc CYC(4) break; + case 0xF6: zpx INC CYC(6) break; + case 0xF7: $ NOP CYC(1) break; + case 0xF8: SED CYC(2) break; + case 0xF9: ABSY_OPT SBCc CYC(4) break; + case 0xFA: PLX CYC(4) break; + case 0xFB: $ NOP CYC(1) break; + case 0xFC: $ ABS LDD CYC(4) break; + case 0xFD: ABSX_OPT SBCc CYC(4) break; + case 0xFE: ABSX_CONST INC CYC(7) break; + case 0xFF: $ NOP CYC(1) break; } #undef $ } diff --git a/source/CPU/cpu65d02.h b/source/CPU/cpu65d02.h index bd55a933..7c3d34ed 100644 --- a/source/CPU/cpu65d02.h +++ b/source/CPU/cpu65d02.h @@ -18,8 +18,8 @@ along with AppleWin; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -typedef unsigned char u8; -typedef unsigned short u16; +typedef unsigned char u8; // TODO: change to uint8_t +typedef unsigned short u16; // TODO: change to uint16_t // return (x < 255) ? (x+1) : 255; inline u8 IncClamp8( u8 x ) @@ -37,43 +37,58 @@ inline u8 DecClamp8( u8 x ) return r; } +// TODO: Verify: RGBA or BGRA (.bmp format) // 0 A n/a // 1 B Exec // 2 G Read // 3 R Write -// RGBA r= write, g = read, b = pc -int g_aMemoryAccess[ 65536 ]; -u8 *g_pRead = 0; -u8 *g_pWrite = 0; -u8 *g_pExeec = 0; +// +// 0xAARRGGBB +// [0] B Exec +// [1] G Load +// [2] R Store +// [3] A n/a +// RGBA r = write, g = read, b = Program Counter +const int HEATMAP_W_MASK = 0x00FF0000; // Red Store +const int HEATMAP_R_MASK = 0x0000FF00; // Green Load +const int HEATMAP_X_MASK = 0x000000FF; // Blue Exec + + +// This is a memory heatmap +// FF = accessed on this clock cycle +// FE = accessed 1 clock cycles ago +// FD = accessed 2 clock cycles ago +// etc. +// Displayed as 256x256 64K memory access +int g_aMemoryHeatmap[ 65536 ]; // TODO: Change to int32_t + +#define HEATMAP_W(addr) g_aMemoryHeatmap[ addr ] |= HEATMAP_W_MASK +#define HEATMAP_R(addr) g_aMemoryHeatmap[ addr ] |= HEATMAP_R_MASK +#define HEATMAP_X(addr) g_aMemoryHeatmap[ addr ] |= HEATMAP_X_MASK #undef READ #define READ ReadByte( addr, uExecutedCycles ) inline u8 ReadByte( u16 addr, int uExecutedCycles ) { - (u8*) g_pRead = ((u8*)g_aMemoryAccess) + (addr * 4) + 3; - *g_pRead = IncClamp8( *g_pRead ); + // TODO: We should have a single g_bDebuggerActive so we can have a single implementation across ][+ //e + HEATMAP_R(addr); - return - ( \ - ((addr & 0xF000) == 0xC000) \ - ? IORead[(addr>>4) & 0xFF](regs.pc,addr,0,0,uExecutedCycles) \ - : *(mem+addr) \ - ); + return ((addr & 0xF000) == 0xC000) + ? IORead[(addr>>4) & 0xFF](regs.pc,addr,0,0,uExecutedCycles) + : *(mem+addr); } -#undef WRITE -#define WRITE(a) \ - (u8*) g_pWrite = ((u8*)g_aMemoryAccess) + (addr * 4) + 0; \ - *g_pWrite = DecClamp8( *g_pWrite ); \ - { \ - memdirty[addr >> 8] = 0xFF; \ - LPBYTE page = memwrite[addr >> 8]; \ - if (page) \ - *(page+(addr & 0xFF)) = (BYTE)(a); \ - else if ((addr & 0xF000) == 0xC000) \ - IOWrite[(addr>>4) & 0xFF](regs.pc,addr,1,(BYTE)(a),uExecutedCycles); \ +#undef WRITE +#define WRITE(a) \ + HEATMAP_W(addr); \ + { \ + memdirty[addr >> 8] = 0xFF; \ + LPBYTE page = memwrite[addr >> 8]; \ + if (page) \ + *(page+(addr & 0xFF)) = (BYTE)(a); \ + else if ((addr & 0xF000) == 0xC000) \ + IOWrite[(addr>>4) & 0xFF](regs.pc,addr,1,(BYTE)(a),uExecutedCycles); \ } #include "cpu/cpu_instructions.inl" @@ -97,7 +112,6 @@ static DWORD Cpu65D02 (DWORD uTotalCycles) WORD val; AF_TO_EF ULONG uExecutedCycles = 0; - BOOL bSlowerOnPagecross = 0; // Set if opcode writes to memory (eg. ASL, STA) WORD base; g_bDebugBreakpointHit = 0; @@ -111,12 +125,14 @@ static DWORD Cpu65D02 (DWORD uTotalCycles) ULONG uPreviousCycles = uExecutedCycles; // NTSC_END - if (g_ActiveCPU == CPU_Z80) + if (GetActiveCpu() == CPU_Z80) { const UINT uZ80Cycles = z80_mainloop(uTotalCycles, uExecutedCycles); CYC(uZ80Cycles) } else + HEATMAP_X( regs.pc ); + if (!Fetch(iOpcode, uExecutedCycles)) break; @@ -131,525 +147,264 @@ static DWORD Cpu65D02 (DWORD uTotalCycles) { // TODO Optimization Note: ?? Move CYC(#) to array ?? -// Version 1 opcode: INV AM Instruction // Form1: INV=DebugBreak AM=AddressingMode -// INV Instruction // Form2: -//! ! ! ! ! ! // Tab-Stops -/* - case 0x00: BRK CYC(7) break; - case 0x01: idx ORA CYC(6) break; - case 0x02: INV IMM NOP CYC(2) break; - case 0x03: INV NOP CYC(2) break; - case 0x04: ZPG TSB CYC(5) break; - case 0x05: ZPG ORA CYC(3) break; - case 0x06: ZPG ASL_CMOS CYC(5) break; - case 0x07: INV NOP CYC(2) break; - case 0x08: PHP CYC(3) break; - case 0x09: IMM ORA CYC(2) break; - case 0x0A: asl CYC(2) break; - case 0x0B: INV NOP CYC(2) break; - case 0x0C: ABS TSB CYC(6) break; - case 0x0D: ABS ORA CYC(4) break; - case 0x0E: ABS ASL_CMOS CYC(6) break; - case 0x0F: INV NOP CYC(2) break; - case 0x10: REL BPL CYC(2) break; - case 0x11: idy ORA CYC(5) break; - case 0x12: izp ORA CYC(5) break; - case 0x13: INV NOP CYC(2) break; - case 0x14: ZPG TRB CYC(5) break; - case 0x15: zpx ORA CYC(4) break; - case 0x16: zpx ASL_CMOS CYC(6) break; - case 0x17: INV NOP CYC(2) break; - case 0x18: CLC CYC(2) break; - case 0x19: aby ORA CYC(4) break; - case 0x1A: INA CYC(2) break; - case 0x1B: INV NOP CYC(2) break; - case 0x1C: ABS TRB CYC(6) break; - case 0x1D: abx ORA CYC(4) break; - case 0x1E: abx ASL_CMOS CYC(6) break; - case 0x1F: INV NOP CYC(2) break; - case 0x20: ABS JSR CYC(6) break; - case 0x21: idx AND CYC(6) break; - case 0x22: INV IMM NOP CYC(2) break; - case 0x23: INV NOP CYC(2) break; - case 0x24: ZPG BIT CYC(3) break; - case 0x25: ZPG AND CYC(3) break; - case 0x26: ZPG ROL_CMOS CYC(5) break; - case 0x27: INV NOP CYC(2) break; - case 0x28: PLP CYC(4) break; - case 0x29: IMM AND CYC(2) break; - case 0x2A: rol CYC(2) break; - case 0x2B: INV NOP CYC(2) break; - case 0x2C: ABS BIT CYC(4) break; - case 0x2D: ABS AND CYC(2) break; - case 0x2E: ABS ROL_CMOS CYC(6) break; - case 0x2F: INV NOP CYC(2) break; - case 0x30: REL BMI CYC(2) break; - case 0x31: idy AND CYC(5) break; - case 0x32: izp AND CYC(5) break; - case 0x33: INV NOP CYC(2) break; - case 0x34: zpx BIT CYC(4) break; - case 0x35: zpx AND CYC(4) break; - case 0x36: zpx ROL_CMOS CYC(6) break; - case 0x37: INV NOP CYC(2) break; - case 0x38: SEC CYC(2) break; - case 0x39: aby AND CYC(4) break; - case 0x3A: DEA CYC(2) break; - case 0x3B: INV NOP CYC(2) break; - case 0x3C: abx BIT CYC(4) break; - case 0x3D: abx AND CYC(4) break; - case 0x3E: abx ROL_CMOS CYC(6) break; - case 0x3F: INV NOP CYC(2) break; - case 0x40: RTI CYC(6) DoIrqProfiling(uExecutedCycles); break; - case 0x41: idx EOR CYC(6) break; - case 0x42: INV IMM NOP CYC(2) break; - case 0x43: INV NOP CYC(2) break; - case 0x44: INV ZPG NOP CYC(3) break; - case 0x45: ZPG EOR CYC(3) break; - case 0x46: ZPG LSR_CMOS CYC(5) break; - case 0x47: INV NOP CYC(2) break; - case 0x48: PHA CYC(3) break; - case 0x49: IMM EOR CYC(2) break; - case 0x4A: lsr CYC(2) break; - case 0x4B: INV NOP CYC(2) break; - case 0x4C: ABS JMP CYC(3) break; - case 0x4D: ABS EOR CYC(4) break; - case 0x4E: ABS LSR_CMOS CYC(6) break; - case 0x4F: INV NOP CYC(2) break; - case 0x50: REL BVC CYC(2) break; - case 0x51: idy EOR CYC(5) break; - case 0x52: izp EOR CYC(5) break; - case 0x53: INV NOP CYC(2) break; - case 0x54: INV zpx NOP CYC(4) break; - case 0x55: zpx EOR CYC(4) break; - case 0x56: zpx LSR_CMOS CYC(6) break; - case 0x57: INV NOP CYC(2) break; - case 0x58: CLI CYC(2) break; - case 0x59: aby EOR CYC(4) break; - case 0x5A: PHY CYC(3) break; - case 0x5B: INV NOP CYC(2) break; - case 0x5C: INV abx NOP CYC(8) break; - case 0x5D: abx EOR CYC(4) break; - case 0x5E: abx LSR_CMOS CYC(6) break; - case 0x5F: INV NOP CYC(2) break; - case 0x60: RTS CYC(6) break; - case 0x61: idx ADC_CMOS CYC(6) break; - case 0x62: INV IMM NOP CYC(2) break; - case 0x63: INV NOP CYC(2) break; - case 0x64: ZPG STZ CYC(3) break; - case 0x65: ZPG ADC_CMOS CYC(3) break; - case 0x66: ZPG ROR_CMOS CYC(5) break; - case 0x67: INV NOP CYC(2) break; - case 0x68: PLA CYC(4) break; - case 0x69: IMM ADC_CMOS CYC(2) break; - case 0x6A: ror CYC(2) break; - case 0x6B: INV NOP CYC(2) break; - case 0x6C: IABSCMOS JMP CYC(6) break; // 0x6C // 65c02 IABSCMOS JMP // 6502 IABSNMOS JMP - case 0x6D: ABS ADC_CMOS CYC(4) break; - case 0x6E: ABS ROR_CMOS CYC(6) break; - case 0x6F: INV NOP CYC(2) break; - case 0x70: REL BVS CYC(2) break; - case 0x71: idy ADC_CMOS CYC(5) break; - case 0x72: izp ADC_CMOS CYC(5) break; - case 0x73: INV NOP CYC(2) break; - case 0x74: zpx STZ CYC(4) break; - case 0x75: zpx ADC_CMOS CYC(4) break; - case 0x76: zpx ROR_CMOS CYC(6) break; - case 0x77: INV NOP CYC(2) break; - case 0x78: SEI CYC(2) break; - case 0x79: aby ADC_CMOS CYC(4) break; - case 0x7A: PLY CYC(4) break; - case 0x7B: INV NOP CYC(2) break; - case 0x7C: IABSX JMP CYC(6) break; // 0x7C // 65c02 IABSX JMP // 6502 ABSX NOP - case 0x7D: abx ADC_CMOS CYC(4) break; - case 0x7E: abx ROR_CMOS CYC(6) break; - case 0x7F: INV NOP CYC(2) break; - case 0x80: REL BRA CYC(2) break; - case 0x81: idx STA CYC(6) break; - case 0x82: INV IMM NOP CYC(2) break; - case 0x83: INV NOP CYC(2) break; - case 0x84: ZPG STY CYC(3) break; - case 0x85: ZPG STA CYC(3) break; - case 0x86: ZPG STX CYC(3) break; - case 0x87: INV NOP CYC(2) break; - case 0x88: DEY CYC(2) break; - case 0x89: IMM BITI CYC(2) break; - case 0x8A: TXA CYC(2) break; - case 0x8B: INV NOP CYC(2) break; - case 0x8C: ABS STY CYC(4) break; - case 0x8D: ABS STA CYC(4) break; - case 0x8E: ABS STX CYC(4) break; - case 0x8F: INV NOP CYC(2) break; - case 0x90: REL BCC CYC(2) break; - case 0x91: idy STA CYC(6) break; - case 0x92: izp STA CYC(5) break; - case 0x93: INV NOP CYC(2) break; - case 0x94: zpx STY CYC(4) break; - case 0x95: zpx STA CYC(4) break; - case 0x96: zpy STX CYC(4) break; - case 0x97: INV NOP CYC(2) break; - case 0x98: TYA CYC(2) break; - case 0x99: aby STA CYC(5) break; - case 0x9A: TXS CYC(2) break; - case 0x9B: INV NOP CYC(2) break; - case 0x9C: ABS STZ CYC(4) break; - case 0x9D: abx STA CYC(5) break; - case 0x9E: abx STZ CYC(5) break; - case 0x9F: INV NOP CYC(2) break; - case 0xA0: IMM LDY CYC(2) break; - case 0xA1: idx LDA CYC(6) break; - case 0xA2: IMM LDX CYC(2) break; - case 0xA3: INV NOP CYC(2) break; - case 0xA4: ZPG LDY CYC(3) break; - case 0xA5: ZPG LDA CYC(3) break; - case 0xA6: ZPG LDX CYC(3) break; - case 0xA7: INV NOP CYC(2) break; - case 0xA8: TAY CYC(2) break; - case 0xA9: IMM LDA CYC(2) break; - case 0xAA: TAX CYC(2) break; - case 0xAB: INV NOP CYC(2) break; - case 0xAC: ABS LDY CYC(4) break; - case 0xAD: ABS LDA CYC(4) break; - case 0xAE: ABS LDX CYC(4) break; - case 0xAF: INV NOP CYC(2) break; - case 0xB0: REL BCS CYC(2) break; - case 0xB1: idy LDA CYC(5) break; - case 0xB2: izp LDA CYC(5) break; - case 0xB3: INV NOP CYC(2) break; - case 0xB4: zpx LDY CYC(4) break; - case 0xB5: zpx LDA CYC(4) break; - case 0xB6: zpy LDX CYC(4) break; - case 0xB7: INV NOP CYC(2) break; - case 0xB8: CLV CYC(2) break; - case 0xB9: aby LDA CYC(4) break; - case 0xBA: TSX CYC(2) break; - case 0xBB: INV NOP CYC(2) break; - case 0xBC: abx LDY CYC(4) break; - case 0xBD: abx LDA CYC(4) break; - case 0xBE: aby LDX CYC(4) break; - case 0xBF: INV NOP CYC(2) break; - case 0xC0: IMM CPY CYC(2) break; - case 0xC1: idx CMP CYC(6) break; - case 0xC2: INV IMM NOP CYC(2) break; - case 0xC3: INV NOP CYC(2) break; - case 0xC4: ZPG CPY CYC(3) break; - case 0xC5: ZPG CMP CYC(3) break; - case 0xC6: ZPG DEC_CMOS CYC(5) break; - case 0xC7: INV NOP CYC(2) break; - case 0xC8: INY CYC(2) break; - case 0xC9: IMM CMP CYC(2) break; - case 0xCA: DEX CYC(2) break; - case 0xCB: INV NOP CYC(2) break; - case 0xCC: ABS CPY CYC(4) break; - case 0xCD: ABS CMP CYC(4) break; - case 0xCE: ABS DEC_CMOS CYC(5) break; - case 0xCF: INV NOP CYC(2) break; - case 0xD0: REL BNE CYC(2) break; - case 0xD1: idy CMP CYC(5) break; - case 0xD2: izp CMP CYC(5) break; - case 0xD3: INV NOP CYC(2) break; - case 0xD4: INV zpx NOP CYC(4) break; - case 0xD5: zpx CMP CYC(4) break; - case 0xD6: zpx DEC_CMOS CYC(6) break; - case 0xD7: INV NOP CYC(2) break; - case 0xD8: CLD CYC(2) break; - case 0xD9: aby CMP CYC(4) break; - case 0xDA: PHX CYC(3) break; - case 0xDB: INV NOP CYC(2) break; - case 0xDC: INV abx NOP CYC(4) break; - case 0xDD: abx CMP CYC(4) break; - case 0xDE: abx DEC_CMOS CYC(6) break; - case 0xDF: INV NOP CYC(2) break; - case 0xE0: IMM CPX CYC(2) break; - case 0xE1: idx SBC_CMOS CYC(6) break; - case 0xE2: INV IMM NOP CYC(2) break; - case 0xE3: INV NOP CYC(2) break; - case 0xE4: ZPG CPX CYC(3) break; - case 0xE5: ZPG SBC_CMOS CYC(3) break; - case 0xE6: ZPG INC_CMOS CYC(5) break; - case 0xE7: INV NOP CYC(2) break; - case 0xE8: INX CYC(2) break; - case 0xE9: IMM SBC_CMOS CYC(2) break; - case 0xEA: NOP CYC(2) break; - case 0xEB: INV NOP CYC(2) break; - case 0xEC: ABS CPX CYC(4) break; - case 0xED: ABS SBC_CMOS CYC(4) break; - case 0xEE: ABS INC_CMOS CYC(6) break; - case 0xEF: INV NOP CYC(2) break; - case 0xF0: REL BEQ CYC(2) break; - case 0xF1: idy SBC_CMOS CYC(5) break; - case 0xF2: izp SBC_CMOS CYC(5) break; - case 0xF3: INV NOP CYC(2) break; - case 0xF4: INV zpx NOP CYC(4) break; - case 0xF5: zpx SBC_CMOS CYC(4) break; - case 0xF6: zpx INC_CMOS CYC(6) break; - case 0xF7: INV NOP CYC(2) break; - case 0xF8: SED CYC(2) break; - case 0xF9: aby SBC_CMOS CYC(4) break; - case 0xFA: PLX CYC(4) break; - case 0xFB: INV NOP CYC(2) break; - case 0xFC: INV abx NOP CYC(4) break; - case 0xFD: abx SBC_CMOS CYC(4) break; - case 0xFE: abx INC_CMOS CYC(6) break; - case 0xFF: INV NOP CYC(2) break; -*/ -// Version 2 opcode: $ AM Instruction // $=DebugBreak AM=AddressingMode -//! ! ! ! ! ! // Tab-Stops - case 0x00: BRK CYC(7) break; - case 0x01: idx ORA CYC(6) break; - case 0x02: $ IMM NOP CYC(2) break; - case 0x03: $ NOP CYC(2) break; - case 0x04: ZPG TSB CYC(5) break; - case 0x05: ZPG ORA CYC(3) break; - case 0x06: ZPG ASLc CYC(5) break; - case 0x07: $ NOP CYC(2) break; - case 0x08: PHP CYC(3) break; - case 0x09: IMM ORA CYC(2) break; - case 0x0A: asl CYC(2) break; - case 0x0B: $ NOP CYC(2) break; - case 0x0C: ABS TSB CYC(6) break; - case 0x0D: ABS ORA CYC(4) break; - case 0x0E: ABS ASLc CYC(6) break; - case 0x0F: $ NOP CYC(2) break; - case 0x10: REL BPL CYC(2) break; - case 0x11: idy ORA CYC(5) break; - case 0x12: izp ORA CYC(5) break; - case 0x13: $ NOP CYC(2) break; - case 0x14: ZPG TRB CYC(5) break; - case 0x15: zpx ORA CYC(4) break; - case 0x16: zpx ASLc CYC(6) break; - case 0x17: $ NOP CYC(2) break; - case 0x18: CLC CYC(2) break; - case 0x19: aby ORA CYC(4) break; - case 0x1A: INA CYC(2) break; - case 0x1B: $ NOP CYC(2) break; - case 0x1C: ABS TRB CYC(6) break; - case 0x1D: abx ORA CYC(4) break; - case 0x1E: abx ASLc CYC(6) break; - case 0x1F: $ NOP CYC(2) break; - case 0x20: ABS JSR CYC(6) break; - case 0x21: idx AND CYC(6) break; - case 0x22: $ IMM NOP CYC(2) break; - case 0x23: $ NOP CYC(2) break; - case 0x24: ZPG BIT CYC(3) break; - case 0x25: ZPG AND CYC(3) break; - case 0x26: ZPG ROLc CYC(5) break; - case 0x27: $ NOP CYC(2) break; - case 0x28: PLP CYC(4) break; - case 0x29: IMM AND CYC(2) break; - case 0x2A: rol CYC(2) break; - case 0x2B: $ NOP CYC(2) break; - case 0x2C: ABS BIT CYC(4) break; - case 0x2D: ABS AND CYC(2) break; - case 0x2E: ABS ROLc CYC(6) break; - case 0x2F: $ NOP CYC(2) break; - case 0x30: REL BMI CYC(2) break; - case 0x31: idy AND CYC(5) break; - case 0x32: izp AND CYC(5) break; - case 0x33: $ NOP CYC(2) break; - case 0x34: zpx BIT CYC(4) break; - case 0x35: zpx AND CYC(4) break; - case 0x36: zpx ROLc CYC(6) break; - case 0x37: $ NOP CYC(2) break; - case 0x38: SEC CYC(2) break; - case 0x39: aby AND CYC(4) break; - case 0x3A: DEA CYC(2) break; - case 0x3B: $ NOP CYC(2) break; - case 0x3C: abx BIT CYC(4) break; - case 0x3D: abx AND CYC(4) break; - case 0x3E: abx ROLc CYC(6) break; - case 0x3F: $ NOP CYC(2) break; - case 0x40: RTI CYC(6) DoIrqProfiling(uExecutedCycles); break; - case 0x41: idx EOR CYC(6) break; - case 0x42: $ IMM NOP CYC(2) break; - case 0x43: $ NOP CYC(2) break; - case 0x44: $ ZPG NOP CYC(3) break; - case 0x45: ZPG EOR CYC(3) break; - case 0x46: ZPG LSRc CYC(5) break; - case 0x47: $ NOP CYC(2) break; - case 0x48: PHA CYC(3) break; - case 0x49: IMM EOR CYC(2) break; - case 0x4A: lsr CYC(2) break; - case 0x4B: $ NOP CYC(2) break; - case 0x4C: ABS JMP CYC(3) break; - case 0x4D: ABS EOR CYC(4) break; - case 0x4E: ABS LSRc CYC(6) break; - case 0x4F: $ NOP CYC(2) break; - case 0x50: REL BVC CYC(2) break; - case 0x51: idy EOR CYC(5) break; - case 0x52: izp EOR CYC(5) break; - case 0x53: $ NOP CYC(2) break; - case 0x54: $ zpx NOP CYC(4) break; - case 0x55: zpx EOR CYC(4) break; - case 0x56: zpx LSRc CYC(6) break; - case 0x57: $ NOP CYC(2) break; - case 0x58: CLI CYC(2) break; - case 0x59: aby EOR CYC(4) break; - case 0x5A: PHY CYC(3) break; - case 0x5B: $ NOP CYC(2) break; - case 0x5C: $ abx NOP CYC(8) break; - case 0x5D: abx EOR CYC(4) break; - case 0x5E: abx LSRc CYC(6) break; - case 0x5F: $ NOP CYC(2) break; - case 0x60: RTS CYC(6) break; - case 0x61: idx ADCc CYC(6) break; - case 0x62: $ IMM NOP CYC(2) break; - case 0x63: $ NOP CYC(2) break; - case 0x64: ZPG STZ CYC(3) break; - case 0x65: ZPG ADCc CYC(3) break; - case 0x66: ZPG RORc CYC(5) break; - case 0x67: $ NOP CYC(2) break; - case 0x68: PLA CYC(4) break; - case 0x69: IMM ADCc CYC(2) break; - case 0x6A: ror CYC(2) break; - case 0x6B: $ NOP CYC(2) break; - case 0x6C: IABSCMOS JMP CYC(6) break; // 0x6C // 65c02 IABSCMOS JMP // 6502 IABSNMOS JMP - case 0x6D: ABS ADCc CYC(4) break; - case 0x6E: ABS RORc CYC(6) break; - case 0x6F: $ NOP CYC(2) break; - case 0x70: REL BVS CYC(2) break; - case 0x71: idy ADCc CYC(5) break; - case 0x72: izp ADCc CYC(5) break; - case 0x73: $ NOP CYC(2) break; - case 0x74: zpx STZ CYC(4) break; - case 0x75: zpx ADCc CYC(4) break; - case 0x76: zpx RORc CYC(6) break; - case 0x77: $ NOP CYC(2) break; - case 0x78: SEI CYC(2) break; - case 0x79: aby ADCc CYC(4) break; - case 0x7A: PLY CYC(4) break; - case 0x7B: $ NOP CYC(2) break; - case 0x7C: IABSX JMP CYC(6) break; // 0x7C // 65c02 IABSX JMP // 6502 ABSX NOP - case 0x7D: abx ADCc CYC(4) break; - case 0x7E: abx RORc CYC(6) break; - case 0x7F: $ NOP CYC(2) break; - case 0x80: REL BRA CYC(2) break; - case 0x81: idx STA CYC(6) break; - case 0x82: $ IMM NOP CYC(2) break; - case 0x83: $ NOP CYC(2) break; - case 0x84: ZPG STY CYC(3) break; - case 0x85: ZPG STA CYC(3) break; - case 0x86: ZPG STX CYC(3) break; - case 0x87: $ NOP CYC(2) break; - case 0x88: DEY CYC(2) break; - case 0x89: IMM BITI CYC(2) break; - case 0x8A: TXA CYC(2) break; - case 0x8B: $ NOP CYC(2) break; - case 0x8C: ABS STY CYC(4) break; - case 0x8D: ABS STA CYC(4) break; - case 0x8E: ABS STX CYC(4) break; - case 0x8F: $ NOP CYC(2) break; - case 0x90: REL BCC CYC(2) break; - case 0x91: idy STA CYC(6) break; - case 0x92: izp STA CYC(5) break; - case 0x93: $ NOP CYC(2) break; - case 0x94: zpx STY CYC(4) break; - case 0x95: zpx STA CYC(4) break; - case 0x96: zpy STX CYC(4) break; - case 0x97: $ NOP CYC(2) break; - case 0x98: TYA CYC(2) break; - case 0x99: aby STA CYC(5) break; - case 0x9A: TXS CYC(2) break; - case 0x9B: $ NOP CYC(2) break; - case 0x9C: ABS STZ CYC(4) break; - case 0x9D: abx STA CYC(5) break; - case 0x9E: abx STZ CYC(5) break; - case 0x9F: $ NOP CYC(2) break; - case 0xA0: IMM LDY CYC(2) break; - case 0xA1: idx LDA CYC(6) break; - case 0xA2: IMM LDX CYC(2) break; - case 0xA3: $ NOP CYC(2) break; - case 0xA4: ZPG LDY CYC(3) break; - case 0xA5: ZPG LDA CYC(3) break; - case 0xA6: ZPG LDX CYC(3) break; - case 0xA7: $ NOP CYC(2) break; - case 0xA8: TAY CYC(2) break; - case 0xA9: IMM LDA CYC(2) break; - case 0xAA: TAX CYC(2) break; - case 0xAB: $ NOP CYC(2) break; - case 0xAC: ABS LDY CYC(4) break; - case 0xAD: ABS LDA CYC(4) break; - case 0xAE: ABS LDX CYC(4) break; - case 0xAF: $ NOP CYC(2) break; - case 0xB0: REL BCS CYC(2) break; - case 0xB1: idy LDA CYC(5) break; - case 0xB2: izp LDA CYC(5) break; - case 0xB3: $ NOP CYC(2) break; - case 0xB4: zpx LDY CYC(4) break; - case 0xB5: zpx LDA CYC(4) break; - case 0xB6: zpy LDX CYC(4) break; - case 0xB7: $ NOP CYC(2) break; - case 0xB8: CLV CYC(2) break; - case 0xB9: aby LDA CYC(4) break; - case 0xBA: TSX CYC(2) break; - case 0xBB: $ NOP CYC(2) break; - case 0xBC: abx LDY CYC(4) break; - case 0xBD: abx LDA CYC(4) break; - case 0xBE: aby LDX CYC(4) break; - case 0xBF: $ NOP CYC(2) break; - case 0xC0: IMM CPY CYC(2) break; - case 0xC1: idx CMP CYC(6) break; - case 0xC2: $ IMM NOP CYC(2) break; - case 0xC3: $ NOP CYC(2) break; - case 0xC4: ZPG CPY CYC(3) break; - case 0xC5: ZPG CMP CYC(3) break; - case 0xC6: ZPG DECc CYC(5) break; - case 0xC7: $ NOP CYC(2) break; - case 0xC8: INY CYC(2) break; - case 0xC9: IMM CMP CYC(2) break; - case 0xCA: DEX CYC(2) break; - case 0xCB: $ NOP CYC(2) break; - case 0xCC: ABS CPY CYC(4) break; - case 0xCD: ABS CMP CYC(4) break; - case 0xCE: ABS DECc CYC(5) break; - case 0xCF: $ NOP CYC(2) break; - case 0xD0: REL BNE CYC(2) break; - case 0xD1: idy CMP CYC(5) break; - case 0xD2: izp CMP CYC(5) break; - case 0xD3: $ NOP CYC(2) break; - case 0xD4: $ zpx NOP CYC(4) break; - case 0xD5: zpx CMP CYC(4) break; - case 0xD6: zpx DECc CYC(6) break; - case 0xD7: $ NOP CYC(2) break; - case 0xD8: CLD CYC(2) break; - case 0xD9: aby CMP CYC(4) break; - case 0xDA: PHX CYC(3) break; - case 0xDB: $ NOP CYC(2) break; - case 0xDC: $ abx NOP CYC(4) break; - case 0xDD: abx CMP CYC(4) break; - case 0xDE: abx DECc CYC(6) break; - case 0xDF: $ NOP CYC(2) break; - case 0xE0: IMM CPX CYC(2) break; - case 0xE1: idx SBCc CYC(6) break; - case 0xE2: $ IMM NOP CYC(2) break; - case 0xE3: $ NOP CYC(2) break; - case 0xE4: ZPG CPX CYC(3) break; - case 0xE5: ZPG SBCc CYC(3) break; - case 0xE6: ZPG INCc CYC(5) break; - case 0xE7: $ NOP CYC(2) break; - case 0xE8: INX CYC(2) break; - case 0xE9: IMM SBCc CYC(2) break; - case 0xEA: NOP CYC(2) break; - case 0xEB: $ NOP CYC(2) break; - case 0xEC: ABS CPX CYC(4) break; - case 0xED: ABS SBCc CYC(4) break; - case 0xEE: ABS INCc CYC(6) break; - case 0xEF: $ NOP CYC(2) break; - case 0xF0: REL BEQ CYC(2) break; - case 0xF1: idy SBCc CYC(5) break; - case 0xF2: izp SBCc CYC(5) break; - case 0xF3: $ NOP CYC(2) break; - case 0xF4: $ zpx NOP CYC(4) break; - case 0xF5: zpx SBCc CYC(4) break; - case 0xF6: zpx INCc CYC(6) break; - case 0xF7: $ NOP CYC(2) break; - case 0xF8: SED CYC(2) break; - case 0xF9: aby SBCc CYC(4) break; - case 0xFA: PLX CYC(4) break; - case 0xFB: $ NOP CYC(2) break; - case 0xFC: $ abx NOP CYC(4) break; - case 0xFD: abx SBCc CYC(4) break; - case 0xFE: abx INCc CYC(6) break; - case 0xFF: $ NOP CYC(2) break; +// Version 2 opcode: $ AM Instruction // $=DebugBreak AM=AddressingMode +//! ! ! ! ! ! // Tab-Stops + case 0x00: BRK CYC(7) break; + case 0x01: idx ORA CYC(6) break; + case 0x02: $ IMM NOP CYC(2) break; + case 0x03: $ NOP CYC(2) break; + case 0x04: ZPG TSB CYC(5) break; + case 0x05: ZPG ORA CYC(3) break; + case 0x06: ZPG ASLc CYC(5) break; + case 0x07: $ NOP CYC(2) break; + case 0x08: PHP CYC(3) break; + case 0x09: IMM ORA CYC(2) break; + case 0x0A: asl CYC(2) break; + case 0x0B: $ NOP CYC(2) break; + case 0x0C: ABS TSB CYC(6) break; + case 0x0D: ABS ORA CYC(4) break; + case 0x0E: ABS ASLc CYC(6) break; + case 0x0F: $ NOP CYC(2) break; + case 0x10: REL BPL CYC(2) break; + case 0x11: INDY_OPT ORA CYC(5) break; + case 0x12: izp ORA CYC(5) break; + case 0x13: $ NOP CYC(2) break; + case 0x14: ZPG TRB CYC(5) break; + case 0x15: zpx ORA CYC(4) break; + case 0x16: zpx ASLc CYC(6) break; + case 0x17: $ NOP CYC(2) break; + case 0x18: CLC CYC(2) break; + case 0x19: ABSY_OPT ORA CYC(4) break; + case 0x1A: INA CYC(2) break; + case 0x1B: $ NOP CYC(2) break; + case 0x1C: ABS TRB CYC(6) break; + case 0x1D: ABSX_OPT ORA CYC(4) break; + case 0x1E: ABSX_OPT ASLc CYC(6) break; + case 0x1F: $ NOP CYC(2) break; + case 0x20: ABS JSR CYC(6) break; + case 0x21: idx AND CYC(6) break; + case 0x22: $ IMM NOP CYC(2) break; + case 0x23: $ NOP CYC(2) break; + case 0x24: ZPG BIT CYC(3) break; + case 0x25: ZPG AND CYC(3) break; + case 0x26: ZPG ROLc CYC(5) break; + case 0x27: $ NOP CYC(2) break; + case 0x28: PLP CYC(4) break; + case 0x29: IMM AND CYC(2) break; + case 0x2A: rol CYC(2) break; + case 0x2B: $ NOP CYC(2) break; + case 0x2C: ABS BIT CYC(4) break; + case 0x2D: ABS AND CYC(2) break; + case 0x2E: ABS ROLc CYC(6) break; + case 0x2F: $ NOP CYC(2) break; + case 0x30: REL BMI CYC(2) break; + case 0x31: INDY_OPT AND CYC(5) break; + case 0x32: izp AND CYC(5) break; + case 0x33: $ NOP CYC(2) break; + case 0x34: zpx BIT CYC(4) break; + case 0x35: zpx AND CYC(4) break; + case 0x36: zpx ROLc CYC(6) break; + case 0x37: $ NOP CYC(2) break; + case 0x38: SEC CYC(2) break; + case 0x39: ABSY_OPT AND CYC(4) break; + case 0x3A: DEA CYC(2) break; + case 0x3B: $ NOP CYC(2) break; + case 0x3C: ABSX_OPT BIT CYC(4) break; + case 0x3D: ABSX_OPT AND CYC(4) break; + case 0x3E: ABSX_OPT ROLc CYC(6) break; + case 0x3F: $ NOP CYC(2) break; + case 0x40: RTI CYC(6) DoIrqProfiling(uExecutedCycles); break; + case 0x41: idx EOR CYC(6) break; + case 0x42: $ IMM NOP CYC(2) break; + case 0x43: $ NOP CYC(2) break; + case 0x44: $ ZPG NOP CYC(3) break; + case 0x45: ZPG EOR CYC(3) break; + case 0x46: ZPG LSRc CYC(5) break; + case 0x47: $ NOP CYC(2) break; + case 0x48: PHA CYC(3) break; + case 0x49: IMM EOR CYC(2) break; + case 0x4A: lsr CYC(2) break; + case 0x4B: $ NOP CYC(2) break; + case 0x4C: ABS JMP CYC(3) break; + case 0x4D: ABS EOR CYC(4) break; + case 0x4E: ABS LSRc CYC(6) break; + case 0x4F: $ NOP CYC(2) break; + case 0x50: REL BVC CYC(2) break; + case 0x51: INDY_OPT EOR CYC(5) break; + case 0x52: izp EOR CYC(5) break; + case 0x53: $ NOP CYC(2) break; + case 0x54: $ zpx NOP CYC(4) break; + case 0x55: zpx EOR CYC(4) break; + case 0x56: zpx LSRc CYC(6) break; + case 0x57: $ NOP CYC(2) break; + case 0x58: CLI CYC(2) break; + case 0x59: ABSY_OPT EOR CYC(4) break; + case 0x5A: PHY CYC(3) break; + case 0x5B: $ NOP CYC(2) break; + case 0x5C: $ ABSX_OPT NOP CYC(8) break; + case 0x5D: ABSX_OPT EOR CYC(4) break; + case 0x5E: ABSX_OPT LSRc CYC(6) break; + case 0x5F: $ NOP CYC(2) break; + case 0x60: RTS CYC(6) break; + case 0x61: idx ADCc CYC(6) break; + case 0x62: $ IMM NOP CYC(2) break; + case 0x63: $ NOP CYC(2) break; + case 0x64: ZPG STZ CYC(3) break; + case 0x65: ZPG ADCc CYC(3) break; + case 0x66: ZPG RORc CYC(5) break; + case 0x67: $ NOP CYC(2) break; + case 0x68: PLA CYC(4) break; + case 0x69: IMM ADCc CYC(2) break; + case 0x6A: ror CYC(2) break; + case 0x6B: $ NOP CYC(2) break; + case 0x6C: IABS_CMOS JMP CYC(6) break; + case 0x6D: ABS ADCc CYC(4) break; + case 0x6E: ABS RORc CYC(6) break; + case 0x6F: $ NOP CYC(2) break; + case 0x70: REL BVS CYC(2) break; + case 0x71: INDY_OPT ADCc CYC(5) break; + case 0x72: izp ADCc CYC(5) break; + case 0x73: $ NOP CYC(2) break; + case 0x74: zpx STZ CYC(4) break; + case 0x75: zpx ADCc CYC(4) break; + case 0x76: zpx RORc CYC(6) break; + case 0x77: $ NOP CYC(2) break; + case 0x78: SEI CYC(2) break; + case 0x79: ABSY_OPT ADCc CYC(4) break; + case 0x7A: PLY CYC(4) break; + case 0x7B: $ NOP CYC(2) break; + case 0x7C: IABSX JMP CYC(6) break; + case 0x7D: ABSX_OPT ADCc CYC(4) break; + case 0x7E: ABSX_OPT RORc CYC(6) break; + case 0x7F: $ NOP CYC(2) break; + case 0x80: REL BRA CYC(2) break; + case 0x81: idx STA CYC(6) break; + case 0x82: $ IMM NOP CYC(2) break; + case 0x83: $ NOP CYC(2) break; + case 0x84: ZPG STY CYC(3) break; + case 0x85: ZPG STA CYC(3) break; + case 0x86: ZPG STX CYC(3) break; + case 0x87: $ NOP CYC(2) break; + case 0x88: DEY CYC(2) break; + case 0x89: IMM BITI CYC(2) break; + case 0x8A: TXA CYC(2) break; + case 0x8B: $ NOP CYC(2) break; + case 0x8C: ABS STY CYC(4) break; + case 0x8D: ABS STA CYC(4) break; + case 0x8E: ABS STX CYC(4) break; + case 0x8F: $ NOP CYC(2) break; + case 0x90: REL BCC CYC(2) break; + case 0x91: INDY_CONST STA CYC(6) break; + case 0x92: izp STA CYC(5) break; + case 0x93: $ NOP CYC(2) break; + case 0x94: zpx STY CYC(4) break; + case 0x95: zpx STA CYC(4) break; + case 0x96: zpy STX CYC(4) break; + case 0x97: $ NOP CYC(2) break; + case 0x98: TYA CYC(2) break; + case 0x99: ABSY_CONST STA CYC(5) break; + case 0x9A: TXS CYC(2) break; + case 0x9B: $ NOP CYC(2) break; + case 0x9C: ABS STZ CYC(4) break; + case 0x9D: ABSX_CONST STA CYC(5) break; + case 0x9E: ABSX_CONST STZ CYC(5) break; + case 0x9F: $ NOP CYC(2) break; + case 0xA0: IMM LDY CYC(2) break; + case 0xA1: idx LDA CYC(6) break; + case 0xA2: IMM LDX CYC(2) break; + case 0xA3: $ NOP CYC(2) break; + case 0xA4: ZPG LDY CYC(3) break; + case 0xA5: ZPG LDA CYC(3) break; + case 0xA6: ZPG LDX CYC(3) break; + case 0xA7: $ NOP CYC(2) break; + case 0xA8: TAY CYC(2) break; + case 0xA9: IMM LDA CYC(2) break; + case 0xAA: TAX CYC(2) break; + case 0xAB: $ NOP CYC(2) break; + case 0xAC: ABS LDY CYC(4) break; + case 0xAD: ABS LDA CYC(4) break; + case 0xAE: ABS LDX CYC(4) break; + case 0xAF: $ NOP CYC(2) break; + case 0xB0: REL BCS CYC(2) break; + case 0xB1: INDY_OPT LDA CYC(5) break; + case 0xB2: izp LDA CYC(5) break; + case 0xB3: $ NOP CYC(2) break; + case 0xB4: zpx LDY CYC(4) break; + case 0xB5: zpx LDA CYC(4) break; + case 0xB6: zpy LDX CYC(4) break; + case 0xB7: $ NOP CYC(2) break; + case 0xB8: CLV CYC(2) break; + case 0xB9: ABSY_OPT LDA CYC(4) break; + case 0xBA: TSX CYC(2) break; + case 0xBB: $ NOP CYC(2) break; + case 0xBC: ABSX_OPT LDY CYC(4) break; + case 0xBD: ABSX_OPT LDA CYC(4) break; + case 0xBE: ABSY_OPT LDX CYC(4) break; + case 0xBF: $ NOP CYC(2) break; + case 0xC0: IMM CPY CYC(2) break; + case 0xC1: idx CMP CYC(6) break; + case 0xC2: $ IMM NOP CYC(2) break; + case 0xC3: $ NOP CYC(2) break; + case 0xC4: ZPG CPY CYC(3) break; + case 0xC5: ZPG CMP CYC(3) break; + case 0xC6: ZPG DEC CYC(5) break; + case 0xC7: $ NOP CYC(2) break; + case 0xC8: INY CYC(2) break; + case 0xC9: IMM CMP CYC(2) break; + case 0xCA: DEX CYC(2) break; + case 0xCB: $ NOP CYC(2) break; + case 0xCC: ABS CPY CYC(4) break; + case 0xCD: ABS CMP CYC(4) break; + case 0xCE: ABS DEC CYC(6) break; + case 0xCF: $ NOP CYC(2) break; + case 0xD0: REL BNE CYC(2) break; + case 0xD1: INDY_OPT CMP CYC(5) break; + case 0xD2: izp CMP CYC(5) break; + case 0xD3: $ NOP CYC(2) break; + case 0xD4: $ zpx NOP CYC(4) break; + case 0xD5: zpx CMP CYC(4) break; + case 0xD6: zpx DEC CYC(6) break; + case 0xD7: $ NOP CYC(2) break; + case 0xD8: CLD CYC(2) break; + case 0xD9: ABSY_OPT CMP CYC(4) break; + case 0xDA: PHX CYC(3) break; + case 0xDB: $ NOP CYC(2) break; + case 0xDC: $ ABSX_OPT NOP CYC(4) break; + case 0xDD: ABSX_OPT CMP CYC(4) break; + case 0xDE: ABSX_CONST DEC CYC(7) break; + case 0xDF: $ NOP CYC(2) break; + case 0xE0: IMM CPX CYC(2) break; + case 0xE1: idx SBCc CYC(6) break; + case 0xE2: $ IMM NOP CYC(2) break; + case 0xE3: $ NOP CYC(2) break; + case 0xE4: ZPG CPX CYC(3) break; + case 0xE5: ZPG SBCc CYC(3) break; + case 0xE6: ZPG INC CYC(5) break; + case 0xE7: $ NOP CYC(2) break; + case 0xE8: INX CYC(2) break; + case 0xE9: IMM SBCc CYC(2) break; + case 0xEA: NOP CYC(2) break; + case 0xEB: $ NOP CYC(2) break; + case 0xEC: ABS CPX CYC(4) break; + case 0xED: ABS SBCc CYC(4) break; + case 0xEE: ABS INC CYC(6) break; + case 0xEF: $ NOP CYC(2) break; + case 0xF0: REL BEQ CYC(2) break; + case 0xF1: INDY_OPT SBCc CYC(5) break; + case 0xF2: izp SBCc CYC(5) break; + case 0xF3: $ NOP CYC(2) break; + case 0xF4: $ zpx NOP CYC(4) break; + case 0xF5: zpx SBCc CYC(4) break; + case 0xF6: zpx INC CYC(6) break; + case 0xF7: $ NOP CYC(2) break; + case 0xF8: SED CYC(2) break; + case 0xF9: ABSY_OPT SBCc CYC(4) break; + case 0xFA: PLX CYC(4) break; + case 0xFB: $ NOP CYC(2) break; + case 0xFC: $ ABSX_OPT NOP CYC(4) break; + case 0xFD: ABSX_OPT SBCc CYC(4) break; + case 0xFE: ABSX_CONST INC CYC(7) break; + case 0xFF: $ NOP CYC(2) break; } #undef $ diff --git a/source/CPU/cpu_general.inl b/source/CPU/cpu_general.inl index 25f7086e..4d565efb 100644 --- a/source/CPU/cpu_general.inl +++ b/source/CPU/cpu_general.inl @@ -73,6 +73,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA IOWrite[(addr>>4) & 0xFF](regs.pc,addr,1,(BYTE)(a),uExecutedCycles); \ } +#define ON_PAGECROSS_REPLACE_HI_ADDR if ((base ^ addr) >> 8) {addr = (val<<8) | (addr&0xff);} /* GH#282 */ + // // ExtraCycles: @@ -89,10 +91,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // -#define CHECK_PAGE_CHANGE if (bSlowerOnPagecross) { \ - if ((base ^ addr) & 0xFF00) \ - uExtraCycles=1; \ - } +// TODO Optimization Note: uExtraCycles = ((base ^ addr) >> 8) & 1; +#define CHECK_PAGE_CHANGE if ((base ^ addr) & 0xFF00) \ + uExtraCycles=1; /**************************************************************************** * @@ -102,53 +103,71 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define ABS addr = *(LPWORD)(mem+regs.pc); regs.pc += 2; #define IABSX addr = *(LPWORD)(mem+(*(LPWORD)(mem+regs.pc))+(WORD)regs.x); regs.pc += 2; -#define ABSX base = *(LPWORD)(mem+regs.pc); addr = base+(WORD)regs.x; regs.pc += 2; CHECK_PAGE_CHANGE; -#define ABSY base = *(LPWORD)(mem+regs.pc); addr = base+(WORD)regs.y; regs.pc += 2; CHECK_PAGE_CHANGE; -// TODO Optimization Note: uExtraCycles = ((base & 0xFF) + 1) >> 8; -#define IABSCMOS base = *(LPWORD)(mem+regs.pc); \ + +// Optimised for page-cross +#define ABSX_OPT base = *(LPWORD)(mem+regs.pc); addr = base+(WORD)regs.x; regs.pc += 2; CHECK_PAGE_CHANGE; +// Not optimised for page-cross +#define ABSX_CONST base = *(LPWORD)(mem+regs.pc); addr = base+(WORD)regs.x; regs.pc += 2; + +// Optimised for page-cross +#define ABSY_OPT base = *(LPWORD)(mem+regs.pc); addr = base+(WORD)regs.y; regs.pc += 2; CHECK_PAGE_CHANGE; +// Not optimised for page-cross +#define ABSY_CONST base = *(LPWORD)(mem+regs.pc); addr = base+(WORD)regs.y; regs.pc += 2; + +// TODO Optimization Note (just for IABSCMOS): uExtraCycles = ((base & 0xFF) + 1) >> 8; +#define IABS_CMOS base = *(LPWORD)(mem+regs.pc); \ addr = *(LPWORD)(mem+base); \ if ((base & 0xFF) == 0xFF) uExtraCycles=1; \ regs.pc += 2; -#define IABSNMOS base = *(LPWORD)(mem+regs.pc); \ +#define IABS_NMOS base = *(LPWORD)(mem+regs.pc); \ if ((base & 0xFF) == 0xFF) \ addr = *(mem+base)+((WORD)*(mem+(base&0xFF00))<<8);\ - else \ + else \ addr = *(LPWORD)(mem+base); \ regs.pc += 2; + #define IMM addr = regs.pc++; + #define INDX base = ((*(mem+regs.pc++))+regs.x) & 0xFF; \ if (base == 0xFF) \ addr = *(mem+0xFF)+(((WORD)*mem)<<8); \ else \ addr = *(LPWORD)(mem+base); -#define INDY if (*(mem+regs.pc) == 0xFF) \ + +// Optimised for page-cross +#define INDY_OPT if (*(mem+regs.pc) == 0xFF) /*incurs an extra cycle for page-crossing*/ \ base = *(mem+0xFF)+(((WORD)*mem)<<8); \ else \ base = *(LPWORD)(mem+*(mem+regs.pc)); \ regs.pc++; \ addr = base+(WORD)regs.y; \ CHECK_PAGE_CHANGE; +// Not optimised for page-cross +#define INDY_CONST if (*(mem+regs.pc) == 0xFF) /*no extra cycle for page-crossing*/ \ + base = *(mem+0xFF)+(((WORD)*mem)<<8); \ + else \ + base = *(LPWORD)(mem+*(mem+regs.pc)); \ + regs.pc++; \ + addr = base+(WORD)regs.y; + #define IZPG base = *(mem+regs.pc++); \ if (base == 0xFF) \ addr = *(mem+0xFF)+(((WORD)*mem)<<8); \ else \ addr = *(LPWORD)(mem+base); + #define REL addr = (signed char)*(mem+regs.pc++); // TODO Optimization Note: // . Opcodes that generate zero-page addresses can't be accessing $C000..$CFFF // so they could be paired with special READZP/WRITEZP macros (instead of READ/WRITE) -#define ZPG addr = *(mem+regs.pc++); +#define ZPG addr = *(mem+regs.pc++); #define ZPGX addr = ((*(mem+regs.pc++))+regs.x) & 0xFF; #define ZPGY addr = ((*(mem+regs.pc++))+regs.y) & 0xFF; // Tidy 3 char addressing modes to keep the opcode table visually aligned, clean, and readable. -#undef abx -#undef abx -#undef aby #undef asl #undef idx -#undef idy #undef imm #undef izp #undef lsr @@ -158,11 +177,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #undef zpx #undef zpy -#define abx ABSX -#define aby ABSY #define asl ASLA // Arithmetic Shift Left #define idx INDX -#define idy INDY #define imm IMM #define izp IZPG #define lsr LSRA // Logical Shift Right @@ -171,6 +187,3 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define ror RORA // Rotate Right #define zpx ZPGX #define zpy ZPGY -// 0x6C // 65c02 IABSCMOS JMP // 6502 IABSNMOS JMP -// 0x7C IABSX - diff --git a/source/CPU/cpu_instructions.inl b/source/CPU/cpu_instructions.inl index 84e68bae..8daa6178 100644 --- a/source/CPU/cpu_instructions.inl +++ b/source/CPU/cpu_instructions.inl @@ -68,15 +68,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #undef CPY #undef DCM #undef DEA -#undef DEC_NMOS -#undef DEC_CMOS +#undef DEC #undef DEX #undef DEY #undef EOR #undef HLT #undef INA -#undef INC_NMOS -#undef INC_CMOS +#undef INC #undef INS #undef INX #undef INY @@ -139,8 +137,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #undef ADCn #undef ASLn -#undef DECn -#undef INCn #undef LSRn #undef ROLn #undef RORn @@ -148,8 +144,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define ADCn ADC_NMOS #define ASLn ASL_NMOS -#define DECn DEC_NMOS -#define INCn INC_NMOS #define LSRn LSR_NMOS #define ROLn ROL_NMOS #define RORn ROR_NMOS @@ -159,8 +153,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #undef ADCc #undef ASLc -#undef DECc -#undef INCc #undef LSRc #undef ROLc #undef RORc @@ -168,8 +160,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define ADCc ADC_CMOS #define ASLc ASL_CMOS -#define DECc DEC_CMOS -#define INCc INC_CMOS #define LSRc LSR_CMOS #define ROLc ROL_CMOS #define RORc ROR_CMOS @@ -177,7 +167,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // ========== -#define ADC_NMOS bSlowerOnPagecross = 1; \ +#define ADC_NMOS /*bSlowerOnPagecross = 1;*/ \ temp = READ; \ if (regs.ps & AF_DECIMAL) { \ val = (regs.a & 0x0F) + (temp & 0x0F) + flagc; \ @@ -203,7 +193,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA regs.a = val & 0xFF; \ SETNZ(regs.a); \ } -#define ADC_CMOS bSlowerOnPagecross = 1; \ +#define ADC_CMOS /*bSlowerOnPagecross = 1*/; \ temp = READ; \ flagv = !((regs.a ^ temp) & 0x80); \ if (regs.ps & AF_DECIMAL) { \ @@ -242,7 +232,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA flagn = 0; \ regs.a >>= 1; \ SETZ(regs.a) -#define AND bSlowerOnPagecross = 1; \ +#define AND /*bSlowerOnPagecross = 1;*/ \ regs.a &= READ; \ SETNZ(regs.a) #define ANC regs.a &= READ; \ @@ -274,12 +264,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA flagv = ((val & 0x40) ^ ((val & 0x20) << 1)); \ regs.a = (val & 0xFF); \ } -#define ASL_NMOS bSlowerOnPagecross = 0; \ +#define ASL_NMOS /*bSlowerOnPagecross = 0;*/ \ val = READ << 1; \ flagc = (val > 0xFF); \ SETNZ(val) \ WRITE(val) -#define ASL_CMOS bSlowerOnPagecross = 1; \ +#define ASL_CMOS /*bSlowerOnPagecross = 1*/; \ val = READ << 1; \ flagc = (val > 0xFF); \ SETNZ(val) \ @@ -288,21 +278,22 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA flagc = (val > 0xFF); \ SETNZ(val) \ regs.a = (BYTE)val; -#define ASO bSlowerOnPagecross = 0; \ +#define ASO /*bSlowerOnPagecross = 0;*/ \ val = READ << 1; \ flagc = (val > 0xFF); \ WRITE(val) \ regs.a |= val; \ SETNZ(regs.a) -#define AXA bSlowerOnPagecross = 0;/*FIXME: $93 case is still unclear*/ \ +#define AXA /*bSlowerOnPagecross = 0;*/ \ val = regs.a & regs.x & (((base >> 8) + 1) & 0xFF); \ + ON_PAGECROSS_REPLACE_HI_ADDR \ WRITE(val) -#define AXS bSlowerOnPagecross = 0; \ +#define AXS /*bSlowerOnPagecross = 0;*/ \ WRITE(regs.a & regs.x) #define BCC if (!flagc) BRANCH_TAKEN; #define BCS if ( flagc) BRANCH_TAKEN; #define BEQ if ( flagz) BRANCH_TAKEN; -#define BIT bSlowerOnPagecross = 1; \ +#define BIT /*bSlowerOnPagecross = 1;*/ \ val = READ; \ flagz = !(regs.a & val); \ flagn = val & 0x80; \ @@ -325,7 +316,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define CLD regs.ps &= ~AF_DECIMAL; #define CLI regs.ps &= ~AF_INTERRUPT; #define CLV flagv = 0; -#define CMP bSlowerOnPagecross = 1; \ +#define CMP /*bSlowerOnPagecross = 1;*/ \ val = READ; \ flagc = (regs.a >= val); \ val = regs.a-val; \ @@ -338,7 +329,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA flagc = (regs.y >= val); \ val = regs.y-val; \ SETNZ(val) -#define DCM bSlowerOnPagecross = 0; \ +#define DCM /*bSlowerOnPagecross = 0;*/ \ val = READ-1; \ WRITE(val) \ flagc = (regs.a >= val); \ @@ -346,11 +337,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA SETNZ(val) #define DEA --regs.a; \ SETNZ(regs.a) -#define DEC_NMOS bSlowerOnPagecross = 0; \ - val = READ-1; \ - SETNZ(val) \ - WRITE(val) -#define DEC_CMOS bSlowerOnPagecross = 1; \ +#define DEC /*bSlowerOnPagecross = 0;*/ \ val = READ-1; \ SETNZ(val) \ WRITE(val) @@ -358,22 +345,18 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA SETNZ(regs.x) #define DEY --regs.y; \ SETNZ(regs.y) -#define EOR bSlowerOnPagecross = 1; \ +#define EOR /*bSlowerOnPagecross = 1;*/ \ regs.a ^= READ; \ SETNZ(regs.a) #define HLT regs.bJammed = 1; \ --regs.pc; #define INA ++regs.a; \ SETNZ(regs.a) -#define INC_NMOS bSlowerOnPagecross = 0; \ +#define INC /*bSlowerOnPagecross = 0;*/ \ val = READ+1; \ SETNZ(val) \ WRITE(val) -#define INC_CMOS bSlowerOnPagecross = 1; \ - val = READ+1; \ - SETNZ(val) \ - WRITE(val) -#define INS bSlowerOnPagecross = 0; \ +#define INS /*bSlowerOnPagecross = 0;*/ \ val = READ+1; \ WRITE(val) \ temp = val; \ @@ -408,38 +391,40 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA PUSH(regs.pc >> 8) \ PUSH(regs.pc & 0xFF) \ regs.pc = addr; -#define LAS bSlowerOnPagecross = 1; \ +#define LAS /*bSlowerOnPagecross = 1*/; \ val = (BYTE)(READ & regs.sp); \ regs.a = regs.x = (BYTE) val; \ regs.sp = val | 0x100; \ SETNZ(val) -#define LAX bSlowerOnPagecross = 1; \ +#define LAX /*bSlowerOnPagecross = 1;*/ \ regs.a = regs.x = READ; \ SETNZ(regs.a) -#define LDA bSlowerOnPagecross = 1; \ +#define LDA /*bSlowerOnPagecross = 1;*/ \ regs.a = READ; \ SETNZ(regs.a) -#define LDX bSlowerOnPagecross = 1; \ +#define LDD /*Undocumented 65C02: LoaD and Discard*/ \ + READ; +#define LDX /*bSlowerOnPagecross = 1;*/ \ regs.x = READ; \ SETNZ(regs.x) -#define LDY bSlowerOnPagecross = 1; \ +#define LDY /*bSlowerOnPagecross = 1;*/ \ regs.y = READ; \ SETNZ(regs.y) -#define LSE bSlowerOnPagecross = 0; \ +#define LSE /*bSlowerOnPagecross = 0;*/ \ val = READ; \ flagc = (val & 1); \ val >>= 1; \ WRITE(val) \ regs.a ^= val; \ SETNZ(regs.a) -#define LSR_NMOS bSlowerOnPagecross = 0; \ +#define LSR_NMOS /*bSlowerOnPagecross = 0;*/ \ val = READ; \ flagc = (val & 1); \ flagn = 0; \ val >>= 1; \ SETZ(val) \ WRITE(val) -#define LSR_CMOS bSlowerOnPagecross = 1; \ +#define LSR_CMOS /*bSlowerOnPagecross = 1;*/ \ val = READ; \ flagc = (val & 1); \ flagn = 0; \ @@ -450,12 +435,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA flagn = 0; \ regs.a >>= 1; \ SETZ(regs.a) -#define NOP bSlowerOnPagecross = 1; +#define NOP /*bSlowerOnPagecross = 1;*/ #define OAL regs.a |= 0xEE; \ regs.a &= READ; \ regs.x = regs.a; \ SETNZ(regs.a) -#define ORA bSlowerOnPagecross = 1; \ +#define ORA /*bSlowerOnPagecross = 1;*/ \ regs.a |= READ; \ SETNZ(regs.a) #define PHA PUSH(regs.a) @@ -471,18 +456,18 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA SETNZ(regs.x) #define PLY regs.y = POP; \ SETNZ(regs.y) -#define RLA bSlowerOnPagecross = 0; \ +#define RLA /*bSlowerOnPagecross = 0;*/ \ val = (READ << 1) | flagc; \ flagc = (val > 0xFF); \ WRITE(val) \ regs.a &= val; \ SETNZ(regs.a) -#define ROL_NMOS bSlowerOnPagecross = 0; \ +#define ROL_NMOS /*bSlowerOnPagecross = 0;*/ \ val = (READ << 1) | flagc; \ flagc = (val > 0xFF); \ SETNZ(val) \ WRITE(val) -#define ROL_CMOS bSlowerOnPagecross = 1; \ +#define ROL_CMOS /*bSlowerOnPagecross = 1;*/ \ val = (READ << 1) | flagc; \ flagc = (val > 0xFF); \ SETNZ(val) \ @@ -491,13 +476,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA flagc = (val > 0xFF); \ regs.a = val & 0xFF; \ SETNZ(regs.a); -#define ROR_NMOS bSlowerOnPagecross = 0; \ +#define ROR_NMOS /*bSlowerOnPagecross = 0;*/ \ temp = READ; \ val = (temp >> 1) | (flagc ? 0x80 : 0); \ flagc = (temp & 1); \ SETNZ(val) \ WRITE(val) -#define ROR_CMOS bSlowerOnPagecross = 1; \ +#define ROR_CMOS /*bSlowerOnPagecross = 1;*/ \ temp = READ; \ val = (temp >> 1) | (flagc ? 0x80 : 0); \ flagc = (temp & 1); \ @@ -507,7 +492,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA flagc = (regs.a & 1); \ regs.a = val & 0xFF; \ SETNZ(regs.a) -#define RRA bSlowerOnPagecross = 0; \ +#define RRA /*bSlowerOnPagecross = 0;*/ \ temp = READ; \ val = (temp >> 1) | (flagc ? 0x80 : 0); \ flagc = (temp & 1); \ @@ -549,10 +534,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA flagc = (temp >= val); \ regs.x = temp-val; \ SETNZ(regs.x) -#define SAY bSlowerOnPagecross = 0; \ +#define SAY /*bSlowerOnPagecross = 0;*/ \ val = regs.y & (((base >> 8) + 1) & 0xFF); \ + ON_PAGECROSS_REPLACE_HI_ADDR \ WRITE(val) -#define SBC_NMOS bSlowerOnPagecross = 1; \ +#define SBC_NMOS /*bSlowerOnPagecross = 1;*/ \ temp = READ; \ temp2 = regs.a - temp - !flagc; \ if (regs.ps & AF_DECIMAL) { \ @@ -576,7 +562,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA regs.a = val & 0xFF; \ SETNZ(regs.a); \ } -#define SBC_CMOS bSlowerOnPagecross = 1; \ +#define SBC_CMOS /*bSlowerOnPagecross = 1;*/ \ temp = READ; \ flagv = ((regs.a ^ temp) & 0x80); \ if (regs.ps & AF_DECIMAL) { \ @@ -622,29 +608,30 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define SEC flagc = 1; #define SED regs.ps |= AF_DECIMAL; #define SEI regs.ps |= AF_INTERRUPT; -#define STA bSlowerOnPagecross = 0; \ +#define STA /*bSlowerOnPagecross = 0;*/ \ WRITE(regs.a) -#define STX bSlowerOnPagecross = 0; \ +#define STX /*bSlowerOnPagecross = 0;*/ \ WRITE(regs.x) -#define STY bSlowerOnPagecross = 0; \ +#define STY /*bSlowerOnPagecross = 0;*/ \ WRITE(regs.y) -#define STZ bSlowerOnPagecross = 0; \ +#define STZ /*bSlowerOnPagecross = 0;*/ \ WRITE(0) -#define TAS bSlowerOnPagecross = 0; \ +#define TAS /*bSlowerOnPagecross = 0;*/ \ val = regs.a & regs.x; \ regs.sp = 0x100 | val; \ val &= (((base >> 8) + 1) & 0xFF); \ + ON_PAGECROSS_REPLACE_HI_ADDR \ WRITE(val) #define TAX regs.x = regs.a; \ SETNZ(regs.x) #define TAY regs.y = regs.a; \ SETNZ(regs.y) -#define TRB bSlowerOnPagecross = 0; \ +#define TRB /*bSlowerOnPagecross = 0;*/ \ val = READ; \ flagz = !(regs.a & val); \ val &= ~regs.a; \ WRITE(val) -#define TSB bSlowerOnPagecross = 0; \ +#define TSB /*bSlowerOnPagecross = 0;*/ \ val = READ; \ flagz = !(regs.a & val); \ val |= regs.a; \ @@ -659,7 +646,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define XAA regs.a = regs.x; \ regs.a &= READ; \ SETNZ(regs.a) -#define XAS bSlowerOnPagecross = 0; \ +#define XAS /*bSlowerOnPagecross = 0;*/ \ val = regs.x & (((base >> 8) + 1) & 0xFF); \ + ON_PAGECROSS_REPLACE_HI_ADDR \ WRITE(val) - diff --git a/source/Common.h b/source/Common.h index f89db922..2bc2a071 100644 --- a/source/Common.h +++ b/source/Common.h @@ -70,6 +70,7 @@ enum AppMode_e // Configuration #define REG_CONFIG "Configuration" #define REGVALUE_APPLE2_TYPE "Apple2 Type" +#define REGVALUE_CPU_TYPE "CPU Type" #define REGVALUE_OLD_APPLE2_TYPE "Computer Emulation" // Deprecated #define REGVALUE_CONFIRM_REBOOT "Confirm Reboot" // Added at 1.24.1 PageConfig #define REGVALUE_SPKR_VOLUME "Speaker Volume" @@ -165,7 +166,7 @@ enum eIRQSRC {IS_6522=0, IS_SPEECH, IS_SSC, IS_MOUSE}; #define IS_APPLE2C (g_Apple2Type & APPLE2C_MASK) #define IS_CLONE() (g_Apple2Type & APPLECLONE_MASK) -// NB. These get persisted to the Registry, so don't change the values for these enums! +// NB. These get persisted to the Registry & save-state file, so don't change the values for these enums! enum eApple2Type { A2TYPE_APPLE2=0, A2TYPE_APPLE2PLUS, diff --git a/source/Configuration/Config.h b/source/Configuration/Config.h index 2915d6cb..36be83af 100644 --- a/source/Configuration/Config.h +++ b/source/Configuration/Config.h @@ -1,6 +1,7 @@ #pragma once #include "..\AppleWin.h" +#include "..\CPU.h" #include "..\Disk.h" // BOOL enhancedisk #include "..\HardDisk.h" // HD_CardIsEnabled() @@ -8,13 +9,15 @@ class CConfigNeedingRestart { public: CConfigNeedingRestart(UINT bEnableTheFreezesF8Rom = false) : - m_Apple2Type(g_Apple2Type), + m_Apple2Type( GetApple2Type() ), + m_CpuType( GetMainCpu() ), m_bEnhanceDisk(enhancedisk), m_uSaveLoadStateMsg(0) { 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; } @@ -22,6 +25,7 @@ public: const CConfigNeedingRestart& operator= (const CConfigNeedingRestart& other) { m_Apple2Type = other.m_Apple2Type; + m_CpuType = other.m_CpuType; memcpy(m_Slot, other.m_Slot, sizeof(m_Slot)); m_bEnhanceDisk = other.m_bEnhanceDisk; m_bEnableHDD = other.m_bEnableHDD; @@ -33,6 +37,7 @@ public: bool operator== (const CConfigNeedingRestart& other) const { return m_Apple2Type == other.m_Apple2Type && + m_CpuType == other.m_CpuType && memcmp(m_Slot, other.m_Slot, sizeof(m_Slot)) == 0 && m_bEnhanceDisk == other.m_bEnhanceDisk && m_bEnableHDD == other.m_bEnableHDD && @@ -46,7 +51,9 @@ public: } eApple2Type m_Apple2Type; + eCpuType m_CpuType; SS_CARDTYPE m_Slot[NUM_SLOTS]; // 0..7 + SS_CARDTYPE m_SlotAux; BOOL m_bEnhanceDisk; bool m_bEnableHDD; UINT m_bEnableTheFreezesF8Rom; diff --git a/source/Configuration/IPropertySheet.h b/source/Configuration/IPropertySheet.h index c25b2ce8..b0312009 100644 --- a/source/Configuration/IPropertySheet.h +++ b/source/Configuration/IPropertySheet.h @@ -1,10 +1,13 @@ #pragma once +class CConfigNeedingRestart; + __interface IPropertySheet { void Init(void); DWORD GetVolumeMax(void); // TODO:TC: Move out of here bool SaveStateSelectImage(HWND hWindow, bool bSave); // TODO:TC: Move out of here + void ApplyNewConfig(const CConfigNeedingRestart& ConfigNew, const CConfigNeedingRestart& ConfigOld); UINT GetScrollLockToggle(void); void SetScrollLockToggle(UINT uValue); diff --git a/source/Configuration/PageAdvanced.cpp b/source/Configuration/PageAdvanced.cpp index de469041..c50cf5c7 100644 --- a/source/Configuration/PageAdvanced.cpp +++ b/source/Configuration/PageAdvanced.cpp @@ -22,7 +22,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "StdAfx.h" -#include "..\Structs.h" #include "..\Common.h" #include "..\ParallelPrinter.h" diff --git a/source/Configuration/PageConfig.cpp b/source/Configuration/PageConfig.cpp index a5c47884..f525fc8c 100644 --- a/source/Configuration/PageConfig.cpp +++ b/source/Configuration/PageConfig.cpp @@ -129,6 +129,7 @@ BOOL CPageConfig::DlgProcInternal(HWND hWnd, UINT message, WPARAM wparam, LPARAM const DWORD NewComputerMenuItem = (DWORD) SendDlgItemMessage(hWnd, IDC_COMPUTER, CB_GETCURSEL, 0, 0); const eApple2Type NewApple2Type = GetApple2Type(NewComputerMenuItem); m_PropertySheetHelper.GetConfigNew().m_Apple2Type = NewApple2Type; + m_PropertySheetHelper.GetConfigNew().m_CpuType = ProbeMainCpuDefault(NewApple2Type); } break; diff --git a/source/Configuration/PageInput.cpp b/source/Configuration/PageInput.cpp index 9326afee..7bd0a20b 100644 --- a/source/Configuration/PageInput.cpp +++ b/source/Configuration/PageInput.cpp @@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "StdAfx.h" -#include "..\Structs.h" +#include "..\SaveState_Structs_common.h" #include "..\Common.h" #include "..\Keyboard.h" @@ -214,12 +214,12 @@ void CPageInput::DlgOK(HWND hWnd) if (JoySetEmulationType(hWnd, m_nJoy0ChoiceTranlationTbl[uNewJoyType0], JN_JOYSTICK0, bIsSlot4Mouse)) { - REGSAVE(TEXT(REGVALUE_JOYSTICK0_EMU_TYPE), joytype[0]); + REGSAVE(TEXT(REGVALUE_JOYSTICK0_EMU_TYPE), JoyGetJoyType(0)); } if (JoySetEmulationType(hWnd, m_nJoy1ChoiceTranlationTbl[uNewJoyType1], JN_JOYSTICK1, bIsSlot4Mouse)) { - REGSAVE(TEXT(REGVALUE_JOYSTICK1_EMU_TYPE), joytype[1]); + REGSAVE(TEXT(REGVALUE_JOYSTICK1_EMU_TYPE), JoyGetJoyType(1)); } JoySetTrim((short)SendDlgItemMessage(hWnd, IDC_SPIN_XTRIM, UDM_GETPOS, 0, 0), true); @@ -305,7 +305,7 @@ void CPageInput::InitJoystickChoices(HWND hWnd, int nJoyNum, int nIdcValue) for(UINT i=nJC_KEYBD_CURSORS; i "file" + ".aws.yaml" + else + strcpy(&szFilename[ofn.nFileOffset+uStrLenFile], szAWS_EXT3); // "file" += ".aws.yaml" + } + else if ((uStrLenFile <= uStrLenExt3) || (strcmp(&szFilename[ofn.nFileOffset+uStrLenFile-uStrLenExt3], szAWS_EXT3) != 0)) + { + if (strcmp(&szFilename[ofn.nFileOffset+uStrLenFile-uStrLenExt1], szAWS_EXT1) == 0) + strcpy(&szFilename[ofn.nFileOffset+uStrLenFile-uStrLenExt1], szAWS_EXT3); // "file.aws" -> "file" + ".aws.yaml" + else if (strcmp(&szFilename[ofn.nFileOffset+uStrLenFile-uStrLenExt2], szAWS_EXT2) == 0) + strcpy(&szFilename[ofn.nFileOffset+uStrLenFile-uStrLenExt2], szAWS_EXT3); // "file.yaml" -> "file" + ".aws.yaml" + else + strcpy(&szFilename[ofn.nFileOffset+uStrLenFile], szAWS_EXT3); // "file" += ".aws.yaml" + } } + strcpy(m_szSSNewFilename, &szFilename[ofn.nFileOffset]); strcpy(m_szSSNewPathname, szFilename); szFilename[ofn.nFileOffset] = 0; @@ -319,41 +353,52 @@ bool CPropertySheetHelper::CheckChangesForRestart(HWND hWnd) return true; // OK } -#define CONFIG_CHANGED(var) \ - (m_ConfigOld.var != m_ConfigNew.var) +#define CONFIG_CHANGED_LOCAL(var) \ + (ConfigOld.var != ConfigNew.var) // Apply changes to Registry +void CPropertySheetHelper::ApplyNewConfig(const CConfigNeedingRestart& ConfigNew, const CConfigNeedingRestart& ConfigOld) +{ + if (CONFIG_CHANGED_LOCAL(m_Apple2Type)) + { + SaveComputerType(ConfigNew.m_Apple2Type); + } + + if (CONFIG_CHANGED_LOCAL(m_CpuType)) + { + SaveCpuType(ConfigNew.m_CpuType); + } + + if (CONFIG_CHANGED_LOCAL(m_Slot[4])) + SetSlot4(ConfigNew.m_Slot[4]); + + if (CONFIG_CHANGED_LOCAL(m_Slot[5])) + SetSlot5(ConfigNew.m_Slot[5]); + + if (CONFIG_CHANGED_LOCAL(m_bEnhanceDisk)) + REGSAVE(TEXT(REGVALUE_ENHANCE_DISK_SPEED), ConfigNew.m_bEnhanceDisk); + + if (CONFIG_CHANGED_LOCAL(m_bEnableHDD)) + { + REGSAVE(TEXT(REGVALUE_HDD_ENABLED), ConfigNew.m_bEnableHDD ? 1 : 0); + } + + if (CONFIG_CHANGED_LOCAL(m_bEnableTheFreezesF8Rom)) + { + REGSAVE(TEXT(REGVALUE_THE_FREEZES_F8_ROM), ConfigNew.m_bEnableTheFreezesF8Rom); + } +} + void CPropertySheetHelper::ApplyNewConfig(void) { - if (CONFIG_CHANGED(m_Apple2Type)) - { - SaveComputerType(m_ConfigNew.m_Apple2Type); - } - - if (CONFIG_CHANGED(m_Slot[4])) - SetSlot4(m_ConfigNew.m_Slot[4]); - - if (CONFIG_CHANGED(m_Slot[5])) - SetSlot5(m_ConfigNew.m_Slot[5]); - - if (CONFIG_CHANGED(m_bEnhanceDisk)) - REGSAVE(TEXT(REGVALUE_ENHANCE_DISK_SPEED), m_ConfigNew.m_bEnhanceDisk); - - if (CONFIG_CHANGED(m_bEnableHDD)) - { - REGSAVE(TEXT(REGVALUE_HDD_ENABLED), m_ConfigNew.m_bEnableHDD ? 1 : 0); - } - - if (CONFIG_CHANGED(m_bEnableTheFreezesF8Rom)) - { - REGSAVE(TEXT(REGVALUE_THE_FREEZES_F8_ROM), m_ConfigNew.m_bEnableTheFreezesF8Rom); - } + ApplyNewConfig(m_ConfigNew, m_ConfigOld); } void CPropertySheetHelper::SaveCurrentConfig(void) { // NB. clone-type is encoded in g_Apple2Type - m_ConfigOld.m_Apple2Type = g_Apple2Type; + m_ConfigOld.m_Apple2Type = GetApple2Type(); + m_ConfigOld.m_CpuType = GetMainCpu(); m_ConfigOld.m_Slot[4] = g_Slot4; m_ConfigOld.m_Slot[5] = g_Slot5; m_ConfigOld.m_bEnhanceDisk = enhancedisk; @@ -371,7 +416,8 @@ void CPropertySheetHelper::SaveCurrentConfig(void) void CPropertySheetHelper::RestoreCurrentConfig(void) { // NB. clone-type is encoded in g_Apple2Type - g_Apple2Type = m_ConfigOld.m_Apple2Type; + SetApple2Type(m_ConfigOld.m_Apple2Type); + SetMainCpu(m_ConfigOld.m_CpuType); g_Slot4 = m_ConfigOld.m_Slot[4]; g_Slot5 = m_ConfigOld.m_Slot[5]; enhancedisk = m_ConfigOld.m_bEnhanceDisk; @@ -411,6 +457,9 @@ bool CPropertySheetHelper::IsOkToRestart(HWND hWnd) return true; } +#define CONFIG_CHANGED(var) \ + (m_ConfigOld.var != m_ConfigNew.var) + bool CPropertySheetHelper::HardwareConfigChanged(HWND hWnd) { std::string strMsg("The emulator needs to restart as the hardware configuration has changed:\n"); @@ -421,6 +470,9 @@ bool CPropertySheetHelper::HardwareConfigChanged(HWND hWnd) if (CONFIG_CHANGED(m_Apple2Type)) strMsgMain += ". Emulated computer has changed\n"; + if (CONFIG_CHANGED(m_CpuType)) + strMsgMain += ". Emulated main CPU has changed\n"; + if (CONFIG_CHANGED(m_Slot[4])) strMsgMain += GetSlot(4); diff --git a/source/Configuration/PropertySheetHelper.h b/source/Configuration/PropertySheetHelper.h index 74896cdb..5fd83fd4 100644 --- a/source/Configuration/PropertySheetHelper.h +++ b/source/Configuration/PropertySheetHelper.h @@ -18,7 +18,6 @@ public: void SetSlot5(SS_CARDTYPE NewCardType); std::string BrowseToFile(HWND hWindow, TCHAR* pszTitle, TCHAR* REGVALUE,TCHAR* FILEMASKS); void SaveStateUpdate(); - void GetDiskBaseNameWithAWS(TCHAR* pszFilename); int SaveStateSelectImage(HWND hWindow, TCHAR* pszTitle, bool bSave); void PostMsgAfterClose(HWND hWnd, PAGETYPE page); @@ -37,17 +36,20 @@ public: CConfigNeedingRestart& GetConfigNew(void) { return m_ConfigNew; } bool IsConfigChanged(void) { return m_ConfigNew != m_ConfigOld; } void SetDoBenchmark(void) { m_bDoBenchmark = true; } + void ApplyNewConfig(const CConfigNeedingRestart& ConfigNew, const CConfigNeedingRestart& ConfigOld); private: bool IsOkToSaveLoadState(HWND hWnd, const bool bConfigChanged); bool IsOkToRestart(HWND hWnd); void SaveComputerType(eApple2Type NewApple2Type); + void SaveCpuType(eCpuType NewCpuType); bool HardwareConfigChanged(HWND hWnd); bool CheckChangesForRestart(HWND hWnd); void ApplyNewConfig(void); void RestoreCurrentConfig(void); std::string GetSlot(const UINT uSlot); std::string GetCardName(const SS_CARDTYPE CardType); + void GetDiskBaseNameWithAWS(TCHAR* pszFilename); PAGETYPE m_LastPage; UINT32 m_bmPages; diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index 1441ad97..a985c577 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -1955,7 +1955,7 @@ Update_t CmdTraceFile (int nArgs) fclose( g_hTraceFile ); g_hTraceFile = NULL; - sprintf( sText, "Trace stopped." ); + _snprintf( sText, sizeof(sText), "Trace stopped." ); } else { @@ -1975,16 +1975,17 @@ Update_t CmdTraceFile (int nArgs) if (g_hTraceFile) { - sprintf( sText, "Trace started: %s", sFilePath ); + _snprintf( sText, sizeof(sText), "Trace started: %s", sFilePath ); g_bTraceHeader = true; } else { - sprintf( sText, "Trace ERROR: %s", sFilePath ); + _snprintf( sText, sizeof(sText), "Trace ERROR: %s", sFilePath ); } } - + + sText[sizeof(sText)-1] = 0; // _snprintf needs null if string was longer than buffer ConsoleBufferPush( sText ); ConsoleBufferToDisplay(); @@ -2313,7 +2314,7 @@ void ConfigSave_PrepareHeader ( const Parameters_e eCategory, const Commands_e e sprintf( sText, "%s %s = %s\n" , g_aTokens[ TOKEN_COMMENT_EOL ].sToken , g_aParameters[ PARAM_CATEGORY ].m_sName - , g_aParameters[ eCategory ] + , g_aParameters[ eCategory ].m_sName ); g_ConfigState.PushLine( sText ); @@ -4297,10 +4298,10 @@ Update_t CmdMemoryLoad (int nArgs) TCHAR sLoadSaveFilePath[ MAX_PATH ]; _tcscpy( sLoadSaveFilePath, g_sCurrentDir ); // TODO: g_sDebugDir - WORD nAddressStart; - WORD nAddress2 = 0; - WORD nAddressEnd = 0; - int nAddressLen = 0; + WORD nAddressStart = 0; + WORD nAddress2 = 0; + WORD nAddressEnd = 0; + int nAddressLen = 0; if( pFileType ) { @@ -4370,7 +4371,7 @@ Update_t CmdMemoryLoad (int nArgs) if (bBankSpecified) { - MemUpdatePaging(1); + MemUpdatePaging(TRUE); } else { @@ -5975,6 +5976,7 @@ Update_t CmdOutputPrintf (int nArgs) { case '\\': eThis = PS_ESCAPE; + break; case '%': eThis = PS_TYPE; break; @@ -7027,7 +7029,6 @@ Update_t CmdWindowViewCode (int nArgs) Update_t CmdWindowViewConsole (int nArgs) { return _CmdWindowViewFull( WINDOW_CONSOLE ); - return UPDATE_ALL; } //=========================================================================== @@ -7049,14 +7050,12 @@ Update_t CmdWindowViewOutput (int nArgs) Update_t CmdWindowViewSource (int nArgs) { return _CmdWindowViewFull( WINDOW_CONSOLE ); - return UPDATE_ALL; } //=========================================================================== Update_t CmdWindowViewSymbols (int nArgs) { return _CmdWindowViewFull( WINDOW_CONSOLE ); - return UPDATE_ALL; } //=========================================================================== @@ -7771,7 +7770,7 @@ void OutputTraceLine () (unsigned)regs.sp, (char*) sFlags , sDisassembly - , sTarget + //, sTarget // TODO: Show target? ); } } diff --git a/source/Debugger/Debug.h b/source/Debugger/Debug.h index 8c1fdc79..add6cca5 100644 --- a/source/Debugger/Debug.h +++ b/source/Debugger/Debug.h @@ -1,6 +1,6 @@ #pragma once -#include "..\Structs.h" +#include "..\SaveState_Structs_v1.h" // For SS_CARD_MOCKINGBOARD #include "..\Common.h" #include "Debugger_Types.h" diff --git a/source/Debugger/Debugger_Assembler.cpp b/source/Debugger/Debugger_Assembler.cpp index 63a46f81..4c2730cd 100644 --- a/source/Debugger/Debugger_Assembler.cpp +++ b/source/Debugger/Debugger_Assembler.cpp @@ -565,7 +565,6 @@ bool _6502_GetStackReturnAddress ( WORD & nAddress_ ) if (nStack <= (_6502_STACK_END - 1)) { - nAddress_ = 0; nAddress_ = (unsigned)*(LPBYTE)(mem + nStack); nStack++; diff --git a/source/Debugger/Debugger_Commands.cpp b/source/Debugger/Debugger_Commands.cpp index 105561d2..970ec3d1 100644 --- a/source/Debugger/Debugger_Commands.cpp +++ b/source/Debugger/Debugger_Commands.cpp @@ -40,345 +40,345 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Command_t g_aCommands[] = { // Assembler -// {"!" , CmdAssemberMini , CMD_ASSEMBLER_MINI , "Mini assembler" } - {"A" , CmdAssemble , CMD_ASSEMBLE , "Assemble instructions" } +// {TEXT("!") , CmdAssemberMini , CMD_ASSEMBLER_MINI , "Mini assembler" }, + {TEXT("A") , CmdAssemble , CMD_ASSEMBLE , "Assemble instructions" }, // CPU (Main) - ,{"." , CmdCursorJumpPC , CMD_CURSOR_JUMP_PC , "Locate the cursor in the disasm window" } // centered - ,{"=" , CmdCursorSetPC , CMD_CURSOR_SET_PC , "Sets the PC to the current instruction" } -// ,{"g" , CmdGoNormalSpeed , CMD_GO_NORMAL , "Run @ normal speed [until PC == address]" } -// ,{"G" , CmdGoFullSpeed , CMD_GO_FULL , "Run @ full speed [until PC == address]" } - ,{"G" , CmdGo , CMD_GO , "Run @ full speed [until PC == address]" } - ,{"IN" , CmdIn , CMD_IN , "Input byte from IO $C0xx" } - ,{"KEY" , CmdKey , CMD_INPUT_KEY , "Feed key into emulator" } - ,{"JSR" , CmdJSR , CMD_JSR , "Call sub-routine" } - ,{"NOP" , CmdNOP , CMD_NOP , "Zap the current instruction with a NOP" } - ,{"OUT" , CmdOut , CMD_OUT , "Output byte to IO $C0xx" } + {TEXT(".") , CmdCursorJumpPC , CMD_CURSOR_JUMP_PC , "Locate the cursor in the disasm window" }, // centered + {TEXT("=") , CmdCursorSetPC , CMD_CURSOR_SET_PC , "Sets the PC to the current instruction" }, +// {TEXT("g") , CmdGoNormalSpeed , CMD_GO_NORMAL , "Run @ normal speed [until PC == address]" }, +// {TEXT("G") , CmdGoFullSpeed , CMD_GO_FULL , "Run @ full speed [until PC == address]" }, + {TEXT("G") , CmdGo , CMD_GO , "Run @ full speed [until PC == address]" }, + {TEXT("IN") , CmdIn , CMD_IN , "Input byte from IO $C0xx" }, + {TEXT("KEY") , CmdKey , CMD_INPUT_KEY , "Feed key into emulator" }, + {TEXT("JSR") , CmdJSR , CMD_JSR , "Call sub-routine" }, + {TEXT("NOP") , CmdNOP , CMD_NOP , "Zap the current instruction with a NOP" }, + {TEXT("OUT") , CmdOut , CMD_OUT , "Output byte to IO $C0xx" }, // CPU - Meta Info - ,{"PROFILE" , CmdProfile , CMD_PROFILE , "List/Save 6502 profiling" } - ,{"R" , CmdRegisterSet , CMD_REGISTER_SET , "Set register" } + {TEXT("PROFILE") , CmdProfile , CMD_PROFILE , "List/Save 6502 profiling" }, + {TEXT("R") , CmdRegisterSet , CMD_REGISTER_SET , "Set register" }, // CPU - Stack - ,{"POP" , CmdStackPop , CMD_STACK_POP } - ,{"PPOP" , CmdStackPopPseudo , CMD_STACK_POP_PSEUDO } - ,{"PUSH" , CmdStackPop , CMD_STACK_PUSH } -// ,{"RTS" , CmdStackReturn , CMD_STACK_RETURN } - ,{"P" , CmdStepOver , CMD_STEP_OVER , "Step current instruction" } - ,{"RTS" , CmdStepOut , CMD_STEP_OUT , "Step out of subroutine" } + {TEXT("POP") , CmdStackPop , CMD_STACK_POP }, + {TEXT("PPOP") , CmdStackPopPseudo , CMD_STACK_POP_PSEUDO }, + {TEXT("PUSH") , CmdStackPop , CMD_STACK_PUSH }, +// {TEXT("RTS") , CmdStackReturn , CMD_STACK_RETURN }, + {TEXT("P") , CmdStepOver , CMD_STEP_OVER , "Step current instruction" }, + {TEXT("RTS") , CmdStepOut , CMD_STEP_OUT , "Step out of subroutine" }, // CPU - Meta Info - ,{"T" , CmdTrace , CMD_TRACE , "Trace current instruction" } - ,{"TF" , CmdTraceFile , CMD_TRACE_FILE , "Save trace to filename" } - ,{"TL" , CmdTraceLine , CMD_TRACE_LINE , "Trace (with cycle counting)" } - ,{"U" , CmdUnassemble , CMD_UNASSEMBLE , "Disassemble instructions" } -// ,{"WAIT" , CmdWait , CMD_WAIT , "Run until" + {TEXT("T") , CmdTrace , CMD_TRACE , "Trace current instruction" }, + {TEXT("TF") , CmdTraceFile , CMD_TRACE_FILE , "Save trace to filename" }, + {TEXT("TL") , CmdTraceLine , CMD_TRACE_LINE , "Trace (with cycle counting)" }, + {TEXT("U") , CmdUnassemble , CMD_UNASSEMBLE , "Disassemble instructions" }, +// {TEXT("WAIT") , CmdWait , CMD_WAIT , "Run until // Bookmarks - ,{"BM" , CmdBookmark , CMD_BOOKMARK , "Alias for BMA (Bookmark Add)" } - ,{"BMA" , CmdBookmarkAdd , CMD_BOOKMARK_ADD , "Add/Update addess to bookmark" } - ,{"BMC" , CmdBookmarkClear , CMD_BOOKMARK_CLEAR , "Clear (remove) bookmark" } - ,{"BML" , CmdBookmarkList , CMD_BOOKMARK_LIST , "List all bookmarks" } - ,{"BMG" , CmdBookmarkGoto , CMD_BOOKMARK_GOTO , "Move cursor to bookmark" } -// ,{"BMLOAD" , CmdBookmarkLoad , CMD_BOOKMARK_LOAD , "Load bookmarks" } - ,{"BMSAVE" , CmdBookmarkSave , CMD_BOOKMARK_SAVE , "Save bookmarks" } + {TEXT("BM") , CmdBookmark , CMD_BOOKMARK , "Alias for BMA (Bookmark Add)" }, + {TEXT("BMA") , CmdBookmarkAdd , CMD_BOOKMARK_ADD , "Add/Update addess to bookmark" }, + {TEXT("BMC") , CmdBookmarkClear , CMD_BOOKMARK_CLEAR , "Clear (remove) bookmark" }, + {TEXT("BML") , CmdBookmarkList , CMD_BOOKMARK_LIST , "List all bookmarks" }, + {TEXT("BMG") , CmdBookmarkGoto , CMD_BOOKMARK_GOTO , "Move cursor to bookmark" }, +// {TEXT("BMLOAD") , CmdBookmarkLoad , CMD_BOOKMARK_LOAD , "Load bookmarks" }, + {TEXT("BMSAVE") , CmdBookmarkSave , CMD_BOOKMARK_SAVE , "Save bookmarks" }, // Breakpoints - ,{"BRK" , CmdBreakInvalid , CMD_BREAK_INVALID , "Enter debugger on BRK or INVALID" } - ,{"BRKOP" , CmdBreakOpcode , CMD_BREAK_OPCODE , "Enter debugger on opcode" } - ,{"BP" , CmdBreakpoint , CMD_BREAKPOINT , "Alias for BPR (Breakpoint Register Add)" } - ,{"BPA" , CmdBreakpointAddSmart , CMD_BREAKPOINT_ADD_SMART , "Add (smart) breakpoint" } -// ,{"BPP" , CmdBreakpointAddFlag , CMD_BREAKPOINT_ADD_FLAG , "Add breakpoint on flags" } - ,{"BPR" , CmdBreakpointAddReg , CMD_BREAKPOINT_ADD_REG , "Add breakpoint on register value" } // NOTE! Different from SoftICE !!!! - ,{"BPX" , CmdBreakpointAddPC , CMD_BREAKPOINT_ADD_PC , "Add breakpoint at current instruction" } - ,{"BPIO" , CmdBreakpointAddIO , CMD_BREAKPOINT_ADD_IO , "Add breakpoint for IO address $C0xx" } - ,{"BPM" , CmdBreakpointAddMem , CMD_BREAKPOINT_ADD_MEM , "Add breakpoint on memory access" } // SoftICE + {TEXT("BRK") , CmdBreakInvalid , CMD_BREAK_INVALID , "Enter debugger on BRK or INVALID" }, + {TEXT("BRKOP") , CmdBreakOpcode , CMD_BREAK_OPCODE , "Enter debugger on opcode" }, + {TEXT("BP") , CmdBreakpoint , CMD_BREAKPOINT , "Alias for BPR (Breakpoint Register Add)" }, + {TEXT("BPA") , CmdBreakpointAddSmart, CMD_BREAKPOINT_ADD_SMART , "Add (smart) breakpoint" }, +// {TEXT("BPP") , CmdBreakpointAddFlag , CMD_BREAKPOINT_ADD_FLAG , "Add breakpoint on flags" }, + {TEXT("BPR") , CmdBreakpointAddReg , CMD_BREAKPOINT_ADD_REG , "Add breakpoint on register value" }, // NOTE! Different from SoftICE !!!! + {TEXT("BPX") , CmdBreakpointAddPC , CMD_BREAKPOINT_ADD_PC , "Add breakpoint at current instruction" }, + {TEXT("BPIO") , CmdBreakpointAddIO , CMD_BREAKPOINT_ADD_IO , "Add breakpoint for IO address $C0xx" }, + {TEXT("BPM") , CmdBreakpointAddMem , CMD_BREAKPOINT_ADD_MEM , "Add breakpoint on memory access" }, // SoftICE - ,{"BPC" , CmdBreakpointClear , CMD_BREAKPOINT_CLEAR , "Clear (remove) breakpoint" } // SoftICE - ,{"BPD" , CmdBreakpointDisable , CMD_BREAKPOINT_DISABLE , "Disable breakpoint- it is still in the list, just not active" } // SoftICE - ,{"BPEDIT" , CmdBreakpointEdit , CMD_BREAKPOINT_EDIT , "Edit breakpoint" } // SoftICE - ,{"BPE" , CmdBreakpointEnable , CMD_BREAKPOINT_ENABLE , "(Re)Enable disabled breakpoint" } // SoftICE - ,{"BPL" , CmdBreakpointList , CMD_BREAKPOINT_LIST , "List all breakpoints" } // SoftICE -// ,{"BPLOAD" , CmdBreakpointLoad , CMD_BREAKPOINT_LOAD , "Loads breakpoints" } - ,{"BPSAVE" , CmdBreakpointSave , CMD_BREAKPOINT_SAVE , "Saves breakpoints" } + {TEXT("BPC") , CmdBreakpointClear , CMD_BREAKPOINT_CLEAR , "Clear (remove) breakpoint" }, // SoftICE + {TEXT("BPD") , CmdBreakpointDisable , CMD_BREAKPOINT_DISABLE , "Disable breakpoint- it is still in the list, just not active" }, // SoftICE + {TEXT("BPEDIT") , CmdBreakpointEdit , CMD_BREAKPOINT_EDIT , "Edit breakpoint" }, // SoftICE + {TEXT("BPE") , CmdBreakpointEnable , CMD_BREAKPOINT_ENABLE , "(Re)Enable disabled breakpoint" }, // SoftICE + {TEXT("BPL") , CmdBreakpointList , CMD_BREAKPOINT_LIST , "List all breakpoints" }, // SoftICE +// {TEXT("BPLOAD") , CmdBreakpointLoad , CMD_BREAKPOINT_LOAD , "Loads breakpoints" }, + {TEXT("BPSAVE") , CmdBreakpointSave , CMD_BREAKPOINT_SAVE , "Saves breakpoints" }, // Config - ,{"BENCHMARK" , CmdBenchmark , CMD_BENCHMARK , "Benchmark the emulator" } - ,{"BW" , CmdConfigColorMono , CMD_CONFIG_BW , "Sets/Shows RGB for Black & White scheme" } - ,{"COLOR" , CmdConfigColorMono , CMD_CONFIG_COLOR , "Sets/Shows RGB for color scheme" } -// ,{"OPTION" , CmdConfigMenu , CMD_CONFIG_MENU , "Access config options" } - ,{"DISASM" , CmdConfigDisasm , CMD_CONFIG_DISASM , "Sets/Shows disassembly view options." } - ,{"FONT" , CmdConfigFont , CMD_CONFIG_FONT , "Shows current font or sets new one" } - ,{"HCOLOR" , CmdConfigHColor , CMD_CONFIG_HCOLOR , "Sets/Shows colors mapped to Apple HGR" } - ,{"LOAD" , CmdConfigLoad , CMD_CONFIG_LOAD , "Load debugger configuration" } - ,{"MONO" , CmdConfigColorMono , CMD_CONFIG_MONOCHROME , "Sets/Shows RGB for monochrome scheme" } - ,{"SAVE" , CmdConfigSave , CMD_CONFIG_SAVE , "Save debugger configuration" } - ,{"PWD" , CmdConfigGetDebugDir , CMD_CONFIG_GET_DEBUG_DIR , "Display current debugger directory for scripts & mem load/save." } - ,{"CD" , CmdConfigSetDebugDir , CMD_CONFIG_SET_DEBUG_DIR , "Update current debugger directory." } + {TEXT("BENCHMARK") , CmdBenchmark , CMD_BENCHMARK , "Benchmark the emulator" }, + {TEXT("BW") , CmdConfigColorMono , CMD_CONFIG_BW , "Sets/Shows RGB for Black & White scheme" }, + {TEXT("COLOR") , CmdConfigColorMono , CMD_CONFIG_COLOR , "Sets/Shows RGB for color scheme" }, +// {TEXT("OPTION") , CmdConfigMenu , CMD_CONFIG_MENU , "Access config options" }, + {TEXT("DISASM") , CmdConfigDisasm , CMD_CONFIG_DISASM , "Sets/Shows disassembly view options." }, + {TEXT("FONT") , CmdConfigFont , CMD_CONFIG_FONT , "Shows current font or sets new one" }, + {TEXT("HCOLOR") , CmdConfigHColor , CMD_CONFIG_HCOLOR , "Sets/Shows colors mapped to Apple HGR" }, + {TEXT("LOAD") , CmdConfigLoad , CMD_CONFIG_LOAD , "Load debugger configuration" }, + {TEXT("MONO") , CmdConfigColorMono , CMD_CONFIG_MONOCHROME , "Sets/Shows RGB for monochrome scheme" }, + {TEXT("SAVE") , CmdConfigSave , CMD_CONFIG_SAVE , "Save debugger configuration" }, + {TEXT("PWD") , CmdConfigGetDebugDir , CMD_CONFIG_GET_DEBUG_DIR , "Displays the current debugger directory. Used for scripts & mem load/save." }, + {TEXT("CD") , CmdConfigSetDebugDir , CMD_CONFIG_SET_DEBUG_DIR , "Updates the current debugger directory." }, // Cursor - ,{"RET" , CmdCursorJumpRetAddr , CMD_CURSOR_JUMP_RET_ADDR , "Sets the cursor to the subroutine caller" } - ,{ "^" , NULL , CMD_CURSOR_LINE_UP } // \x2191 = Up Arrow (Unicode) - ,{"Shift ^" , NULL , CMD_CURSOR_LINE_UP_1 } - ,{ "v" , NULL , CMD_CURSOR_LINE_DOWN } // \x2193 = Dn Arrow (Unicode) - ,{"Shift v" , NULL , CMD_CURSOR_LINE_DOWN_1 } - ,{"PAGEUP" , CmdCursorPageUp , CMD_CURSOR_PAGE_UP , "Scroll up one screen" } - ,{"PAGEUP256" , CmdCursorPageUp256 , CMD_CURSOR_PAGE_UP_256 , "Scroll up 256 bytes" } // Shift - ,{"PAGEUP4K" , CmdCursorPageUp4K , CMD_CURSOR_PAGE_UP_4K , "Scroll up 4096 bytes" } // Ctrl - ,{"PAGEDN" , CmdCursorPageDown , CMD_CURSOR_PAGE_DOWN , "Scroll down one scren" } - ,{"PAGEDOWN256" , CmdCursorPageDown256 , CMD_CURSOR_PAGE_DOWN_256 , "Scroll down 256 bytes" } // Shift - ,{"PAGEDOWN4K" , CmdCursorPageDown4K , CMD_CURSOR_PAGE_DOWN_4K , "Scroll down 4096 bytes" } // Ctrl + {TEXT("RET") , CmdCursorJumpRetAddr , CMD_CURSOR_JUMP_RET_ADDR , "Sets the cursor to the sub-routine caller" }, + {TEXT( "^") , NULL , CMD_CURSOR_LINE_UP }, // \x2191 = Up Arrow (Unicode) + {TEXT("Shift ^") , NULL , CMD_CURSOR_LINE_UP_1 }, + {TEXT( "v") , NULL , CMD_CURSOR_LINE_DOWN }, // \x2193 = Dn Arrow (Unicode) + {TEXT("Shift v") , NULL , CMD_CURSOR_LINE_DOWN_1 }, + {TEXT("PAGEUP" ) , CmdCursorPageUp , CMD_CURSOR_PAGE_UP , "Scroll up one screen" }, + {TEXT("PAGEUP256") , CmdCursorPageUp256 , CMD_CURSOR_PAGE_UP_256 , "Scroll up 256 bytes" }, // Shift + {TEXT("PAGEUP4K" ) , CmdCursorPageUp4K , CMD_CURSOR_PAGE_UP_4K , "Scroll up 4096 bytes" }, // Ctrl + {TEXT("PAGEDN" ) , CmdCursorPageDown , CMD_CURSOR_PAGE_DOWN , "Scroll down one scren" }, + {TEXT("PAGEDOWN256") , CmdCursorPageDown256 , CMD_CURSOR_PAGE_DOWN_256 , "Scroll down 256 bytes" }, // Shift + {TEXT("PAGEDOWN4K" ) , CmdCursorPageDown4K , CMD_CURSOR_PAGE_DOWN_4K , "Scroll down 4096 bytes" }, // Ctrl // Disassembler Data - ,{"Z" , CmdDisasmDataDefByte1 , CMD_DISASM_DATA , "Treat byte [range] as data" } - ,{"X" , CmdDisasmDataDefCode , CMD_DISASM_CODE , "Treat byte [range] as code" } + {TEXT("Z") , CmdDisasmDataDefByte1 , CMD_DISASM_DATA , "Treat byte [range] as data" }, + {TEXT("X") , CmdDisasmDataDefCode , CMD_DISASM_CODE , "Treat byte [range] as code" }, // TODO: Conflicts with monitor command #L -> 000DL - ,{"B" , CmdDisasmDataList , CMD_DISASM_LIST , "List all byte ranges treated as data" } + {TEXT("B") , CmdDisasmDataList , CMD_DISASM_LIST , "List all byte ranges treated as data" }, // without symbol lookup - ,{"DB" , CmdDisasmDataDefByte1 , CMD_DEFINE_DATA_BYTE1 , "Define byte(s)" } - ,{"DB2" , CmdDisasmDataDefByte2 , CMD_DEFINE_DATA_BYTE2 , "Define byte array, display 2 bytes/line" } - ,{"DB4" , CmdDisasmDataDefByte4 , CMD_DEFINE_DATA_BYTE4 , "Define byte array, display 4 bytes/line" } - ,{"DB8" , CmdDisasmDataDefByte8 , CMD_DEFINE_DATA_BYTE8 , "Define byte array, display 8 bytes/line" } - ,{"DW" , CmdDisasmDataDefWord1 , CMD_DEFINE_DATA_WORD1 , "Define address array" } - ,{"DW2" , CmdDisasmDataDefWord2 , CMD_DEFINE_DATA_WORD2 , "Define address array, display 2 words/line" } - ,{"DW4" , CmdDisasmDataDefWord4 , CMD_DEFINE_DATA_WORD4 , "Define address array, display 4 words/line" } - ,{"ASC" , CmdDisasmDataDefString , CMD_DEFINE_DATA_STR , "Define text string" } // 2.7.0.26 Changed: DS to ASC because DS is used as "Define Space" assembler directive -// .{"DF" , CmdDisasmDataDefFloat , CMD_DEFINE_DATA_FLOAT , "Define AppleSoft (packed) Float" } -// .{"DFX" , CmdDisasmDataDefFloatUnpack , CMD_DEFINE_DATA_FLOAT2 , "Define AppleSoft (unpacked) Float" } + {TEXT("DB") , CmdDisasmDataDefByte1 , CMD_DEFINE_DATA_BYTE1, "Define byte(s)" }, + {TEXT("DB2") , CmdDisasmDataDefByte2 , CMD_DEFINE_DATA_BYTE2, "Define byte array, display 2 bytes/line" }, + {TEXT("DB4") , CmdDisasmDataDefByte4 , CMD_DEFINE_DATA_BYTE4, "Define byte array, display 4 bytes/line" }, + {TEXT("DB8") , CmdDisasmDataDefByte8 , CMD_DEFINE_DATA_BYTE8, "Define byte array, display 8 bytes/line" }, + {TEXT("DW") , CmdDisasmDataDefWord1 , CMD_DEFINE_DATA_WORD1, "Define address array" }, + {TEXT("DW2") , CmdDisasmDataDefWord2 , CMD_DEFINE_DATA_WORD2, "Define address array, display 2 words/line" }, + {TEXT("DW4") , CmdDisasmDataDefWord4 , CMD_DEFINE_DATA_WORD4, "Define address array, display 4 words/line" }, + {TEXT("ASC") , CmdDisasmDataDefString , CMD_DEFINE_DATA_STR , "Define text string" }, // 2.7.0.26 Changed: DS to ASC because DS is used as "Define Space" assembler directive +// {TEXT("DF") , CmdDisasmDataDefFloat , CMD_DEFINE_DATA_FLOAT, "Define AppleSoft (packed) Float" }, +// {TEXT("DFX") , CmdDisasmDataDefFloatUnpack , CMD_DEFINE_DATA_FLOAT2,"Define AppleSoft (unpacked) Float" }, // with symbol lookup -// .{"DA<>" , CmdDisasmDataDefAddress8HL , CMD_DEFINE_ADDR_8_HL , "Define split array of addresses, high byte section followed by low byte section" } -// .{"DA><" , CmdDisasmDataDefAddress8LH , CMD_DEFINE_ADDR_8_LH , "Define split array of addresses, low byte section followed by high byte section" } -// .{"DA<" , CmdDisasmDataDefAddress8H , CMD_DEFINE_ADDR_BYTE_H , "Define array of high byte addresses" } -// .{"DB>" , CmdDisasmDataDefAddress8L , CMD_DEFINE_ADDR_BYTE_L , "Define array of low byte addresses" } - ,{"DA" , CmdDisasmDataDefAddress16 , CMD_DEFINE_ADDR_WORD , "Define array of word addresses" } +// {TEXT("DA<>") , CmdDisasmDataDefAddress8HL , CMD_DEFINE_ADDR_8_HL , "Define split array of addresses, high byte section followed by low byte section" }, +// {TEXT("DA><") , CmdDisasmDataDefAddress8LH , CMD_DEFINE_ADDR_8_LH , "Define split array of addresses, low byte section followed by high byte section" }, +// {TEXT("DA<") , CmdDisasmDataDefAddress8H , CMD_DEFINE_ADDR_BYTE_H , "Define array of high byte addresses" }, +// {TEXT("DB>") , CmdDisasmDataDefAddress8L , CMD_DEFINE_ADDR_BYTE_L , "Define array of low byte addresses" } + {TEXT("DA") , CmdDisasmDataDefAddress16 , CMD_DEFINE_ADDR_WORD , "Define array of word addresses" }, // TODO: Rename config cmd: DISASM -// {"UA" , CmdDisasmDataSmart , CMD_SMART_DISASSEMBLE , "Analyze opcodes to determine if code or data" } +// {TEXT("UA") , CmdDisasmDataSmart , CMD_SMART_DISASSEMBLE, "Analyze opcodes to determine if code or data" }, // Disk - ,{"DISK" , CmdDisk , CMD_DISK , "Access Disk Drive Functions" } + {TEXT("DISK") , CmdDisk , CMD_DISK , "Access Disk Drive Functions" }, // Flags -// {"FC" , CmdFlag , CMD_FLAG_CLEAR , "Clear specified Flag" } // NVRBDIZC see AW_CPU.cpp AF_* +// {TEXT("FC") , CmdFlag , CMD_FLAG_CLEAR , "Clear specified Flag" }, // NVRBDIZC see AW_CPU.cpp AF_* // TODO: Conflicts with monitor command #L -> 000CL - ,{"CL" , CmdFlag , CMD_FLAG_CLEAR , "Clear specified Flag" } // NVRBDIZC see AW_CPU.cpp AF_* + {TEXT("CL") , CmdFlag , CMD_FLAG_CLEAR , "Clear specified Flag" }, // NVRBDIZC see AW_CPU.cpp AF_* - ,{"CLC" , CmdFlagClear , CMD_FLAG_CLR_C , "Clear Flag Carry" } // 0 // Legacy - ,{"CLZ" , CmdFlagClear , CMD_FLAG_CLR_Z , "Clear Flag Zero" } // 1 - ,{"CLI" , CmdFlagClear , CMD_FLAG_CLR_I , "Clear Flag Interrupts Disabled" } // 2 - ,{"CLD" , CmdFlagClear , CMD_FLAG_CLR_D , "Clear Flag Decimal (BCD)" } // 3 - ,{"CLB" , CmdFlagClear , CMD_FLAG_CLR_B , "CLear Flag Break" } // 4 // Legacy - ,{"CLR" , CmdFlagClear , CMD_FLAG_CLR_R , "Clear Flag Reserved" } // 5 - ,{"CLV" , CmdFlagClear , CMD_FLAG_CLR_V , "Clear Flag Overflow" } // 6 - ,{"CLN" , CmdFlagClear , CMD_FLAG_CLR_N , "Clear Flag Negative (Sign)" } // 7 + {TEXT("CLC") , CmdFlagClear , CMD_FLAG_CLR_C , "Clear Flag Carry" }, // 0 // Legacy + {TEXT("CLZ") , CmdFlagClear , CMD_FLAG_CLR_Z , "Clear Flag Zero" }, // 1 + {TEXT("CLI") , CmdFlagClear , CMD_FLAG_CLR_I , "Clear Flag Interrupts Disabled" }, // 2 + {TEXT("CLD") , CmdFlagClear , CMD_FLAG_CLR_D , "Clear Flag Decimal (BCD)" }, // 3 + {TEXT("CLB") , CmdFlagClear , CMD_FLAG_CLR_B , "CLear Flag Break" }, // 4 // Legacy + {TEXT("CLR") , CmdFlagClear , CMD_FLAG_CLR_R , "Clear Flag Reserved" }, // 5 + {TEXT("CLV") , CmdFlagClear , CMD_FLAG_CLR_V , "Clear Flag Overflow" }, // 6 + {TEXT("CLN") , CmdFlagClear , CMD_FLAG_CLR_N , "Clear Flag Negative (Sign)" }, // 7 -// ,{"FS" , CmdFlag , CMD_FLAG_SET , "Set specified Flag" } - ,{"SE" , CmdFlag , CMD_FLAG_SET , "Set specified Flag" } +// {TEXT("FS") , CmdFlag , CMD_FLAG_SET , "Set specified Flag" }, + {TEXT("SE") , CmdFlag , CMD_FLAG_SET , "Set specified Flag" }, - ,{"SEC" , CmdFlagSet , CMD_FLAG_SET_C , "Set Flag Carry" } // 0 - ,{"SEZ" , CmdFlagSet , CMD_FLAG_SET_Z , "Set Flag Zero" } // 1 - ,{"SEI" , CmdFlagSet , CMD_FLAG_SET_I , "Set Flag Interrupts Disabled" } // 2 - ,{"SED" , CmdFlagSet , CMD_FLAG_SET_D , "Set Flag Decimal (BCD)" } // 3 - ,{"SEB" , CmdFlagSet , CMD_FLAG_SET_B , "Set Flag Break" } // 4 // Legacy - ,{"SER" , CmdFlagSet , CMD_FLAG_SET_R , "Set Flag Reserved" } // 5 - ,{"SEV" , CmdFlagSet , CMD_FLAG_SET_V , "Set Flag Overflow" } // 6 - ,{"SEN" , CmdFlagSet , CMD_FLAG_SET_N , "Set Flag Negative" } // 7 + {TEXT("SEC") , CmdFlagSet , CMD_FLAG_SET_C , "Set Flag Carry" }, // 0 + {TEXT("SEZ") , CmdFlagSet , CMD_FLAG_SET_Z , "Set Flag Zero" }, // 1 + {TEXT("SEI") , CmdFlagSet , CMD_FLAG_SET_I , "Set Flag Interrupts Disabled" }, // 2 + {TEXT("SED") , CmdFlagSet , CMD_FLAG_SET_D , "Set Flag Decimal (BCD)" }, // 3 + {TEXT("SEB") , CmdFlagSet , CMD_FLAG_SET_B , "Set Flag Break" }, // 4 // Legacy + {TEXT("SER") , CmdFlagSet , CMD_FLAG_SET_R , "Set Flag Reserved" }, // 5 + {TEXT("SEV") , CmdFlagSet , CMD_FLAG_SET_V , "Set Flag Overflow" }, // 6 + {TEXT("SEN") , CmdFlagSet , CMD_FLAG_SET_N , "Set Flag Negative" }, // 7 // Help - ,{"?" , CmdHelpList , CMD_HELP_LIST , "List all available commands" } - ,{"HELP" , CmdHelpSpecific , CMD_HELP_SPECIFIC , "Help on specific command" } - ,{"VERSION" , CmdVersion , CMD_VERSION , "Displays version of emulator/debugger" } - ,{"MOTD" , CmdMOTD , CMD_MOTD } // MOTD: Message Of The Day + {TEXT("?") , CmdHelpList , CMD_HELP_LIST , "List all available commands" }, + {TEXT("HELP") , CmdHelpSpecific , CMD_HELP_SPECIFIC , "Help on specific command" }, + {TEXT("VERSION") , CmdVersion , CMD_VERSION , "Displays version of emulator/debugger" }, + {TEXT("MOTD") , CmdMOTD , CMD_MOTD }, // MOTD: Message Of The Day // Memory - ,{"MC" , CmdMemoryCompare , CMD_MEMORY_COMPARE } + {TEXT("MC") , CmdMemoryCompare , CMD_MEMORY_COMPARE }, - ,{"MD1" , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 , "Hex dump in the mini memory area 1" } - ,{"MD2" , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_2 , "Hex dump in the mini memory area 2" } + {TEXT("MD1") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 , "Hex dump in the mini memory area 1" }, + {TEXT("MD2") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_2 , "Hex dump in the mini memory area 2" }, - ,{"MA1" , CmdMemoryMiniDumpAscii , CMD_MEM_MINI_DUMP_ASCII_1 , "ASCII text in mini memory area 1" } - ,{"MA2" , CmdMemoryMiniDumpAscii , CMD_MEM_MINI_DUMP_ASCII_2 , "ASCII text in mini memory area 2" } - ,{"MT1" , CmdMemoryMiniDumpApple , CMD_MEM_MINI_DUMP_APPLE_1 , "Apple Text in mini memory area 1" } - ,{"MT2" , CmdMemoryMiniDumpApple , CMD_MEM_MINI_DUMP_APPLE_2 , "Apple Text in mini memory area 2" } -// {"ML1" , CmdMemoryMiniDumpLow , CMD_MEM_MINI_DUMP_TXT_LO_1 , "Text (Ctrl) in mini memory dump area 1" } -// {"ML2" , CmdMemoryMiniDumpLow , CMD_MEM_MINI_DUMP_TXT_LO_2 , "Text (Ctrl) in mini memory dump area 2" } -// {"MH1" , CmdMemoryMiniDumpHigh , CMD_MEM_MINI_DUMP_TXT_HI_1 , "Text (High) in mini memory dump area 1" } -// {"MH2" , CmdMemoryMiniDumpHigh , CMD_MEM_MINI_DUMP_TXT_HI_2 , "Text (High) in mini memory dump area 2" } + {TEXT("MA1") , CmdMemoryMiniDumpAscii,CMD_MEM_MINI_DUMP_ASCII_1, "ASCII text in mini memory area 1" }, + {TEXT("MA2") , CmdMemoryMiniDumpAscii,CMD_MEM_MINI_DUMP_ASCII_2, "ASCII text in mini memory area 2" }, + {TEXT("MT1") , CmdMemoryMiniDumpApple,CMD_MEM_MINI_DUMP_APPLE_1, "Apple Text in mini memory area 1" }, + {TEXT("MT2") , CmdMemoryMiniDumpApple,CMD_MEM_MINI_DUMP_APPLE_2, "Apple Text in mini memory area 2" }, +// {TEXT("ML1") , CmdMemoryMiniDumpLow , CMD_MEM_MINI_DUMP_TXT_LO_1, "Text (Ctrl) in mini memory dump area 1" }, +// {TEXT("ML2") , CmdMemoryMiniDumpLow , CMD_MEM_MINI_DUMP_TXT_LO_2, "Text (Ctrl) in mini memory dump area 2" }, +// {TEXT("MH1") , CmdMemoryMiniDumpHigh, CMD_MEM_MINI_DUMP_TXT_HI_1, "Text (High) in mini memory dump area 1" }, +// {TEXT("MH2") , CmdMemoryMiniDumpHigh, CMD_MEM_MINI_DUMP_TXT_HI_2, "Text (High) in mini memory dump area 2" }, - ,{"ME" , CmdMemoryEdit , CMD_MEMORY_EDIT , "Memory Editor - Not Implemented!" } // TODO: like Copy ][+ Sector Edit - ,{"MEB" , CmdMemoryEnterByte , CMD_MEMORY_ENTER_BYTE , "Enter byte" } - ,{"MEW" , CmdMemoryEnterWord , CMD_MEMORY_ENTER_WORD , "Enter word" } - ,{"BLOAD" , CmdMemoryLoad , CMD_MEMORY_LOAD , "Load a region of memory" } - ,{"M" , CmdMemoryMove , CMD_MEMORY_MOVE , "Memory move" } - ,{"BSAVE" , CmdMemorySave , CMD_MEMORY_SAVE , "Save a region of memory" } - ,{"S" , CmdMemorySearch , CMD_MEMORY_SEARCH , "Search memory for text / hex values" } - ,{"@" ,_SearchMemoryDisplay , CMD_MEMORY_FIND_RESULTS , "Display search memory results" } -// ,{"SA" , CmdMemorySearchAscii , CMD_MEMORY_SEARCH_ASCII , "Search ASCII text" } -// ,{"ST" , CmdMemorySearchApple , CMD_MEMORY_SEARCH_APPLE , "Search Apple text (hi-bit)" } - ,{"SH" , CmdMemorySearchHex , CMD_MEMORY_SEARCH_HEX , "Search memory for hex values" } - ,{"F" , CmdMemoryFill , CMD_MEMORY_FILL , "Memory fill" } + {TEXT("ME") , CmdMemoryEdit , CMD_MEMORY_EDIT , "Memory Editor - Not Implemented!" }, // TODO: like Copy ][+ Sector Edit + {TEXT("MEB") , CmdMemoryEnterByte , CMD_MEMORY_ENTER_BYTE , "Enter byte" }, + {TEXT("MEW") , CmdMemoryEnterWord , CMD_MEMORY_ENTER_WORD , "Enter word" }, + {TEXT("BLOAD") , CmdMemoryLoad , CMD_MEMORY_LOAD , "Load a region of memory" }, + {TEXT("M") , CmdMemoryMove , CMD_MEMORY_MOVE , "Memory move" }, + {TEXT("BSAVE") , CmdMemorySave , CMD_MEMORY_SAVE , "Save a region of memory" }, + {TEXT("S") , CmdMemorySearch , CMD_MEMORY_SEARCH , "Search memory for text / hex values" }, + {TEXT("@") ,_SearchMemoryDisplay , CMD_MEMORY_FIND_RESULTS , "Display search memory results" }, +// {TEXT("SA") , CmdMemorySearchAscii, CMD_MEMORY_SEARCH_ASCII , "Search ASCII text" }, +// {TEXT("ST") , CmdMemorySearchApple , CMD_MEMORY_SEARCH_APPLE , "Search Apple text (hi-bit)" }, + {TEXT("SH") , CmdMemorySearchHex , CMD_MEMORY_SEARCH_HEX , "Search memory for hex values" }, + {TEXT("F") , CmdMemoryFill , CMD_MEMORY_FILL , "Memory fill" }, - ,{"NTSC" , CmdNTSC , CMD_NTSC , "Save/Load the NTSC palette" } - ,{"TSAVE" , CmdTextSave , CMD_TEXT_SAVE , "Save text screen" } + {TEXT("NTSC") , CmdNTSC , CMD_NTSC , "Save/Load the NTSC palette" }, + {TEXT("TSAVE") , CmdTextSave , CMD_TEXT_SAVE , "Save text screen" }, // Output / Scripts - ,{"CALC" , CmdOutputCalc , CMD_OUTPUT_CALC , "Display mini calc result" } - ,{"ECHO" , CmdOutputEcho , CMD_OUTPUT_ECHO , "Echo string to console" } // or toggle command echoing" - ,{"PRINT" , CmdOutputPrint , CMD_OUTPUT_PRINT , "Display string and/or hex values" } - ,{"PRINTF" , CmdOutputPrintf , CMD_OUTPUT_PRINTF , "Display formatted string" } - ,{"RUN" , CmdOutputRun , CMD_OUTPUT_RUN , "Run script file of debugger commands" } + {TEXT("CALC") , CmdOutputCalc , CMD_OUTPUT_CALC , "Display mini calc result" }, + {TEXT("ECHO") , CmdOutputEcho , CMD_OUTPUT_ECHO , "Echo string to console" }, // or toggle command echoing" + {TEXT("PRINT") , CmdOutputPrint , CMD_OUTPUT_PRINT , "Display string and/or hex values" }, + {TEXT("PRINTF") , CmdOutputPrintf , CMD_OUTPUT_PRINTF , "Display formatted string" }, + {TEXT("RUN") , CmdOutputRun , CMD_OUTPUT_RUN , "Run script file of debugger commands" }, // Source Level Debugging - ,{"SOURCE" , CmdSource , CMD_SOURCE , "Starts/Stops source level debugging" } - ,{"SYNC" , CmdSync , CMD_SYNC , "Syncs the cursor to the source file" } + {TEXT("SOURCE") , CmdSource , CMD_SOURCE , "Starts/Stops source level debugging" }, + {TEXT("SYNC") , CmdSync , CMD_SYNC , "Syncs the cursor to the source file" }, // Symbols - ,{"SYM" , CmdSymbols , CMD_SYMBOLS_LOOKUP , "Lookup symbol or address, or define symbol" } + {TEXT("SYM") , CmdSymbols , CMD_SYMBOLS_LOOKUP , "Lookup symbol or address, or define symbol" }, - ,{"SYMMAIN" , CmdSymbolsCommand , CMD_SYMBOLS_ROM , "Main/ROM symbol table lookup/menu" } // CLEAR,LOAD,SAVE - ,{"SYMBASIC" , CmdSymbolsCommand , CMD_SYMBOLS_APPLESOFT , "Applesoft symbol table lookup/menu" } // CLEAR,LOAD,SAVE - ,{"SYMASM" , CmdSymbolsCommand , CMD_SYMBOLS_ASSEMBLY , "Assembly symbol table lookup/menu" } // CLEAR,LOAD,SAVE - ,{"SYMUSER" , CmdSymbolsCommand , CMD_SYMBOLS_USER_1 , "First user symbol table lookup/menu" } // CLEAR,LOAD,SAVE - ,{"SYMUSER2" , CmdSymbolsCommand , CMD_SYMBOLS_USER_2 , "Second User symbol table lookup/menu" } // CLEAR,LOAD,SAVE - ,{"SYMSRC" , CmdSymbolsCommand , CMD_SYMBOLS_SRC_1 , "First Source symbol table lookup/menu" } // CLEAR,LOAD,SAVE - ,{"SYMSRC2" , CmdSymbolsCommand , CMD_SYMBOLS_SRC_2 , "Second Source symbol table lookup/menu" } // CLEAR,LOAD,SAVE - ,{"SYMDOS33" , CmdSymbolsCommand , CMD_SYMBOLS_DOS33 , "DOS 3.3 symbol table lookup/menu" } // CLEAR,LOAD,SAVE - ,{"SYMPRODOS" , CmdSymbolsCommand , CMD_SYMBOLS_PRODOS , "ProDOS symbol table lookup/menu" } // CLEAR,LOAD,SAVE + {"SYMMAIN" , CmdSymbolsCommand , CMD_SYMBOLS_ROM , "Main/ROM symbol table lookup/menu" }, // CLEAR,LOAD,SAVE + {"SYMBASIC" , CmdSymbolsCommand , CMD_SYMBOLS_APPLESOFT , "Applesoft symbol table lookup/menu" }, // CLEAR,LOAD,SAVE + {"SYMASM" , CmdSymbolsCommand , CMD_SYMBOLS_ASSEMBLY , "Assembly symbol table lookup/menu" }, // CLEAR,LOAD,SAVE + {"SYMUSER" , CmdSymbolsCommand , CMD_SYMBOLS_USER_1 , "First user symbol table lookup/menu" }, // CLEAR,LOAD,SAVE + {"SYMUSER2" , CmdSymbolsCommand , CMD_SYMBOLS_USER_2 , "Second User symbol table lookup/menu" }, // CLEAR,LOAD,SAVE + {"SYMSRC" , CmdSymbolsCommand , CMD_SYMBOLS_SRC_1 , "First Source symbol table lookup/menu" }, // CLEAR,LOAD,SAVE + {"SYMSRC2" , CmdSymbolsCommand , CMD_SYMBOLS_SRC_2 , "Second Source symbol table lookup/menu" }, // CLEAR,LOAD,SAVE + {"SYMDOS33" , CmdSymbolsCommand , CMD_SYMBOLS_DOS33 , "DOS 3.3 symbol table lookup/menu" }, // CLEAR,LOAD,SAVE + {"SYMPRODOS" , CmdSymbolsCommand , CMD_SYMBOLS_PRODOS , "ProDOS symbol table lookup/menu" }, // CLEAR,LOAD,SAVE -// ,{"SYMCLEAR" , CmdSymbolsClear , CMD_SYMBOLS_CLEAR } // can't use SC = SetCarry - ,{"SYMINFO" , CmdSymbolsInfo , CMD_SYMBOLS_INFO , "Display summary of symbols" } - ,{"SYMLIST" , CmdSymbolsList , CMD_SYMBOLS_LIST , "Lookup symbol in main/user/src tables" } // 'symbolname', can't use param '*' +// {TEXT("SYMCLEAR") , CmdSymbolsClear , CMD_SYMBOLS_CLEAR }, // can't use SC = SetCarry + {TEXT("SYMINFO") , CmdSymbolsInfo , CMD_SYMBOLS_INFO , "Display summary of symbols" }, + {TEXT("SYMLIST") , CmdSymbolsList , CMD_SYMBOLS_LIST , "Lookup symbol in main/user/src tables" }, // 'symbolname', can't use param '*' // Variables -// ,{"CLEAR" , CmdVarsClear , CMD_VARIABLES_CLEAR } -// ,{"VAR" , CmdVarsDefine , CMD_VARIABLES_DEFINE } -// ,{"INT8" , CmdVarsDefineInt8 , CMD_VARIABLES_DEFINE_INT8 } -// ,{"INT16" , CmdVarsDefineInt16 , CMD_VARIABLES_DEFINE_INT16 } -// ,{"VARS" , CmdVarsList , CMD_VARIABLES_LIST } -// ,{"VARSLOAD" , CmdVarsLoad , CMD_VARIABLES_LOAD } -// ,{"VARSSAVE" , CmdVarsSave , CMD_VARIABLES_SAVE } -// ,{"SET" , CmdVarsSet , CMD_VARIABLES_SET } +// {TEXT("CLEAR") , CmdVarsClear , CMD_VARIABLES_CLEAR }, +// {TEXT("VAR") , CmdVarsDefine , CMD_VARIABLES_DEFINE }, +// {TEXT("INT8") , CmdVarsDefineInt8 , CMD_VARIABLES_DEFINE_INT8}, +// {TEXT("INT16") , CmdVarsDefineInt16 , CMD_VARIABLES_DEFINE_INT16}, +// {TEXT("VARS") , CmdVarsList , CMD_VARIABLES_LIST }, +// {TEXT("VARSLOAD") , CmdVarsLoad , CMD_VARIABLES_LOAD }, +// {TEXT("VARSSAVE") , CmdVarsSave , CMD_VARIABLES_SAVE }, +// {TEXT("SET") , CmdVarsSet , CMD_VARIABLES_SET }, // View - ,{"TEXT" , CmdViewOutput_Text4X , CMD_VIEW_TEXT4X , "View Text screen (current page)" } - ,{"TEXT1" , CmdViewOutput_Text41 , CMD_VIEW_TEXT41 , "View Text screen Page 1" } - ,{"TEXT2" , CmdViewOutput_Text42 , CMD_VIEW_TEXT42 , "View Text screen Page 2" } - ,{"TEXT80" , CmdViewOutput_Text8X , CMD_VIEW_TEXT8X , "View 80-col Text screen (current page)" } - ,{"TEXT81" , CmdViewOutput_Text81 , CMD_VIEW_TEXT81 , "View 80-col Text screen Page 1" } - ,{"TEXT82" , CmdViewOutput_Text82 , CMD_VIEW_TEXT82 , "View 80-col Text screen Page 2" } - ,{"GR" , CmdViewOutput_GRX , CMD_VIEW_GRX , "View Lo-Res screen (current page)" } - ,{"GR1" , CmdViewOutput_GR1 , CMD_VIEW_GR1 , "View Lo-Res screen Page 1" } - ,{"GR2" , CmdViewOutput_GR2 , CMD_VIEW_GR2 , "View Lo-Res screen Page 2" } - ,{"DGR" , CmdViewOutput_DGRX , CMD_VIEW_DGRX , "View Double lo-res (current page)" } - ,{"DGR1" , CmdViewOutput_DGR1 , CMD_VIEW_DGR1 , "View Double lo-res Page 1" } - ,{"DGR2" , CmdViewOutput_DGR2 , CMD_VIEW_DGR2 , "View Double lo-res Page 2" } - ,{"HGR" , CmdViewOutput_HGRX , CMD_VIEW_HGRX , "View Hi-res (current page)" } - ,{"HGR1" , CmdViewOutput_HGR1 , CMD_VIEW_HGR1 , "View Hi-res Page 1" } - ,{"HGR2" , CmdViewOutput_HGR2 , CMD_VIEW_HGR2 , "View Hi-res Page 2" } - ,{"DHGR" , CmdViewOutput_DHGRX , CMD_VIEW_DHGRX , "View Double Hi-res (current page)" } - ,{"DHGR1" , CmdViewOutput_DHGR1 , CMD_VIEW_DHGR1 , "View Double Hi-res Page 1" } - ,{"DHGR2" , CmdViewOutput_DHGR2 , CMD_VIEW_DHGR2 , "View Double Hi-res Page 2" } + {TEXT("TEXT") , CmdViewOutput_Text4X , CMD_VIEW_TEXT4X, "View Text screen (current page)" }, + {TEXT("TEXT1") , CmdViewOutput_Text41 , CMD_VIEW_TEXT41, "View Text screen Page 1" }, + {TEXT("TEXT2") , CmdViewOutput_Text42 , CMD_VIEW_TEXT42, "View Text screen Page 2" }, + {TEXT("TEXT80") , CmdViewOutput_Text8X , CMD_VIEW_TEXT8X, "View 80-col Text screen (current page)" }, + {TEXT("TEXT81") , CmdViewOutput_Text81 , CMD_VIEW_TEXT81, "View 80-col Text screen Page 1" }, + {TEXT("TEXT82") , CmdViewOutput_Text82 , CMD_VIEW_TEXT82, "View 80-col Text screen Page 2" }, + {TEXT("GR") , CmdViewOutput_GRX , CMD_VIEW_GRX , "View Lo-Res screen (current page)" }, + {TEXT("GR1") , CmdViewOutput_GR1 , CMD_VIEW_GR1 , "View Lo-Res screen Page 1" }, + {TEXT("GR2") , CmdViewOutput_GR2 , CMD_VIEW_GR2 , "View Lo-Res screen Page 2" }, + {TEXT("DGR") , CmdViewOutput_DGRX , CMD_VIEW_DGRX , "View Double lo-res (current page)" }, + {TEXT("DGR1") , CmdViewOutput_DGR1 , CMD_VIEW_DGR1 , "View Double lo-res Page 1" }, + {TEXT("DGR2") , CmdViewOutput_DGR2 , CMD_VIEW_DGR2 , "View Double lo-res Page 2" }, + {TEXT("HGR") , CmdViewOutput_HGRX , CMD_VIEW_HGRX , "View Hi-res (current page)" }, + {TEXT("HGR1") , CmdViewOutput_HGR1 , CMD_VIEW_HGR1 , "View Hi-res Page 1" }, + {TEXT("HGR2") , CmdViewOutput_HGR2 , CMD_VIEW_HGR2 , "View Hi-res Page 2" }, + {TEXT("DHGR") , CmdViewOutput_DHGRX , CMD_VIEW_DHGRX , "View Double Hi-res (current page)" }, + {TEXT("DHGR1") , CmdViewOutput_DHGR1 , CMD_VIEW_DHGR1 , "View Double Hi-res Page 1" }, + {TEXT("DHGR2") , CmdViewOutput_DHGR2 , CMD_VIEW_DHGR2 , "View Double Hi-res Page 2" }, // Watch - ,{"W" , CmdWatch , CMD_WATCH , "Alias for WA (Watch Add)" } - ,{"WA" , CmdWatchAdd , CMD_WATCH_ADD , "Add/Update address or symbol to watch" } - ,{"WC" , CmdWatchClear , CMD_WATCH_CLEAR , "Clear (remove) watch" } - ,{"WD" , CmdWatchDisable , CMD_WATCH_DISABLE , "Disable specific watch - listed not active" } - ,{"WE" , CmdWatchEnable , CMD_WATCH_ENABLE , "(Re)Enable disabled watch" } - ,{"WL" , CmdWatchList , CMD_WATCH_LIST , "List all watches" } -// ,{"WLOAD" , CmdWatchLoad , CMD_WATCH_LOAD , "Load Watches" } // Cant use as param to W - ,{"WSAVE" , CmdWatchSave , CMD_WATCH_SAVE , "Save Watches" } // due to symbol look-up + {TEXT("W") , CmdWatch , CMD_WATCH , "Alias for WA (Watch Add)" }, + {TEXT("WA") , CmdWatchAdd , CMD_WATCH_ADD , "Add/Update address or symbol to watch" }, + {TEXT("WC") , CmdWatchClear , CMD_WATCH_CLEAR , "Clear (remove) watch" }, + {TEXT("WD") , CmdWatchDisable , CMD_WATCH_DISABLE , "Disable specific watch - it is still in the list, just not active" }, + {TEXT("WE") , CmdWatchEnable , CMD_WATCH_ENABLE , "(Re)Enable disabled watch" }, + {TEXT("WL") , CmdWatchList , CMD_WATCH_LIST , "List all watches" }, +// {TEXT("WLOAD") , CmdWatchLoad , CMD_WATCH_LOAD , "Load Watches" }, // Cant use as param to W + {TEXT("WSAVE") , CmdWatchSave , CMD_WATCH_SAVE , "Save Watches" }, // due to symbol look-up // Window - ,{"WIN" , CmdWindow , CMD_WINDOW , "Show specified debugger window" } + {TEXT("WIN") , CmdWindow , CMD_WINDOW , "Show specified debugger window" }, // CODE 0, CODE 1, CODE 2 ... ??? - ,{"CODE" , CmdWindowViewCode , CMD_WINDOW_CODE , "Switch to full code window" } // Can't use WC = WatchClear - ,{"CODE1" , CmdWindowShowCode1 , CMD_WINDOW_CODE_1 , "Show code on top split window" } - ,{"CODE2" , CmdWindowShowCode2 , CMD_WINDOW_CODE_2 , "Show code on bottom split window" } - ,{"CONSOLE" , CmdWindowViewConsole , CMD_WINDOW_CONSOLE , "Switch to full console window" } - ,{"DATA" , CmdWindowViewData , CMD_WINDOW_DATA , "Switch to full data window" } - ,{"DATA1" , CmdWindowShowData1 , CMD_WINDOW_DATA_1 , "Show data on top split window" } - ,{"DATA2" , CmdWindowShowData2 , CMD_WINDOW_DATA_2 , "Show data on bottom split window" } - ,{"SOURCE1" , CmdWindowShowSource1 , CMD_WINDOW_SOURCE_1 , "Show source on top split screen" } - ,{"SOURCE2" , CmdWindowShowSource2 , CMD_WINDOW_SOURCE_2 , "Show source on bottom split screen" } + {TEXT("CODE") , CmdWindowViewCode , CMD_WINDOW_CODE , "Switch to full code window" }, // Can't use WC = WatchClear + {TEXT("CODE1") , CmdWindowShowCode1 , CMD_WINDOW_CODE_1 , "Show code on top split window" }, + {TEXT("CODE2") , CmdWindowShowCode2 , CMD_WINDOW_CODE_2 , "Show code on bottom split window" }, + {TEXT("CONSOLE") , CmdWindowViewConsole , CMD_WINDOW_CONSOLE , "Switch to full console window" }, + {TEXT("DATA") , CmdWindowViewData , CMD_WINDOW_DATA , "Switch to full data window" }, + {TEXT("DATA1") , CmdWindowShowData1 , CMD_WINDOW_DATA_1 , "Show data on top split window" }, + {TEXT("DATA2") , CmdWindowShowData2 , CMD_WINDOW_DATA_2 , "Show data on bottom split window" }, + {TEXT("SOURCE1") , CmdWindowShowSource1 , CMD_WINDOW_SOURCE_1, "Show source on top split screen" }, + {TEXT("SOURCE2") , CmdWindowShowSource2 , CMD_WINDOW_SOURCE_2, "Show source on bottom split screen" }, - ,{"\\" , CmdWindowViewOutput , CMD_WINDOW_OUTPUT , "Display Apple output until key pressed" } -// ,{"INFO" , CmdToggleInfoPanel , CMD_WINDOW_TOGGLE } -// ,{"WINSOURCE" , CmdWindowShowSource , CMD_WINDOW_SOURCE } -// ,{"ZEROPAGE" , CmdWindowShowZeropage , CMD_WINDOW_ZEROPAGE } + {TEXT("\\") , CmdWindowViewOutput , CMD_WINDOW_OUTPUT , "Display Apple output until key pressed" }, +// {TEXT("INFO") , CmdToggleInfoPanel , CMD_WINDOW_TOGGLE }, +// {TEXT("WINSOURCE") , CmdWindowShowSource , CMD_WINDOW_SOURCE }, +// {TEXT("ZEROPAGE") , CmdWindowShowZeropage, CMD_WINDOW_ZEROPAGE }, // Zero Page - ,{"ZP" , CmdZeroPage , CMD_ZEROPAGE_POINTER , "Alias for ZPA (Zero Page Add)" } - ,{"ZP0" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_0 , "Set/Update/Remove ZP watch 0 " } - ,{"ZP1" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_1 , "Set/Update/Remove ZP watch 1" } - ,{"ZP2" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_2 , "Set/Update/Remove ZP watch 2" } - ,{"ZP3" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_3 , "Set/Update/Remove ZP watch 3" } - ,{"ZP4" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_4 , "Set/Update/Remove ZP watch 4" } - ,{"ZP5" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_5 , "Set/Update/Remove ZP watch 5 " } - ,{"ZP6" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_6 , "Set/Update/Remove ZP watch 6" } - ,{"ZP7" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_7 , "Set/Update/Remove ZP watch 7" } - ,{"ZPA" , CmdZeroPageAdd , CMD_ZEROPAGE_POINTER_ADD , "Add/Update address to zero page pointer" } - ,{"ZPC" , CmdZeroPageClear , CMD_ZEROPAGE_POINTER_CLEAR , "Clear (remove) zero page pointer" } - ,{"ZPD" , CmdZeroPageDisable , CMD_ZEROPAGE_POINTER_DISABLE, "Disable zero page pointer" } - ,{"ZPE" , CmdZeroPageEnable , CMD_ZEROPAGE_POINTER_ENABLE , "(Re)Enable disabled zero page pointer" } - ,{"ZPL" , CmdZeroPageList , CMD_ZEROPAGE_POINTER_LIST , "List all zero page pointers" } -// ,{"ZPLOAD" , CmdZeroPageLoad , CMD_ZEROPAGE_POINTER_LOAD , "Load zero page pointers" } // Cant use as param to ZP - ,{"ZPSAVE" , CmdZeroPageSave , CMD_ZEROPAGE_POINTER_SAVE , "Save zero page pointers" } // due to symbol look-up + {TEXT("ZP") , CmdZeroPage , CMD_ZEROPAGE_POINTER , "Alias for ZPA (Zero Page Add)" }, + {TEXT("ZP0") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_0 , "Set/Update/Remove ZP watch 0 " }, + {TEXT("ZP1") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_1 , "Set/Update/Remove ZP watch 1" }, + {TEXT("ZP2") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_2 , "Set/Update/Remove ZP watch 2" }, + {TEXT("ZP3") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_3 , "Set/Update/Remove ZP watch 3" }, + {TEXT("ZP4") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_4 , "Set/Update/Remove ZP watch 4" }, + {TEXT("ZP5") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_5 , "Set/Update/Remove ZP watch 5 " }, + {TEXT("ZP6") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_6 , "Set/Update/Remove ZP watch 6" }, + {TEXT("ZP7") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_7 , "Set/Update/Remove ZP watch 7" }, + {TEXT("ZPA") , CmdZeroPageAdd , CMD_ZEROPAGE_POINTER_ADD , "Add/Update address to zero page pointer"}, + {TEXT("ZPC") , CmdZeroPageClear , CMD_ZEROPAGE_POINTER_CLEAR , "Clear (remove) zero page pointer" }, + {TEXT("ZPD") , CmdZeroPageDisable , CMD_ZEROPAGE_POINTER_DISABLE,"Disable zero page pointer - it is still in the list, just not active" }, + {TEXT("ZPE") , CmdZeroPageEnable , CMD_ZEROPAGE_POINTER_ENABLE, "(Re)Enable disabled zero page pointer" }, + {TEXT("ZPL") , CmdZeroPageList , CMD_ZEROPAGE_POINTER_LIST , "List all zero page pointers" }, +// {TEXT("ZPLOAD") , CmdZeroPageLoad , CMD_ZEROPAGE_POINTER_LOAD , "Load zero page pointers" }, // Cant use as param to ZP + {TEXT("ZPSAVE") , CmdZeroPageSave , CMD_ZEROPAGE_POINTER_SAVE , "Save zero page pointers" }, // due to symbol look-up -// {"TIMEDEMO"),CmdTimeDemo, CMD_TIMEDEMO }, // CmdBenchmarkStart(), CmdBenchmarkStop() -// {"WC"),CmdShowCodeWindow}, // Can't use since WatchClear -// {"WD"),CmdShowDataWindow}, // +// {TEXT("TIMEDEMO"),CmdTimeDemo, CMD_TIMEDEMO }, // CmdBenchmarkStart(), CmdBenchmarkStop() +// {TEXT("WC"),CmdShowCodeWindow}, // Can't use since WatchClear +// {TEXT("WD"),CmdShowDataWindow}, // // Internal Consistency Check - ,{ DEBUGGER__COMMANDS_VERIFY_TXT__, NULL, NUM_COMMANDS } + { DEBUGGER__COMMANDS_VERIFY_TXT__, NULL, NUM_COMMANDS }, // Aliasies - Can be in any order - ,{"->" , NULL , CMD_CURSOR_JUMP_PC } - ,{"Ctrl ->" , NULL , CMD_CURSOR_SET_PC } - ,{"Shift ->" , NULL , CMD_CURSOR_JUMP_PC } // at top - ,{"INPUT" , CmdIn , CMD_IN } + {TEXT("->") , NULL , CMD_CURSOR_JUMP_PC }, + {TEXT("Ctrl ->" ) , NULL , CMD_CURSOR_SET_PC }, + {TEXT("Shift ->") , NULL , CMD_CURSOR_JUMP_PC }, // at top + {TEXT("INPUT") , CmdIn , CMD_IN }, // Data // Flags - Clear - ,{"RC" , CmdFlagClear , CMD_FLAG_CLR_C , "Clear Flag Carry" } // 0 // Legacy - ,{"RZ" , CmdFlagClear , CMD_FLAG_CLR_Z , "Clear Flag Zero" } // 1 - ,{"RI" , CmdFlagClear , CMD_FLAG_CLR_I , "Clear Flag Interrupts Disabled" } // 2 - ,{"RD" , CmdFlagClear , CMD_FLAG_CLR_D , "Clear Flag Decimal (BCD)" } // 3 - ,{"RB" , CmdFlagClear , CMD_FLAG_CLR_B , "CLear Flag Break" } // 4 // Legacy - ,{"RR" , CmdFlagClear , CMD_FLAG_CLR_R , "Clear Flag Reserved" } // 5 - ,{"RV" , CmdFlagClear , CMD_FLAG_CLR_V , "Clear Flag Overflow" } // 6 - ,{"RN" , CmdFlagClear , CMD_FLAG_CLR_N , "Clear Flag Negative (Sign)" } // 7 + {TEXT("RC") , CmdFlagClear , CMD_FLAG_CLR_C , "Clear Flag Carry" }, // 0 // Legacy + {TEXT("RZ") , CmdFlagClear , CMD_FLAG_CLR_Z , "Clear Flag Zero" }, // 1 + {TEXT("RI") , CmdFlagClear , CMD_FLAG_CLR_I , "Clear Flag Interrupts Disabled" }, // 2 + {TEXT("RD") , CmdFlagClear , CMD_FLAG_CLR_D , "Clear Flag Decimal (BCD)" }, // 3 + {TEXT("RB") , CmdFlagClear , CMD_FLAG_CLR_B , "CLear Flag Break" }, // 4 // Legacy + {TEXT("RR") , CmdFlagClear , CMD_FLAG_CLR_R , "Clear Flag Reserved" }, // 5 + {TEXT("RV") , CmdFlagClear , CMD_FLAG_CLR_V , "Clear Flag Overflow" }, // 6 + {TEXT("RN") , CmdFlagClear , CMD_FLAG_CLR_N , "Clear Flag Negative (Sign)" }, // 7 // Flags - Set - ,{"SC" , CmdFlagSet , CMD_FLAG_SET_C , "Set Flag Carry" } // 0 - ,{"SZ" , CmdFlagSet , CMD_FLAG_SET_Z , "Set Flag Zero" } // 1 - ,{"SI" , CmdFlagSet , CMD_FLAG_SET_I , "Set Flag Interrupts Disabled" } // 2 - ,{"SD" , CmdFlagSet , CMD_FLAG_SET_D , "Set Flag Decimal (BCD)" } // 3 - ,{"SB" , CmdFlagSet , CMD_FLAG_SET_B , "CLear Flag Break" } // 4 // Legacy - ,{"SR" , CmdFlagSet , CMD_FLAG_SET_R , "Clear Flag Reserved" } // 5 - ,{"SV" , CmdFlagSet , CMD_FLAG_SET_V , "Clear Flag Overflow" } // 6 - ,{"SN" , CmdFlagSet , CMD_FLAG_SET_N , "Clear Flag Negative" } // 7 + {TEXT("SC") , CmdFlagSet , CMD_FLAG_SET_C , "Set Flag Carry" }, // 0 + {TEXT("SZ") , CmdFlagSet , CMD_FLAG_SET_Z , "Set Flag Zero" }, // 1 + {TEXT("SI") , CmdFlagSet , CMD_FLAG_SET_I , "Set Flag Interrupts Disabled" }, // 2 + {TEXT("SD") , CmdFlagSet , CMD_FLAG_SET_D , "Set Flag Decimal (BCD)" }, // 3 + {TEXT("SB") , CmdFlagSet , CMD_FLAG_SET_B , "CLear Flag Break" }, // 4 // Legacy + {TEXT("SR") , CmdFlagSet , CMD_FLAG_SET_R , "Clear Flag Reserved" }, // 5 + {TEXT("SV") , CmdFlagSet , CMD_FLAG_SET_V , "Clear Flag Overflow" }, // 6 + {TEXT("SN") , CmdFlagSet , CMD_FLAG_SET_N , "Clear Flag Negative" }, // 7 // Memory - ,{"D" , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 , "Hex dump in the mini memory area 1" } // FIXME: Must also work in DATA screen - ,{"M1" , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 } // alias - ,{"M2" , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_2 } // alias + {TEXT("D") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 , "Hex dump in the mini memory area 1" }, // FIXME: Must also work in DATA screen + {TEXT("M1") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 }, // alias + {TEXT("M2") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_2 }, // alias - ,{"ME8" , CmdMemoryEnterByte , CMD_MEMORY_ENTER_BYTE } // changed from EB -- bugfix: EB:## ## - ,{"ME16" , CmdMemoryEnterWord , CMD_MEMORY_ENTER_WORD } - ,{"MM" , CmdMemoryMove , CMD_MEMORY_MOVE } - ,{"MS" , CmdMemorySearch , CMD_MEMORY_SEARCH } // CmdMemorySearch - ,{"P0" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_0 } - ,{"P1" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_1 } - ,{"P2" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_2 } - ,{"P3" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_3 } - ,{"P4" , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_4 } - ,{"REGISTER" , CmdRegisterSet , CMD_REGISTER_SET } -// ,{"RET" , CmdStackReturn , CMD_STACK_RETURN } - ,{"TRACE" , CmdTrace , CMD_TRACE } + {TEXT("ME8") , CmdMemoryEnterByte , CMD_MEMORY_ENTER_BYTE }, // changed from EB -- bugfix: EB:## ## + {TEXT("ME16") , CmdMemoryEnterWord , CMD_MEMORY_ENTER_WORD }, + {TEXT("MM") , CmdMemoryMove , CMD_MEMORY_MOVE }, + {TEXT("MS") , CmdMemorySearch , CMD_MEMORY_SEARCH }, // CmdMemorySearch + {TEXT("P0") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_0 }, + {TEXT("P1") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_1 }, + {TEXT("P2") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_2 }, + {TEXT("P3") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_3 }, + {TEXT("P4") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_4 }, + {TEXT("REGISTER") , CmdRegisterSet , CMD_REGISTER_SET }, +// {TEXT("RET") , CmdStackReturn , CMD_STACK_RETURN }, + {TEXT("TRACE") , CmdTrace , CMD_TRACE }, -// ,{"SYMBOLS" , CmdSymbols , CMD_SYMBOLS_LOOKUP , "Return " } -// ,{"SYMBOLS1" , CmdSymbolsInfo , CMD_SYMBOLS_1 } -// ,{"SYMBOLS2" , CmdSymbolsInfo , CMD_SYMBOLS_2 } -// ,{"SYM0" , CmdSymbolsInfo , CMD_SYMBOLS_ROM } -// ,{"SYM1" , CmdSymbolsInfo , CMD_SYMBOLS_APPLESOFT } -// ,{"SYM2" , CmdSymbolsInfo , CMD_SYMBOLS_ASSEMBLY } -// ,{"SYM3" , CmdSymbolsInfo , CMD_SYMBOLS_USER_1 } -// ,{"SYM4" , CmdSymbolsInfo , CMD_SYMBOLS_USER_2 } -// ,{"SYM5" , CmdSymbolsInfo , CMD_SYMBOLS_SRC_1 } -// ,{"SYM6" , CmdSymbolsInfo , CMD_SYMBOLS_SRC_2 } - ,{"SYMDOS" , CmdSymbolsCommand , CMD_SYMBOLS_DOS33 } - ,{"SYMPRO" , CmdSymbolsCommand , CMD_SYMBOLS_PRODOS } +// {TEXT("SYMBOLS") , CmdSymbols , CMD_SYMBOLS_LOOKUP , "Return " }, +// {TEXT("SYMBOLS1") , CmdSymbolsInfo , CMD_SYMBOLS_1 }, +// {TEXT("SYMBOLS2") , CmdSymbolsInfo , CMD_SYMBOLS_2 }, +// {"SYM0" , CmdSymbolsInfo , CMD_SYMBOLS_ROM }, +// {"SYM1" , CmdSymbolsInfo , CMD_SYMBOLS_APPLESOFT }, +// {"SYM2" , CmdSymbolsInfo , CMD_SYMBOLS_ASSEMBLY }, +// {"SYM3" , CmdSymbolsInfo , CMD_SYMBOLS_USER_1 }, +// {"SYM4" , CmdSymbolsInfo , CMD_SYMBOLS_USER_2 }, +// {"SYM5" , CmdSymbolsInfo , CMD_SYMBOLS_SRC_1 }, +// {"SYM6" , CmdSymbolsInfo , CMD_SYMBOLS_SRC_2 }, + {"SYMDOS" , CmdSymbolsCommand , CMD_SYMBOLS_DOS33 }, + {"SYMPRO" , CmdSymbolsCommand , CMD_SYMBOLS_PRODOS }, - ,{"TEXT40" , CmdViewOutput_Text4X , CMD_VIEW_TEXT4X } - ,{"TEXT41" , CmdViewOutput_Text41 , CMD_VIEW_TEXT41 } - ,{"TEXT42" , CmdViewOutput_Text42 , CMD_VIEW_TEXT42 } + {TEXT("TEXT40") , CmdViewOutput_Text4X , CMD_VIEW_TEXT4X }, + {TEXT("TEXT41") , CmdViewOutput_Text41 , CMD_VIEW_TEXT41 }, + {TEXT("TEXT42") , CmdViewOutput_Text42 , CMD_VIEW_TEXT42 }, -// ,{"WATCH" , CmdWatchAdd , CMD_WATCH_ADD } - ,{"WINDOW" , CmdWindow , CMD_WINDOW } -// ,{"W?" , CmdWatchAdd , CMD_WATCH_ADD } - ,{"ZAP" , CmdNOP , CMD_NOP } +// {TEXT("WATCH") , CmdWatchAdd , CMD_WATCH_ADD }, + {TEXT("WINDOW") , CmdWindow , CMD_WINDOW }, +// {TEXT("W?") , CmdWatchAdd , CMD_WATCH_ADD }, + {TEXT("ZAP") , CmdNOP , CMD_NOP }, // DEPRECATED -- Probably should be removed in a future version - ,{"BENCH" , CmdBenchmarkStart , CMD_BENCHMARK } // already hae BENCHMARK - ,{"EXITBENCH" , NULL , CMD_BENCHMARK } // 2.8.03 was incorrectly alias with 'E' Bug #246. // CmdBenchmarkStop - ,{"MDB" , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 } // MemoryDumpByte // Did anyone actually use this?? -// ,{"MEMORY" , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 } // MemoryDumpByte // Did anyone actually use this?? + {TEXT("BENCH") , CmdBenchmarkStart , CMD_BENCHMARK }, + {TEXT("EXITBENCH") , NULL , CMD_BENCHMARK }, // 2.8.03 was incorrectly alias with 'E' Bug #246. // CmdBenchmarkStop + {TEXT("MDB") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 }, // MemoryDumpByte // Did anyone actually use this?? +// {TEXT("MEMORY") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 }, // MemoryDumpByte // Did anyone actually use this?? }; const int NUM_COMMANDS_WITH_ALIASES = sizeof(g_aCommands) / sizeof (Command_t); // Determined at compile-time ;-) @@ -391,114 +391,113 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Command_t g_aParameters[] = { // Breakpoint - {"<=" , NULL, PARAM_BP_LESS_EQUAL } - ,{"<" , NULL, PARAM_BP_LESS_THAN } - ,{"=" , NULL, PARAM_BP_EQUAL } - ,{"!=" , NULL, PARAM_BP_NOT_EQUAL } - ,{"!" , NULL, PARAM_BP_NOT_EQUAL_1 } - ,{">" , NULL, PARAM_BP_GREATER_THAN } - ,{">=" , NULL, PARAM_BP_GREATER_EQUAL } - ,{"R" , NULL, PARAM_BP_READ } - ,{"?" , NULL, PARAM_BP_READ } - ,{"W" , NULL, PARAM_BP_WRITE } - ,{"@" , NULL, PARAM_BP_WRITE } - ,{"*" , NULL, PARAM_BP_READ_WRITE } + {TEXT("<=") , NULL, PARAM_BP_LESS_EQUAL }, + {TEXT("<" ) , NULL, PARAM_BP_LESS_THAN }, + {TEXT("=" ) , NULL, PARAM_BP_EQUAL }, + {TEXT("!=") , NULL, PARAM_BP_NOT_EQUAL }, + {TEXT("!" ) , NULL, PARAM_BP_NOT_EQUAL_1 }, + {TEXT(">" ) , NULL, PARAM_BP_GREATER_THAN }, + {TEXT(">=") , NULL, PARAM_BP_GREATER_EQUAL }, + {TEXT("R") , NULL, PARAM_BP_READ }, + {TEXT("?") , NULL, PARAM_BP_READ }, + {TEXT("W") , NULL, PARAM_BP_WRITE }, + {TEXT("@") , NULL, PARAM_BP_WRITE }, + {TEXT("*") , NULL, PARAM_BP_READ_WRITE }, // Regs (for PUSH / POP) - ,{"A" , NULL, PARAM_REG_A } - ,{"X" , NULL, PARAM_REG_X } - ,{"Y" , NULL, PARAM_REG_Y } - ,{"PC" , NULL, PARAM_REG_PC } - ,{"S" , NULL, PARAM_REG_SP } -// ,{"G" , NULL, PARAM_REG_PC } + {TEXT("A") , NULL, PARAM_REG_A }, + {TEXT("X") , NULL, PARAM_REG_X }, + {TEXT("Y") , NULL, PARAM_REG_Y }, + {TEXT("PC") , NULL, PARAM_REG_PC }, + {TEXT("S") , NULL, PARAM_REG_SP }, // Flags - ,{"P" , NULL, PARAM_FLAGS } - ,{"C" , NULL, PARAM_FLAG_C } // ---- ---1 Carry - ,{"Z" , NULL, PARAM_FLAG_Z } // ---- --1- Zero - ,{"I" , NULL, PARAM_FLAG_I } // ---- -1-- Interrupt - ,{"D" , NULL, PARAM_FLAG_D } // ---- 1--- Decimal - ,{"B" , NULL, PARAM_FLAG_B } // ---1 ---- Break - ,{"R" , NULL, PARAM_FLAG_R } // --1- ---- Reserved - ,{"V" , NULL, PARAM_FLAG_V } // -1-- ---- Overflow - ,{"N" , NULL, PARAM_FLAG_N } // 1--- ---- Sign + {TEXT("P") , NULL, PARAM_FLAGS }, + {TEXT("C") , NULL, PARAM_FLAG_C }, // ---- ---1 Carry + {TEXT("Z") , NULL, PARAM_FLAG_Z }, // ---- --1- Zero + {TEXT("I") , NULL, PARAM_FLAG_I }, // ---- -1-- Interrupt + {TEXT("D") , NULL, PARAM_FLAG_D }, // ---- 1--- Decimal + {TEXT("B") , NULL, PARAM_FLAG_B }, // ---1 ---- Break + {TEXT("R") , NULL, PARAM_FLAG_R }, // --1- ---- Reserved + {TEXT("V") , NULL, PARAM_FLAG_V }, // -1-- ---- Overflow + {TEXT("N") , NULL, PARAM_FLAG_N }, // 1--- ---- Sign // Disasm - ,{"BRANCH" , NULL, PARAM_CONFIG_BRANCH } - ,{"COLON" , NULL, PARAM_CONFIG_COLON } - ,{"OPCODE" , NULL, PARAM_CONFIG_OPCODE } - ,{"POINTER" , NULL, PARAM_CONFIG_POINTER } - ,{"SPACES" , NULL, PARAM_CONFIG_SPACES } - ,{"TARGET" , NULL, PARAM_CONFIG_TARGET } + {TEXT("BRANCH") , NULL, PARAM_CONFIG_BRANCH }, + {TEXT("COLON") , NULL, PARAM_CONFIG_COLON }, + {TEXT("OPCODE") , NULL, PARAM_CONFIG_OPCODE }, + {TEXT("POINTER") , NULL, PARAM_CONFIG_POINTER }, + {TEXT("SPACES") , NULL, PARAM_CONFIG_SPACES }, + {TEXT("TARGET") , NULL, PARAM_CONFIG_TARGET }, // Disk - ,{"EJECT" , NULL, PARAM_DISK_EJECT } - ,{"INFO" , NULL, PARAM_DISK_INFO } - ,{"PROTECT" , NULL, PARAM_DISK_PROTECT } - ,{"READ" , NULL, PARAM_DISK_READ } + {TEXT("EJECT") , NULL, PARAM_DISK_EJECT }, + {TEXT("INFO") , NULL, PARAM_DISK_INFO }, + {TEXT("PROTECT") , NULL, PARAM_DISK_PROTECT }, + {TEXT("READ") , NULL, PARAM_DISK_READ }, // Font (Config) - ,{"MODE" , NULL, PARAM_FONT_MODE } // also INFO, CONSOLE, DISASM (from Window) + {TEXT("MODE") , NULL, PARAM_FONT_MODE }, // also INFO, CONSOLE, DISASM (from Window) // General - ,{"FIND" , NULL, PARAM_FIND } - ,{"BRANCH" , NULL, PARAM_BRANCH } - ,{"CATEGORY" , NULL, PARAM_CATEGORY } - ,{"CLEAR" , NULL, PARAM_CLEAR } - ,{"LOAD" , NULL, PARAM_LOAD } - ,{"LIST" , NULL, PARAM_LIST } - ,{"OFF" , NULL, PARAM_OFF } - ,{"ON" , NULL, PARAM_ON } - ,{"RESET" , NULL, PARAM_RESET } - ,{"SAVE" , NULL, PARAM_SAVE } - ,{"START" , NULL, PARAM_START } // benchmark - ,{"STOP" , NULL, PARAM_STOP } // benchmark + {TEXT("FIND") , NULL, PARAM_FIND }, + {TEXT("BRANCH") , NULL, PARAM_BRANCH }, + {"CATEGORY" , NULL, PARAM_CATEGORY }, + {TEXT("CLEAR") , NULL, PARAM_CLEAR }, + {TEXT("LOAD") , NULL, PARAM_LOAD }, + {TEXT("LIST") , NULL, PARAM_LIST }, + {TEXT("OFF") , NULL, PARAM_OFF }, + {TEXT("ON") , NULL, PARAM_ON }, + {TEXT("RESET") , NULL, PARAM_RESET }, + {TEXT("SAVE") , NULL, PARAM_SAVE }, + {TEXT("START") , NULL, PARAM_START }, // benchmark + {TEXT("STOP") , NULL, PARAM_STOP }, // benchmark // Help Categories - ,{"*" , NULL, PARAM_WILDSTAR } - ,{"BOOKMARKS" , NULL, PARAM_CAT_BOOKMARKS } - ,{"BREAKPOINTS", NULL, PARAM_CAT_BREAKPOINTS } - ,{"CONFIG" , NULL, PARAM_CAT_CONFIG } - ,{"CPU" , NULL, PARAM_CAT_CPU } -// ,{"EXPRESSION" , - ,{"FLAGS" , NULL, PARAM_CAT_FLAGS } - ,{"HELP" , NULL, PARAM_CAT_HELP } - ,{"KEYBOARD" , NULL, PARAM_CAT_KEYBOARD } - ,{"MEMORY" , NULL, PARAM_CAT_MEMORY } // alias // SOURCE [SYMBOLS] [MEMORY] filename - ,{"OUTPUT" , NULL, PARAM_CAT_OUTPUT } - ,{"OPERATORS" , NULL, PARAM_CAT_OPERATORS } - ,{"RANGE" , NULL, PARAM_CAT_RANGE } -// ,{"REGISTERS" NULL, PARAM_CAT_REGISTERS } - ,{"SYMBOLS" , NULL, PARAM_CAT_SYMBOLS } - ,{"VIEW" , NULL, PARAM_CAT_VIEW } - ,{"WATCHES" , NULL, PARAM_CAT_WATCHES } - ,{"WINDOW" , NULL, PARAM_CAT_WINDOW } - ,{"ZEROPAGE" , NULL, PARAM_CAT_ZEROPAGE } + {"*" , NULL, PARAM_WILDSTAR }, + {"BOOKMARKS" , NULL, PARAM_CAT_BOOKMARKS }, + {"BREAKPOINTS" , NULL, PARAM_CAT_BREAKPOINTS }, + {"CONFIG" , NULL, PARAM_CAT_CONFIG }, + {"CPU" , NULL, PARAM_CAT_CPU }, +// {TEXT("EXPRESSION") , + {"FLAGS" , NULL, PARAM_CAT_FLAGS }, + {"HELP" , NULL, PARAM_CAT_HELP }, + {"KEYBOARD" , NULL, PARAM_CAT_KEYBOARD }, + {"MEMORY" , NULL, PARAM_CAT_MEMORY }, // alias // SOURCE [SYMBOLS] [MEMORY] filename + {"OUTPUT" , NULL, PARAM_CAT_OUTPUT }, + {"OPERATORS" , NULL, PARAM_CAT_OPERATORS }, + {"RANGE" , NULL, PARAM_CAT_RANGE }, +// {TEXT("REGISTERS") , NULL, PARAM_CAT_REGISTERS }, + {"SYMBOLS" , NULL, PARAM_CAT_SYMBOLS }, + {"VIEW" , NULL, PARAM_CAT_VIEW }, + {"WATCHES" , NULL, PARAM_CAT_WATCHES }, + {"WINDOW" , NULL, PARAM_CAT_WINDOW }, + {"ZEROPAGE" , NULL, PARAM_CAT_ZEROPAGE }, // Memory - ,{"?" , NULL, PARAM_MEM_SEARCH_WILD } -// ,{"*" , NULL, PARAM_MEM_SEARCH_BYTE } + {TEXT("?") , NULL, PARAM_MEM_SEARCH_WILD }, +// {TEXT("*") , NULL, PARAM_MEM_SEARCH_BYTE }, // Source level debugging - ,{"MEM" , NULL, PARAM_SRC_MEMORY } - ,{"MEMORY" , NULL, PARAM_SRC_MEMORY } - ,{"SYM" , NULL, PARAM_SRC_SYMBOLS } - ,{"SYMBOLS" , NULL, PARAM_SRC_SYMBOLS } - ,{"MERLIN" , NULL, PARAM_SRC_MERLIN } - ,{"ORCA" , NULL, PARAM_SRC_ORCA } + {TEXT("MEM") , NULL, PARAM_SRC_MEMORY }, + {TEXT("MEMORY") , NULL, PARAM_SRC_MEMORY }, + {TEXT("SYM") , NULL, PARAM_SRC_SYMBOLS }, + {TEXT("SYMBOLS") , NULL, PARAM_SRC_SYMBOLS }, + {TEXT("MERLIN") , NULL, PARAM_SRC_MERLIN }, + {TEXT("ORCA") , NULL, PARAM_SRC_ORCA }, // View -// ,{"VIEW") , NULL, PARAM_SRC_??? }, +// {TEXT("VIEW") , NULL, PARAM_SRC_??? }, // Window Win Cmd WinEffects CmdEffects - ,{"CODE" , NULL, PARAM_CODE } // x x code win only switch to code window -// ,{"CODE1" , NULL, PARAM_CODE_1 } // - x code/data win - ,{"CODE2" , NULL, PARAM_CODE_2 } // - x code/data win - ,{"CONSOLE" , NULL, PARAM_CONSOLE } // x - switch to console window - ,{"DATA" , NULL, PARAM_DATA } // x x data win only switch to data window -// ,{"DATA1" , NULL, PARAM_DATA_1 } // - x code/data win - ,{"DATA2" , NULL, PARAM_DATA_2 } // - x code/data win - ,{"DISASM" , NULL, PARAM_DISASM } // - ,{"INFO" , NULL, PARAM_INFO } // - x code/data Toggles showing/hiding Regs/Stack/BP/Watches/ZP - ,{"SOURCE" , NULL, PARAM_SOURCE } // x x switch to source window - ,{"SRC" , NULL, PARAM_SOURCE } // alias -// ,{"SOURCE_1" , NULL, PARAM_SOURCE_1 } // - x code/data - ,{"SOURCE2 " , NULL, PARAM_SOURCE_2 } // - x - ,{"SYMBOLS" , NULL, PARAM_SYMBOLS } // x x code/data win switch to symbols window - ,{"SYM" , NULL, PARAM_SYMBOLS } // alias x SOURCE [SYM] [MEM] filename -// ,{"SYMBOL1" , NULL, PARAM_SYMBOL_1 } // - x code/data win - ,{"SYMBOL2" , NULL, PARAM_SYMBOL_2 } // - x code/data win + {TEXT("CODE") , NULL, PARAM_CODE }, // x x code win only switch to code window +// {TEXT("CODE1") , NULL, PARAM_CODE_1 }, // - x code/data win + {TEXT("CODE2") , NULL, PARAM_CODE_2 }, // - x code/data win + {TEXT("CONSOLE") , NULL, PARAM_CONSOLE }, // x - switch to console window + {TEXT("DATA") , NULL, PARAM_DATA }, // x x data win only switch to data window +// {TEXT("DATA1") , NULL, PARAM_DATA_1 }, // - x code/data win + {TEXT("DATA2") , NULL, PARAM_DATA_2 }, // - x code/data win + {TEXT("DISASM") , NULL, PARAM_DISASM }, // + {TEXT("INFO") , NULL, PARAM_INFO }, // - x code/data Toggles showing/hiding Regs/Stack/BP/Watches/ZP + {TEXT("SOURCE") , NULL, PARAM_SOURCE }, // x x switch to source window + {TEXT("SRC") , NULL, PARAM_SOURCE }, // alias +// {TEXT("SOURCE_1") , NULL, PARAM_SOURCE_1 }, // - x code/data + {TEXT("SOURCE2 ") , NULL, PARAM_SOURCE_2 }, // - x + {TEXT("SYMBOLS") , NULL, PARAM_SYMBOLS }, // x x code/data win switch to symbols window + {TEXT("SYM") , NULL, PARAM_SYMBOLS }, // alias x SOURCE [SYM] [MEM] filename +// {TEXT("SYMBOL1") , NULL, PARAM_SYMBOL_1 }, // - x code/data win + {TEXT("SYMBOL2") , NULL, PARAM_SYMBOL_2 }, // - x code/data win // Internal Consistency Check - ,{DEBUGGER__PARAMS_VERIFY_TXT__,NULL,NUM_PARAMS} + { DEBUGGER__PARAMS_VERIFY_TXT__, NULL, NUM_PARAMS }, }; //=========================================================================== @@ -512,7 +511,7 @@ void VerifyDebuggerCommandTable() if ( g_aCommands[ iCmd ].iCommand != iCmd) { sprintf( sText, "*** ERROR *** Enumerated Commands mis-matched at #%d!", iCmd ); - MessageBoxA( g_hFrameWindow, sText, "ERROR", MB_OK ); + MessageBoxA( g_hFrameWindow, sText, TEXT("ERROR"), MB_OK ); PostQuitMessage( 1 ); } } @@ -521,14 +520,14 @@ void VerifyDebuggerCommandTable() if (strcmp( g_aCommands[ NUM_COMMANDS ].m_sName, DEBUGGER__COMMANDS_VERIFY_TXT__)) { sprintf( sText, "*** ERROR *** Total Commands mis-matched!" ); - MessageBoxA( g_hFrameWindow, sText, "ERROR", MB_OK ); + MessageBoxA( g_hFrameWindow, sText, TEXT("ERROR"), MB_OK ); PostQuitMessage( 1 ); } if (strcmp( g_aParameters[ NUM_PARAMS ].m_sName, DEBUGGER__PARAMS_VERIFY_TXT__)) { sprintf( sText, "*** ERROR *** Total Parameters mis-matched!" ); - MessageBoxA( g_hFrameWindow, sText, "ERROR", MB_OK ); + MessageBoxA( g_hFrameWindow, sText, TEXT("ERROR"), MB_OK ); PostQuitMessage( 2 ); } } diff --git a/source/Debugger/Debugger_Console.cpp b/source/Debugger/Debugger_Console.cpp index 4b907f72..901e9248 100644 --- a/source/Debugger/Debugger_Console.cpp +++ b/source/Debugger/Debugger_Console.cpp @@ -279,8 +279,9 @@ bool ConsoleBufferPush ( const char * pText ) const char *pSrc = pText; conchar_t *pDst = & g_aConsoleBuffer[ g_nConsoleBuffer ][ 0 ]; - while ((x < CONSOLE_WIDTH) && (c = *pSrc)) + while ((x < CONSOLE_WIDTH) && *pSrc) { + c = *pSrc; if ((c == '\n') || (x == (CONSOLE_WIDTH - 1))) { *pDst = 0; diff --git a/source/Debugger/Debugger_Display.cpp b/source/Debugger/Debugger_Display.cpp index 6e4c98dd..9b854941 100644 --- a/source/Debugger/Debugger_Display.cpp +++ b/source/Debugger/Debugger_Display.cpp @@ -1223,7 +1223,7 @@ void DrawBreakpoints ( int line ) //=========================================================================== int GetConsoleLineHeightPixels() { - int nHeight = nHeight = g_aFontConfig[ FONT_CONSOLE ]._nFontHeight; // _nLineHeight; // _nFontHeight; + int nHeight = g_aFontConfig[ FONT_CONSOLE ]._nFontHeight; // _nLineHeight; // _nFontHeight; /* if (g_iFontSpacing == FONT_SPACING_CLASSIC) { @@ -2434,10 +2434,10 @@ 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(&SS_MB, 4+(nAddr>>1)); // Slot4 or Slot5 + MB_GetSnapshot_v1(&SS_MB, 4+(nAddr>>1)); // Slot4 or Slot5 int nFontWidth = g_aFontConfig[ FONT_INFO ]._nFontWidthAvg; diff --git a/source/Debugger/Debugger_Help.cpp b/source/Debugger/Debugger_Help.cpp index b92223ba..84ed29ea 100644 --- a/source/Debugger/Debugger_Help.cpp +++ b/source/Debugger/Debugger_Help.cpp @@ -126,7 +126,7 @@ Update_t Help_Arg_1( int iCommandHelp ) { _Arg_1( iCommandHelp ); - wsprintf( g_aArgs[ 1 ].sArg, g_aCommands[ iCommandHelp ].m_sName ); // .3 Fixed: Help_Arg_1() now copies command name into arg.name + wsprintf( g_aArgs[ 1 ].sArg, "%s", g_aCommands[ iCommandHelp ].m_sName ); // .3 Fixed: Help_Arg_1() now copies command name into arg.name return CmdHelpSpecific( 1 ); } @@ -669,49 +669,49 @@ Update_t CmdHelpSpecific (int nArgs) // HACK: Major kludge to display category!!! if (iCmd <= CMD_UNASSEMBLE) - wsprintf( sCategory, g_aParameters[ PARAM_CAT_CPU ].m_sName ); + wsprintf( sCategory, "%s", g_aParameters[ PARAM_CAT_CPU ].m_sName ); else if (iCmd <= CMD_BOOKMARK_SAVE) - wsprintf( sCategory, g_aParameters[ PARAM_CAT_BOOKMARKS ].m_sName ); + wsprintf( sCategory, "%s", g_aParameters[ PARAM_CAT_BOOKMARKS ].m_sName ); else if (iCmd <= CMD_BREAKPOINT_SAVE) - wsprintf( sCategory, g_aParameters[ PARAM_CAT_BREAKPOINTS ].m_sName ); + wsprintf( sCategory, "%s", g_aParameters[ PARAM_CAT_BREAKPOINTS ].m_sName ); else if (iCmd <= CMD_CONFIG_SAVE) - wsprintf( sCategory, g_aParameters[ PARAM_CAT_CONFIG ].m_sName ); + wsprintf( sCategory, "%s", g_aParameters[ PARAM_CAT_CONFIG ].m_sName ); else if (iCmd <= CMD_CURSOR_PAGE_DOWN_4K) wsprintf( sCategory, "Scrolling" ); else if (iCmd <= CMD_FLAG_SET_N) - wsprintf( sCategory, g_aParameters[ PARAM_CAT_FLAGS ].m_sName ); + wsprintf( sCategory, "%s", g_aParameters[ PARAM_CAT_FLAGS ].m_sName ); else if (iCmd <= CMD_MOTD) - wsprintf( sCategory, g_aParameters[ PARAM_CAT_HELP ].m_sName ); + wsprintf( sCategory, "%s", g_aParameters[ PARAM_CAT_HELP ].m_sName ); else if (iCmd <= CMD_MEMORY_FILL) - wsprintf( sCategory, g_aParameters[ PARAM_CAT_MEMORY ].m_sName ); + wsprintf( sCategory, "%s", g_aParameters[ PARAM_CAT_MEMORY ].m_sName ); else if (iCmd <= CMD_OUTPUT_RUN) - wsprintf( sCategory, g_aParameters[ PARAM_CAT_OUTPUT ].m_sName ); + wsprintf( sCategory, "%s", g_aParameters[ PARAM_CAT_OUTPUT ].m_sName ); else if (iCmd <= CMD_SYNC) wsprintf( sCategory, "Source" ); else if (iCmd <= CMD_SYMBOLS_LIST) - wsprintf( sCategory, g_aParameters[ PARAM_CAT_SYMBOLS ].m_sName ); + wsprintf( sCategory, "%s", g_aParameters[ PARAM_CAT_SYMBOLS ].m_sName ); else if (iCmd <= CMD_VIEW_DHGR2) - wsprintf( sCategory, g_aParameters[ PARAM_CAT_VIEW ].m_sName ); + wsprintf( sCategory, "%s", g_aParameters[ PARAM_CAT_VIEW ].m_sName ); else if (iCmd <= CMD_WATCH_SAVE) - wsprintf( sCategory, g_aParameters[ PARAM_CAT_WATCHES ].m_sName ); + wsprintf( sCategory, "%s", g_aParameters[ PARAM_CAT_WATCHES ].m_sName ); else if (iCmd <= CMD_WINDOW_OUTPUT) - wsprintf( sCategory, g_aParameters[ PARAM_CAT_WINDOW ].m_sName ); + wsprintf( sCategory, "%s", g_aParameters[ PARAM_CAT_WINDOW ].m_sName ); else if (iCmd <= CMD_ZEROPAGE_POINTER_SAVE) - wsprintf( sCategory, g_aParameters[ PARAM_CAT_ZEROPAGE ].m_sName ); + wsprintf( sCategory, "%s", g_aParameters[ PARAM_CAT_ZEROPAGE ].m_sName ); else wsprintf( sCategory, "Unknown!" ); diff --git a/source/Disk.cpp b/source/Disk.cpp index 211ca632..a239e1c8 100644 --- a/source/Disk.cpp +++ b/source/Disk.cpp @@ -4,7 +4,7 @@ AppleWin : An Apple //e emulator for Windows Copyright (C) 1994-1996, Michael O'Brien Copyright (C) 1999-2001, Oliver Schmidt Copyright (C) 2002-2005, Tom Charlesworth -Copyright (C) 2006-2014, Tom Charlesworth, Michael Pohoreski +Copyright (C) 2006-2015, Tom Charlesworth, Michael Pohoreski, Nick Westgate AppleWin is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -24,21 +24,31 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /* Description: Disk * * Author: Various + * + * In comments, UTA2E is an abbreviation for a reference to "Understanding the Apple //e" by James Sather */ #include "StdAfx.h" +#include "SaveState_Structs_v1.h" + #include "AppleWin.h" #include "Disk.h" #include "DiskImage.h" #include "Frame.h" +#include "Log.h" #include "Memory.h" #include "Registry.h" #include "Video.h" +#include "YamlHelper.h" #include "..\resource\resource.h" #define LOG_DISK_ENABLED 0 +#define LOG_DISK_TRACKS 1 +#define LOG_DISK_MOTOR 0 +#define LOG_DISK_PHASES 0 +#define LOG_DISK_NIBBLES 0 // __VA_ARGS__ not supported on MSVC++ .NET 7.x #if (LOG_DISK_ENABLED) @@ -61,21 +71,18 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Private ________________________________________________________________________________________ - const int MAX_DISK_IMAGE_NAME = 15; - const int MAX_DISK_FULL_NAME = 127; - struct Disk_t { TCHAR imagename[ MAX_DISK_IMAGE_NAME + 1 ]; // (ie. no extension) TCHAR fullname [ MAX_DISK_FULL_NAME + 1 ]; // or : This is persisted to the snapshot file - std::string strDiskPathFilename; - std::string strFilenameInZip; // 0x00 or + std::string strFilenameInZip; // "" or HIMAGE imagehandle; // Init'd by DiskInsert() -> ImageOpen() + bool bWriteProtected; + // int track; LPBYTE trackimage; int phase; int byte; - bool bWriteProtected; BOOL trackimagedata; BOOL trackimagedirty; DWORD spinning; @@ -86,14 +93,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA { memcpy(imagename, other.imagename, sizeof(imagename)); memcpy(fullname , other.fullname, sizeof(fullname)); - strDiskPathFilename = other.strDiskPathFilename; strFilenameInZip = other.strFilenameInZip; imagehandle = other.imagehandle; + bWriteProtected = other.bWriteProtected; track = other.track; trackimage = other.trackimage; phase = other.phase; byte = other.byte; - bWriteProtected = other.bWriteProtected; trackimagedata = other.trackimagedata; trackimagedirty = other.trackimagedirty; spinning = other.spinning; @@ -108,9 +114,11 @@ static BOOL diskaccessed = 0; static Disk_t g_aFloppyDisk[NUM_DRIVES]; static BYTE floppylatch = 0; static BOOL floppymotoron = 0; +static BOOL floppyloadmode = 0; // for efficiency this is not used; it's extremely unlikely to affect emulation (nickw) static BOOL floppywritemode = 0; -static WORD phases; // state bits for stepper magnet phases 0 - 3 +static WORD phases = 0; // state bits for stepper magnet phases 0 - 3 static bool g_bSaveDiskImage = true; // Save the DiskImage name to Registry +static UINT g_uSlot = 0; static void CheckSpinning(); static Disk_Status_e GetDriveLightStatus( const int iDrive ); @@ -118,6 +126,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); //=========================================================================== @@ -127,14 +136,9 @@ int DiskGetCurrentPhase(void) { return g_aFloppyDisk[currdrive].phase; } int DiskGetCurrentOffset(void) { return g_aFloppyDisk[currdrive].byte; } int DiskGetTrack( int drive ) { return g_aFloppyDisk[ drive ].track; } -const std::string& DiskGetDiskPathFilename(const int iDrive) +const char* DiskGetDiskPathFilename(const int iDrive) { - return g_aFloppyDisk[iDrive].strDiskPathFilename; -} - -static void DiskSetDiskPathFilename(const int iDrive, const std::string strPathName) -{ - g_aFloppyDisk[iDrive].strDiskPathFilename = strPathName; + return g_aFloppyDisk[iDrive].fullname; } char* DiskGetCurrentState(void) @@ -152,19 +156,27 @@ char* DiskGetCurrentState(void) else if (floppywritemode) { if (g_aFloppyDisk[currdrive].bWriteProtected) - return "Writing"; - else return "Writing (write protected)"; + else + return "Writing"; } else { - return "Reading"; + /*if (floppyloadmode) + { + if (g_aFloppyDisk[currdrive].bWriteProtected) + return "Reading write protect state (write protected)"; + else + return "Reading write protect state (not write protected)"; + } + else*/ + return "Reading"; } } //=========================================================================== - void Disk_LoadLastDiskImage(const int iDrive) +void Disk_LoadLastDiskImage(const int iDrive) { _ASSERT(iDrive == DRIVE_1 || iDrive == DRIVE_2); @@ -175,22 +187,15 @@ char* DiskGetCurrentState(void) ? REGVALUE_PREF_LAST_DISK_1 : REGVALUE_PREF_LAST_DISK_2; - if (RegLoadString(TEXT(REG_PREFS),pRegKey,1,sFilePath,MAX_PATH)) + if (RegLoadString(TEXT(REG_PREFS), pRegKey, 1, sFilePath, MAX_PATH)) { sFilePath[ MAX_PATH ] = 0; - DiskSetDiskPathFilename(iDrive, sFilePath); -#if _DEBUG -// MessageBox(g_hFrameWindow,pFileName,pRegKey,MB_OK); -#endif - - // _tcscat(imagefilename,TEXT("MASTER.DSK")); // TODO: Should remember last disk by user g_bSaveDiskImage = false; // Pass in ptr to local copy of filepath, since RemoveDisk() sets DiskPathFilename = "" DiskInsert(iDrive, sFilePath, IMAGE_USE_FILES_WRITE_PROTECT_STATUS, IMAGE_DONT_CREATE); g_bSaveDiskImage = true; } - //else MessageBox(g_hFrameWindow,"Reg Key/Value not found",pRegKey,MB_OK); } //=========================================================================== @@ -202,12 +207,23 @@ void Disk_SaveLastDiskImage(const int iDrive) if (!g_bSaveDiskImage) return; - const char *pFileName = DiskGetDiskPathFilename(iDrive).c_str(); + const char *pFileName = g_aFloppyDisk[iDrive].fullname; if (iDrive == DRIVE_1) 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); + } } //=========================================================================== @@ -249,53 +265,6 @@ static Disk_Status_e GetDriveLightStatus(const int iDrive) return DISK_STATUS_OFF; } -//=========================================================================== - -static void GetImageTitle(LPCTSTR imagefilename, Disk_t* fptr) -{ - TCHAR imagetitle[ MAX_DISK_FULL_NAME+1 ]; - LPCTSTR startpos = imagefilename; - - // imagetitle = - if (_tcsrchr(startpos,TEXT('\\'))) - startpos = _tcsrchr(startpos,TEXT('\\'))+1; - - _tcsncpy(imagetitle,startpos,MAX_DISK_FULL_NAME); - imagetitle[MAX_DISK_FULL_NAME] = 0; - - // if imagetitle contains a lowercase char, then found=1 (why?) - BOOL found = 0; - int loop = 0; - while (imagetitle[loop] && !found) - { - if (IsCharLower(imagetitle[loop])) - found = 1; - else - loop++; - } - - if ((!found) && (loop > 2)) - CharLowerBuff(imagetitle+1,_tcslen(imagetitle+1)); - - // fptr->fullname = - _tcsncpy( fptr->fullname, imagetitle, MAX_DISK_FULL_NAME ); - fptr->fullname[ MAX_DISK_FULL_NAME ] = 0; - - if (imagetitle[0]) - { - LPTSTR dot = imagetitle; - if (_tcsrchr(dot,TEXT('.'))) - dot = _tcsrchr(dot,TEXT('.')); - if (dot > imagetitle) - *dot = 0; - } - - // fptr->imagename = (ie. no extension) - _tcsncpy( fptr->imagename, imagetitle, MAX_DISK_IMAGE_NAME ); - fptr->imagename[ MAX_DISK_IMAGE_NAME ] = 0; -} - - //=========================================================================== static bool IsDriveValid(const int iDrive) @@ -331,8 +300,9 @@ static void ReadTrack(const int iDrive) if (pFloppy->trackimage && pFloppy->imagehandle) { - LOG_DISK("read track %2X%s\r", pFloppy->track, (pFloppy->phase & 1) ? ".5" : ""); - +#if LOG_DISK_TRACKS + LOG_DISK("track $%02X%s read\r\n", pFloppy->track, (pFloppy->phase & 1) ? ".5" : " "); +#endif ImageReadTrack( pFloppy->imagehandle, pFloppy->track, @@ -370,7 +340,6 @@ static void RemoveDisk(const int iDrive) memset( pFloppy->imagename, 0, MAX_DISK_IMAGE_NAME+1 ); memset( pFloppy->fullname , 0, MAX_DISK_FULL_NAME +1 ); pFloppy->strFilenameInZip = ""; - DiskSetDiskPathFilename(iDrive, ""); Disk_SaveLastDiskImage( iDrive ); Video_ResetScreenshotCounter( NULL ); @@ -389,12 +358,17 @@ static void WriteTrack(const int iDrive) return; if (pFloppy->trackimage && pFloppy->imagehandle) + { +#if LOG_DISK_TRACKS + LOG_DISK("track $%02X%s write\r\n", pFloppy->track, (pFloppy->phase & 0) ? ".5" : " "); // TODO: hard-coded to whole tracks - see below (nickw) +#endif ImageWriteTrack( pFloppy->imagehandle, pFloppy->track, - pFloppy->phase, + pFloppy->phase, // TODO: this should never be used; it's the current phase (half-track), not that of the track to be written (nickw) pFloppy->trackimage, - pFloppy->nibbles ); + pFloppy->nibbles); + } pFloppy->trackimagedirty = 0; } @@ -415,34 +389,34 @@ void DiskBoot(void) //=========================================================================== -static BYTE __stdcall DiskControlMotor(WORD, WORD address, BYTE, BYTE, ULONG uExecutedCycles) +static void __stdcall DiskControlMotor(WORD, WORD address, BYTE, BYTE, ULONG uExecutedCycles) { floppymotoron = address & 1; +#if LOG_DISK_MOTOR + LOG_DISK("motor %s\r\n", (floppymotoron) ? "on" : "off"); +#endif CheckSpinning(); - return MemReadFloatingBus(1, uExecutedCycles); // TC-TODO: Check b7 always set } //=========================================================================== -static BYTE __stdcall DiskControlStepper(WORD, WORD address, BYTE, BYTE, ULONG uExecutedCycles) +static void __stdcall DiskControlStepper(WORD, WORD address, BYTE, BYTE, ULONG uExecutedCycles) { Disk_t * fptr = &g_aFloppyDisk[currdrive]; -#if 1 - int phase = (address >> 1) & 3; + int phase = (address >> 1) & 3; int phase_bit = (1 << phase); +#if 1 // update the magnet states if (address & 1) { // phase on phases |= phase_bit; - LOG_DISK("track %02X phases %X phase %d on address $C0E%X\r", fptr->phase, phases, phase, address & 0xF); } else { // phase off phases &= ~phase_bit; - LOG_DISK("track %02X phases %X phase %d off address $C0E%X\r", fptr->phase, phases, phase, address & 0xF); } // check for any stepping effect from a magnet @@ -463,7 +437,6 @@ static BYTE __stdcall DiskControlStepper(WORD, WORD address, BYTE, BYTE, ULONG u const int nNumTracksInImage = ImageGetNumTracks(fptr->imagehandle); const int newtrack = (nNumTracksInImage == 0) ? 0 : MIN(nNumTracksInImage-1, fptr->phase >> 1); // (round half tracks down) - LOG_DISK("newtrack %2X%s\r", newtrack, (fptr->phase & 1) ? ".5" : ""); if (newtrack != fptr->track) { if (fptr->trackimage && fptr->trackimagedirty) @@ -478,31 +451,21 @@ static BYTE __stdcall DiskControlStepper(WORD, WORD address, BYTE, BYTE, ULONG u // https://github.com/AppleWin/AppleWin/issues/201 FrameDrawDiskStatus( (HDC)0 ); } -#else // Old 1.13.1 code for Chessmaster 2000 to work! (see bug#18109) - const int nNumTracksInImage = ImageGetNumTracks(fptr->imagehandle); - if (address & 1) { - int phase = (address >> 1) & 3; - int direction = 0; - if (phase == ((fptr->phase+1) & 3)) - direction = 1; - if (phase == ((fptr->phase+3) & 3)) - direction = -1; - if (direction) { - fptr->phase = MAX(0,MIN(79,fptr->phase+direction)); - if (!(fptr->phase & 1)) { - int newtrack = MIN(nNumTracksInImage-1,fptr->phase >> 1); - if (newtrack != fptr->track) { - if (fptr->trackimage && fptr->trackimagedirty) - WriteTrack(currdrive); - fptr->track = newtrack; - fptr->trackimagedata = 0; - } - } - } - } +#else + // substitute alternate stepping code here to test +#endif +#if LOG_DISK_PHASES + LOG_DISK("track $%02X%s phases %d%d%d%d phase %d %s address $%4X\r\n", + fptr->phase >> 1, + (fptr->phase & 1) ? ".5" : " ", + (phases >> 3) & 1, + (phases >> 2) & 1, + (phases >> 1) & 1, + (phases >> 0) & 1, + phase, + (address & 1) ? "on " : "off", + address); #endif - return ((address & 0xF) == 0) ? 0xFF // TC-TODO: Check why $C0E0 only returns 0xFF - : MemReadFloatingBus(1, uExecutedCycles); // TC-TODO: Check b7 always set } //=========================================================================== @@ -520,13 +483,12 @@ void DiskDestroy(void) //=========================================================================== -static BYTE __stdcall DiskEnable(WORD, WORD address, BYTE, BYTE, ULONG uExecutedCycles) +static void __stdcall DiskEnable(WORD, WORD address, BYTE, BYTE, ULONG uExecutedCycles) { currdrive = address & 1; g_aFloppyDisk[!currdrive].spinning = 0; g_aFloppyDisk[!currdrive].writelight = 0; CheckSpinning(); - return MemReadFloatingBus(uExecutedCycles); } //=========================================================================== @@ -558,6 +520,11 @@ LPCTSTR DiskGetFullDiskFilename(const int iDrive) return DiskGetFullName(iDrive); } +static LPCTSTR DiskGetFullPathName(const int iDrive) +{ + return ImageGetPathname(g_aFloppyDisk[iDrive].imagehandle); +} + // Return the imagename // . Used by Drive Button's icons & Property Sheet Page (Save snapshot) LPCTSTR DiskGetBaseName(const int iDrive) @@ -581,7 +548,7 @@ void DiskInitialize(void) { int loop = NUM_DRIVES; while (loop--) - ZeroMemory(&g_aFloppyDisk[loop],sizeof(Disk_t )); + ZeroMemory(&g_aFloppyDisk[loop], sizeof(Disk_t)); TCHAR imagefilename[MAX_PATH]; _tcscpy(imagefilename,g_sProgramDir); @@ -611,10 +578,20 @@ ImageError_e DiskInsert(const int iDrive, LPCTSTR pszImageFilename, const bool b else fptr->bWriteProtected = bForceWriteProtected ? true : (dwAttributes & FILE_ATTRIBUTE_READONLY); - // Check if image is being used by the other HDD, and unplug it in order to be swapped - std::string otherDisk = DiskGetDiskPathFilename(!iDrive); - if (!strcmp(otherDisk.c_str(), pszImageFilename)) { - DiskEject(!iDrive); + // Check if image is being used by the other drive, and if so remove it in order so it can be swapped + { + const char* pszOtherPathname = DiskGetFullPathName(!iDrive); + + char szCurrentPathname[MAX_PATH]; + DWORD uNameLen = GetFullPathName(pszImageFilename, MAX_PATH, szCurrentPathname, NULL); + if (uNameLen == 0 || uNameLen >= MAX_PATH) + strcpy_s(szCurrentPathname, MAX_PATH, pszImageFilename); + + if (!strcmp(pszOtherPathname, szCurrentPathname)) + { + DiskEject(!iDrive); + FrameRefreshStatus(DRAW_LEDS | DRAW_BUTTON_DRIVES); + } } ImageError_e Error = ImageOpen(pszImageFilename, @@ -637,19 +614,15 @@ ImageError_e DiskInsert(const int iDrive, LPCTSTR pszImageFilename, const bool b if (Error == eIMAGE_ERROR_NONE) { - GetImageTitle(pszImageFilename, fptr); - - DiskSetDiskPathFilename(iDrive, pszImageFilename); - - //MessageBox( g_hFrameWindow, imagefilename, fptr->imagename, MB_OK ); - Video_ResetScreenshotCounter( fptr->imagename ); + GetImageTitle(pszImageFilename, fptr->imagename, fptr->fullname); + Video_ResetScreenshotCounter(fptr->imagename); } else { - Video_ResetScreenshotCounter( NULL ); + Video_ResetScreenshotCounter(NULL); } - Disk_SaveLastDiskImage( iDrive ); + Disk_SaveLastDiskImage(iDrive); return Error; } @@ -730,6 +703,13 @@ void DiskNotifyInvalidImage(const int iDrive, LPCTSTR pszImageFilename, const Im pszImageFilename); break; + case eIMAGE_ERROR_FAILED_TO_GET_PATHNAME: + wsprintf( + szBuffer, + TEXT("Unable to GetFullPathName() for the file: %s."), + pszImageFilename); + break; + default: // IGNORE OTHER ERRORS SILENTLY return; @@ -793,8 +773,9 @@ bool Disk_IsDriveEmpty(const int iDrive) //=========================================================================== -static BYTE __stdcall DiskReadWrite (WORD programcounter, WORD, BYTE, BYTE, ULONG) +static void __stdcall DiskReadWrite(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) { + /* floppyloadmode = 0; */ Disk_t * fptr = &g_aFloppyDisk[currdrive]; diskaccessed = 1; @@ -803,32 +784,23 @@ static BYTE __stdcall DiskReadWrite (WORD programcounter, WORD, BYTE, BYTE, ULON ReadTrack(currdrive); if (!fptr->trackimagedata) - return 0xFF; - - BYTE result = 0; - - if (!floppywritemode || !fptr->bWriteProtected) { - if (floppywritemode) - { - if (floppylatch & 0x80) - { - *(fptr->trackimage+fptr->byte) = floppylatch; - fptr->trackimagedirty = 1; - } - else - { - return 0; - } - } - else - { - result = *(fptr->trackimage+fptr->byte); - } + floppylatch = 0xFF; + return; } - if (0) - { LOG_DISK("nib %4X = %2X\r", fptr->byte, result); } + if (!floppywritemode) + { + floppylatch = *(fptr->trackimage + fptr->byte); +#if LOG_DISK_NIBBLES + LOG_DISK("read %4X = %2X\r\n", fptr->byte, floppylatch); +#endif + } + else if ((floppylatch & 0x80) && !fptr->bWriteProtected) // && floppywritemode + { + *(fptr->trackimage + fptr->byte) = floppylatch; + fptr->trackimagedirty = 1; + } if (++fptr->byte >= fptr->nibbles) fptr->byte = 0; @@ -838,8 +810,6 @@ static BYTE __stdcall DiskReadWrite (WORD programcounter, WORD, BYTE, BYTE, ULON // NB. Prevent flooding of forcing UI to redraw!!! if( ((fptr->byte) & 0xFF) == 0 ) FrameDrawDiskStatus( (HDC)0 ); - - return result; } //=========================================================================== @@ -852,7 +822,7 @@ void DiskReset(void) //=========================================================================== -void DiskSelectImage(const int iDrive, LPSTR pszFilename) +static bool DiskSelectImage(const int iDrive, LPCSTR pszFilename) { TCHAR directory[MAX_PATH] = TEXT(""); TCHAR filename[MAX_PATH] = TEXT(""); @@ -880,6 +850,8 @@ void DiskSelectImage(const int iDrive, LPSTR pszFilename) ofn.Flags = OFN_PATHMUSTEXIST; ofn.lpstrTitle = title; + bool bRes = false; + if (GetOpenFileName(&ofn)) { if ((!ofn.nFileExtension) || !filename[ofn.nFileExtension]) @@ -888,16 +860,15 @@ void DiskSelectImage(const int iDrive, LPSTR pszFilename) ImageError_e Error = DiskInsert(iDrive, filename, ofn.Flags & OFN_READONLY, IMAGE_CREATE); if (Error == eIMAGE_ERROR_NONE) { - DiskSetDiskPathFilename(iDrive, filename); - filename[ofn.nFileOffset] = 0; - if (_tcsicmp(directory, filename)) - RegSaveString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_START_DIR), 1, filename); + bRes = true; } else { DiskNotifyInvalidImage(iDrive, filename, Error); } } + + return bRes; } //=========================================================================== @@ -909,24 +880,31 @@ void DiskSelect(const int iDrive) //=========================================================================== -static BYTE __stdcall DiskSetLatchValue(WORD, WORD, BYTE write, BYTE value, ULONG) -{ - if (write) - floppylatch = value; - return floppylatch; +static void __stdcall DiskLoadWriteProtect(WORD, WORD, BYTE write, BYTE value, ULONG) { + /* floppyloadmode = 1; */ + if (!write) + { + if (floppymotoron && !floppywritemode) + { + // phase 1 on also forces write protect in the Disk II drive (UTA2E page 9-7) but we don't implement that + if (g_aFloppyDisk[currdrive].bWriteProtected) + floppylatch |= 0x80; + else + floppylatch &= 0x7F; + } + } } //=========================================================================== -static BYTE __stdcall DiskSetReadMode(WORD, WORD, BYTE, BYTE, ULONG uExecutedCycles) +static void __stdcall DiskSetReadMode(WORD, WORD, BYTE, BYTE, ULONG) { floppywritemode = 0; - return MemReadFloatingBus(g_aFloppyDisk[currdrive].bWriteProtected, uExecutedCycles); } //=========================================================================== -static BYTE __stdcall DiskSetWriteMode(WORD, WORD, BYTE, BYTE, ULONG uExecutedCycles) +static void __stdcall DiskSetWriteMode(WORD, WORD, BYTE, BYTE, ULONG uExecutedCycles) { floppywritemode = 1; BOOL modechange = !g_aFloppyDisk[currdrive].writelight; @@ -936,8 +914,6 @@ static BYTE __stdcall DiskSetWriteMode(WORD, WORD, BYTE, BYTE, ULONG uExecutedCy //FrameRefreshStatus(DRAW_LEDS); FrameDrawDiskLEDS( (HDC)0 ); } - - return MemReadFloatingBus(1, uExecutedCycles); // TC-TODO: Check b7 always set } //=========================================================================== @@ -1032,121 +1008,88 @@ void DiskLoadRom(LPBYTE pCxRomPeripheral, UINT uSlot) memcpy(pCxRomPeripheral + uSlot*APPLE_SLOT_SIZE, pData, DISK2_FW_SIZE); - // NB. We used to disable the track stepping delay in the Disk II controller firmware by + // Note: We used to disable the track stepping delay in the Disk II controller firmware by // patching $C64C with $A9,$00,$EA. Now not doing this since: // . Authentic Speed should be authentic // . Enhanced Speed runs emulation unthrottled, so removing the delay has negligible effect // . Patching the firmware breaks the ADC checksum used by "The CIA Files" (Tricky Dick) - // . In this case we can patch to compensate for an ADC or EOR checksum but not both + // . In this case we can patch to compensate for an ADC or EOR checksum but not both (nickw) RegisterIoHandler(uSlot, Disk_IORead, Disk_IOWrite, NULL, NULL, NULL, NULL); + + g_uSlot = uSlot; } //=========================================================================== static BYTE __stdcall Disk_IORead(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) { - addr &= 0xFF; - - switch (addr & 0xf) + switch (addr & 0xF) { - case 0x0: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x1: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x2: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x3: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x4: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x5: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x6: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x7: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x8: return DiskControlMotor(pc, addr, bWrite, d, nCyclesLeft); - case 0x9: return DiskControlMotor(pc, addr, bWrite, d, nCyclesLeft); - case 0xA: return DiskEnable(pc, addr, bWrite, d, nCyclesLeft); - case 0xB: return DiskEnable(pc, addr, bWrite, d, nCyclesLeft); - case 0xC: return DiskReadWrite(pc, addr, bWrite, d, nCyclesLeft); - case 0xD: return DiskSetLatchValue(pc, addr, bWrite, d, nCyclesLeft); - case 0xE: return DiskSetReadMode(pc, addr, bWrite, d, nCyclesLeft); - case 0xF: return DiskSetWriteMode(pc, addr, bWrite, d, nCyclesLeft); + case 0x0: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x1: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x2: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x3: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x4: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x5: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x6: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x7: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x8: DiskControlMotor(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x9: DiskControlMotor(pc, addr, bWrite, d, nCyclesLeft); break; + case 0xA: DiskEnable(pc, addr, bWrite, d, nCyclesLeft); break; + case 0xB: DiskEnable(pc, addr, bWrite, d, nCyclesLeft); break; + case 0xC: DiskReadWrite(pc, addr, bWrite, d, nCyclesLeft); break; + case 0xD: DiskLoadWriteProtect(pc, addr, bWrite, d, nCyclesLeft); break; + case 0xE: DiskSetReadMode(pc, addr, bWrite, d, nCyclesLeft); break; + case 0xF: DiskSetWriteMode(pc, addr, bWrite, d, nCyclesLeft); break; } - return 0; + // only even addresses return the latch (UTA2E Table 9.1) + if (!(addr & 1)) + return floppylatch; + else + return MemReadFloatingBus(nCyclesLeft); } static BYTE __stdcall Disk_IOWrite(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) { - addr &= 0xFF; - - switch (addr & 0xf) + switch (addr & 0xF) { - case 0x0: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x1: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x2: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x3: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x4: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x5: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x6: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x7: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x8: return DiskControlMotor(pc, addr, bWrite, d, nCyclesLeft); - case 0x9: return DiskControlMotor(pc, addr, bWrite, d, nCyclesLeft); - case 0xA: return DiskEnable(pc, addr, bWrite, d, nCyclesLeft); - case 0xB: return DiskEnable(pc, addr, bWrite, d, nCyclesLeft); - case 0xC: return DiskReadWrite(pc, addr, bWrite, d, nCyclesLeft); - case 0xD: return DiskSetLatchValue(pc, addr, bWrite, d, nCyclesLeft); - case 0xE: return DiskSetReadMode(pc, addr, bWrite, d, nCyclesLeft); - case 0xF: return DiskSetWriteMode(pc, addr, bWrite, d, nCyclesLeft); + case 0x0: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x1: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x2: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x3: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x4: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x5: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x6: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x7: DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x8: DiskControlMotor(pc, addr, bWrite, d, nCyclesLeft); break; + case 0x9: DiskControlMotor(pc, addr, bWrite, d, nCyclesLeft); break; + case 0xA: DiskEnable(pc, addr, bWrite, d, nCyclesLeft); break; + case 0xB: DiskEnable(pc, addr, bWrite, d, nCyclesLeft); break; + case 0xC: DiskReadWrite(pc, addr, bWrite, d, nCyclesLeft); break; + case 0xD: DiskLoadWriteProtect(pc, addr, bWrite, d, nCyclesLeft); break; + case 0xE: DiskSetReadMode(pc, addr, bWrite, d, nCyclesLeft); break; + case 0xF: DiskSetWriteMode(pc, addr, bWrite, d, nCyclesLeft); break; } + // any address writes the latch via sequencer LD command (74LS323 datasheet) + if (floppywritemode /* && floppyloadmode */) + { + floppylatch = d; + } return 0; } //=========================================================================== -DWORD DiskGetSnapshot(SS_CARD_DISK2* pSS, DWORD dwSlot) +int DiskSetSnapshot_v1(const SS_CARD_DISK2* const pSS) { - pSS->Hdr.UnitHdr.dwLength = sizeof(SS_CARD_DISK2); - pSS->Hdr.UnitHdr.dwVersion = MAKE_VERSION(1,0,0,2); + if(pSS->Hdr.UnitHdr.hdr.v1.dwVersion > MAKE_VERSION(1,0,0,2)) + return -1; - pSS->Hdr.dwSlot = dwSlot; - pSS->Hdr.dwType = CT_Disk2; - - pSS->phases = phases; // new in 1.0.0.2 disk snapshots - pSS->currdrive = currdrive; // this was an int in 1.0.0.1 disk snapshots - pSS->diskaccessed = diskaccessed; - pSS->enhancedisk = enhancedisk; - pSS->floppylatch = floppylatch; - pSS->floppymotoron = floppymotoron; - pSS->floppywritemode = floppywritemode; - - for(UINT i=0; iUnit[i].szFileName, g_aFloppyDisk[i].fullname); - pSS->Unit[i].track = g_aFloppyDisk[i].track; - pSS->Unit[i].phase = g_aFloppyDisk[i].phase; - pSS->Unit[i].byte = g_aFloppyDisk[i].byte; - pSS->Unit[i].writeprotected = g_aFloppyDisk[i].bWriteProtected ? TRUE : FALSE; - pSS->Unit[i].trackimagedata = g_aFloppyDisk[i].trackimagedata; - pSS->Unit[i].trackimagedirty = g_aFloppyDisk[i].trackimagedirty; - pSS->Unit[i].spinning = g_aFloppyDisk[i].spinning; - pSS->Unit[i].writelight = g_aFloppyDisk[i].writelight; - pSS->Unit[i].nibbles = g_aFloppyDisk[i].nibbles; - - if(g_aFloppyDisk[i].trackimage) - memcpy(pSS->Unit[i].nTrack, g_aFloppyDisk[i].trackimage, NIBBLES_PER_TRACK); - else - memset(pSS->Unit[i].nTrack, 0, NIBBLES_PER_TRACK); - } - - return 0; -} - -DWORD DiskSetSnapshot(SS_CARD_DISK2* pSS, DWORD /*dwSlot*/) -{ - if(pSS->Hdr.UnitHdr.dwVersion > MAKE_VERSION(1,0,0,2)) - { - return -1; - } - - phases = pSS->phases; // new in 1.0.0.2 disk snapshots - currdrive = pSS->currdrive; // this was an int in 1.0.0.1 disk snapshots + phases = pSS->phases; + currdrive = pSS->currdrive; diskaccessed = pSS->diskaccessed; enhancedisk = pSS->enhancedisk; floppylatch = pSS->floppylatch; @@ -1157,7 +1100,7 @@ DWORD DiskSetSnapshot(SS_CARD_DISK2* pSS, DWORD /*dwSlot*/) for(UINT i=0; i pTrack( new BYTE [NIBBLES_PER_TRACK] ); + memset(pTrack.get(), 0, NIBBLES_PER_TRACK); + if (yamlLoadHelper.GetSubMap(SS_YAML_KEY_TRACK_IMAGE)) + { + yamlLoadHelper.LoadMemory(pTrack.get(), NIBBLES_PER_TRACK); + yamlLoadHelper.PopMap(); + } + + yamlLoadHelper.PopMap(); + + // + + if (!filename.empty() && !bImageError) + { + if ((g_aFloppyDisk[unit].trackimage == NULL) && g_aFloppyDisk[unit].nibbles) + AllocTrack(unit); + + if (g_aFloppyDisk[unit].trackimage == NULL) + bImageError = true; + else + memcpy(g_aFloppyDisk[unit].trackimage, pTrack.get(), NIBBLES_PER_TRACK); + } + + if (bImageError) + { + g_aFloppyDisk[unit].trackimagedata = 0; + g_aFloppyDisk[unit].trackimagedirty = 0; + g_aFloppyDisk[unit].nibbles = 0; + } +} + +bool DiskLoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version) +{ + if (slot != 6) // fixme + throw std::string("Card: wrong slot"); + + if (version != 1) + throw std::string("Card: wrong version"); + + phases = yamlLoadHelper.LoadUint(SS_YAML_KEY_PHASES); + currdrive = yamlLoadHelper.LoadUint(SS_YAML_KEY_CURRENT_DRIVE); + diskaccessed = yamlLoadHelper.LoadBool(SS_YAML_KEY_DISK_ACCESSED); + enhancedisk = yamlLoadHelper.LoadBool(SS_YAML_KEY_ENHANCE_DISK); + floppylatch = yamlLoadHelper.LoadUint(SS_YAML_KEY_FLOPPY_LATCH); + floppymotoron = yamlLoadHelper.LoadBool(SS_YAML_KEY_FLOPPY_MOTOR_ON); + floppywritemode = yamlLoadHelper.LoadBool(SS_YAML_KEY_FLOPPY_WRITE_MODE); + + // Eject all disks first in case Drive-2 contains disk to be inserted into Drive-1 + for(UINT i=0; ibWriteProtected = *pWriteProtected_; + ZeroMemory(*hDiskImage, sizeof(ImageInfo)); + ImageInfo* pImageInfo = (ImageInfo*) *hDiskImage; + pImageInfo->bWriteProtected = *pWriteProtected; ImageError_e Err = sg_DiskImageHelper.Open(pszImageFilename, pImageInfo, bCreateIfNecessary, strFilenameInZip); - if (pImageInfo->pImageType != NULL && Err == eIMAGE_ERROR_NONE && pImageInfo->pImageType->GetType() == eImageHDV) - Err = eIMAGE_ERROR_UNSUPPORTED_HDV; - if (Err != eIMAGE_ERROR_NONE) { - ImageClose(*hDiskImage_, true); - *hDiskImage_ = (HIMAGE)0; + ImageClose(*hDiskImage, true); + *hDiskImage = (HIMAGE)0; + return Err; + } + + if (pImageInfo->pImageType && pImageInfo->pImageType->GetType() == eImageHDV) + { + if (bExpectFloppy) + Err = eIMAGE_ERROR_UNSUPPORTED_HDV; return Err; } @@ -76,7 +80,7 @@ ImageError_e ImageOpen( LPCTSTR pszImageFilename, for (UINT uTrack = 0; uTrack < pImageInfo->uNumTracks; uTrack++) pImageInfo->ValidTrack[uTrack] = (pImageInfo->uImageSize > 0) ? 1 : 0; - *pWriteProtected_ = pImageInfo->bWriteProtected; + *pWriteProtected = pImageInfo->bWriteProtected; return eIMAGE_ERROR_NONE; } @@ -185,6 +189,36 @@ void ImageWriteTrack( const HIMAGE hDiskImage, //=========================================================================== +bool ImageReadBlock( const HIMAGE hDiskImage, + UINT nBlock, + LPBYTE pBlockBuffer) +{ + ImageInfo* ptr = (ImageInfo*) hDiskImage; + + bool bRes = false; + if (ptr->pImageType->AllowRW()) + bRes = ptr->pImageType->Read(ptr, nBlock, pBlockBuffer); + + return bRes; +} + +//=========================================================================== + +bool ImageWriteBlock( const HIMAGE hDiskImage, + UINT nBlock, + LPBYTE pBlockBuffer) +{ + ImageInfo* ptr = (ImageInfo*) hDiskImage; + + bool bRes = false; + if (ptr->pImageType->AllowRW() && !ptr->bWriteProtected) + bRes = ptr->pImageType->Write(ptr, nBlock, pBlockBuffer); + + return bRes; +} + +//=========================================================================== + int ImageGetNumTracks(const HIMAGE hDiskImage) { ImageInfo* ptr = (ImageInfo*) hDiskImage; @@ -202,3 +236,60 @@ bool ImageIsMultiFileZip(const HIMAGE hDiskImage) ImageInfo* ptr = (ImageInfo*) hDiskImage; return ptr ? (ptr->uNumEntriesInZip > 1) : false; } + +const char* ImageGetPathname(const HIMAGE hDiskImage) +{ + static char* szEmpty = ""; + ImageInfo* ptr = (ImageInfo*) hDiskImage; + return ptr ? ptr->szFilename : szEmpty; +} + +UINT ImageGetImageSize(const HIMAGE hDiskImage) +{ + ImageInfo* ptr = (ImageInfo*) hDiskImage; + return ptr ? ptr->uImageSize : 0; +} + +void GetImageTitle(LPCTSTR pPathname, TCHAR* pImageName, TCHAR* pFullName) +{ + TCHAR imagetitle[ MAX_DISK_FULL_NAME+1 ]; + LPCTSTR startpos = pPathname; + + // imagetitle = + if (_tcsrchr(startpos, TEXT('\\'))) + startpos = _tcsrchr(startpos, TEXT('\\'))+1; + + _tcsncpy(imagetitle, startpos, MAX_DISK_FULL_NAME); + imagetitle[MAX_DISK_FULL_NAME] = 0; + + // if imagetitle contains a lowercase char, then found=1 (why?) + BOOL found = 0; + int loop = 0; + while (imagetitle[loop] && !found) + { + if (IsCharLower(imagetitle[loop])) + found = 1; + else + loop++; + } + + if ((!found) && (loop > 2)) + CharLowerBuff(imagetitle+1, _tcslen(imagetitle+1)); + + // pFullName = + _tcsncpy( pFullName, imagetitle, MAX_DISK_FULL_NAME ); + pFullName[ MAX_DISK_FULL_NAME ] = 0; + + if (imagetitle[0]) + { + LPTSTR dot = imagetitle; + if (_tcsrchr(dot, TEXT('.'))) + dot = _tcsrchr(dot, TEXT('.')); + if (dot > imagetitle) + *dot = 0; + } + + // pImageName = (ie. no extension) + _tcsncpy( pImageName, imagetitle, MAX_DISK_IMAGE_NAME ); + pImageName[ MAX_DISK_IMAGE_NAME ] = 0; +} diff --git a/source/DiskImage.h b/source/DiskImage.h index b712399f..73b5bd4d 100644 --- a/source/DiskImage.h +++ b/source/DiskImage.h @@ -55,9 +55,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA eIMAGE_ERROR_UNABLE_TO_OPEN, eIMAGE_ERROR_UNABLE_TO_OPEN_GZ, eIMAGE_ERROR_UNABLE_TO_OPEN_ZIP, + eIMAGE_ERROR_FAILED_TO_GET_PATHNAME, }; -ImageError_e ImageOpen(LPCTSTR pszImageFilename, HIMAGE* hDiskImage_, bool* pWriteProtected_, const bool bCreateIfNecessary, std::string& strFilenameInZip); + const int MAX_DISK_IMAGE_NAME = 15; + const int MAX_DISK_FULL_NAME = 127; + + +ImageError_e ImageOpen(LPCTSTR pszImageFilename, HIMAGE* hDiskImage, bool* pWriteProtected, const bool bCreateIfNecessary, std::string& strFilenameInZip, const bool bExpectFloppy=true); void ImageClose(const HIMAGE hDiskImage, const bool bOpenError=false); BOOL ImageBoot(const HIMAGE hDiskImage); void ImageDestroy(void); @@ -65,7 +70,13 @@ void ImageInitialize(void); void ImageReadTrack(const HIMAGE hDiskImage, int nTrack, int nQuarterTrack, LPBYTE pTrackImageBuffer, int* pNibbles); void ImageWriteTrack(const HIMAGE hDiskImage, int nTrack, int nQuarterTrack, LPBYTE pTrackImage, int nNibbles); +bool ImageReadBlock(const HIMAGE hDiskImage, UINT nBlock, LPBYTE pBlockBuffer); +bool ImageWriteBlock(const HIMAGE hDiskImage, UINT nBlock, LPBYTE pBlockBuffer); int ImageGetNumTracks(const HIMAGE hDiskImage); bool ImageIsWriteProtected(const HIMAGE hDiskImage); bool ImageIsMultiFileZip(const HIMAGE hDiskImage); +const char* ImageGetPathname(const HIMAGE hDiskImage); +UINT ImageGetImageSize(const HIMAGE hDiskImage); + +void GetImageTitle(LPCTSTR pPathname, TCHAR* pImageName, TCHAR* pFullName); diff --git a/source/DiskImageHelper.cpp b/source/DiskImageHelper.cpp index 4eeef4a8..c4e8cb26 100644 --- a/source/DiskImageHelper.cpp +++ b/source/DiskImageHelper.cpp @@ -28,7 +28,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "stdafx.h" -#include "Structs.h" #include "Common.h" #include "zlib.h" @@ -436,7 +435,7 @@ void CImageBase::DenibblizeTrack(LPBYTE trackimage, SectorOrder_e SectorOrder, i offset = 0; } - if ((bytenum == 3) && (byteval[1] = 0xAA)) + if ((bytenum == 3) && (byteval[1] == 0xAA)) { int loop = 0; int tempoffset = offset; @@ -1435,7 +1434,9 @@ ImageError_e CImageHelperBase::Open( LPCTSTR pszImageFilename, if (Err != eIMAGE_ERROR_NONE) return Err; - _tcsncpy(pImageInfo->szFilename, pszImageFilename, MAX_PATH); + DWORD uNameLen = GetFullPathName(pszImageFilename, MAX_PATH, pImageInfo->szFilename, NULL); + if (uNameLen == 0 || uNameLen >= MAX_PATH) + Err = eIMAGE_ERROR_FAILED_TO_GET_PATHNAME; return eIMAGE_ERROR_NONE; } @@ -1453,9 +1454,10 @@ void CImageHelperBase::Close(ImageInfo* pImageInfo, const bool bDeleteFile) if (bDeleteFile) { DeleteFile(pImageInfo->szFilename); - pImageInfo->szFilename[0] = 0; } + pImageInfo->szFilename[0] = 0; + delete [] pImageInfo->pImageBuffer; pImageInfo->pImageBuffer = NULL; } diff --git a/source/Frame.cpp b/source/Frame.cpp index 8bbd0783..e590b92c 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -41,6 +41,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Mockingboard.h" #include "MouseInterface.h" #include "ParallelPrinter.h" +#include "Pravets.h" #include "Registry.h" #include "SaveState.h" #include "SerialComms.h" @@ -183,7 +184,7 @@ static bool g_bFullScreen32Bit = true; // Updates g_pAppTitle // ==================================================================== -void GetAppleWindowTitle() +static void GetAppleWindowTitle() { g_pAppTitle = g_pAppleWindowTitle; @@ -568,6 +569,7 @@ static void DrawFrameWindow () DebugDisplay(1); else // Win7: In fullscreen mode with 1 redraw the screen doesn't get redrawn. + // TC: 07/01/2015: Tryed with MP's double-buffered DX full-screen code, but still the same. //VideoRedrawScreen(g_bIsFullScreen ? 2 : 1); // TC: 22/06/2014: Why 2 redraws in full-screen mode (32-bit only)? (8-bit doesn't need this nor does Win8, just Win7 or older OS's) //VideoRefreshScreen(0); VideoRedrawScreen(); @@ -622,6 +624,9 @@ void FrameDrawDiskLEDS( HDC passdc ) //=========================================================================== void FrameDrawDiskStatus( HDC passdc ) { + if (mem == NULL) + return; + // We use the actual drive since probing from memory doesn't tell us anything we don't already know. // DOS3.3 ProDOS // Drive $B7EA $BE3D @@ -764,6 +769,14 @@ void FrameDrawDiskStatus( HDC passdc ) //=========================================================================== static void DrawStatusArea (HDC passdc, int drawflags) { + if (g_hFrameWindow == NULL) + { + // TC: Fix drawing of drive buttons before frame created: + // . Main init loop: LoadConfiguration() called before FrameCreateWindow(), eg: + // LoadConfiguration() -> Disk_LoadLastDiskImage() -> DiskInsert() -> FrameRefreshStatus() + return; + } + FrameReleaseDC(); HDC dc = (passdc ? passdc : GetDC(g_hFrameWindow)); int x = buttonx; @@ -1025,7 +1038,7 @@ LRESULT CALLBACK FrameWndProc ( if (!restart) { DiskDestroy(); ImageDestroy(); - HD_Cleanup(); + HD_Destroy(); } PrintDestroy(); sg_SSC.CommDestroy(); @@ -1314,7 +1327,7 @@ LRESULT CALLBACK FrameWndProc ( { RevealCursor(); } - else if (g_nAppMode == MODE_RUNNING) + else if (g_nAppMode == MODE_RUNNING || g_nAppMode == MODE_STEPPING) { if (!sg_Mouse.IsEnabled()) { @@ -1391,7 +1404,7 @@ LRESULT CALLBACK FrameWndProc ( DrawCrosshairs(x,y); JoySetPosition(x-viewportx-2, g_nViewportCX-4, y-viewporty-2, g_nViewportCY-4); } - else if (sg_Mouse.IsActiveAndEnabled() && (g_nAppMode == MODE_RUNNING)) + else if (sg_Mouse.IsActiveAndEnabled() && (g_nAppMode == MODE_RUNNING || g_nAppMode == MODE_STEPPING)) { if (g_bLastCursorInAppleViewport) break; @@ -1422,7 +1435,7 @@ LRESULT CALLBACK FrameWndProc ( if (wparam == IDEVENT_TIMER_MOUSE) { // NB. Need to check /g_bAppActive/ since WM_TIMER events still occur after AppleWin app has lost focus - if (g_bAppActive && sg_Mouse.IsActiveAndEnabled() && (g_nAppMode == MODE_RUNNING)) + if (g_bAppActive && sg_Mouse.IsActiveAndEnabled() && (g_nAppMode == MODE_RUNNING || g_nAppMode == MODE_STEPPING)) { if (!g_bLastCursorInAppleViewport) break; @@ -1973,12 +1986,15 @@ void RelayEvent (UINT message, WPARAM wparam, LPARAM lparam) { } //=========================================================================== + +// todo: consolidate CtrlReset() and ResetMachineState() void ResetMachineState () { DiskReset(); // Set floppymotoron=0 g_bFullSpeed = 0; // Might've hit reset in middle of InternalCpuExecute() - so beep may get (partially) muted MemReset(); + PravetsReset(); DiskBoot(); VideoResetState(); sg_SSC.CommReset(); @@ -1987,7 +2003,7 @@ void ResetMachineState () MB_Reset(); SpkrReset(); sg_Mouse.Reset(); - g_ActiveCPU = CPU_6502; + SetActiveCpu( GetMainCpu() ); #ifdef USE_SPEECH_API g_Speech.Reset(); #endif @@ -1997,12 +2013,15 @@ void ResetMachineState () //=========================================================================== + +// todo: consolidate CtrlReset() and ResetMachineState() void CtrlReset() { // Ctrl+Reset - TODO: This is a terrible place for this code! if (!IS_APPLE2) MemResetPaging(); + PravetsReset(); DiskReset(); KeybReset(); if (!IS_APPLE2) @@ -2468,7 +2487,6 @@ void FrameSetCursorPosByMousePos() int iY, iMinY, iMaxY; sg_Mouse.GetXY(iX, iMinX, iMaxX, iY, iMinY, iMaxY); - _ASSERT(iMinX == 0 && iMinY == 0); float fScaleX = (float)(iX-iMinX) / ((float)(iMaxX-iMinX)); float fScaleY = (float)(iY-iMinY) / ((float)(iMaxY-iMinY)); @@ -2504,7 +2522,6 @@ static void FrameSetCursorPosByMousePos(int x, int y, int dx, int dy, bool bLeav int iX, iMinX, iMaxX; int iY, iMinY, iMaxY; sg_Mouse.GetXY(iX, iMinX, iMaxX, iY, iMinY, iMaxY); - _ASSERT(iMinX == 0 && iMinY == 0); if (bLeavingAppleScreen) { @@ -2624,3 +2641,17 @@ void GetViewportCXCY(int& nViewportCX, int& nViewportCY) nViewportCX = g_nViewportCX; nViewportCY = g_nViewportCY; } + +// Call all funcs with dependency on g_Apple2Type +void FrameUpdateApple2Type(void) +{ + DeleteGdiObjects(); + CreateGdiObjects(); + + // DRAW_TITLE : calls GetAppleWindowTitle() + // DRAW_LEDS : update LEDs (eg. CapsLock varies on Apple2 type) + DrawStatusArea( (HDC)0, DRAW_TITLE|DRAW_LEDS ); + + // Draw buttons & call DrawStatusArea(DRAW_BACKGROUND | DRAW_LEDS | DRAW_DISK_STATUS) + DrawFrameWindow(); +} diff --git a/source/Frame.h b/source/Frame.h index 81f87278..e54f4187 100644 --- a/source/Frame.h +++ b/source/Frame.h @@ -59,6 +59,7 @@ void GetViewportCXCY(int& nViewportCX, int& nViewportCY); bool GetFullScreen32Bit(void); void SetFullScreen32Bit(bool b32Bit); + void FrameUpdateApple2Type(void); void FrameDrawDiskLEDS( HDC hdc ); void FrameDrawDiskStatus( HDC hdc ); diff --git a/source/Harddisk.cpp b/source/Harddisk.cpp index 3406140e..90b3a0bc 100644 --- a/source/Harddisk.cpp +++ b/source/Harddisk.cpp @@ -4,7 +4,7 @@ AppleWin : An Apple //e emulator for Windows Copyright (C) 1994-1996, Michael O'Brien Copyright (C) 1999-2001, Oliver Schmidt Copyright (C) 2002-2005, Tom Charlesworth -Copyright (C) 2006-2007, Tom Charlesworth, Michael Pohoreski +Copyright (C) 2006-2015, Tom Charlesworth, Michael Pohoreski AppleWin is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -35,6 +35,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "HardDisk.h" #include "Memory.h" #include "Registry.h" +#include "YamlHelper.h" #include "..\resource\resource.h" @@ -114,28 +115,29 @@ Overview struct HDD { // From Disk_t - TCHAR imagename[16]; // Not used - TCHAR fullname[128]; + TCHAR imagename[ MAX_DISK_IMAGE_NAME + 1 ]; // (ie. no extension) [not used] + TCHAR fullname[ MAX_DISK_FULL_NAME + 1 ]; // or + std::string strFilenameInZip; // "" or [not used] + HIMAGE imagehandle; // Init'd by HD_Insert() -> ImageOpen() + bool bWriteProtected; // Needed for ImageOpen() [otherwise not used] // BYTE hd_error; WORD hd_memblock; UINT hd_diskblock; WORD hd_buf_ptr; - BOOL hd_imageloaded; - BYTE hd_buf[HD_BLOCK_SIZE+1]; // Why +1? + bool hd_imageloaded; + BYTE hd_buf[HD_BLOCK_SIZE+1]; // Why +1? Probably for erroreous reads beyond the block size (ie. reads from I/O addr 0xC0F8) #if HD_LED Disk_Status_e hd_status_next; Disk_Status_e hd_status_prev; #endif - - ImageInfo Info; }; static bool g_bHD_RomLoaded = false; static bool g_bHD_Enabled = false; -static BYTE g_nHD_UnitNum = HARDDISK_1; +static BYTE g_nHD_UnitNum = HARDDISK_1<<7; // b7=unit // The HDD interface has a single Command register for both drives: // . ProDOS will write to Command before switching drives @@ -143,114 +145,96 @@ static BYTE g_nHD_Command; static HDD g_HardDisk[NUM_HARDDISKS] = {0}; +static bool g_bSaveDiskImage = true; // Save the DiskImage name to Registry static UINT g_uSlot = 7; static CHardDiskImageHelper sg_HardDiskImageHelper; //=========================================================================== +static void HD_SaveLastDiskImage(const int iDrive); + static void HD_CleanupDrive(const int iDrive) { - sg_HardDiskImageHelper.Close(&g_HardDisk[iDrive].Info, false); - - g_HardDisk[iDrive].hd_imageloaded = false; - g_HardDisk[iDrive].imagename[0] = 0; - g_HardDisk[iDrive].fullname[0] = 0; - g_HardDisk[iDrive].Info.szFilename[0] = 0; -} - -static ImageError_e ImageOpen( LPCTSTR pszImageFilename, - const int iDrive, - const bool bCreateIfNecessary, - std::string& strFilenameInZip) -{ - if (!pszImageFilename) - return eIMAGE_ERROR_BAD_POINTER; - - HDD* pHDD = &g_HardDisk[iDrive]; - ImageInfo* pImageInfo = &pHDD->Info; - pImageInfo->bWriteProtected = false; - - ImageError_e Err = sg_HardDiskImageHelper.Open(pszImageFilename, pImageInfo, bCreateIfNecessary, strFilenameInZip); - - if (Err != eIMAGE_ERROR_NONE) + if (g_HardDisk[iDrive].imagehandle) { - HD_CleanupDrive(iDrive); - return Err; + ImageClose(g_HardDisk[iDrive].imagehandle); + g_HardDisk[iDrive].imagehandle = (HIMAGE)0; } - return eIMAGE_ERROR_NONE; + g_HardDisk[iDrive].hd_imageloaded = false; + + g_HardDisk[iDrive].imagename[0] = 0; + g_HardDisk[iDrive].fullname[0] = 0; + g_HardDisk[iDrive].strFilenameInZip = ""; + + HD_SaveLastDiskImage(iDrive); } //----------------------------------------------------------------------------- -static void GetImageTitle(LPCTSTR pszImageFilename, HDD* pHardDrive) -{ - TCHAR imagetitle[128]; - LPCTSTR startpos = pszImageFilename; - - // imagetitle = - if (_tcsrchr(startpos,TEXT('\\'))) - startpos = _tcsrchr(startpos,TEXT('\\'))+1; - _tcsncpy(imagetitle,startpos,127); - imagetitle[127] = 0; - - // if imagetitle contains a lowercase char, then found=1 (why?) - BOOL found = 0; - int loop = 0; - while (imagetitle[loop] && !found) - { - if (IsCharLower(imagetitle[loop])) - found = 1; - else - loop++; - } - - if ((!found) && (loop > 2)) - CharLowerBuff(imagetitle+1,_tcslen(imagetitle+1)); - - // hdptr->fullname = - _tcsncpy(pHardDrive->fullname,imagetitle,127); - pHardDrive->fullname[127] = 0; - - if (imagetitle[0]) - { - LPTSTR dot = imagetitle; - if (_tcsrchr(dot,TEXT('.'))) - dot = _tcsrchr(dot,TEXT('.')); - if (dot > imagetitle) - *dot = 0; - } - - // hdptr->imagename = (ie. no extension) - _tcsncpy(pHardDrive->imagename,imagetitle,15); - pHardDrive->imagename[15] = 0; -} - static void NotifyInvalidImage(TCHAR* pszImageFilename) { // TC: TO DO } -static BOOL HD_Load_Image(const int iDrive, LPCSTR pszImageFilename) +//=========================================================================== + +BOOL HD_Insert(const int iDrive, LPCTSTR pszImageFilename); + +void HD_LoadLastDiskImage(const int iDrive) { - const bool bCreateIfNecessary = false; // NB. Don't allow creation of HDV files - std::string strFilenameInZip; // TODO: Use this - ImageError_e Error = ImageOpen(pszImageFilename, iDrive, bCreateIfNecessary, strFilenameInZip); + _ASSERT(iDrive == HARDDISK_1 || iDrive == HARDDISK_2); - g_HardDisk[iDrive].hd_imageloaded = (Error == eIMAGE_ERROR_NONE); + char sFilePath[ MAX_PATH + 1]; + sFilePath[0] = 0; -#if HD_LED - g_HardDisk[iDrive].hd_status_next = DISK_STATUS_OFF; - g_HardDisk[iDrive].hd_status_prev = DISK_STATUS_OFF; -#endif + char *pRegKey = (iDrive == HARDDISK_1) + ? REGVALUE_PREF_LAST_HARDDISK_1 + : REGVALUE_PREF_LAST_HARDDISK_2; - return g_HardDisk[iDrive].hd_imageloaded; + if (RegLoadString(TEXT(REG_PREFS), pRegKey, 1, sFilePath, MAX_PATH)) + { + sFilePath[ MAX_PATH ] = 0; + + g_bSaveDiskImage = false; + // Pass in ptr to local copy of filepath, since RemoveDisk() sets DiskPathFilename = "" // todo: update comment for HD func + HD_Insert(iDrive, sFilePath); + g_bSaveDiskImage = true; + } } //=========================================================================== -// everything below is global +static void HD_SaveLastDiskImage(const int iDrive) +{ + _ASSERT(iDrive == HARDDISK_1 || iDrive == HARDDISK_2); + + if (!g_bSaveDiskImage) + return; + + const char *pFileName = g_HardDisk[iDrive].fullname; + + if (iDrive == HARDDISK_1) + 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); + } +} + +//=========================================================================== + +// (Nearly) everything below is global static BYTE __stdcall HD_IO_EMUL(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft); @@ -263,7 +247,8 @@ bool HD_CardIsEnabled(void) // Called by: // . LoadConfiguration() - Done at each restart -// . DiskDlg_OK() - When HD is enabled/disabled on UI +// . RestoreCurrentConfig() - Done when Config dialog is cancelled +// . Snapshot_LoadState_v2() - Done to default to disabled state void HD_SetEnabled(const bool bEnabled) { if(g_bHD_Enabled == bEnabled) @@ -298,17 +283,17 @@ LPCTSTR HD_GetFullName(const int iDrive) LPCTSTR HD_GetFullPathName(const int iDrive) { - return g_HardDisk[iDrive].Info.szFilename; + return ImageGetPathname(g_HardDisk[iDrive].imagehandle); } -static LPCTSTR HD_DiskGetBaseName (const int iDrive) // Not used +static LPCTSTR HD_DiskGetBaseName(const int iDrive) // Not used { return g_HardDisk[iDrive].imagename; } //------------------------------------- -VOID HD_Load_Rom(const LPBYTE pCxRomPeripheral, const UINT uSlot) +void HD_Load_Rom(const LPBYTE pCxRomPeripheral, const UINT uSlot) { if(!g_bHD_Enabled) return; @@ -336,46 +321,82 @@ VOID HD_Load_Rom(const LPBYTE pCxRomPeripheral, const UINT uSlot) RegisterIoHandler(g_uSlot, HD_IO_EMUL, HD_IO_EMUL, NULL, NULL, NULL, NULL); } -VOID HD_Cleanup(void) +void HD_Destroy(void) { - for(int i=HARDDISK_1; i= MAX_PATH) + strcpy_s(szCurrentPathname, MAX_PATH, pszImageFilename); + + if (!strcmp(pszOtherPathname, szCurrentPathname)) + { + HD_Unplug(!iDrive); + FrameRefreshStatus(DRAW_LEDS); + } } - BOOL bResult = HD_Load_Image(iDrive, pszImageFilename); + const bool bCreateIfNecessary = false; // NB. Don't allow creation of HDV files + const bool bExpectFloppy = false; + ImageError_e Error = ImageOpen(pszImageFilename, + &g_HardDisk[iDrive].imagehandle, + &g_HardDisk[iDrive].bWriteProtected, + bCreateIfNecessary, + g_HardDisk[iDrive].strFilenameInZip, // TODO: Use this + bExpectFloppy); - if (bResult) - GetImageTitle(pszImageFilename, &g_HardDisk[iDrive]); + g_HardDisk[iDrive].hd_imageloaded = (Error == eIMAGE_ERROR_NONE); - return bResult; +#if HD_LED + g_HardDisk[iDrive].hd_status_next = DISK_STATUS_OFF; + g_HardDisk[iDrive].hd_status_prev = DISK_STATUS_OFF; +#endif + + if (Error == eIMAGE_ERROR_NONE) + { + GetImageTitle(pszImageFilename, g_HardDisk[iDrive].imagename, g_HardDisk[iDrive].fullname); + } + + HD_SaveLastDiskImage(iDrive); + + return g_HardDisk[iDrive].hd_imageloaded; } -void HD_Select(const int iDrive) +static bool HD_SelectImage(const int iDrive, LPCSTR pszFilename) { TCHAR directory[MAX_PATH] = TEXT(""); TCHAR filename[MAX_PATH] = TEXT(""); TCHAR title[40]; + strcpy(filename, pszFilename); + RegLoadString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_HDV_START_DIR), 1, directory, MAX_PATH); _tcscpy(title, TEXT("Select HDV Image For HDD ")); _tcscat(title, iDrive ? TEXT("2") : TEXT("1")); + _ASSERT(sizeof(OPENFILENAME) == sizeof(OPENFILENAME_NT4)); // Required for Win98/ME support (selected by _WIN32_WINNT=0x0400 in stdafx.h) + OPENFILENAME ofn; ZeroMemory(&ofn,sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); @@ -389,22 +410,29 @@ void HD_Select(const int iDrive) ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; // Don't allow creation & hide the read-only checkbox ofn.lpstrTitle = title; + bool bRes = false; + if (GetOpenFileName(&ofn)) { if ((!ofn.nFileExtension) || !filename[ofn.nFileExtension]) _tcscat(filename,TEXT(".hdv")); - if (HD_InsertDisk(iDrive, filename)) + 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 { NotifyInvalidImage(filename); } } + + return bRes; +} + +void HD_Select(const int iDrive) +{ + HD_SelectImage(iDrive, TEXT("")); } void HD_Unplug(const int iDrive) @@ -415,7 +443,7 @@ void HD_Unplug(const int iDrive) bool HD_IsDriveUnplugged(const int iDrive) { - return g_HardDisk[iDrive].hd_imageloaded == FALSE; + return g_HardDisk[iDrive].hd_imageloaded == false; } //----------------------------------------------------------------------------- @@ -450,33 +478,33 @@ static BYTE __stdcall HD_IO_EMUL(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG { default: case 0x00: //status - if (pHDD->Info.uImageSize == 0) + if (ImageGetImageSize(pHDD->imagehandle) == 0) { pHDD->hd_error = 1; r = DEVICE_IO_ERROR; } break; case 0x01: //read - if ((pHDD->hd_diskblock * HD_BLOCK_SIZE) < pHDD->Info.uImageSize) + if ((pHDD->hd_diskblock * HD_BLOCK_SIZE) < ImageGetImageSize(pHDD->imagehandle)) + { + bool bRes = ImageReadBlock(pHDD->imagehandle, pHDD->hd_diskblock, pHDD->hd_buf); + if (bRes) { - bool bRes = pHDD->Info.pImageType->Read(&pHDD->Info, pHDD->hd_diskblock, pHDD->hd_buf); - if (bRes) - { - pHDD->hd_error = 0; - r = 0; - pHDD->hd_buf_ptr = 0; - } - else - { - pHDD->hd_error = 1; - r = DEVICE_IO_ERROR; - } + pHDD->hd_error = 0; + r = 0; + pHDD->hd_buf_ptr = 0; } else { pHDD->hd_error = 1; r = DEVICE_IO_ERROR; } + } + else + { + pHDD->hd_error = 1; + r = DEVICE_IO_ERROR; + } break; case 0x02: //write { @@ -484,17 +512,17 @@ static BYTE __stdcall HD_IO_EMUL(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG pHDD->hd_status_next = DISK_STATUS_WRITE; #endif bool bRes = true; - const bool bAppendBlocks = (pHDD->hd_diskblock * HD_BLOCK_SIZE) >= pHDD->Info.uImageSize; + const bool bAppendBlocks = (pHDD->hd_diskblock * HD_BLOCK_SIZE) >= ImageGetImageSize(pHDD->imagehandle); if (bAppendBlocks) { ZeroMemory(pHDD->hd_buf, HD_BLOCK_SIZE); // Inefficient (especially for gzip/zip files!) - UINT uBlock = pHDD->Info.uImageSize / HD_BLOCK_SIZE; + UINT uBlock = ImageGetImageSize(pHDD->imagehandle) / HD_BLOCK_SIZE; while (uBlock < pHDD->hd_diskblock) { - bRes = pHDD->Info.pImageType->Write(&pHDD->Info, uBlock++, pHDD->hd_buf); + bRes = ImageWriteBlock(pHDD->imagehandle, uBlock++, pHDD->hd_buf); _ASSERT(bRes); if (!bRes) break; @@ -504,7 +532,7 @@ static BYTE __stdcall HD_IO_EMUL(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG MoveMemory(pHDD->hd_buf, mem+pHDD->hd_memblock, HD_BLOCK_SIZE); if (bRes) - bRes = pHDD->Info.pImageType->Write(&pHDD->Info, pHDD->hd_diskblock, pHDD->hd_buf); + bRes = ImageWriteBlock(pHDD->imagehandle, pHDD->hd_diskblock, pHDD->hd_buf); if (bRes) { @@ -560,7 +588,8 @@ static BYTE __stdcall HD_IO_EMUL(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG break; case 0xF8: r = pHDD->hd_buf[pHDD->hd_buf_ptr]; - pHDD->hd_buf_ptr++; + if (pHDD->hd_buf_ptr < sizeof(pHDD->hd_buf)-1) + pHDD->hd_buf_ptr++; break; default: #if HD_LED @@ -631,3 +660,156 @@ void HD_GetLightStatus (Disk_Status_e *pDisk1Status_) *pDisk1Status_ = DISK_STATUS_OFF; } } + +//=========================================================================== + +#define SS_YAML_VALUE_CARD_HDD "Generic HDD" + +#define SS_YAML_KEY_CURRENT_UNIT "Current Unit" +#define SS_YAML_KEY_COMMAND "Command" + +#define SS_YAML_KEY_HDDUNIT "Unit" +#define SS_YAML_KEY_FILENAME "Filename" +#define SS_YAML_KEY_ERROR "Error" +#define SS_YAML_KEY_MEMBLOCK "MemBlock" +#define SS_YAML_KEY_DISKBLOCK "DiskBlock" +#define SS_YAML_KEY_IMAGELOADED "ImageLoaded" +#define SS_YAML_KEY_STATUS_NEXT "Status Next" +#define SS_YAML_KEY_STATUS_PREV "Status Prev" +#define SS_YAML_KEY_BUF_PTR "Buffer Offset" +#define SS_YAML_KEY_BUF "Buffer" + +std::string HD_GetSnapshotCardName(void) +{ + static const std::string name(SS_YAML_VALUE_CARD_HDD); + return name; +} + +static void HD_SaveSnapshotHDDUnit(YamlSaveHelper& yamlSaveHelper, UINT unit) +{ + YamlSaveHelper::Label label(yamlSaveHelper, "%s%d:\n", SS_YAML_KEY_HDDUNIT, unit); + yamlSaveHelper.SaveString(SS_YAML_KEY_FILENAME, g_HardDisk[unit].fullname); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_ERROR, g_HardDisk[unit].hd_error); + yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_MEMBLOCK, g_HardDisk[unit].hd_memblock); + yamlSaveHelper.SaveHexUint32(SS_YAML_KEY_DISKBLOCK, g_HardDisk[unit].hd_diskblock); + yamlSaveHelper.SaveBool(SS_YAML_KEY_IMAGELOADED, g_HardDisk[unit].hd_imageloaded); + yamlSaveHelper.SaveUint(SS_YAML_KEY_STATUS_NEXT, g_HardDisk[unit].hd_status_next); + yamlSaveHelper.SaveUint(SS_YAML_KEY_STATUS_PREV, g_HardDisk[unit].hd_status_prev); + yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_BUF_PTR, g_HardDisk[unit].hd_buf_ptr); + + // New label + { + YamlSaveHelper::Label buffer(yamlSaveHelper, "%s:\n", SS_YAML_KEY_BUF); + yamlSaveHelper.SaveMemory(g_HardDisk[unit].hd_buf, HD_BLOCK_SIZE); + } +} + +void HD_SaveSnapshot(YamlSaveHelper& yamlSaveHelper) +{ + if (!HD_CardIsEnabled()) + return; + + YamlSaveHelper::Slot slot(yamlSaveHelper, HD_GetSnapshotCardName(), g_uSlot, 1); + + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); + yamlSaveHelper.Save("%s: %d # b7=unit\n", SS_YAML_KEY_CURRENT_UNIT, g_nHD_UnitNum); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_COMMAND, g_nHD_Command); + + HD_SaveSnapshotHDDUnit(yamlSaveHelper, HARDDISK_1); + HD_SaveSnapshotHDDUnit(yamlSaveHelper, HARDDISK_2); +} + +static bool HD_LoadSnapshotHDDUnit(YamlLoadHelper& yamlLoadHelper, UINT unit) +{ + std::string hddUnitName = std::string(SS_YAML_KEY_HDDUNIT) + (unit == HARDDISK_1 ? std::string("0") : std::string("1")); + if (!yamlLoadHelper.GetSubMap(hddUnitName)) + throw std::string("Card: Expected key: ") + hddUnitName; + + g_HardDisk[unit].fullname[0] = 0; + g_HardDisk[unit].imagename[0] = 0; + g_HardDisk[unit].hd_imageloaded = false; // Default to false (until image is successfully loaded below) + g_HardDisk[unit].hd_status_next = DISK_STATUS_OFF; + g_HardDisk[unit].hd_status_prev = DISK_STATUS_OFF; + + std::string filename = yamlLoadHelper.LoadString(SS_YAML_KEY_FILENAME); + g_HardDisk[unit].hd_error = yamlLoadHelper.LoadUint(SS_YAML_KEY_ERROR); + g_HardDisk[unit].hd_memblock = yamlLoadHelper.LoadUint(SS_YAML_KEY_MEMBLOCK); + g_HardDisk[unit].hd_diskblock = yamlLoadHelper.LoadUint(SS_YAML_KEY_DISKBLOCK); + yamlLoadHelper.LoadBool(SS_YAML_KEY_IMAGELOADED); // Consume + Disk_Status_e diskStatusNext = (Disk_Status_e) yamlLoadHelper.LoadUint(SS_YAML_KEY_STATUS_NEXT); + Disk_Status_e diskStatusPrev = (Disk_Status_e) yamlLoadHelper.LoadUint(SS_YAML_KEY_STATUS_PREV); + g_HardDisk[unit].hd_buf_ptr = yamlLoadHelper.LoadUint(SS_YAML_KEY_BUF_PTR); + + if (!yamlLoadHelper.GetSubMap(SS_YAML_KEY_BUF)) + throw hddUnitName + std::string(": Missing: ") + std::string(SS_YAML_KEY_BUF); + yamlLoadHelper.LoadMemory(g_HardDisk[unit].hd_buf, HD_BLOCK_SIZE); + + yamlLoadHelper.PopMap(); + yamlLoadHelper.PopMap(); + + // + + bool bResSelectImage = false; + + if (!filename.empty()) + { + DWORD dwAttributes = GetFileAttributes(filename.c_str()); + if (dwAttributes == INVALID_FILE_ATTRIBUTES) + { + // Get user to browse for file + bResSelectImage = HD_SelectImage(unit, filename.c_str()); + + dwAttributes = GetFileAttributes(filename.c_str()); + } + + bool bImageError = (dwAttributes == INVALID_FILE_ATTRIBUTES); + if (!bImageError) + { + if (!HD_Insert(unit, filename.c_str())) + bImageError = true; + + // HD_Insert() sets up: + // . imagename + // . fullname + // . hd_imageloaded + // . hd_status_next = DISK_STATUS_OFF + // . hd_status_prev = DISK_STATUS_OFF + + g_HardDisk[unit].hd_status_next = diskStatusNext; + g_HardDisk[unit].hd_status_prev = diskStatusPrev; + } + } + + return bResSelectImage; +} + +bool HD_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version, const std::string strSaveStatePath) +{ + if (slot != 7) // fixme + throw std::string("Card: wrong slot"); + + if (version != 1) + throw std::string("Card: wrong version"); + + g_nHD_UnitNum = yamlLoadHelper.LoadUint(SS_YAML_KEY_CURRENT_UNIT); // b7=unit + g_nHD_Command = yamlLoadHelper.LoadUint(SS_YAML_KEY_COMMAND); + + // Unplug all HDDs first in case HDD-2 is to be plugged in as HDD-1 + for (UINT i=0; i JN_JOYSTICK1) + return; + + joytype[num] = type; + + // Refresh centre positions whenever 'joytype' changes + JoySetTrim(JoyGetTrim(true) , true); + JoySetTrim(JoyGetTrim(false), false); +} + +DWORD JoyGetJoyType(UINT num) +{ + _ASSERT(num <= JN_JOYSTICK1); + if (num > JN_JOYSTICK1) + return J0C_DISABLED; + + return joytype[num]; +} + +//=========================================================================== + void JoySetTrim(short nValue, bool bAxisX) { if(bAxisX) @@ -824,14 +849,45 @@ void JoyportControl(const UINT uControl) //=========================================================================== -DWORD JoyGetSnapshot(SS_IO_Joystick* pSS) +void JoySetSnapshot_v1(const unsigned __int64 JoyCntrResetCycle) { - pSS->g_nJoyCntrResetCycle = g_nJoyCntrResetCycle; - return 0; + g_nJoyCntrResetCycle = JoyCntrResetCycle; } -DWORD JoySetSnapshot(SS_IO_Joystick* pSS) +// + +#define SS_YAML_KEY_COUNTERRESETCYCLE "Counter Reset Cycle" +#define SS_YAML_KEY_JOY0TRIMX "Joystick0 TrimX" +#define SS_YAML_KEY_JOY0TRIMY "Joystick0 TrimY" +#define SS_YAML_KEY_JOY1TRIMX "Joystick1 TrimX" +#define SS_YAML_KEY_JOY1TRIMY "Joystick1 TrimY" + +static std::string JoyGetSnapshotStructName(void) { - g_nJoyCntrResetCycle = pSS->g_nJoyCntrResetCycle; - return 0; + static const std::string name("Joystick"); + return name; +} + +void JoySaveSnapshot(YamlSaveHelper& yamlSaveHelper) +{ + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", JoyGetSnapshotStructName().c_str()); + yamlSaveHelper.SaveHexUint64(SS_YAML_KEY_COUNTERRESETCYCLE, g_nJoyCntrResetCycle); + yamlSaveHelper.SaveInt(SS_YAML_KEY_JOY0TRIMX, JoyGetTrim(true)); + yamlSaveHelper.SaveInt(SS_YAML_KEY_JOY0TRIMY, JoyGetTrim(false)); + yamlSaveHelper.Save("%s: %d # not implemented yet\n", SS_YAML_KEY_JOY1TRIMX, 0); // not implemented yet + yamlSaveHelper.Save("%s: %d # not implemented yet\n", SS_YAML_KEY_JOY1TRIMY, 0); // not implemented yet +} + +void JoyLoadSnapshot(YamlLoadHelper& yamlLoadHelper) +{ + if (!yamlLoadHelper.GetSubMap(JoyGetSnapshotStructName())) + return; + + g_nJoyCntrResetCycle = yamlLoadHelper.LoadUint64(SS_YAML_KEY_COUNTERRESETCYCLE); + JoySetTrim(yamlLoadHelper.LoadInt(SS_YAML_KEY_JOY0TRIMX), true); + JoySetTrim(yamlLoadHelper.LoadInt(SS_YAML_KEY_JOY0TRIMY), false); + yamlLoadHelper.LoadInt(SS_YAML_KEY_JOY1TRIMX); // dump value + yamlLoadHelper.LoadInt(SS_YAML_KEY_JOY1TRIMY); // dump value + + yamlLoadHelper.PopMap(); } diff --git a/source/Joystick.h b/source/Joystick.h index 9889c2c9..517b9fcd 100644 --- a/source/Joystick.h +++ b/source/Joystick.h @@ -5,8 +5,6 @@ enum JOYNUM {JN_JOYSTICK0=0, JN_JOYSTICK1}; enum JOY0CHOICE {J0C_DISABLED=0, J0C_JOYSTICK1, J0C_KEYBD_CURSORS, J0C_KEYBD_NUMPAD, J0C_MOUSE, J0C_MAX}; enum JOY1CHOICE {J1C_DISABLED=0, J1C_JOYSTICK2, J1C_KEYBD_CURSORS, J1C_KEYBD_NUMPAD, J1C_MOUSE, J1C_MAX}; -extern DWORD joytype[2]; - enum {JOYSTICK_MODE_FLOATING=0, JOYSTICK_MODE_CENTERING}; // Joystick centering control void JoyInitialize(); @@ -21,11 +19,14 @@ BOOL JoyUsingKeyboard(); BOOL JoyUsingKeyboardCursors(); BOOL JoyUsingKeyboardNumpad(); void JoyDisableUsingMouse(); +void JoySetJoyType(UINT num, DWORD type); +DWORD JoyGetJoyType(UINT num); void JoySetTrim(short nValue, bool bAxisX); short JoyGetTrim(bool bAxisX); void JoyportControl(const UINT uControl); -DWORD JoyGetSnapshot(SS_IO_Joystick* pSS); -DWORD JoySetSnapshot(SS_IO_Joystick* pSS); +void JoySetSnapshot_v1(const unsigned __int64 JoyCntrResetCycle); +void JoySaveSnapshot(class YamlSaveHelper& yamlSaveHelper); +void JoyLoadSnapshot(class YamlLoadHelper& yamlLoadHelper); BYTE __stdcall JoyReadButton(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft); BYTE __stdcall JoyReadPosition(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft); diff --git a/source/Keyboard.cpp b/source/Keyboard.cpp index 2b1e1727..936eb63b 100644 --- a/source/Keyboard.cpp +++ b/source/Keyboard.cpp @@ -31,7 +31,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "AppleWin.h" #include "Frame.h" #include "Keyboard.h" +#include "Pravets.h" #include "Tape.h" +#include "YamlHelper.h" static bool g_bKeybBufferEnable = false; @@ -50,7 +52,6 @@ static bool g_bCapsLock = true; //Caps lock key for Apple2 and Lat/Cyr lock for static bool g_bP8CapsLock = true; //Caps lock key of Pravets 8A/C static int lastvirtkey = 0; // Current PC keycode static BYTE keycode = 0; // Current Apple keycode -static DWORD keyboardqueries = 0; #ifdef KEY_OLD // Original @@ -160,14 +161,6 @@ BYTE KeybGetKeycode () // Used by MemCheckPaging() & VideoCheckMode() return keycode; } -//=========================================================================== -DWORD KeybGetNumQueries () // Used in determining 'idleness' of Apple system -{ - DWORD result = keyboardqueries; - keyboardqueries = 0; - return result; -} - //=========================================================================== void KeybQueueKeypress (int key, BOOL bASCII) { @@ -425,10 +418,6 @@ static char ClipboardCurrChar(bool bIncPtr) BYTE __stdcall KeybReadData (WORD, WORD, BYTE, BYTE, ULONG) { - keyboardqueries++; - - // - if(g_bPasteFromClipboard) ClipboardInit(); @@ -463,10 +452,6 @@ BYTE __stdcall KeybReadData (WORD, WORD, BYTE, BYTE, ULONG) BYTE __stdcall KeybReadFlag (WORD, WORD, BYTE, BYTE, ULONG) { - keyboardqueries++; - - // - if(g_bPasteFromClipboard) ClipboardInit(); @@ -516,16 +501,33 @@ void KeybToggleP8ACapsLock () //=========================================================================== -DWORD KeybGetSnapshot(SS_IO_Keyboard* pSS) +void KeybSetSnapshot_v1(const BYTE LastKey) { - pSS->keyboardqueries = keyboardqueries; - pSS->nLastKey = g_nLastKey; - return 0; + g_nLastKey = LastKey; } -DWORD KeybSetSnapshot(SS_IO_Keyboard* pSS) +// + +#define SS_YAML_KEY_LASTKEY "Last Key" + +static std::string KeybGetSnapshotStructName(void) { - keyboardqueries = pSS->keyboardqueries; - g_nLastKey = pSS->nLastKey; - return 0; + static const std::string name("Keyboard"); + return name; +} + +void KeybSaveSnapshot(YamlSaveHelper& yamlSaveHelper) +{ + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", KeybGetSnapshotStructName().c_str()); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_LASTKEY, g_nLastKey); +} + +void KeybLoadSnapshot(YamlLoadHelper& yamlLoadHelper) +{ + if (!yamlLoadHelper.GetSubMap(KeybGetSnapshotStructName())) + return; + + g_nLastKey = (BYTE) yamlLoadHelper.LoadUint(SS_YAML_KEY_LASTKEY); + + yamlLoadHelper.PopMap(); } diff --git a/source/Keyboard.h b/source/Keyboard.h index 0010b677..f79cb203 100644 --- a/source/Keyboard.h +++ b/source/Keyboard.h @@ -11,12 +11,12 @@ bool KeybGetShiftStatus(); bool KeybGetCapsAllowed(); //For Pravets8A/C only void KeybUpdateCtrlShiftStatus(); BYTE KeybGetKeycode (); -DWORD KeybGetNumQueries (); void KeybQueueKeypress (int,BOOL); void KeybToggleCapsLock (); void KeybToggleP8ACapsLock (); -DWORD KeybGetSnapshot(SS_IO_Keyboard* pSS); -DWORD KeybSetSnapshot(SS_IO_Keyboard* pSS); +void KeybSetSnapshot_v1(const BYTE LastKey); +void KeybSaveSnapshot(class YamlSaveHelper& yamlSaveHelper); +void KeybLoadSnapshot(class YamlLoadHelper& yamlLoadHelper); BYTE __stdcall KeybReadData (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft); BYTE __stdcall KeybReadFlag (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft); diff --git a/source/Log.cpp b/source/Log.cpp index e277a56c..fb419b05 100644 --- a/source/Log.cpp +++ b/source/Log.cpp @@ -33,13 +33,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA void LogOutput(LPCTSTR format, ...) { - TCHAR output[256]; + TCHAR output[256]; - va_list args; - va_start(args, format); + va_list args; + va_start(args, format); - _vsntprintf(output, sizeof(output) - 1, format, args); - OutputDebugString(output); + _vsntprintf(output, sizeof(output) - 1, format, args); + OutputDebugString(output); } //--------------------------------------------------------------------------- @@ -51,11 +51,11 @@ void LogFileOutput(LPCTSTR format, ...) if (!g_fh) return; - TCHAR output[256]; + TCHAR output[256]; - va_list args; - va_start(args, format); + va_list args; + va_start(args, format); - _vsntprintf(output, sizeof(output) - 1, format, args); - fprintf(g_fh, output); + _vsntprintf(output, sizeof(output) - 1, format, args); + fprintf(g_fh, "%s", output); } diff --git a/source/Memory.cpp b/source/Memory.cpp index 56c36b00..5d2bcd18 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -24,6 +24,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /* Description: Memory emulation * * Author: Various + * + * In comments, UTA2E is an abbreviation for a reference to "Understanding the Apple //e" by James Sather */ #include "StdAfx.h" @@ -42,6 +44,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "NoSlotClock.h" #include "ParallelPrinter.h" #include "Registry.h" +#include "SAM.h" #include "SerialComms.h" #include "Speaker.h" #include "Tape.h" @@ -52,6 +55,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "..\resource\resource.h" #include "Configuration\PropertySheet.h" #include "Debugger\DebugDefs.h" +#include "YamlHelper.h" // Memory Flag #define MF_80STORE 0x00000001 @@ -170,7 +174,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,12 +198,12 @@ static BOOL Pravets8charmode = 0; static CNoSlotClock g_NoSlotClock; #ifdef RAMWORKS -UINT g_uMaxExPages = 1; // user requested ram pages -static LPBYTE RWpages[128]; // pointers to RW memory banks +UINT g_uMaxExPages = 1; // user requested ram pages (default to 1 aux bank: so total = 128KB) +UINT g_uActiveBank = 0; // 0 = aux 64K for: //e extended 80 Col card, or //c +static LPBYTE RWpages[kMaxExMemoryBanks]; // pointers to RW memory banks #endif BYTE __stdcall IO_Annunciator(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles); -void UpdatePaging(BOOL initialize); //============================================================================= @@ -231,7 +235,7 @@ static BYTE __stdcall IORead_C01x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG case 0x6: return MemCheckPaging(pc, addr, bWrite, d, nCyclesLeft); case 0x7: return MemCheckPaging(pc, addr, bWrite, d, nCyclesLeft); case 0x8: return MemCheckPaging(pc, addr, bWrite, d, nCyclesLeft); - case 0x9: return VideoCheckVbl( nCyclesLeft ); // NTSC cleanup + case 0x9: return VideoCheckVbl(nCyclesLeft); case 0xA: return VideoCheckMode(pc, addr, bWrite, d, nCyclesLeft); case 0xB: return VideoCheckMode(pc, addr, bWrite, d, nCyclesLeft); case 0xC: return MemCheckPaging(pc, addr, bWrite, d, nCyclesLeft); @@ -342,7 +346,7 @@ static BYTE __stdcall IORead_C06x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG { static byte CurrentKestroke = 0; CurrentKestroke = KeybGetKeycode(); - switch (addr & 0xf) + switch (addr & 0x7) // address bit 4 is ignored (UTA2E page 7-5) { //In Pravets8A/C if SETMODE (8bit character encoding) is enabled, bit6 in $C060 is 0; Else it is 1 //If (CAPS lOCK of Pravets8A/C is on or Shift is pressed) and (MODE is enabled), bit7 in $C000 is 1; Else it is 0 @@ -356,14 +360,6 @@ static BYTE __stdcall IORead_C06x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG case 0x5: return JoyReadPosition(pc, addr, bWrite, d, nCyclesLeft); //$C065 Analog input 1 case 0x6: return JoyReadPosition(pc, addr, bWrite, d, nCyclesLeft); //$C066 Analog input 2 case 0x7: return JoyReadPosition(pc, addr, bWrite, d, nCyclesLeft); //$C067 Analog input 3 - case 0x8: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); - case 0x9: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); - case 0xA: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); - case 0xB: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); - case 0xC: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); - case 0xD: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); - case 0xE: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); - case 0xF: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); } return 0; @@ -694,11 +690,6 @@ static void InitIoHandlers() // - IO_SELECT = 0; - IO_SELECT_InternalROM = 0; - g_eExpansionRomType = eExpRomNull; - g_uPeripheralRomSlot = 0; - for (i=0; i> 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 @@ -1104,17 +1106,14 @@ LPBYTE MemGetCxRomPeripheral() //=========================================================================== +const UINT CxRomSize = 4*1024; +const UINT Apple2RomSize = 12*1024; +const UINT Apple2eRomSize = Apple2RomSize+CxRomSize; +//const UINT Pravets82RomSize = 12*1024; +//const UINT Pravets8ARomSize = Pravets82RomSize+CxRomSize; + void MemInitialize() { - // Init the I/O handlers - InitIoHandlers(); - - const UINT CxRomSize = 4*1024; - const UINT Apple2RomSize = 12*1024; - const UINT Apple2eRomSize = Apple2RomSize+CxRomSize; - //const UINT Pravets82RomSize = 12*1024; - //const UINT Pravets8ARomSize = Pravets82RomSize+CxRomSize; - // ALLOCATE MEMORY FOR THE APPLE MEMORY IMAGE AND ASSOCIATED DATA STRUCTURES memaux = (LPBYTE)VirtualAlloc(NULL,_6502_MEM_END+1,MEM_COMMIT,PAGE_READWRITE); memmain = (LPBYTE)VirtualAlloc(NULL,_6502_MEM_END+1,MEM_COMMIT,PAGE_READWRITE); @@ -1149,12 +1148,22 @@ 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++; #endif + MemInitializeROM(); + MemInitializeCustomF8ROM(); + MemInitializeIO(); + MemReset(); +} + +void MemInitializeROM(void) +{ // READ THE APPLE FIRMWARE ROMS INTO THE ROM IMAGE UINT ROM_SIZE = 0; HRSRC hResInfo = NULL; @@ -1211,8 +1220,6 @@ void MemInitialize() if (pData == NULL) return; - // - memset(pCxRomInternal,0,CxRomSize); memset(pCxRomPeripheral,0,CxRomSize); @@ -1224,17 +1231,23 @@ void MemInitialize() } _ASSERT(ROM_SIZE == Apple2RomSize); - memcpy(memrom, pData, Apple2RomSize); // ROM at $D000...$FFFF + memcpy(memrom, pData, Apple2RomSize); // ROM at $D000...$FFFF +} +void MemInitializeCustomF8ROM(void) +{ const UINT F8RomSize = 0x800; if (g_hCustomRomF8 != INVALID_HANDLE_VALUE) { + BYTE OldRom[Apple2RomSize]; // NB. 12KB on stack + memcpy(OldRom, memrom, Apple2RomSize); + SetFilePointer(g_hCustomRomF8, 0, NULL, FILE_BEGIN); DWORD uNumBytesRead; BOOL bRes = ReadFile(g_hCustomRomF8, memrom+Apple2RomSize-F8RomSize, F8RomSize, &uNumBytesRead, NULL); if (uNumBytesRead != F8RomSize) { - memcpy(memrom, pData, Apple2RomSize); // ROM at $D000...$FFFF + memcpy(memrom, OldRom, Apple2RomSize); // ROM at $D000...$FFFF bRes = FALSE; } @@ -1249,15 +1262,27 @@ void MemInitialize() if (sg_PropertySheet.GetTheFreezesF8Rom() && IS_APPLE2) { - hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_FREEZES_F8_ROM), "ROM"); + HGLOBAL hResData = NULL; + BYTE* pData = NULL; + + HRSRC hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_FREEZES_F8_ROM), "ROM"); if (hResInfo && (SizeofResource(NULL, hResInfo) == 0x800) && (hResData = LoadResource(NULL, hResInfo)) && (pData = (BYTE*) LockResource(hResData))) { memcpy(memrom+Apple2RomSize-F8RomSize, pData, F8RomSize); } } +} - // +// Called by: +// . MemInitialize() +// . Snapshot_LoadState_v2() +// +// Since called by LoadState(), then this must not init any cards +// - it should only init the card I/O hooks +void MemInitializeIO(void) +{ + InitIoHandlers(); const UINT uSlot = 0; RegisterIoHandler(uSlot, MemSetPaging, MemSetPaging, NULL, NULL, NULL, NULL); @@ -1295,11 +1320,12 @@ void MemInitialize() { ConfigureSoftcard(pCxRomPeripheral, 5); // $C500 : Z80 card } + else + if (g_Slot5 == CT_SAM) + ConfigureSAM(pCxRomPeripheral, 5); // $C500 : Z80 card DiskLoadRom(pCxRomPeripheral, 6); // $C600 : Disk][ f/w HD_Load_Rom(pCxRomPeripheral, 7); // $C700 : HDD f/w - - MemReset(); } inline DWORD getRandomTime() @@ -1312,7 +1338,8 @@ inline DWORD getRandomTime() // Called by: // . MemInitialize() // . ResetMachineState() eg. Power-cycle ('Apple-Go' button) -// . Snapshot_LoadState() +// . Snapshot_LoadState_v1() +// . Snapshot_LoadState_v2() void MemReset() { // INITIALIZE THE PAGING TABLES @@ -1321,9 +1348,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 @@ -1394,14 +1428,14 @@ void MemReset() break; case MIP_RANDOM: - unsigned char random[ 256 + 4 ]; + unsigned char random[ 256 ]; for( iByte = 0x0000; iByte < 0xC000; iByte += 256 ) { for( int i = 0; i < 256; i++ ) { clock = getRandomTime(); - random[ i+0 ] ^= (clock >> 0) & 0xFF; - random[ i+1 ] ^= (clock >> 11) & 0xFF; + random[ (i+0) & 0xFF ] ^= (clock >> 0) & 0xFF; + random[ (i+1) & 0xFF ] ^= (clock >> 11) & 0xFF; } memcpy( &memmain[ iByte ], random, 256 ); @@ -1434,7 +1468,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" @@ -1455,23 +1489,7 @@ void MemReset() CpuInitialize(); //Sets Caps Lock = false (Pravets 8A/C only) - z80_reset(); -} - -//=========================================================================== - -// Call by: -// . Soft-reset (Ctrl+Reset) -// . Snapshot_LoadState() -void MemResetPaging() -{ - ResetPaging(0); // Initialize=0 - if (g_Apple2Type == A2TYPE_PRAVETS8A) - { - P8CAPS_ON = false; - TapeWrite (0, 0, 0, 0 ,0); - FrameRefreshStatus(DRAW_LEDS); - } + z80_reset(); // NB. Also called above in CpuInitialize() } //=========================================================================== @@ -1592,7 +1610,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; @@ -1670,34 +1689,218 @@ LPVOID MemGetSlotParameters(UINT uSlot) // . If we were to save the state when 'modechanging' is set, then on restoring the state, the 6502 code will immediately update the read memory mode. // . This will work correctly. -DWORD MemGetSnapshot(SS_BaseMemory* pSS) +void MemSetSnapshot_v1(const DWORD MemMode, const BOOL LastWriteRam, const BYTE* const pMemMain, const BYTE* const pMemAux) { - pSS->dwMemMode = memmode; - pSS->bLastWriteRam = lastwriteram; + SetMemMode(MemMode); + lastwriteram = LastWriteRam; - for(DWORD dwOffset = 0x0000; dwOffset < 0x10000; dwOffset+=0x100) - { - memcpy(pSS->nMemMain+dwOffset, MemGetMainPtr((WORD)dwOffset), 0x100); - memcpy(pSS->nMemAux+dwOffset, MemGetAuxPtr((WORD)dwOffset), 0x100); - } - - return 0; -} - -DWORD MemSetSnapshot(SS_BaseMemory* pSS) -{ - SetMemMode(pSS->dwMemMode); - lastwriteram = pSS->bLastWriteRam; - - memcpy(memmain, pSS->nMemMain, nMemMainSize); - memcpy(memaux, pSS->nMemAux, nMemAuxSize); + memcpy(memmain, pMemMain, nMemMainSize); + memcpy(memaux, pMemAux, nMemAuxSize); memset(memdirty, 0, 0x100); // modechanging = 0; - + // NB. MemUpdatePaging(TRUE) called at end of Snapshot_LoadState_v1() UpdatePaging(1); // Initialize=1 - - return 0; +} + +// + +#define UNIT_AUXSLOT_VER 1 + +#define SS_YAML_KEY_MEMORYMODE "Memory Mode" +#define SS_YAML_KEY_LASTRAMWRITE "Last RAM Write" +#define SS_YAML_KEY_IOSELECT "IO_SELECT" +#define SS_YAML_KEY_IOSELECT_INT "IO_SELECT_InternalROM" +#define SS_YAML_KEY_EXPANSIONROMTYPE "Expansion ROM Type" +#define SS_YAML_KEY_PERIPHERALROMSLOT "Peripheral ROM Slot" + +#define SS_YAML_VALUE_CARD_80COL "80 Column" +#define SS_YAML_VALUE_CARD_EXTENDED80COL "Extended 80 Column" +#define SS_YAML_VALUE_CARD_RAMWORKSIII "RamWorksIII" + +#define SS_YAML_KEY_NUMAUXBANKS "Num Aux Banks" +#define SS_YAML_KEY_ACTIVEAUXBANK "Active Aux Bank" + +static std::string MemGetSnapshotStructName(void) +{ + static const std::string name("Memory"); + return name; +} + +std::string MemGetSnapshotUnitAuxSlotName(void) +{ + static const std::string name("Auxiliary Slot"); + return name; +} + +static std::string MemGetSnapshotMainMemStructName(void) +{ + static const std::string name("Main Memory"); + return name; +} + +static std::string MemGetSnapshotAuxMemStructName(void) +{ + static const std::string name("Auxiliary Memory Bank"); + return name; +} + +static void MemSaveSnapshotMemory(YamlSaveHelper& yamlSaveHelper, bool bIsMainMem, UINT bank=0) +{ + LPBYTE pMemBase = MemGetBankPtr(bank); + + if (bIsMainMem) + { + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", MemGetSnapshotMainMemStructName().c_str()); + yamlSaveHelper.SaveMemory(pMemBase, 64*1024); + } + else + { + YamlSaveHelper::Label state(yamlSaveHelper, "%s%02X:\n", MemGetSnapshotAuxMemStructName().c_str(), bank-1); + yamlSaveHelper.SaveMemory(pMemBase, 64*1024); + } +} + +void MemSaveSnapshot(YamlSaveHelper& yamlSaveHelper) +{ + // Scope so that "Memory" & "Main Memory" are at same indent level + { + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", MemGetSnapshotStructName().c_str()); + yamlSaveHelper.SaveHexUint32(SS_YAML_KEY_MEMORYMODE, memmode); + yamlSaveHelper.SaveUint(SS_YAML_KEY_LASTRAMWRITE, lastwriteram ? 1 : 0); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_IOSELECT, IO_SELECT); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_IOSELECT_INT, IO_SELECT_InternalROM); + yamlSaveHelper.SaveUint(SS_YAML_KEY_EXPANSIONROMTYPE, (UINT) g_eExpansionRomType); + yamlSaveHelper.SaveUint(SS_YAML_KEY_PERIPHERALROMSLOT, g_uPeripheralRomSlot); + } + + MemSaveSnapshotMemory(yamlSaveHelper, true); +} + +bool MemLoadSnapshot(YamlLoadHelper& yamlLoadHelper) +{ + if (!yamlLoadHelper.GetSubMap(MemGetSnapshotStructName())) + return false; + + SetMemMode( yamlLoadHelper.LoadUint(SS_YAML_KEY_MEMORYMODE) ); + lastwriteram = yamlLoadHelper.LoadUint(SS_YAML_KEY_LASTRAMWRITE) ? TRUE : FALSE; + IO_SELECT = (BYTE) yamlLoadHelper.LoadUint(SS_YAML_KEY_IOSELECT); + IO_SELECT_InternalROM = (BYTE) yamlLoadHelper.LoadUint(SS_YAML_KEY_IOSELECT_INT); + g_eExpansionRomType = (eExpansionRomType) yamlLoadHelper.LoadUint(SS_YAML_KEY_EXPANSIONROMTYPE); + g_uPeripheralRomSlot = yamlLoadHelper.LoadUint(SS_YAML_KEY_PERIPHERALROMSLOT); + + yamlLoadHelper.PopMap(); + + // + + if (!yamlLoadHelper.GetSubMap( MemGetSnapshotMainMemStructName() )) + throw std::string("Card: Expected key: ") + MemGetSnapshotMainMemStructName(); + + yamlLoadHelper.LoadMemory(memmain, _6502_MEM_END+1); + memset(memdirty, 0, 0x100); + + yamlLoadHelper.PopMap(); + + // + + modechanging = 0; + // NB. MemUpdatePaging(TRUE) called at end of Snapshot_LoadState_v2() + UpdatePaging(1); // Initialize=1 (Still needed, even with call to MemUpdatePaging() - why?) + + return true; +} + +void MemSaveSnapshotAux(YamlSaveHelper& yamlSaveHelper) +{ + if (IS_APPLE2) + { + return; // No Aux slot for AppleII + } + + if (IS_APPLE2C) + { + _ASSERT(g_uMaxExPages == 1); + } + + yamlSaveHelper.UnitHdr(MemGetSnapshotUnitAuxSlotName(), UNIT_AUXSLOT_VER); + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); + + std::string card = g_uMaxExPages == 0 ? SS_YAML_VALUE_CARD_80COL : // todo: support empty slot + g_uMaxExPages == 1 ? SS_YAML_VALUE_CARD_EXTENDED80COL : + SS_YAML_VALUE_CARD_RAMWORKSIII; + yamlSaveHelper.SaveString(SS_YAML_KEY_CARD, card.c_str()); + yamlSaveHelper.Save("%s: %02X # [0,1..7F] 0=no aux mem, 1=128K system, etc\n", SS_YAML_KEY_NUMAUXBANKS, g_uMaxExPages); + yamlSaveHelper.Save("%s: %02X # [ 0..7E] 0=memaux\n", SS_YAML_KEY_ACTIVEAUXBANK, g_uActiveBank); + + for(UINT uBank = 1; uBank <= g_uMaxExPages; uBank++) + { + MemSaveSnapshotMemory(yamlSaveHelper, false, uBank); + } +} + +bool MemLoadSnapshotAux(YamlLoadHelper& yamlLoadHelper, UINT version) +{ + if (version != UNIT_AUXSLOT_VER) + throw std::string(SS_YAML_KEY_UNIT ": AuxSlot: Version mismatch"); + + // "State" + UINT numAuxBanks = yamlLoadHelper.LoadUint(SS_YAML_KEY_NUMAUXBANKS); + UINT activeAuxBank = yamlLoadHelper.LoadUint(SS_YAML_KEY_ACTIVEAUXBANK); + + std::string card = yamlLoadHelper.LoadString(SS_YAML_KEY_CARD); + if (card == SS_YAML_VALUE_CARD_80COL) + { + if (numAuxBanks != 0 || activeAuxBank != 0) + throw std::string(SS_YAML_KEY_UNIT ": AuxSlot: Bad aux slot card state"); + } + else if (card == SS_YAML_VALUE_CARD_EXTENDED80COL) + { + if (numAuxBanks != 1 || activeAuxBank != 0) + throw std::string(SS_YAML_KEY_UNIT ": AuxSlot: Bad aux slot card state"); + } + else if (card == SS_YAML_VALUE_CARD_RAMWORKSIII) + { + if (numAuxBanks < 2 || numAuxBanks > 0x7F || (activeAuxBank+1) > numAuxBanks) + throw std::string(SS_YAML_KEY_UNIT ": AuxSlot: Bad aux slot card state"); + } + else + { + // todo: support empty slot + throw std::string(SS_YAML_KEY_UNIT ": AuxSlot: Unknown card: " + card); + } + + g_uMaxExPages = numAuxBanks; + g_uActiveBank = activeAuxBank; + + // + + for(UINT uBank = 1; uBank <= g_uMaxExPages; uBank++) + { + LPBYTE pBank = MemGetBankPtr(uBank); + if (!pBank) + { + pBank = RWpages[uBank-1] = (LPBYTE) VirtualAlloc(NULL,_6502_MEM_END+1,MEM_COMMIT,PAGE_READWRITE); + if (!pBank) + throw std::string("Card: mem alloc failed"); + } + + // "Auxiliary Memory Bankxx" + char szBank[3]; + sprintf(szBank, "%02X", uBank-1); + std::string auxMemName = MemGetSnapshotAuxMemStructName() + szBank; + + if (!yamlLoadHelper.GetSubMap(auxMemName)) + throw std::string("Memory: Missing map name: " + auxMemName); + + yamlLoadHelper.LoadMemory(pBank, _6502_MEM_END+1); + + yamlLoadHelper.PopMap(); + } + + memaux = RWpages[g_uActiveBank]; + // NB. MemUpdatePaging(TRUE) called at end of Snapshot_LoadState_v2() + + return true; } diff --git a/source/Memory.h b/source/Memory.h index 207cd1b1..3a104755 100644 --- a/source/Memory.h +++ b/source/Memory.h @@ -32,6 +32,7 @@ extern LPBYTE mem; extern LPBYTE memdirty; #ifdef RAMWORKS +const UINT kMaxExMemoryBanks = 127; // 127 * aux mem(64K) + main mem(64K) = 8MB extern UINT g_uMaxExPages; // user requested ram pages (from cmd line) #endif @@ -44,14 +45,21 @@ LPBYTE MemGetMainPtr(const WORD); LPBYTE MemGetBankPtr(const UINT nBank); LPBYTE MemGetCxRomPeripheral(); void MemInitialize (); +void MemInitializeROM(void); +void MemInitializeCustomF8ROM(void); +void MemInitializeIO(void); BYTE MemReadFloatingBus(const ULONG uExecutedCycles); BYTE MemReadFloatingBus(const BYTE highbit, const ULONG uExecutedCycles); void MemReset (); void MemResetPaging (); void MemUpdatePaging(BOOL initialize); LPVOID MemGetSlotParameters (UINT uSlot); -DWORD MemGetSnapshot(SS_BaseMemory* pSS); -DWORD MemSetSnapshot(SS_BaseMemory* pSS); +void MemSetSnapshot_v1(const DWORD MemMode, const BOOL LastWriteRam, const BYTE* const pMemMain, const BYTE* const pMemAux); +std::string MemGetSnapshotUnitAuxSlotName(void); +void MemSaveSnapshot(class YamlSaveHelper& yamlSaveHelper); +bool MemLoadSnapshot(class YamlLoadHelper& yamlLoadHelper); +void MemSaveSnapshotAux(class YamlSaveHelper& yamlSaveHelper); +bool MemLoadSnapshotAux(class YamlLoadHelper& yamlLoadHelper, UINT version); BYTE __stdcall IO_Null(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles); diff --git a/source/Mockingboard.cpp b/source/Mockingboard.cpp index 590c7870..0143f8e9 100644 --- a/source/Mockingboard.cpp +++ b/source/Mockingboard.cpp @@ -77,12 +77,15 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "StdAfx.h" +#include "SaveState_Structs_v1.h" + #include "AppleWin.h" #include "CPU.h" #include "Log.h" #include "Memory.h" #include "Mockingboard.h" #include "SoundCore.h" +#include "YamlHelper.h" #include "AY8910.h" #include "SSI263Phonemes.h" @@ -114,14 +117,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define Phasor_SY6522A_Offset (1<SpeechChip.CurrentMode &= ~1; // Clear SSI263's D7 pin - pMB->SpeechChip.DurationPhonome = nValue; + pMB->SpeechChip.DurationPhoneme = nValue; g_nSSI263Device = nDevice; @@ -632,7 +636,7 @@ static void SSI263_Write(BYTE nDevice, BYTE nReg, BYTE nValue) if(g_fh) fprintf(g_fh, "CTRL = %d, ART = 0x%02X, AMP=0x%02X\n", nValue>>7, (nValue&ARTICULATION_MASK)>>4, nValue&LITUDE_MASK); #endif if((pMB->SpeechChip.CtrlArtAmp & CONTROL_MASK) && !(nValue & CONTROL_MASK)) // H->L - pMB->SpeechChip.CurrentMode = pMB->SpeechChip.DurationPhonome & DURATION_MODE_MASK; + pMB->SpeechChip.CurrentMode = pMB->SpeechChip.DurationPhoneme & DURATION_MODE_MASK; pMB->SpeechChip.CtrlArtAmp = nValue; break; case SSI_FILFREQ: @@ -826,7 +830,7 @@ static void MB_Update() double fTicksSecs = (double)GetTickCount() / 1000.0; sprintf(szDbg, "%010.3f: [MBUpdt] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X xxx\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples); OutputDebugString(szDbg); - if (g_fh) fprintf(g_fh, szDbg); + if (g_fh) fprintf(g_fh, "%s", szDbg); dwByteOffset = dwCurrentWriteCursor; } @@ -839,7 +843,7 @@ static void MB_Update() double fTicksSecs = (double)GetTickCount() / 1000.0; sprintf(szDbg, "%010.3f: [MBUpdt] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X XXX\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples); OutputDebugString(szDbg); - if (g_fh) fprintf(g_fh, szDbg); + if (g_fh) fprintf(g_fh, "%s", szDbg); dwByteOffset = dwCurrentWriteCursor; } @@ -1002,11 +1006,22 @@ static void SSI263_Play(unsigned int nPhoneme) #if 1 HRESULT hr; - if(g_nCurrentActivePhoneme >= 0) { - // A write to DURPHON before previous phoneme has completed - g_bStopPhoneme = true; - hr = SSI263Voice[g_nCurrentActivePhoneme].lpDSBvoice->Stop(); + int nCurrPhoneme = g_nCurrentActivePhoneme; // local copy in case SSI263Thread sets it to -1 + if (nCurrPhoneme >= 0) + { + // A write to DURPHON before previous phoneme has completed + g_bStopPhoneme = true; + hr = SSI263Voice[nCurrPhoneme].lpDSBvoice->Stop(); + + // Busy-wait until ACK from SSI263Thread + // . required to avoid data-race + while ( g_bStopPhoneme && // wait for SSI263Thread to ACK the lpDSBVoice->Stop() + g_nCurrentActivePhoneme >= 0) // wait for SSI263Thread to get end of sample event + ; + + g_bStopPhoneme = false; + } } g_nCurrentActivePhoneme = nPhoneme; @@ -1371,7 +1386,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 } //----------------------------------------------------------------------------- @@ -1403,9 +1419,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() @@ -1553,9 +1570,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); } @@ -1761,45 +1778,48 @@ void MB_SetVolume(DWORD dwVolume, DWORD dwVolumeMax) //=========================================================================== -DWORD MB_GetSnapshot(SS_CARD_MOCKINGBOARD* pSS, DWORD dwSlot) +// Called by debugger - Debugger_Display.cpp +void MB_GetSnapshot_v1(SS_CARD_MOCKINGBOARD_v1* const pSS, const DWORD dwSlot) { - pSS->Hdr.UnitHdr.dwLength = sizeof(SS_CARD_DISK2); - pSS->Hdr.UnitHdr.dwVersion = MAKE_VERSION(1,0,0,0); + 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; - pSS->Hdr.dwSlot = dwSlot; - pSS->Hdr.dwType = CT_MockingboardC; + pSS->Hdr.Slot = dwSlot; + pSS->Hdr.Type = CT_MockingboardC; UINT nMbCardNum = dwSlot - SLOT4; UINT nDeviceNum = nMbCardNum*2; SY6522_AY8910* pMB = &g_MB[nDeviceNum]; - for(UINT i=0; iUnit[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++; } - - return 0; } -DWORD MB_SetSnapshot(SS_CARD_MOCKINGBOARD* pSS, DWORD /*dwSlot*/) +int MB_SetSnapshot_v1(const SS_CARD_MOCKINGBOARD_v1* const pSS, const DWORD /*dwSlot*/) { - if(pSS->Hdr.UnitHdr.dwVersion != MAKE_VERSION(1,0,0,0)) + if(pSS->Hdr.UnitHdr.hdr.v1.dwVersion != MAKE_VERSION(1,0,0,0)) return -1; - UINT nMbCardNum = pSS->Hdr.dwSlot - SLOT4; + UINT nMbCardNum = pSS->Hdr.Slot - SLOT4; UINT nDeviceNum = nMbCardNum*2; SY6522_AY8910* pMB = &g_MB[nDeviceNum]; g_nSSI263Device = 0; g_nCurrentActivePhoneme = -1; - for(UINT i=0; isy6522, &pSS->Unit[i].RegsSY6522, sizeof(SY6522)); memcpy(AY8910_GetRegsPtr(nDeviceNum), &pSS->Unit[i].RegsAY8910, 16); @@ -1814,7 +1834,7 @@ DWORD MB_SetSnapshot(SS_CARD_MOCKINGBOARD* pSS, DWORD /*dwSlot*/) // FIX THIS: // . Speech chip could be Votrax instead // . Is this IRQ compatible with Phasor? - if(pMB->SpeechChip.DurationPhonome) + if(pMB->SpeechChip.DurationPhoneme) { g_nSSI263Device = nDeviceNum; @@ -1832,3 +1852,357 @@ DWORD MB_SetSnapshot(SS_CARD_MOCKINGBOARD* pSS, DWORD /*dwSlot*/) return 0; } + +//=========================================================================== + +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; +} + +//=========================================================================== + +const UINT NUM_MB_UNITS = 2; +const UINT NUM_PHASOR_UNITS = 2; + +#define SS_YAML_KEY_MB_UNIT "Unit" +#define SS_YAML_KEY_SY6522 "SY6522" +#define SS_YAML_KEY_SY6522_REG_ORB "ORB" +#define SS_YAML_KEY_SY6522_REG_ORA "ORA" +#define SS_YAML_KEY_SY6522_REG_DDRB "DDRB" +#define SS_YAML_KEY_SY6522_REG_DDRA "DDRA" +#define SS_YAML_KEY_SY6522_REG_T1_COUNTER "Timer1 Counter" +#define SS_YAML_KEY_SY6522_REG_T1_LATCH "Timer1 Latch" +#define SS_YAML_KEY_SY6522_REG_T2_COUNTER "Timer2 Counter" +#define SS_YAML_KEY_SY6522_REG_T2_LATCH "Timer2 Latch" +#define SS_YAML_KEY_SY6522_REG_SERIAL_SHIFT "Serial Shift" +#define SS_YAML_KEY_SY6522_REG_ACR "ACR" +#define SS_YAML_KEY_SY6522_REG_PCR "PCR" +#define SS_YAML_KEY_SY6522_REG_IFR "IFR" +#define SS_YAML_KEY_SY6522_REG_IER "IER" +#define SS_YAML_KEY_SSI263 "SSI263" +#define SS_YAML_KEY_SSI263_REG_DUR_PHON "Duration / Phoneme" +#define SS_YAML_KEY_SSI263_REG_INF "Inflection" +#define SS_YAML_KEY_SSI263_REG_RATE_INF "Rate / Inflection" +#define SS_YAML_KEY_SSI263_REG_CTRL_ART_AMP "Control / Articulation / Amplitude" +#define SS_YAML_KEY_SSI263_REG_FILTER_FREQ "Filter Frequency" +#define SS_YAML_KEY_SSI263_REG_CURRENT_MODE "Current Mode" +#define SS_YAML_KEY_AY_CURR_REG "AY Current Register" +#define SS_YAML_KEY_TIMER1_IRQ "Timer1 IRQ Pending" +#define SS_YAML_KEY_TIMER2_IRQ "Timer2 IRQ Pending" +#define SS_YAML_KEY_SPEECH_IRQ "Speech IRQ Pending" + +#define SS_YAML_KEY_PHASOR_UNIT "Unit" +#define SS_YAML_KEY_PHASOR_CLOCK_SCALE_FACTOR "Clock Scale Factor" +#define SS_YAML_KEY_PHASOR_MODE "Mode" + +std::string MB_GetSnapshotCardName(void) +{ + static const std::string name("Mockingboard C"); + return name; +} + +std::string Phasor_GetSnapshotCardName(void) +{ + static const std::string name("Phasor"); + return name; +} + +static void SaveSnapshotSY6522(YamlSaveHelper& yamlSaveHelper, SY6522& sy6522) +{ + YamlSaveHelper::Label label(yamlSaveHelper, "%s:\n", SS_YAML_KEY_SY6522); + + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SY6522_REG_ORB, sy6522.ORB); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SY6522_REG_ORA, sy6522.ORA); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SY6522_REG_DDRB, sy6522.DDRB); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SY6522_REG_DDRA, sy6522.DDRA); + yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_SY6522_REG_T1_COUNTER, sy6522.TIMER1_COUNTER.w); + yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_SY6522_REG_T1_LATCH, sy6522.TIMER1_LATCH.w); + yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_SY6522_REG_T2_COUNTER, sy6522.TIMER2_COUNTER.w); + yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_SY6522_REG_T2_LATCH, sy6522.TIMER2_LATCH.w); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SY6522_REG_SERIAL_SHIFT, sy6522.SERIAL_SHIFT); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SY6522_REG_ACR, sy6522.ACR); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SY6522_REG_PCR, sy6522.PCR); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SY6522_REG_IFR, sy6522.IFR); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SY6522_REG_IER, sy6522.IER); + // NB. No need to write ORA_NO_HS, since same data as ORA, just without handshake +} + +static void SaveSnapshotSSI263(YamlSaveHelper& yamlSaveHelper, SSI263A& ssi263) +{ + YamlSaveHelper::Label label(yamlSaveHelper, "%s:\n", SS_YAML_KEY_SSI263); + + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SSI263_REG_DUR_PHON, ssi263.DurationPhoneme); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SSI263_REG_INF, ssi263.Inflection); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SSI263_REG_RATE_INF, ssi263.RateInflection); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SSI263_REG_CTRL_ART_AMP, ssi263.CtrlArtAmp); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SSI263_REG_FILTER_FREQ, ssi263.FilterFreq); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SSI263_REG_CURRENT_MODE, ssi263.CurrentMode); +} + +void MB_SaveSnapshot(YamlSaveHelper& yamlSaveHelper, const UINT uSlot) +{ + const UINT nMbCardNum = uSlot - SLOT4; + UINT nDeviceNum = nMbCardNum*2; + SY6522_AY8910* pMB = &g_MB[nDeviceNum]; + + YamlSaveHelper::Slot slot(yamlSaveHelper, MB_GetSnapshotCardName(), uSlot, 1); // fixme: object should be just 1 Mockingboard card & it will know its slot + + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); + + for(UINT i=0; isy6522); + AY8910_SaveSnapshot(yamlSaveHelper, nDeviceNum, std::string("")); + SaveSnapshotSSI263(yamlSaveHelper, pMB->SpeechChip); + + yamlSaveHelper.SaveHexUint4(SS_YAML_KEY_AY_CURR_REG, pMB->nAYCurrentRegister); + yamlSaveHelper.Save("%s: %s # Not supported\n", SS_YAML_KEY_TIMER1_IRQ, "false"); + yamlSaveHelper.Save("%s: %s # Not supported\n", SS_YAML_KEY_TIMER2_IRQ, "false"); + yamlSaveHelper.Save("%s: %s # Not supported\n", SS_YAML_KEY_SPEECH_IRQ, "false"); + + nDeviceNum++; + pMB++; + } +} + +static void LoadSnapshotSY6522(YamlLoadHelper& yamlLoadHelper, SY6522& sy6522) +{ + if (!yamlLoadHelper.GetSubMap(SS_YAML_KEY_SY6522)) + throw std::string("Card: Expected key: ") + std::string(SS_YAML_KEY_SY6522); + + sy6522.ORB = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_ORB); + sy6522.ORA = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_ORA); + sy6522.DDRB = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_DDRB); + sy6522.DDRA = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_DDRA); + sy6522.TIMER1_COUNTER.w = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_T1_COUNTER); + sy6522.TIMER1_LATCH.w = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_T1_LATCH); + sy6522.TIMER2_COUNTER.w = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_T2_COUNTER); + sy6522.TIMER2_LATCH.w = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_T2_LATCH); + sy6522.SERIAL_SHIFT = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_SERIAL_SHIFT); + sy6522.ACR = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_ACR); + sy6522.PCR = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_PCR); + sy6522.IFR = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_IFR); + sy6522.IER = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_IER); + sy6522.ORA_NO_HS = 0; // Not saved + + yamlLoadHelper.PopMap(); +} + +static void LoadSnapshotSSI263(YamlLoadHelper& yamlLoadHelper, SSI263A& ssi263) +{ + if (!yamlLoadHelper.GetSubMap(SS_YAML_KEY_SSI263)) + throw std::string("Card: Expected key: ") + std::string(SS_YAML_KEY_SSI263); + + ssi263.DurationPhoneme = yamlLoadHelper.LoadUint(SS_YAML_KEY_SSI263_REG_DUR_PHON); + ssi263.Inflection = yamlLoadHelper.LoadUint(SS_YAML_KEY_SSI263_REG_INF); + ssi263.RateInflection = yamlLoadHelper.LoadUint(SS_YAML_KEY_SSI263_REG_RATE_INF); + ssi263.CtrlArtAmp = yamlLoadHelper.LoadUint(SS_YAML_KEY_SSI263_REG_CTRL_ART_AMP); + ssi263.FilterFreq = yamlLoadHelper.LoadUint(SS_YAML_KEY_SSI263_REG_FILTER_FREQ); + ssi263.CurrentMode = yamlLoadHelper.LoadUint(SS_YAML_KEY_SSI263_REG_CURRENT_MODE); + + yamlLoadHelper.PopMap(); +} + +bool MB_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version) +{ + if (slot != 4 && slot != 5) // fixme + throw std::string("Card: wrong slot"); + + if (version != 1) + throw std::string("Card: wrong version"); + + AY8910UpdateSetCycles(); + + const UINT nMbCardNum = slot - SLOT4; + UINT nDeviceNum = nMbCardNum*2; + SY6522_AY8910* pMB = &g_MB[nDeviceNum]; + + g_nSSI263Device = 0; + g_nCurrentActivePhoneme = -1; + + for(UINT i=0; isy6522); + AY8910_LoadSnapshot(yamlLoadHelper, nDeviceNum, std::string("")); + LoadSnapshotSSI263(yamlLoadHelper, pMB->SpeechChip); + + pMB->nAYCurrentRegister = yamlLoadHelper.LoadUint(SS_YAML_KEY_AY_CURR_REG); + yamlLoadHelper.LoadBool(SS_YAML_KEY_TIMER1_IRQ); // Consume + yamlLoadHelper.LoadBool(SS_YAML_KEY_TIMER2_IRQ); // Consume + yamlLoadHelper.LoadBool(SS_YAML_KEY_SPEECH_IRQ); // Consume + + yamlLoadHelper.PopMap(); + + // + + 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.DurationPhoneme) + { + 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 + } + } + + nDeviceNum++; + pMB++; + } + + AY8910_InitClock((int)CLK_6502); + + // Setup in MB_InitializeIO() -> MB_SetSoundcardType() + g_SoundcardType = CT_Empty; + g_bPhasorEnable = false; + + return true; +} + +void Phasor_SaveSnapshot(YamlSaveHelper& yamlSaveHelper, const UINT uSlot) +{ + if (uSlot != 4) + throw std::string("Card: Phasor only supported in slot-4"); + + UINT nDeviceNum = 0; + SY6522_AY8910* pMB = &g_MB[0]; // fixme: Phasor uses MB's slot4(2x6522), slot4(2xSSI263), but slot4+5(4xAY8910) + + YamlSaveHelper::Slot slot(yamlSaveHelper, Phasor_GetSnapshotCardName(), uSlot, 1); // fixme: object should be just 1 Mockingboard card & it will know its slot + + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); + + yamlSaveHelper.SaveUint(SS_YAML_KEY_PHASOR_CLOCK_SCALE_FACTOR, g_PhasorClockScaleFactor); + yamlSaveHelper.SaveUint(SS_YAML_KEY_PHASOR_MODE, g_nPhasorMode); + + for(UINT i=0; isy6522); + AY8910_SaveSnapshot(yamlSaveHelper, nDeviceNum+0, std::string("-A")); + AY8910_SaveSnapshot(yamlSaveHelper, nDeviceNum+1, std::string("-B")); + SaveSnapshotSSI263(yamlSaveHelper, pMB->SpeechChip); + + yamlSaveHelper.SaveHexUint4(SS_YAML_KEY_AY_CURR_REG, pMB->nAYCurrentRegister); + yamlSaveHelper.Save("%s: %s # Not supported\n", SS_YAML_KEY_TIMER1_IRQ, "false"); + yamlSaveHelper.Save("%s: %s # Not supported\n", SS_YAML_KEY_TIMER2_IRQ, "false"); + yamlSaveHelper.Save("%s: %s # Not supported\n", SS_YAML_KEY_SPEECH_IRQ, "false"); + + nDeviceNum += 2; + pMB++; + } +} + +bool Phasor_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version) +{ + if (slot != 4) // fixme + throw std::string("Card: wrong slot"); + + if (version != 1) + throw std::string("Card: wrong version"); + + g_PhasorClockScaleFactor = yamlLoadHelper.LoadUint(SS_YAML_KEY_PHASOR_CLOCK_SCALE_FACTOR); + g_nPhasorMode = yamlLoadHelper.LoadUint(SS_YAML_KEY_PHASOR_MODE); + + AY8910UpdateSetCycles(); + + UINT nDeviceNum = 0; + SY6522_AY8910* pMB = &g_MB[0]; + + g_nSSI263Device = 0; + g_nCurrentActivePhoneme = -1; + + for(UINT i=0; isy6522); + AY8910_LoadSnapshot(yamlLoadHelper, nDeviceNum+0, std::string("-A")); + AY8910_LoadSnapshot(yamlLoadHelper, nDeviceNum+1, std::string("-B")); + LoadSnapshotSSI263(yamlLoadHelper, pMB->SpeechChip); + + pMB->nAYCurrentRegister = yamlLoadHelper.LoadUint(SS_YAML_KEY_AY_CURR_REG); + yamlLoadHelper.LoadBool(SS_YAML_KEY_TIMER1_IRQ); // Consume + yamlLoadHelper.LoadBool(SS_YAML_KEY_TIMER2_IRQ); // Consume + yamlLoadHelper.LoadBool(SS_YAML_KEY_SPEECH_IRQ); // Consume + + yamlLoadHelper.PopMap(); + + // + + 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.DurationPhoneme) + { + 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 + } + } + + nDeviceNum += 2; + pMB++; + } + + AY8910_InitClock((int)(CLK_6502 * g_PhasorClockScaleFactor)); + + // Setup in MB_InitializeIO() -> MB_SetSoundcardType() + g_SoundcardType = CT_Empty; + g_bPhasorEnable = false; + + return true; +} diff --git a/source/Mockingboard.h b/source/Mockingboard.h index edd337b8..901a9e41 100644 --- a/source/Mockingboard.h +++ b/source/Mockingboard.h @@ -22,5 +22,13 @@ double MB_GetFramePeriod(); bool MB_IsActive(); DWORD MB_GetVolume(); void MB_SetVolume(DWORD dwVolume, DWORD dwVolumeMax); -DWORD MB_GetSnapshot(SS_CARD_MOCKINGBOARD* pSS, DWORD dwSlot); -DWORD MB_SetSnapshot(SS_CARD_MOCKINGBOARD* pSS, 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); +std::string MB_GetSnapshotCardName(void); +void MB_SaveSnapshot(class YamlSaveHelper& yamlSaveHelper, const UINT uSlot); +bool MB_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version); + +std::string Phasor_GetSnapshotCardName(void); +void Phasor_SaveSnapshot(class YamlSaveHelper& yamlSaveHelper, const UINT uSlot); +bool Phasor_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version); diff --git a/source/MouseInterface.cpp b/source/MouseInterface.cpp index 0805e3ff..34b25788 100644 --- a/source/MouseInterface.cpp +++ b/source/MouseInterface.cpp @@ -41,7 +41,7 @@ Etc. #include "stdafx.h" -#include "Structs.h" +#include "SaveState_Structs_common.h" #include "Common.h" #include "CPU.h" @@ -50,6 +50,7 @@ Etc. #include "Memory.h" #include "MouseInterface.h" #include "SoundCore.h" // SAFE_RELEASE() +#include "YamlHelper.h" #include "..\resource\resource.h" @@ -210,7 +211,7 @@ void CMouseInterface::Reset() m_iMinY = 0; m_iMaxY = 1023; - m_bButtons[0] = m_bButtons[1] = FALSE; + m_bButtons[0] = m_bButtons[1] = false; // @@ -447,15 +448,13 @@ void CMouseInterface::OnMouseEvent(bool bEventVBL) if ( !( m_byMode & MODE_MOUSE_ON ) ) // Mouse Off return; - BOOL bBtn0 = m_bButtons[0]; - BOOL bBtn1 = m_bButtons[1]; if ( m_nX != m_iX || m_nY != m_iY ) { byState |= STAT_INT_MOVEMENT|STAT_MOVEMENT_SINCE_READMOUSE; // X/Y moved since last READMOUSE | Movement interrupt m_byState |= STAT_MOVEMENT_SINCE_READMOUSE; // [TC] Used by CopyII+9.1 and ProTERM3.1 } - if ( m_bBtn0 != bBtn0 || m_bBtn1 != bBtn1 ) + if ( m_bBtn0 != m_bButtons[0] || m_bBtn1 != m_bButtons[1] ) byState |= STAT_INT_BUTTON; // Button 0/1 interrupt if ( bEventVBL ) byState |= STAT_INT_VBL; @@ -495,8 +494,8 @@ void CMouseInterface::Clear() m_byState = 0; m_nX = 0; m_nY = 0; - m_bBtn0 = 0; - m_bBtn1 = 0; + m_bBtn0 = false; + m_bBtn1 = false; SetPositionAbs( 0, 0 ); // CpuIrqDeassert(IS_MOUSE); @@ -594,10 +593,168 @@ void CMouseInterface::SetPositionRel(long dX, long dY, int* pOutOfBoundsX, int* void CMouseInterface::SetButton(eBUTTON Button, eBUTTONSTATE State) { - m_bButtons[Button]= (State == BUTTON_DOWN) ? TRUE : FALSE; + m_bButtons[Button] = (State == BUTTON_DOWN); OnMouseEvent(); } +#define SS_YAML_VALUE_CARD_MOUSE "Mouse Card" + +#define SS_YAML_KEY_MC6821 "MC6821" +#define SS_YAML_KEY_PRA "PRA" +#define SS_YAML_KEY_DDRA "DDRA" +#define SS_YAML_KEY_CRA "CRA" +#define SS_YAML_KEY_PRB "PRB" +#define SS_YAML_KEY_DDRB "DDRB" +#define SS_YAML_KEY_CRB "CRB" +#define SS_YAML_KEY_IA "IA" +#define SS_YAML_KEY_IB "IB" + +#define SS_YAML_KEY_DATALEN "DataLen" +#define SS_YAML_KEY_MODE "Mode" +#define SS_YAML_KEY_6821B "6821B" +#define SS_YAML_KEY_6821A "6821A" +#define SS_YAML_KEY_BUFF "Buffer" +#define SS_YAML_KEY_BUFFPOS "Buffer Position" +#define SS_YAML_KEY_MOUSESTATE "State" +#define SS_YAML_KEY_X "X" +#define SS_YAML_KEY_Y "Y" +#define SS_YAML_KEY_BTN0 "Btn0" +#define SS_YAML_KEY_BTN1 "Btn1" +#define SS_YAML_KEY_VBL "VBL" +#define SS_YAML_KEY_IX "iX" +#define SS_YAML_KEY_IMINX "iMinX" +#define SS_YAML_KEY_IMAXX "iMaxX" +#define SS_YAML_KEY_IY "iY" +#define SS_YAML_KEY_IMINY "iMinY" +#define SS_YAML_KEY_IMAXY "iMaxY" +#define SS_YAML_KEY_BUTTON0 "Button0" +#define SS_YAML_KEY_BUTTON1 "Button1" +#define SS_YAML_KEY_ENABLED "Enabled" + +std::string CMouseInterface::GetSnapshotCardName(void) +{ + static const std::string name(SS_YAML_VALUE_CARD_MOUSE); + return name; +} + +void CMouseInterface::SaveSnapshotMC6821(YamlSaveHelper& yamlSaveHelper, std::string key) +{ + mc6821_t mc6821; + BYTE byIA; + BYTE byIB; + + m_6821.Get6821(mc6821, byIA, byIB); + + YamlSaveHelper::Label label(yamlSaveHelper, "%s:\n", key.c_str()); + yamlSaveHelper.SaveUint(SS_YAML_KEY_PRA, mc6821.pra); + yamlSaveHelper.SaveUint(SS_YAML_KEY_DDRA, mc6821.ddra); + yamlSaveHelper.SaveUint(SS_YAML_KEY_CRA, mc6821.cra); + yamlSaveHelper.SaveUint(SS_YAML_KEY_PRB, mc6821.prb); + yamlSaveHelper.SaveUint(SS_YAML_KEY_DDRB, mc6821.ddrb); + yamlSaveHelper.SaveUint(SS_YAML_KEY_CRB, mc6821.crb); + yamlSaveHelper.SaveUint(SS_YAML_KEY_IA, byIA); + yamlSaveHelper.SaveUint(SS_YAML_KEY_IB, byIB); +} + +void CMouseInterface::SaveSnapshot(class YamlSaveHelper& yamlSaveHelper) +{ + if (!m_bActive) + return; + + YamlSaveHelper::Slot slot(yamlSaveHelper, GetSnapshotCardName(), m_uSlot, 1); + + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); + SaveSnapshotMC6821(yamlSaveHelper, SS_YAML_KEY_MC6821); + yamlSaveHelper.Save("%s: %d\n", SS_YAML_KEY_DATALEN, m_nDataLen); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_MODE, m_byMode); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_6821B, m_by6821B); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_6821A, m_by6821A); + + // New label + { + YamlSaveHelper::Label buffer(yamlSaveHelper, "%s:\n", SS_YAML_KEY_BUFF); + yamlSaveHelper.SaveMemory(m_byBuff, sizeof(m_byBuff)); + } + + yamlSaveHelper.Save("%s: %d\n", SS_YAML_KEY_BUFFPOS, m_nBuffPos); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_MOUSESTATE, m_byState); + yamlSaveHelper.SaveUint(SS_YAML_KEY_X, m_nX); + yamlSaveHelper.SaveUint(SS_YAML_KEY_Y, m_nY); + yamlSaveHelper.SaveBool(SS_YAML_KEY_BTN0, m_bBtn0); + yamlSaveHelper.SaveBool(SS_YAML_KEY_BTN1, m_bBtn1); + yamlSaveHelper.SaveBool(SS_YAML_KEY_VBL, m_bVBL); + yamlSaveHelper.SaveUint(SS_YAML_KEY_IX, m_iX); + yamlSaveHelper.SaveUint(SS_YAML_KEY_IMINX, m_iMinX); + yamlSaveHelper.SaveUint(SS_YAML_KEY_IMAXX, m_iMaxX); + yamlSaveHelper.SaveUint(SS_YAML_KEY_IY, m_iY); + yamlSaveHelper.SaveUint(SS_YAML_KEY_IMINY, m_iMinY); + yamlSaveHelper.SaveUint(SS_YAML_KEY_IMAXY, m_iMaxY); + yamlSaveHelper.SaveBool(SS_YAML_KEY_BUTTON0, m_bButtons[0]); + yamlSaveHelper.SaveBool(SS_YAML_KEY_BUTTON1, m_bButtons[1]); + yamlSaveHelper.SaveBool(SS_YAML_KEY_ENABLED, m_bEnabled); +} + +void CMouseInterface::LoadSnapshotMC6821(YamlLoadHelper& yamlLoadHelper, std::string key) +{ + if (!yamlLoadHelper.GetSubMap(key)) + throw std::string("Card: Expected key: ") + key; + + mc6821_t mc6821; + mc6821.pra = yamlLoadHelper.LoadUint(SS_YAML_KEY_PRA); + mc6821.ddra = yamlLoadHelper.LoadUint(SS_YAML_KEY_DDRA); + mc6821.cra = yamlLoadHelper.LoadUint(SS_YAML_KEY_CRA); + mc6821.prb = yamlLoadHelper.LoadUint(SS_YAML_KEY_PRB); + mc6821.ddrb = yamlLoadHelper.LoadUint(SS_YAML_KEY_DDRB); + mc6821.crb = yamlLoadHelper.LoadUint(SS_YAML_KEY_CRB); + + BYTE byIA = yamlLoadHelper.LoadUint(SS_YAML_KEY_IA); + BYTE byIB = yamlLoadHelper.LoadUint(SS_YAML_KEY_IB); + + m_6821.Set6821(mc6821, byIA, byIB); + + yamlLoadHelper.PopMap(); +} + +bool CMouseInterface::LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version) +{ + if (slot != 4) // fixme + throw std::string("Card: wrong slot"); + + if (version != 1) + throw std::string("Card: wrong version"); + + LoadSnapshotMC6821(yamlLoadHelper, SS_YAML_KEY_MC6821); + + m_nDataLen = yamlLoadHelper.LoadUint(SS_YAML_KEY_DATALEN); + m_byMode = yamlLoadHelper.LoadUint(SS_YAML_KEY_MODE); + m_by6821B = yamlLoadHelper.LoadUint(SS_YAML_KEY_6821B); + m_by6821A = yamlLoadHelper.LoadUint(SS_YAML_KEY_6821A); + + if (!yamlLoadHelper.GetSubMap(SS_YAML_KEY_BUFF)) + throw std::string("Card: Expected key: "SS_YAML_KEY_BUFF); + yamlLoadHelper.LoadMemory(m_byBuff, sizeof(m_byBuff)); + yamlLoadHelper.PopMap(); + + m_nBuffPos = yamlLoadHelper.LoadUint(SS_YAML_KEY_BUFFPOS); + m_byState = yamlLoadHelper.LoadUint(SS_YAML_KEY_MOUSESTATE); + m_nX = yamlLoadHelper.LoadInt(SS_YAML_KEY_X); + m_nY = yamlLoadHelper.LoadInt(SS_YAML_KEY_Y); + m_bBtn0 = yamlLoadHelper.LoadBool(SS_YAML_KEY_BTN0); + m_bBtn1 = yamlLoadHelper.LoadBool(SS_YAML_KEY_BTN1); + m_bVBL = yamlLoadHelper.LoadBool(SS_YAML_KEY_VBL); + m_iX = yamlLoadHelper.LoadInt(SS_YAML_KEY_IX); + m_iMinX = yamlLoadHelper.LoadInt(SS_YAML_KEY_IMINX); + m_iMaxX = yamlLoadHelper.LoadInt(SS_YAML_KEY_IMAXX); + m_iY = yamlLoadHelper.LoadInt(SS_YAML_KEY_IY); + m_iMinY = yamlLoadHelper.LoadInt(SS_YAML_KEY_IMINY); + m_iMaxY = yamlLoadHelper.LoadInt(SS_YAML_KEY_IMAXY); + m_bButtons[0] = yamlLoadHelper.LoadBool(SS_YAML_KEY_BUTTON0); + m_bButtons[1] = yamlLoadHelper.LoadBool(SS_YAML_KEY_BUTTON1); + m_bEnabled = yamlLoadHelper.LoadBool(SS_YAML_KEY_ENABLED); // MemInitializeIO() calls Initialize() which sets true + + return true; +} + //============================================================================= // DirectInput interface //============================================================================= @@ -819,4 +976,4 @@ namespace DIMouse return S_OK; } -}; // namespace DIMouse \ No newline at end of file +}; // namespace DIMouse diff --git a/source/MouseInterface.h b/source/MouseInterface.h index 6c13a4f2..2b48f0f0 100644 --- a/source/MouseInterface.h +++ b/source/MouseInterface.h @@ -12,15 +12,14 @@ public: void Initialize(LPBYTE pCxRomPeripheral, UINT uSlot); void Uninitialize(); void Reset(); - void SetSlotRom(); static BYTE __stdcall IORead(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULONG nCyclesLeft); static BYTE __stdcall IOWrite(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULONG nCyclesLeft); void SetPositionRel(long dx, long dy, int* pOutOfBoundsX, int* pOutOfBoundsY); void SetButton(eBUTTON Button, eBUTTONSTATE State); bool IsActive() { return m_bActive; } - bool IsEnabled() { return m_bEnabled; } - bool IsActiveAndEnabled() { return IsActive() && IsEnabled(); } + bool IsEnabled() { return m_bEnabled; } // NB. m_bEnabled == true implies that m_bActive == true + bool IsActiveAndEnabled() { return IsActive() && IsEnabled(); } // todo: just use IsEnabled() void SetEnabled(bool bEnabled) { m_bEnabled = bEnabled; } void SetVBlank(bool bVBL); void GetXY(int& iX, int& iMinX, int& iMaxX, int& iY, int& iMinY, int& iMaxY) @@ -38,7 +37,12 @@ public: m_iY = iY; } + std::string GetSnapshotCardName(void); + void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper); + bool LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version); + protected: + void SetSlotRom(); void On6821_A(BYTE byData); void On6821_B(BYTE byData); void OnCommand(); @@ -55,6 +59,8 @@ protected: void SetClampX(int iMinX, int iMaxX); void SetClampY(int iMinY, int iMaxY); + void SaveSnapshotMC6821(class YamlSaveHelper& yamlSaveHelper, std::string key); + void LoadSnapshotMC6821(class YamlLoadHelper& yamlLoadHelper, std::string key); C6821 m_6821; @@ -69,8 +75,8 @@ protected: BYTE m_byState; int m_nX; int m_nY; - BOOL m_bBtn0; - BOOL m_bBtn1; + bool m_bBtn0; + bool m_bBtn1; bool m_bVBL; @@ -83,12 +89,14 @@ protected: int m_iMinY; int m_iMaxY; - BOOL m_bButtons[2]; + bool m_bButtons[2]; // + // todo: remove m_bActive: + // - instantiate CMouseInterface object when active (and delete when inactive) bool m_bActive; // Mouse h/w is active within the Apple][ VM - bool m_bEnabled; // Windows' mouse events get passed to Apple]['s mouse h/w + bool m_bEnabled; // Windows' mouse events get passed to Apple]['s mouse h/w (m_bEnabled == true implies that m_bActive == true) LPBYTE m_pSlotRom; UINT m_uSlot; }; diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 5894c4e2..44bcc42c 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -99,7 +99,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Globals (Public) ___________________________________________________ uint16_t g_nVideoClockVert = 0; // 9-bit: VC VB VA V5 V4 V3 V2 V1 V0 = 0 .. 262 - uint16_t g_nVideoClockHorz = 0; // 6-bit: H5 H4 H3 H2 H1 H0 = 0 .. 64, 25 >= visible + uint16_t g_nVideoClockHorz = 0; // 6-bit: H5 H4 H3 H2 H1 H0 = 0 .. 64, 25 >= visible (NB. final hpos is 2 cycles long, so a line is 65 cycles) // Globals (Private) __________________________________________________ static int g_nVideoCharSet = 0; @@ -1449,7 +1449,7 @@ void NTSC_SetVideoMode( int bVideoModeFlags ) g_aHorzClockVideoMode[ h ] = bVideoModeFlags; g_nVideoMixed = bVideoModeFlags & VF_MIXED; - g_nVideoCharSet = g_nAltCharSetOffset != 0; + g_nVideoCharSet = VideoGetSWAltCharSet() ? 1 : 0; g_nTextPage = 1; g_nHiresPage = 1; @@ -1654,19 +1654,21 @@ void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit } //=========================================================================== -void NTSC_VideoInitAppleType () +void NTSC_VideoInitAppleType ( DWORD cyclesThisFrame ) { int model = g_Apple2Type; - // anything other than low bit set means not II/II+ + // anything other than low bit set means not II/II+ (TC: include Pravets machines too?) if (model & 0xFFFE) g_pHorzClockOffset = APPLE_IIE_HORZ_CLOCK_OFFSET; else g_pHorzClockOffset = APPLE_IIP_HORZ_CLOCK_OFFSET; - g_nVideoClockVert = 0; - g_nVideoClockHorz = 0; - + // TC: Move these to a better place (as init'ing these 2 vars is nothing to do with g_Apple2Type) + _ASSERT(cyclesThisFrame < VIDEO_SCANNER_6502_CYCLES); + if (cyclesThisFrame >= VIDEO_SCANNER_6502_CYCLES) cyclesThisFrame = 0; // error + g_nVideoClockVert = (uint16_t) (cyclesThisFrame / VIDEO_SCANNER_MAX_HORZ); + g_nVideoClockHorz = cyclesThisFrame % VIDEO_SCANNER_MAX_HORZ; } //=========================================================================== diff --git a/source/NTSC.h b/source/NTSC.h index 3c53caf4..a6f3adec 100644 --- a/source/NTSC.h +++ b/source/NTSC.h @@ -13,7 +13,7 @@ extern uint32_t*NTSC_VideoGetChromaTable( bool bHueTypeMonochrome, bool bMonitorTypeColorTV ); extern uint16_t NTSC_VideoGetScannerAddress( unsigned long cycles6502 ); extern void NTSC_VideoInit( uint8_t *pFramebuffer ); - extern void NTSC_VideoInitAppleType (); + extern void NTSC_VideoInitAppleType ( DWORD cyclesThisFrame ); extern void NTSC_VideoInitChroma(); extern bool NTSC_VideoIsVbl(); extern void NTSC_VideoUpdateCycles( long cycles6502 ); diff --git a/source/ParallelPrinter.cpp b/source/ParallelPrinter.cpp index 2ef531a6..f17609db 100644 --- a/source/ParallelPrinter.cpp +++ b/source/ParallelPrinter.cpp @@ -32,22 +32,24 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Memory.h" #include "ParallelPrinter.h" #include "Registry.h" +#include "YamlHelper.h" #include "..\resource\resource.h" static DWORD inactivity = 0; +static unsigned int g_PrinterIdleLimit = 10; static FILE* file = NULL; DWORD const PRINTDRVR_SIZE = APPLE_SLOT_SIZE; -TCHAR filepath[MAX_PATH * 2]; #define DEFAULT_PRINT_FILENAME "Printer.txt" static char g_szPrintFilename[MAX_PATH] = {0}; bool g_bDumpToPrinter = false; bool g_bConvertEncoding = true; bool g_bFilterUnprintable = true; bool g_bPrinterAppend = false; -int g_iPrinterIdleLimit = 10; bool g_bEnableDumpToRealPrinter = false; +static UINT g_uSlot = 0; + //=========================================================================== static BYTE __stdcall PrintStatus(WORD, WORD, BYTE, BYTE, ULONG); @@ -79,6 +81,8 @@ VOID PrintLoadRom(LPBYTE pCxRomPeripheral, const UINT uSlot) // RegisterIoHandler(uSlot, PrintStatus, PrintTransmit, NULL, NULL, NULL, NULL); + + g_uSlot = uSlot; } //=========================================================================== @@ -242,11 +246,79 @@ void Printer_SetFilename(char* prtFilename) unsigned int Printer_GetIdleLimit() { - return g_iPrinterIdleLimit; + return g_PrinterIdleLimit; } -//unsigned int void Printer_SetIdleLimit(unsigned int Duration) { - g_iPrinterIdleLimit = Duration; + g_PrinterIdleLimit = Duration; +} + +//=========================================================================== + +#define SS_YAML_VALUE_CARD_PRINTER "Generic Printer" + +#define SS_YAML_KEY_INACTIVITY "Inactivity" +#define SS_YAML_KEY_IDLELIMIT "Printer Idle Limit" +#define SS_YAML_KEY_FILENAME "Print Filename" +#define SS_YAML_KEY_FILEOPEN "Is File Open" +#define SS_YAML_KEY_DUMPTOPRINTER "Dump To Printer" +#define SS_YAML_KEY_CONVERTENCODING "Convert Encoding" +#define SS_YAML_KEY_FILTERUNPRINTABLE "Filter Unprintable" +#define SS_YAML_KEY_APPEND "Printer Append" +#define SS_YAML_KEY_DUMPTOREALPRINTER "Enable Dump To Real Printer" + +std::string Printer_GetSnapshotCardName(void) +{ + static const std::string name(SS_YAML_VALUE_CARD_PRINTER); + return name; +} + +void Printer_SaveSnapshot(class YamlSaveHelper& yamlSaveHelper) +{ + YamlSaveHelper::Slot slot(yamlSaveHelper, Printer_GetSnapshotCardName(), g_uSlot, 1); + + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); + yamlSaveHelper.SaveUint(SS_YAML_KEY_INACTIVITY, inactivity); + yamlSaveHelper.SaveUint(SS_YAML_KEY_IDLELIMIT, g_PrinterIdleLimit); + yamlSaveHelper.SaveString(SS_YAML_KEY_FILENAME, g_szPrintFilename); + yamlSaveHelper.SaveBool(SS_YAML_KEY_FILEOPEN, (file != NULL) ? true : false); + yamlSaveHelper.SaveBool(SS_YAML_KEY_DUMPTOPRINTER, g_bDumpToPrinter); + yamlSaveHelper.SaveBool(SS_YAML_KEY_CONVERTENCODING, g_bConvertEncoding); + yamlSaveHelper.SaveBool(SS_YAML_KEY_FILTERUNPRINTABLE, g_bFilterUnprintable); + yamlSaveHelper.SaveBool(SS_YAML_KEY_APPEND, g_bPrinterAppend); + yamlSaveHelper.SaveBool(SS_YAML_KEY_DUMPTOREALPRINTER, g_bEnableDumpToRealPrinter); +} + +bool Printer_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version) +{ + if (slot != 1) // fixme + throw std::string("Card: wrong slot"); + + if (version != 1) + throw std::string("Card: wrong version"); + + inactivity = yamlLoadHelper.LoadUint(SS_YAML_KEY_INACTIVITY); + g_PrinterIdleLimit = yamlLoadHelper.LoadUint(SS_YAML_KEY_IDLELIMIT); + strncpy(g_szPrintFilename, yamlLoadHelper.LoadString(SS_YAML_KEY_FILENAME).c_str(), sizeof(g_szPrintFilename)); + + if (yamlLoadHelper.LoadBool(SS_YAML_KEY_FILEOPEN)) + { + yamlLoadHelper.LoadBool(SS_YAML_KEY_APPEND); // Consume + g_bPrinterAppend = true; // Re-open print-file in append mode + BOOL bRes = CheckPrint(); + if (!bRes) + throw std::string("Printer Card: Unable to resume printing to file"); + } + else + { + g_bPrinterAppend = yamlLoadHelper.LoadBool(SS_YAML_KEY_APPEND); + } + + g_bDumpToPrinter = yamlLoadHelper.LoadBool(SS_YAML_KEY_DUMPTOPRINTER); + g_bConvertEncoding = yamlLoadHelper.LoadBool(SS_YAML_KEY_CONVERTENCODING); + g_bFilterUnprintable = yamlLoadHelper.LoadBool(SS_YAML_KEY_FILTERUNPRINTABLE); + g_bEnableDumpToRealPrinter = yamlLoadHelper.LoadBool(SS_YAML_KEY_DUMPTOREALPRINTER); + + return true; } diff --git a/source/ParallelPrinter.h b/source/ParallelPrinter.h index d2936a13..d2b96bdb 100644 --- a/source/ParallelPrinter.h +++ b/source/ParallelPrinter.h @@ -9,11 +9,12 @@ char* Printer_GetFilename(); void Printer_SetIdleLimit(unsigned int Duration); unsigned int Printer_GetIdleLimit(); +std::string Printer_GetSnapshotCardName(void); +void Printer_SaveSnapshot(class YamlSaveHelper& yamlSaveHelper); +bool Printer_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version); + extern bool g_bDumpToPrinter; extern bool g_bConvertEncoding; extern bool g_bFilterUnprintable; extern bool g_bPrinterAppend; -extern int g_iPrinterIdleLimit; -extern bool g_bFilterUnprintable; -extern bool g_bPrinterAppend; extern bool g_bEnableDumpToRealPrinter; // Set by cmd-line: -printer-real diff --git a/source/Pravets.cpp b/source/Pravets.cpp new file mode 100644 index 00000000..296cf4f7 --- /dev/null +++ b/source/Pravets.cpp @@ -0,0 +1,48 @@ +/* +AppleWin : An Apple //e emulator for Windows + +Copyright (C) 1994-1996, Michael O'Brien +Copyright (C) 1999-2001, Oliver Schmidt +Copyright (C) 2002-2005, Tom Charlesworth +Copyright (C) 2006-2015, Tom Charlesworth, Michael Pohoreski + +AppleWin is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +AppleWin is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with AppleWin; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* Description: Pravets - Apple II clone + * + * Author: Various + */ + +#include "StdAfx.h" + +#include "AppleWin.h" +#include "Frame.h" +#include "Keyboard.h" +#include "Tape.h" + +//Pravets 8A/C variables +bool P8CAPS_ON = false; +bool P8Shift = false; + +void PravetsReset(void) +{ + if (g_Apple2Type == A2TYPE_PRAVETS8A) + { + P8CAPS_ON = false; + TapeWrite(0, 0, 0, 0 ,0); + FrameRefreshStatus(DRAW_LEDS); + } +} diff --git a/source/Pravets.h b/source/Pravets.h new file mode 100644 index 00000000..801d1804 --- /dev/null +++ b/source/Pravets.h @@ -0,0 +1,7 @@ +#pragma once + +//Pravets 8A/C only variables +extern bool P8CAPS_ON; +extern bool P8Shift; + +void PravetsReset(void); diff --git a/source/SAM.cpp b/source/SAM.cpp new file mode 100644 index 00000000..2fa4c420 --- /dev/null +++ b/source/SAM.cpp @@ -0,0 +1,93 @@ +/* + AppleWin : An Apple //e emulator for Windows + + Copyright (C) 1994-1996, Michael O'Brien + Copyright (C) 1999-2001, Oliver Schmidt + Copyright (C) 2002-2005, Tom Charlesworth + Copyright (C) 2006-2007, Tom Charlesworth, Michael Pohoreski + + AppleWin is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + AppleWin is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with AppleWin; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/* + SAM.CPP + + Emulate an 8 bit DAC (eg: SAM card) which writes unsigned byte + data written to its IO area to the audio buffer (as used by the speaker). + This merges the data with the speaker stream, reducing the volume + of the Apple speaker when active. + + Riccardo Macri Mar 2015 +*/ +#include "StdAfx.h" + +#include "AppleWin.h" +#include "Memory.h" +#include "SAM.h" +#include "Speaker.h" + +// +// Write 8 bit data to speaker. Emulates a "SAM" speech card DAC +// + + +static BYTE __stdcall IOWrite_SAM(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) +{ + // Emulate audio from a SAM / 8 bit DAC card + // Only supportable if AppleWin is using WAVE output + // + // This works by using the existing speaker handling but then + // replacing the speaker audio with the 8 bit samples from the DAC + // before they get sent out to the soundcard buffer, whilst + // audio samples are being written to the SAM. + // + // Whilst very unusual, it is possible to intermingle use of SAM and the apple + // speaker. This is crudely supported with g_bQuieterSpeaker making the Apple + // speaker produce quieter clicks which will be crudely intermingled + // with the SAM data. The mute gets reset after the speaker code detects + // silence. + + if (soundtype != SOUND_WAVE) + return MemReadFloatingBus(nCyclesLeft); + + // use existing speaker code to bring timing up to date + BYTE res = SpkrToggle(pc, addr, bWrite, d, nCyclesLeft); + + // The DAC in the SAM uses unsigned 8 bit samples + // The WAV data that g_nSpeakerData is loaded into is a signed short + // + // We convert unsigned 8 bit to signed by toggling the most significant bit + // + // SAM card WAV driver SAM WAV + // 0xFF 255 0x7f 127 _ FF 7F + // 0x81 129 0x01 1 / \ + // 0x80 128 0x00 0 / \ /80 00 + // 0x7f 127 0xFF -1 \_/ + // 0x00 0 0x80 -128 00 80 + // + // SAM is 8 bit, PC WAV is 16 so shift audio to the MSB (<< 8) + + g_nSpeakerData = (d ^ 0x80) << 8; + + // make speaker quieter so eg: a metronome click through the + // Apple speaker is softer vs. the analogue SAM output. + g_bQuieterSpeaker = true; + + return res; +} + +void ConfigureSAM(LPBYTE pCxRomPeripheral, UINT uSlot) +{ + RegisterIoHandler(uSlot, IO_Null, IOWrite_SAM, IO_Null, IO_Null, NULL, NULL); +} diff --git a/source/SAM.h b/source/SAM.h new file mode 100644 index 00000000..291ac5c0 --- /dev/null +++ b/source/SAM.h @@ -0,0 +1,3 @@ +#pragma once + +void ConfigureSAM(LPBYTE pCxRomPeripheral, UINT uSlot); diff --git a/source/SaveState.cpp b/source/SaveState.cpp index 6587e458..3a771cd8 100644 --- a/source/SaveState.cpp +++ b/source/SaveState.cpp @@ -4,7 +4,7 @@ AppleWin : An Apple //e emulator for Windows Copyright (C) 1994-1996, Michael O'Brien Copyright (C) 1999-2001, Oliver Schmidt Copyright (C) 2002-2005, Tom Charlesworth -Copyright (C) 2006-2007, Tom Charlesworth, Michael Pohoreski +Copyright (C) 2006-2015, Tom Charlesworth, Michael Pohoreski AppleWin is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,11 +23,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /* Description: Save-state (snapshot) module * - * Author: Copyright (c) 2004-2006 Tom Charlesworth + * Author: Copyright (c) 2004-2015 Tom Charlesworth */ #include "StdAfx.h" +#include "SaveState_Structs_v1.h" +#include "YamlHelper.h" + #include "AppleWin.h" #include "CPU.h" #include "Disk.h" @@ -36,17 +39,20 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Keyboard.h" #include "Memory.h" #include "Mockingboard.h" +#include "MouseInterface.h" +#include "ParallelPrinter.h" +#include "Pravets.h" #include "SerialComms.h" #include "Speaker.h" +#include "Speech.h" #include "Video.h" +#include "z80emu.h" -// Prototypes (Public) - // Note: This is here and not in Video.h to prevent header include bloat. - // i.e. so we don't need to incude "Structs.h" for NTSC.cpp - DWORD VideoGetSnapshot(SS_IO_Video* pSS); - DWORD VideoSetSnapshot(SS_IO_Video* pSS); +#include "Configuration\Config.h" +#include "Configuration\IPropertySheet.h" -#define DEFAULT_SNAPSHOT_NAME "SaveState.aws" + +#define DEFAULT_SNAPSHOT_NAME "SaveState.aws.yaml" bool g_bSaveStateOnExit = false; @@ -54,6 +60,13 @@ static std::string g_strSaveStateFilename; static std::string g_strSaveStatePathname; static std::string g_strSaveStatePath; +static YamlHelper yamlHelper; + +#define SS_FILE_VER 2 + +#define UNIT_APPLE2_VER 1 +#define UNIT_SLOTS_VER 1 + //----------------------------------------------------------------------------- void Snapshot_SetFilename(std::string strPathname) @@ -98,22 +111,27 @@ const char* Snapshot_GetPath() //----------------------------------------------------------------------------- -void Snapshot_LoadState() +static void Snapshot_LoadState_v1() // .aws v1.0.0.1, up to (and including) AppleWin v1.25.0 { - char szMessage[32 + MAX_PATH]; - std::string strOldImageDir; + std::string strOldImageDir(g_sCurrentDir); - APPLEWIN_SNAPSHOT* pSS = (APPLEWIN_SNAPSHOT*) new char[sizeof(APPLEWIN_SNAPSHOT)]; + APPLEWIN_SNAPSHOT_v1* pSS = (APPLEWIN_SNAPSHOT_v1*) new char[sizeof(APPLEWIN_SNAPSHOT_v1)]; // throw's bad_alloc try { - strOldImageDir = g_sCurrentDir; +#if _MSC_VER >= 1600 // static_assert supported from VS2010 (cl.exe v16.00) + static_assert(kSnapshotSize_v1 == sizeof(APPLEWIN_SNAPSHOT_v1), "Save-state v1 struct size mismatch"); +#else + // A compile error here means sizeof(APPLEWIN_SNAPSHOT_v1) is wrong, eg. one of the constituent structs has been modified + typedef char VerifySizesAreEqual[kSnapshotSize_v1 == sizeof(APPLEWIN_SNAPSHOT_v1) ? 1 : -1]; +#endif + + if (kSnapshotSize_v1 != sizeof(APPLEWIN_SNAPSHOT_v1)) + throw std::string("Save-state v1 struct size mismatch"); + SetCurrentImageDir(g_strSaveStatePath.c_str()); // Allow .dsk's load without prompting - if(pSS == NULL) - throw(0); - - memset(pSS, 0, sizeof(APPLEWIN_SNAPSHOT)); + memset(pSS, 0, sizeof(APPLEWIN_SNAPSHOT_v1)); // @@ -126,49 +144,32 @@ void Snapshot_LoadState() NULL); if(hFile == INVALID_HANDLE_VALUE) - { - strcpy(szMessage, "File not found: "); - strcpy(szMessage + strlen(szMessage), g_strSaveStatePathname.c_str()); - throw(0); - } + throw std::string("File not found: ") + g_strSaveStatePathname; DWORD dwBytesRead; BOOL bRes = ReadFile( hFile, pSS, - sizeof(APPLEWIN_SNAPSHOT), + sizeof(APPLEWIN_SNAPSHOT_v1), &dwBytesRead, NULL); CloseHandle(hFile); - if(!bRes || (dwBytesRead != sizeof(APPLEWIN_SNAPSHOT))) - { + if(!bRes || (dwBytesRead != sizeof(APPLEWIN_SNAPSHOT_v1))) // File size wrong: probably because of version mismatch or corrupt file - strcpy(szMessage, "File size mismatch"); - throw(0); - } + throw std::string("File size mismatch"); if(pSS->Hdr.dwTag != AW_SS_TAG) - { - strcpy(szMessage, "File corrupt"); - throw(0); - } + throw std::string("File corrupt"); if(pSS->Hdr.dwVersion != MAKE_VERSION(1,0,0,1)) - { - strcpy(szMessage, "Version mismatch"); - throw(0); - } + throw std::string("Version mismatch"); // TO DO: Verify checksum // // Reset all sub-systems MemReset(); - - if (!IS_APPLE2) - MemResetPaging(); - DiskReset(); KeybReset(); VideoResetState(); @@ -178,38 +179,46 @@ void Snapshot_LoadState() // Apple2 unit // - CpuSetSnapshot(&pSS->Apple2Unit.CPU6502); - sg_SSC.CommSetSnapshot(&pSS->Apple2Unit.Comms); - JoySetSnapshot(&pSS->Apple2Unit.Joystick); - KeybSetSnapshot(&pSS->Apple2Unit.Keyboard); - SpkrSetSnapshot(&pSS->Apple2Unit.Speaker); - VideoSetSnapshot(&pSS->Apple2Unit.Video); - MemSetSnapshot(&pSS->Apple2Unit.Memory); + SS_CPU6502& CPU = pSS->Apple2Unit.CPU6502; + CpuSetSnapshot_v1(CPU.A, CPU.X, CPU.Y, CPU.P, CPU.S, CPU.PC, CPU.nCumulativeCycles); + + SS_IO_Comms& SSC = pSS->Apple2Unit.Comms; + sg_SSC.SetSnapshot_v1(SSC.baudrate, SSC.bytesize, SSC.commandbyte, SSC.comminactivity, SSC.controlbyte, SSC.parity, SSC.stopbits); + + JoySetSnapshot_v1(pSS->Apple2Unit.Joystick.nJoyCntrResetCycle); + KeybSetSnapshot_v1(pSS->Apple2Unit.Keyboard.nLastKey); + SpkrSetSnapshot_v1(pSS->Apple2Unit.Speaker.nSpkrLastCycle); + VideoSetSnapshot_v1(pSS->Apple2Unit.Video.bAltCharSet, pSS->Apple2Unit.Video.dwVidMode); + MemSetSnapshot_v1(pSS->Apple2Unit.Memory.dwMemMode, pSS->Apple2Unit.Memory.bLastWriteRam, pSS->Apple2Unit.Memory.nMemMain, pSS->Apple2Unit.Memory.nMemAux); // // // Slot4: Mockingboard - MB_SetSnapshot(&pSS->Mockingboard1, 4); + MB_SetSnapshot_v1(&pSS->Mockingboard1, 4); // // Slot5: Mockingboard - MB_SetSnapshot(&pSS->Mockingboard2, 5); + MB_SetSnapshot_v1(&pSS->Mockingboard2, 5); // // Slot6: Disk][ - DiskSetSnapshot(&pSS->Disk2, 6); + DiskSetSnapshot_v1(&pSS->Disk2); SetLoadedSaveStateFlag(true); + + MemUpdatePaging(TRUE); } - catch(int) + catch(std::string szMessage) { MessageBox( g_hFrameWindow, - szMessage, + szMessage.c_str(), TEXT("Load State"), 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; @@ -217,104 +226,393 @@ void Snapshot_LoadState() //----------------------------------------------------------------------------- -void Snapshot_SaveState() +static HANDLE m_hFile = INVALID_HANDLE_VALUE; +static CConfigNeedingRestart m_ConfigNew; + +static std::string GetSnapshotUnitApple2Name(void) { - APPLEWIN_SNAPSHOT* pSS = (APPLEWIN_SNAPSHOT*) new char[sizeof(APPLEWIN_SNAPSHOT)]; - if(pSS == NULL) + static const std::string name("Apple2"); + return name; +} + +static std::string GetSnapshotUnitSlotsName(void) +{ + static const std::string name("Slots"); + return name; +} + +#define SS_YAML_KEY_MODEL "Model" + +#define SS_YAML_VALUE_APPLE2 "Apple][" +#define SS_YAML_VALUE_APPLE2PLUS "Apple][+" +#define SS_YAML_VALUE_APPLE2E "Apple//e" +#define SS_YAML_VALUE_APPLE2EENHANCED "Enhanced Apple//e" +#define SS_YAML_VALUE_APPLE2C "Apple2c" +#define SS_YAML_VALUE_PRAVETS82 "Pravets82" +#define SS_YAML_VALUE_PRAVETS8M "Pravets8M" +#define SS_YAML_VALUE_PRAVETS8A "Pravets8A" + +static eApple2Type ParseApple2Type(std::string type) +{ + if (type == SS_YAML_VALUE_APPLE2) return A2TYPE_APPLE2; + else if (type == SS_YAML_VALUE_APPLE2PLUS) return A2TYPE_APPLE2PLUS; + else if (type == SS_YAML_VALUE_APPLE2E) return A2TYPE_APPLE2E; + else if (type == SS_YAML_VALUE_APPLE2EENHANCED) return A2TYPE_APPLE2EENHANCED; + else if (type == SS_YAML_VALUE_APPLE2C) return A2TYPE_APPLE2C; + else if (type == SS_YAML_VALUE_PRAVETS82) return A2TYPE_PRAVETS82; + else if (type == SS_YAML_VALUE_PRAVETS8M) return A2TYPE_PRAVETS8M; + else if (type == SS_YAML_VALUE_PRAVETS8A) return A2TYPE_PRAVETS8A; + + throw std::string("Load: Unknown Apple2 type"); +} + +static std::string GetApple2TypeAsString(void) +{ + switch ( GetApple2Type() ) { - // To do - return; + case A2TYPE_APPLE2: return SS_YAML_VALUE_APPLE2; + case A2TYPE_APPLE2PLUS: return SS_YAML_VALUE_APPLE2PLUS; + case A2TYPE_APPLE2E: return SS_YAML_VALUE_APPLE2E; + case A2TYPE_APPLE2EENHANCED:return SS_YAML_VALUE_APPLE2EENHANCED; + case A2TYPE_APPLE2C: return SS_YAML_VALUE_APPLE2C; + case A2TYPE_PRAVETS82: return SS_YAML_VALUE_PRAVETS82; + case A2TYPE_PRAVETS8M: return SS_YAML_VALUE_PRAVETS8M; + case A2TYPE_PRAVETS8A: return SS_YAML_VALUE_PRAVETS8A; + default: + throw std::string("Save: Unknown Apple2 type"); + } +} + +//--- + +static UINT ParseFileHdr(void) +{ + std::string scalar; + if (!yamlHelper.GetScalar(scalar)) + throw std::string(SS_YAML_KEY_FILEHDR ": Failed to find scalar"); + + if (scalar != SS_YAML_KEY_FILEHDR) + throw std::string("Failed to find file header"); + + yamlHelper.GetMapStartEvent(); + + YamlLoadHelper yamlLoadHelper(yamlHelper); + + // + + std::string value = yamlLoadHelper.LoadString(SS_YAML_KEY_TAG); + if (value != SS_YAML_VALUE_AWSS) + { + //printf("%s: Bad tag (%s) - expected %s\n", SS_YAML_KEY_FILEHDR, value.c_str(), SS_YAML_VALUE_AWSS); + throw std::string(SS_YAML_KEY_FILEHDR ": Bad tag"); } - memset(pSS, 0, sizeof(APPLEWIN_SNAPSHOT)); + return yamlLoadHelper.LoadUint(SS_YAML_KEY_VERSION); +} - pSS->Hdr.dwTag = AW_SS_TAG; - pSS->Hdr.dwVersion = MAKE_VERSION(1,0,0,1); - pSS->Hdr.dwChecksum = 0; // TO DO +//--- - // - // Apple2 unit - // +static void ParseUnitApple2(YamlLoadHelper& yamlLoadHelper, UINT version) +{ + if (version != UNIT_APPLE2_VER) + throw std::string(SS_YAML_KEY_UNIT ": Apple2: Version mismatch"); - pSS->Apple2Unit.UnitHdr.dwLength = sizeof(SS_APPLE2_Unit); - pSS->Apple2Unit.UnitHdr.dwVersion = MAKE_VERSION(1,0,0,0); + std::string model = yamlLoadHelper.LoadString(SS_YAML_KEY_MODEL); + SetApple2Type( ParseApple2Type(model) ); // NB. Sets default main CPU type + m_ConfigNew.m_Apple2Type = GetApple2Type(); - CpuGetSnapshot(&pSS->Apple2Unit.CPU6502); - sg_SSC.CommGetSnapshot(&pSS->Apple2Unit.Comms); - JoyGetSnapshot(&pSS->Apple2Unit.Joystick); - KeybGetSnapshot(&pSS->Apple2Unit.Keyboard); - SpkrGetSnapshot(&pSS->Apple2Unit.Speaker); - VideoGetSnapshot(&pSS->Apple2Unit.Video); - MemGetSnapshot(&pSS->Apple2Unit.Memory); + CpuLoadSnapshot(yamlLoadHelper); // NB. Overrides default main CPU type + m_ConfigNew.m_CpuType = GetMainCpu(); - // - // Slot1: Empty - pSS->Empty1.Hdr.UnitHdr.dwLength = sizeof(SS_CARD_EMPTY); - pSS->Empty1.Hdr.UnitHdr.dwVersion = MAKE_VERSION(1,0,0,0); - pSS->Empty1.Hdr.dwSlot = 1; - pSS->Empty1.Hdr.dwType = CT_Empty; + JoyLoadSnapshot(yamlLoadHelper); + KeybLoadSnapshot(yamlLoadHelper); + SpkrLoadSnapshot(yamlLoadHelper); + VideoLoadSnapshot(yamlLoadHelper); + MemLoadSnapshot(yamlLoadHelper); +} - // - // Slot2: Empty - pSS->Empty2.Hdr.UnitHdr.dwLength = sizeof(SS_CARD_EMPTY); - pSS->Empty2.Hdr.UnitHdr.dwVersion = MAKE_VERSION(1,0,0,0); - pSS->Empty2.Hdr.dwSlot = 2; - pSS->Empty2.Hdr.dwType = CT_Empty; +//--- - // - // Slot3: Empty - pSS->Empty3.Hdr.UnitHdr.dwLength = sizeof(SS_CARD_EMPTY); - pSS->Empty3.Hdr.UnitHdr.dwVersion = MAKE_VERSION(1,0,0,0); - pSS->Empty3.Hdr.dwSlot = 3; - pSS->Empty3.Hdr.dwType = CT_Empty; +static void ParseSlots(YamlLoadHelper& yamlLoadHelper, UINT version) +{ + if (version != UNIT_SLOTS_VER) + throw std::string(SS_YAML_KEY_UNIT ": Slots: Version mismatch"); - // - // Slot4: Mockingboard - MB_GetSnapshot(&pSS->Mockingboard1, 4); - - // - // Slot5: Mockingboard - MB_GetSnapshot(&pSS->Mockingboard2, 5); - - // - // Slot6: Disk][ - DiskGetSnapshot(&pSS->Disk2, 6); - - // - - HANDLE hFile = CreateFile( g_strSaveStatePathname.c_str(), - GENERIC_WRITE, - 0, - NULL, - CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - NULL); - - DWORD dwError = GetLastError(); - _ASSERT((dwError == 0) || (dwError == ERROR_ALREADY_EXISTS)); - - if(hFile != INVALID_HANDLE_VALUE) + while (1) { - DWORD dwBytesWritten; - BOOL bRes = WriteFile( hFile, - pSS, - sizeof(APPLEWIN_SNAPSHOT), - &dwBytesWritten, - NULL); + std::string scalar = yamlLoadHelper.GetMapNextSlotNumber(); + if (scalar.empty()) + break; // done all slots - if(!bRes || (dwBytesWritten != sizeof(APPLEWIN_SNAPSHOT))) - dwError = GetLastError(); + const int slot = strtoul(scalar.c_str(), NULL, 10); // NB. aux slot supported as a different "unit" + if (slot < 1 || slot > 7) + throw std::string("Slots: Invalid slot #: ") + scalar; - CloseHandle(hFile); + yamlLoadHelper.GetSubMap(scalar); + + std::string card = yamlLoadHelper.LoadString(SS_YAML_KEY_CARD); + UINT version = yamlLoadHelper.LoadUint(SS_YAML_KEY_VERSION); + + if (!yamlLoadHelper.GetSubMap(std::string(SS_YAML_KEY_STATE))) + throw std::string(SS_YAML_KEY_UNIT ": Expected sub-map name: " SS_YAML_KEY_STATE); + + bool bIsCardSupported = true; + SS_CARDTYPE type = CT_Empty; + bool bRes = false; + + if (card == Printer_GetSnapshotCardName()) + { + bRes = Printer_LoadSnapshot(yamlLoadHelper, slot, version); + type = CT_GenericPrinter; + } + else if (card == sg_SSC.GetSnapshotCardName()) + { + bRes = sg_SSC.LoadSnapshot(yamlLoadHelper, slot, version); + type = CT_SSC; + } + else if (card == sg_Mouse.GetSnapshotCardName()) + { + bRes = sg_Mouse.LoadSnapshot(yamlLoadHelper, slot, version); + type = CT_MouseInterface; + } + else if (card == Z80_GetSnapshotCardName()) + { + bRes = Z80_LoadSnapshot(yamlLoadHelper, slot, version); + type = CT_Z80; + } + else if (card == MB_GetSnapshotCardName()) + { + bRes = MB_LoadSnapshot(yamlLoadHelper, slot, version); + type = CT_MockingboardC; + } + else if (card == Phasor_GetSnapshotCardName()) + { + bRes = Phasor_LoadSnapshot(yamlLoadHelper, slot, version); + type = CT_Phasor; + } + else if (card == DiskGetSnapshotCardName()) + { + bRes = DiskLoadSnapshot(yamlLoadHelper, slot, version); + type = CT_Disk2; + } + else if (card == HD_GetSnapshotCardName()) + { + bRes = HD_LoadSnapshot(yamlLoadHelper, slot, version, g_strSaveStatePath); + m_ConfigNew.m_bEnableHDD = true; + type = CT_GenericHDD; + } + else + { + bIsCardSupported = false; + throw std::string("Slots: Unknown card: " + card); // todo: don't throw - just ignore & continue + } + + if (bRes && bIsCardSupported) + { + m_ConfigNew.m_Slot[slot] = type; + } + + yamlLoadHelper.PopMap(); + yamlLoadHelper.PopMap(); + } +} + +//--- + +static void ParseUnit(void) +{ + yamlHelper.GetMapStartEvent(); + + YamlLoadHelper yamlLoadHelper(yamlHelper); + + std::string unit = yamlLoadHelper.LoadString(SS_YAML_KEY_TYPE); + UINT version = yamlLoadHelper.LoadUint(SS_YAML_KEY_VERSION); + + if (!yamlLoadHelper.GetSubMap(std::string(SS_YAML_KEY_STATE))) + throw std::string(SS_YAML_KEY_UNIT ": Expected sub-map name: " SS_YAML_KEY_STATE); + + if (unit == GetSnapshotUnitApple2Name()) + { + ParseUnitApple2(yamlLoadHelper, version); + } + else if (unit == MemGetSnapshotUnitAuxSlotName()) + { + MemLoadSnapshotAux(yamlLoadHelper, version); + } + else if (unit == GetSnapshotUnitSlotsName()) + { + ParseSlots(yamlLoadHelper, version); } else { - dwError = GetLastError(); + throw std::string(SS_YAML_KEY_UNIT ": Unknown type: " ) + unit; + } +} + +static void Snapshot_LoadState_v2(void) +{ + try + { + int res = yamlHelper.InitParser( g_strSaveStatePathname.c_str() ); + if (!res) + throw std::string("Failed to initialize parser or open file"); // TODO: disambiguate + + UINT version = ParseFileHdr(); + if (version != SS_FILE_VER) + throw std::string("Version mismatch"); + + // + + CConfigNeedingRestart ConfigOld; + ConfigOld.m_Slot[1] = CT_GenericPrinter; // fixme + ConfigOld.m_Slot[2] = CT_SSC; // fixme + //ConfigOld.m_Slot[3] = CT_Uthernet; // todo + 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; ibaudrate = m_uBaudRate; - pSS->bytesize = m_uByteSize; - pSS->commandbyte = m_uCommandByte; - pSS->comminactivity = m_dwCommInactivity; - pSS->controlbyte = m_uControlByte; - pSS->parity = m_uParity; -// memcpy(pSS->recvbuffer, m_RecvBuffer, uRecvBufferSize); - pSS->recvbytes = 0; - pSS->stopbits = m_uStopBits; - return 0; + m_uBaudRate = baudrate; + m_uByteSize = bytesize; + m_uCommandByte = commandbyte; + m_dwCommInactivity = comminactivity; + m_uControlByte = controlbyte; + m_uParity = parity; +// memcpy(m_RecvBuffer, pSS->recvbuffer, uRecvBufferSize); +// m_vRecvBytes = recvbytes; + m_uStopBits = stopbits; } -DWORD CSuperSerialCard::CommSetSnapshot(SS_IO_Comms* pSS) +//=========================================================================== + +#define SS_YAML_VALUE_CARD_SSC "Super Serial Card" + +#define SS_YAML_KEY_DIPSWDEFAULT "DIPSW Default" +#define SS_YAML_KEY_DIPSWCURRENT "DIPSW Current" + +#define SS_YAML_KEY_BAUDRATE "Baud Rate" +#define SS_YAML_KEY_FWMODE "Firmware mode" +#define SS_YAML_KEY_STOPBITS "Stop Bits" +#define SS_YAML_KEY_BYTESIZE "Byte Size" +#define SS_YAML_KEY_PARITY "Parity" +#define SS_YAML_KEY_LINEFEED "Linefeed" +#define SS_YAML_KEY_INTERRUPTS "Interrupts" +#define SS_YAML_KEY_CONTROL "Control Byte" +#define SS_YAML_KEY_COMMAND "Command Byte" +#define SS_YAML_KEY_INACTIVITY "Comm Inactivity" +#define SS_YAML_KEY_TXIRQENABLED "TX IRQ Enabled" +#define SS_YAML_KEY_RXIRQENABLED "RX IRQ Enabled" +#define SS_YAML_KEY_TXIRQPENDING "TX IRQ Pending" +#define SS_YAML_KEY_RXIRQPENDING "RX IRQ Pending" +#define SS_YAML_KEY_WRITTENTX "Written TX" +#define SS_YAML_KEY_SERIALPORTNAME "Serial Port Name" + +std::string CSuperSerialCard::GetSnapshotCardName(void) { - m_uBaudRate = pSS->baudrate; - m_uByteSize = pSS->bytesize; - m_uCommandByte = pSS->commandbyte; - m_dwCommInactivity = pSS->comminactivity; - m_uControlByte = pSS->controlbyte; - m_uParity = pSS->parity; -// memcpy(m_RecvBuffer, pSS->recvbuffer, uRecvBufferSize); -// m_vRecvBytes = pSS->recvbytes; - m_uStopBits = pSS->stopbits; - return 0; + static const std::string name(SS_YAML_VALUE_CARD_SSC); + return name; +} + +void CSuperSerialCard::SaveSnapshotDIPSW(YamlSaveHelper& yamlSaveHelper, std::string key, SSC_DIPSW& dipsw) +{ + YamlSaveHelper::Label label(yamlSaveHelper, "%s:\n", key.c_str()); + yamlSaveHelper.SaveUint(SS_YAML_KEY_BAUDRATE, dipsw.uBaudRate); + yamlSaveHelper.SaveUint(SS_YAML_KEY_FWMODE, dipsw.eFirmwareMode); + yamlSaveHelper.SaveUint(SS_YAML_KEY_STOPBITS, dipsw.uStopBits); + yamlSaveHelper.SaveUint(SS_YAML_KEY_BYTESIZE, dipsw.uByteSize); + yamlSaveHelper.SaveUint(SS_YAML_KEY_PARITY, dipsw.uParity); + yamlSaveHelper.SaveBool(SS_YAML_KEY_LINEFEED, dipsw.bLinefeed); + yamlSaveHelper.SaveBool(SS_YAML_KEY_INTERRUPTS, dipsw.bInterrupts); +} + +void CSuperSerialCard::SaveSnapshot(YamlSaveHelper& yamlSaveHelper) +{ + YamlSaveHelper::Slot slot(yamlSaveHelper, GetSnapshotCardName(), m_uSlot, 1); + + YamlSaveHelper::Label unit(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); + SaveSnapshotDIPSW(yamlSaveHelper, SS_YAML_KEY_DIPSWDEFAULT, m_DIPSWDefault); + SaveSnapshotDIPSW(yamlSaveHelper, SS_YAML_KEY_DIPSWCURRENT, m_DIPSWCurrent); + yamlSaveHelper.SaveUint(SS_YAML_KEY_BAUDRATE, m_uBaudRate); + yamlSaveHelper.SaveUint(SS_YAML_KEY_STOPBITS, m_uStopBits); + yamlSaveHelper.SaveUint(SS_YAML_KEY_BYTESIZE, m_uByteSize); + yamlSaveHelper.SaveUint(SS_YAML_KEY_PARITY, m_uParity); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_CONTROL, m_uControlByte); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_COMMAND, m_uCommandByte); + yamlSaveHelper.SaveUint(SS_YAML_KEY_INACTIVITY, m_dwCommInactivity); + yamlSaveHelper.SaveBool(SS_YAML_KEY_TXIRQENABLED, m_bTxIrqEnabled); + yamlSaveHelper.SaveBool(SS_YAML_KEY_RXIRQENABLED, m_bRxIrqEnabled); + yamlSaveHelper.SaveBool(SS_YAML_KEY_TXIRQPENDING, m_vbTxIrqPending); + yamlSaveHelper.SaveBool(SS_YAML_KEY_RXIRQPENDING, m_vbRxIrqPending); + yamlSaveHelper.SaveBool(SS_YAML_KEY_WRITTENTX, m_bWrittenTx); + yamlSaveHelper.SaveString(SS_YAML_KEY_SERIALPORTNAME, GetSerialPortName()); +} + +void CSuperSerialCard::LoadSnapshotDIPSW(YamlLoadHelper& yamlLoadHelper, std::string key, SSC_DIPSW& dipsw) +{ + if (!yamlLoadHelper.GetSubMap(key)) + throw std::string("Card: Expected key: " + key); + + dipsw.uBaudRate = yamlLoadHelper.LoadUint(SS_YAML_KEY_BAUDRATE); + dipsw.eFirmwareMode = (eFWMODE) yamlLoadHelper.LoadUint(SS_YAML_KEY_FWMODE); + dipsw.uStopBits = yamlLoadHelper.LoadUint(SS_YAML_KEY_STOPBITS); + dipsw.uByteSize = yamlLoadHelper.LoadUint(SS_YAML_KEY_BYTESIZE); + dipsw.uParity = yamlLoadHelper.LoadUint(SS_YAML_KEY_PARITY); + dipsw.bLinefeed = yamlLoadHelper.LoadBool(SS_YAML_KEY_LINEFEED); + dipsw.bInterrupts = yamlLoadHelper.LoadBool(SS_YAML_KEY_INTERRUPTS); + + yamlLoadHelper.PopMap(); +} + +bool CSuperSerialCard::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version) +{ + if (slot != 2) // fixme + throw std::string("Card: wrong slot"); + + if (version != 1) + throw std::string("Card: wrong version"); + + LoadSnapshotDIPSW(yamlLoadHelper, SS_YAML_KEY_DIPSWDEFAULT, m_DIPSWDefault); + LoadSnapshotDIPSW(yamlLoadHelper, SS_YAML_KEY_DIPSWCURRENT, m_DIPSWCurrent); + + m_uBaudRate = yamlLoadHelper.LoadUint(SS_YAML_KEY_BAUDRATE); + m_uStopBits = yamlLoadHelper.LoadUint(SS_YAML_KEY_STOPBITS); + m_uByteSize = yamlLoadHelper.LoadUint(SS_YAML_KEY_BYTESIZE); + m_uParity = yamlLoadHelper.LoadUint(SS_YAML_KEY_PARITY); + m_uControlByte = yamlLoadHelper.LoadUint(SS_YAML_KEY_CONTROL); + m_uCommandByte = yamlLoadHelper.LoadUint(SS_YAML_KEY_COMMAND); + m_dwCommInactivity = yamlLoadHelper.LoadUint(SS_YAML_KEY_INACTIVITY); + m_bTxIrqEnabled = yamlLoadHelper.LoadBool(SS_YAML_KEY_TXIRQENABLED); + m_bRxIrqEnabled = yamlLoadHelper.LoadBool(SS_YAML_KEY_RXIRQENABLED); + m_vbTxIrqPending = yamlLoadHelper.LoadBool(SS_YAML_KEY_TXIRQPENDING); + m_vbRxIrqPending = yamlLoadHelper.LoadBool(SS_YAML_KEY_RXIRQPENDING); + m_bWrittenTx = yamlLoadHelper.LoadBool(SS_YAML_KEY_WRITTENTX); + + std::string serialPortName = yamlLoadHelper.LoadString(SS_YAML_KEY_SERIALPORTNAME); + SetSerialPortName(serialPortName.c_str()); + + return true; } diff --git a/source/SerialComms.h b/source/SerialComms.h index d75d2ea9..c86678d2 100644 --- a/source/SerialComms.h +++ b/source/SerialComms.h @@ -33,8 +33,10 @@ public: void CommDestroy(); void CommSetSerialPort(HWND hWindow, DWORD dwNewSerialPortItem); void CommUpdate(DWORD); - DWORD CommGetSnapshot(SS_IO_Comms* pSS); - DWORD CommSetSnapshot(SS_IO_Comms* pSS); + void SetSnapshot_v1(const DWORD baudrate, const BYTE bytesize, const BYTE commandbyte, const DWORD comminactivity, const BYTE controlbyte, const BYTE parity, const BYTE stopbits); + std::string GetSnapshotCardName(void); + void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper); + bool LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version); char* GetSerialPortChoices(); DWORD GetSerialPort() { return m_dwSerialPortItem; } // Drop-down list item @@ -72,6 +74,8 @@ private: void CommThUninit(); UINT GetNumSerialPortChoices() { return m_vecSerialPortsItems.size(); } void ScanCOMPorts(); + void SaveSnapshotDIPSW(class YamlSaveHelper& yamlSaveHelper, std::string key, SSC_DIPSW& dipsw); + void LoadSnapshotDIPSW(class YamlLoadHelper& yamlLoadHelper, std::string key, SSC_DIPSW& dipsw); // @@ -134,4 +138,5 @@ private: OVERLAPPED m_o; BYTE* m_pExpansionRom; + UINT m_uSlot; }; diff --git a/source/Speaker.cpp b/source/Speaker.cpp index 3608ecd6..fcf1dd9f 100644 --- a/source/Speaker.cpp +++ b/source/Speaker.cpp @@ -35,6 +35,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "SoundCore.h" #include "Speaker.h" #include "Video.h" // VideoRedrawScreen() +#include "YamlHelper.h" #include "Debugger\Debug.h" // For DWORD extbench @@ -51,11 +52,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // their buffers are running low. // -#define SOUND_NONE 0 -#define SOUND_DIRECT 1 -#define SOUND_SMART 2 -#define SOUND_WAVE 3 - static const unsigned short g_nSPKR_NumChannels = 1; static const DWORD g_dwDSSpkrBufferSize = MAX_SAMPLES * sizeof(short) * g_nSPKR_NumChannels; @@ -66,18 +62,20 @@ static short* g_pSpeakerBuffer = NULL; // Globals (SOUND_WAVE) const short SPKR_DATA_INIT = (short)0x8000; -static short g_nSpeakerData = SPKR_DATA_INIT; +short g_nSpeakerData = SPKR_DATA_INIT; static UINT g_nBufferIdx = 0; static short* g_pRemainderBuffer = NULL; static UINT g_nRemainderBufferSize; // Setup in SpkrInitialize() static UINT g_nRemainderBufferIdx; // Setup in SpkrInitialize() - // Application-wide globals: DWORD soundtype = SOUND_WAVE; double g_fClksPerSpkrSample; // Setup in SetClksPerSpkrSample() +// Allow temporary quietening of speaker (8 bit DAC) +bool g_bQuieterSpeaker = false; + // Globals static DWORD lastcyclenum = 0; static DWORD toggles = 0; @@ -226,7 +224,7 @@ void SpkrDestroy () g_pSpeakerBuffer = NULL; g_pRemainderBuffer = NULL; } - else + else if (soundtype == SOUND_DIRECT || soundtype == SOUND_SMART) { InternalBeep(0,0); } @@ -328,8 +326,8 @@ void SpkrReset() BOOL SpkrSetEmulationType (HWND window, DWORD newtype) { - if (soundtype != SOUND_NONE) - SpkrDestroy(); + SpkrDestroy(); // GH#295: Destroy for all types (even SOUND_NONE) + soundtype = newtype; if (soundtype != SOUND_NONE) SpkrInitialize(); @@ -447,7 +445,21 @@ BYTE __stdcall SpkrToggle (WORD, WORD, BYTE, BYTE, ULONG nCyclesLeft) UpdateSpkr(); - g_nSpeakerData = ~g_nSpeakerData; + if (g_bQuieterSpeaker) + { + // quieten the speaker if 8 bit DAC in use + if (g_nSpeakerData == (SPKR_DATA_INIT >> 2)) + g_nSpeakerData = ~g_nSpeakerData; + else + g_nSpeakerData = SPKR_DATA_INIT>>2; + } + else + { + if (g_nSpeakerData == SPKR_DATA_INIT) + g_nSpeakerData = ~g_nSpeakerData; + else + g_nSpeakerData = SPKR_DATA_INIT; + } } else if (soundtype != SOUND_NONE) { @@ -875,7 +887,7 @@ static ULONG Spkr_SubmitWaveBuffer(short* pSpeakerBuffer, ULONG nNumSamples) double fTicksSecs = (double)GetTickCount() / 1000.0; sprintf(szDbg, "%010.3f: [Submit] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X XXX\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples); OutputDebugString(szDbg); - if (g_fh) fprintf(g_fh, szDbg); + if (g_fh) fprintf(g_fh, "%s", szDbg); dwByteOffset = dwCurrentWriteCursor; nNumSamplesError = 0; @@ -993,6 +1005,7 @@ static void Spkr_SetActive(bool bActive) // Called by SpkrUpdate() after 0.2s of speaker inactivity g_bSpkrRecentlyActive = false; SpeakerVoice.bRecentlyActive = false; + g_bQuieterSpeaker = 0; // undo any muting (for 8 bit DAC) } } @@ -1080,14 +1093,33 @@ void Spkr_DSUninit() //============================================================================= -DWORD SpkrGetSnapshot(SS_IO_Speaker* pSS) +void SpkrSetSnapshot_v1(const unsigned __int64 SpkrLastCycle) { - pSS->g_nSpkrLastCycle = g_nSpkrLastCycle; - return 0; + g_nSpkrLastCycle = SpkrLastCycle; } -DWORD SpkrSetSnapshot(SS_IO_Speaker* pSS) +// + +#define SS_YAML_KEY_LASTCYCLE "Last Cycle" + +static std::string SpkrGetSnapshotStructName(void) { - g_nSpkrLastCycle = pSS->g_nSpkrLastCycle; - return 0; + static const std::string name("Speaker"); + return name; +} + +void SpkrSaveSnapshot(YamlSaveHelper& yamlSaveHelper) +{ + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SpkrGetSnapshotStructName().c_str()); + yamlSaveHelper.SaveHexUint64(SS_YAML_KEY_LASTCYCLE, g_nSpkrLastCycle); +} + +void SpkrLoadSnapshot(YamlLoadHelper& yamlLoadHelper) +{ + if (!yamlLoadHelper.GetSubMap(SpkrGetSnapshotStructName())) + return; + + g_nSpkrLastCycle = yamlLoadHelper.LoadUint64(SS_YAML_KEY_LASTCYCLE); + + yamlLoadHelper.PopMap(); } diff --git a/source/Speaker.h b/source/Speaker.h index 8e93fbbe..2e6312bd 100644 --- a/source/Speaker.h +++ b/source/Speaker.h @@ -1,7 +1,14 @@ #pragma once +#define SOUND_NONE 0 +#define SOUND_DIRECT 1 +#define SOUND_SMART 2 +#define SOUND_WAVE 3 + extern DWORD soundtype; extern double g_fClksPerSpkrSample; +extern bool g_bQuieterSpeaker; +extern short g_nSpeakerData; void SpkrDestroy (); void SpkrInitialize (); @@ -19,7 +26,8 @@ void Spkr_Demute(); bool Spkr_IsActive(); bool Spkr_DSInit(); void Spkr_DSUninit(); -DWORD SpkrGetSnapshot(SS_IO_Speaker* pSS); -DWORD SpkrSetSnapshot(SS_IO_Speaker* pSS); +void SpkrSetSnapshot_v1(const unsigned __int64 SpkrLastCycle); +void SpkrSaveSnapshot(class YamlSaveHelper& yamlSaveHelper); +void SpkrLoadSnapshot(class YamlLoadHelper& yamlLoadHelper); BYTE __stdcall SpkrToggle (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft); diff --git a/source/StdAfx.h b/source/StdAfx.h index 989c60da..6befb99a 100644 --- a/source/StdAfx.h +++ b/source/StdAfx.h @@ -14,7 +14,7 @@ #endif // Not needed in VC7.1, but needed in VC Express -#include +#include #include #include @@ -23,7 +23,6 @@ #include #include #include -#include #include #if _MSC_VER >= 1600 // supported from VS2010 (cl.exe v16.00) #include // cleanup WORD DWORD -> uint16_t uint32_t @@ -43,6 +42,8 @@ typedef UINT32 uint32_t; #include #include #include +#include +#include #include // SM_CXPADDEDBORDER is not supported on 2000 & XP: diff --git a/source/Structs.h b/source/Structs.h deleted file mode 100644 index f2af25ac..00000000 --- a/source/Structs.h +++ /dev/null @@ -1,285 +0,0 @@ -#pragma once - -#include "DiskDefs.h" - -// Structs used by save-state file - -// *** DON'T CHANGE ANY STRUCT WITHOUT CONSIDERING BACKWARDS COMPATIBILITY WITH .AWS FORMAT *** - -#define MAKE_VERSION(a,b,c,d) ((a<<24) | (b<<16) | (c<<8) | (d)) - -#define AW_SS_TAG 'SSWA' // 'AWSS' = AppleWin SnapShot - -typedef struct -{ - DWORD dwTag; // "AWSS" - DWORD dwVersion; - DWORD dwChecksum; -} SS_FILE_HDR; - -typedef struct -{ - DWORD dwLength; // Byte length of this unit struct - DWORD dwVersion; -} SS_UNIT_HDR; - -///////////////////////////////////////////////////////////////////////////////// - -const UINT nMemMainSize = 64*1024; -const UINT nMemAuxSize = 64*1024; - -typedef struct -{ - BYTE A; - BYTE X; - BYTE Y; - BYTE P; - BYTE S; - USHORT PC; - unsigned __int64 g_nCumulativeCycles; - // IRQ = OR-sum of all interrupt sources -} SS_CPU6502; - -const UINT uRecvBufferSize = 9; - -typedef struct -{ - DWORD baudrate; - BYTE bytesize; - BYTE commandbyte; - DWORD comminactivity; // If non-zero then COM port open - BYTE controlbyte; - BYTE parity; - BYTE recvbuffer[uRecvBufferSize]; - DWORD recvbytes; - BYTE stopbits; -} SS_IO_Comms; - -typedef struct -{ - unsigned __int64 g_nJoyCntrResetCycle; -} SS_IO_Joystick; - -typedef struct -{ - DWORD keyboardqueries; - BYTE nLastKey; -} SS_IO_Keyboard; - -//typedef struct -//{ -//} SS_IO_Memory; - -typedef struct -{ - unsigned __int64 g_nSpkrLastCycle; -} SS_IO_Speaker; - -typedef struct -{ - bool bAltCharSet; // charoffs - DWORD dwVidMode; -} SS_IO_Video; - -typedef struct -{ - DWORD dwMemMode; - BOOL bLastWriteRam; - BYTE nMemMain[nMemMainSize]; - BYTE nMemAux[nMemAuxSize]; -} SS_BaseMemory; - -typedef struct -{ - SS_UNIT_HDR UnitHdr; - SS_CPU6502 CPU6502; - SS_IO_Comms Comms; - SS_IO_Joystick Joystick; - SS_IO_Keyboard Keyboard; -// SS_IO_Memory Memory; - SS_IO_Speaker Speaker; - SS_IO_Video Video; - SS_BaseMemory Memory; -} SS_APPLE2_Unit; - -///////////////////////////////////////////////////////////////////////////////// - -typedef struct -{ - DWORD dwComputerEmulation; - bool bCustomSpeed; - DWORD dwEmulationSpeed; - bool bEnhancedDiskSpeed; - DWORD dwJoystickType[2]; - bool bMockingboardEnabled; - DWORD dwMonochromeColor; - DWORD dwSerialPort; - DWORD dwSoundType; // Sound Emulation - DWORD dwVideoType; // Video Emulation -} SS_AW_CFG; - -typedef struct -{ - char StartingDir[MAX_PATH]; - DWORD dwWindowXpos; - DWORD dwWindowYpos; -} SS_AW_PREFS; - -typedef struct -{ - SS_UNIT_HDR UnitHdr; - DWORD dwAppleWinVersion; - SS_AW_PREFS Prefs; - SS_AW_CFG Cfg; -} SS_APPLEWIN_CONFIG; - -///////////////////////////////////////////////////////////////////////////////// - -typedef struct -{ - SS_UNIT_HDR UnitHdr; - DWORD dwType; // SS_CARDTYPE - DWORD dwSlot; // [1..7] -} SS_CARD_HDR; - -enum SS_CARDTYPE -{ - CT_Empty = 0, - CT_Disk2, // Apple Disk][ - CT_SSC, // Apple Super Serial Card - CT_MockingboardC, // Soundcard - CT_GenericPrinter, - CT_GenericHDD, // Hard disk - CT_GenericClock, - CT_MouseInterface, - CT_Z80, - CT_Phasor, // Soundcard - CT_Echo, // Soundcard - CT_SAM, // Soundcard: Software Automated Mouth -}; - -///////////////////////////////////////////////////////////////////////////////// - -typedef struct -{ - SS_CARD_HDR Hdr; -} SS_CARD_EMPTY; - -///////////////////////////////////////////////////////////////////////////////// - -typedef struct -{ - char szFileName[MAX_PATH]; - int track; - int phase; - int byte; - BOOL writeprotected; - BOOL trackimagedata; - BOOL trackimagedirty; - DWORD spinning; - DWORD writelight; - int nibbles; - BYTE nTrack[NIBBLES_PER_TRACK]; -} DISK2_Unit; - -typedef struct -{ - SS_CARD_HDR Hdr; - DISK2_Unit Unit[2]; - WORD phases; - WORD currdrive; - BOOL diskaccessed; - BOOL enhancedisk; - BYTE floppylatch; - BOOL floppymotoron; - BOOL floppywritemode; -} SS_CARD_DISK2; - -///////////////////////////////////////////////////////////////////////////////// - -typedef struct -{ - union - { - struct - { - BYTE l; - BYTE h; - }; - USHORT w; - }; -} IWORD; - -typedef struct -{ - 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) -} SY6522; - -typedef struct -{ - BYTE DurationPhonome; - BYTE Inflection; // I10..I3 - BYTE RateInflection; - BYTE CtrlArtAmp; - BYTE FilterFreq; - // - BYTE CurrentMode; // b7:6=Mode; b0=D7 pin (for IRQ) -} SSI263A; - -typedef struct -{ - SY6522 RegsSY6522; - BYTE RegsAY8910[16]; - SSI263A RegsSSI263; - BYTE nAYCurrentRegister; - bool bTimer1IrqPending; - bool bTimer2IrqPending; - bool bSpeechIrqPending; -} MB_Unit; - -const UINT MB_UNITS_PER_CARD = 2; - -typedef struct -{ - SS_CARD_HDR Hdr; - MB_Unit Unit[MB_UNITS_PER_CARD]; -} SS_CARD_MOCKINGBOARD; - -///////////////////////////////////////////////////////////////////////////////// - -typedef struct -{ - SS_FILE_HDR Hdr; - SS_APPLE2_Unit Apple2Unit; -// SS_APPLEWIN_CONFIG AppleWinCfg; - 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 -} APPLEWIN_SNAPSHOT; - -///////////////////////////////////////////////////////////////////////////////// diff --git a/source/Tape.cpp b/source/Tape.cpp index 0aef7f03..33dd5872 100644 --- a/source/Tape.cpp +++ b/source/Tape.cpp @@ -24,8 +24,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /* Description: This module is created for emulation of the 8bit character mode (mode 1) switch, * which is located in $c060, and so far does not intend to emulate a tape device. * - * * Author: Various + * + * In comments, UTA2E is an abbreviation for a reference to "Understanding the Apple //e" by James Sather */ #include "StdAfx.h" @@ -33,6 +34,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "AppleWin.h" #include "Keyboard.h" #include "Memory.h" +#include "Pravets.h" static bool g_CapsLockAllowed = false; @@ -76,7 +78,7 @@ BYTE __stdcall TapeRead(WORD, WORD address, BYTE, BYTE, ULONG nCyclesLeft) return C060; } - return (1<<7) | (MemReadFloatingBus(nCyclesLeft) & 0x7F); // Keep high-bit fixed (since TAPEIN isn't supported) + return MemReadFloatingBus(1, nCyclesLeft); // TAPEIN has high bit 1 when input is low or not connected (UTA2E page 7-5, 7-6) } /* diff --git a/source/Video.cpp b/source/Video.cpp index 0c5909a7..d24cd128 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -40,6 +40,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "..\resource\resource.h" #include "Configuration\PropertySheet.h" #include "Debugger\Debugger_Color.h" // For NUM_DEBUG_COLORS +#include "YamlHelper.h" #define HALF_PIXEL_SOLID 1 #define HALF_PIXEL_BLEED 0 @@ -590,7 +591,6 @@ static inline int GetOriginal2EOffset(BYTE ch) } //=========================================================================== -#define ROL_NIB(x) ( (((x)<<1)&0xF) | (((x)>>3)&1) ) // // ----- ALL GLOBALLY ACCESSIBLE FUNCTIONS ARE BELOW THIS LINE ----- @@ -1195,11 +1195,10 @@ void VideoRefreshScreen ( int bVideoModeFlags ) //=========================================================================== void VideoReinitialize () { - NTSC_VideoInitAppleType(); + NTSC_VideoInitAppleType(g_dwCyclesThisFrame); NTSC_SetVideoStyle(); } - //=========================================================================== void VideoResetState () { @@ -1220,8 +1219,8 @@ BYTE VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles) switch (address) { - case 0x00: g_uVideoMode &= ~VF_80STORE; ; break; - case 0x01: g_uVideoMode |= VF_80STORE; ; break; + case 0x00: g_uVideoMode &= ~VF_80STORE; break; + case 0x01: g_uVideoMode |= VF_80STORE; break; case 0x0C: if (!IS_APPLE2){g_uVideoMode &= ~VF_80COL; NTSC_SetVideoTextMode(40);}; break; case 0x0D: if (!IS_APPLE2){g_uVideoMode |= VF_80COL; NTSC_SetVideoTextMode(80);}; break; case 0x0E: if (!IS_APPLE2) g_nAltCharSetOffset = 0; break; // Alternate char set off @@ -1238,7 +1237,7 @@ BYTE VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles) case 0x5F: if (!IS_APPLE2) g_uVideoMode &= ~VF_DHIRES; break; } - // Apple IIe, Techical Nodtes, #3: Double High-Resolution Graphics + // Apple IIe, Techical Notes, #3: Double High-Resolution Graphics // 80STORE must be OFF to display page 2 if (SW_80STORE) g_uVideoMode &= ~VF_PAGE2; @@ -1260,7 +1259,7 @@ BYTE VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles) // NB. Deferring the update by just setting /g_VideoForceFullRedraw/ is not an option, since this doesn't provide "flip-immediate" // // Ultimately this isn't the correct solution, and proper cycle-accurate video rendering should be done, but this is a much bigger job! - // TODO: Is MemReadFloatingBus() still accurate now that we have proper per cycle video rendering?? + // TODO-Michael: Is MemReadFloatingBus() still accurate now that we have proper per cycle video rendering?? if (!g_bVideoUpdatedThisFrame) { @@ -1323,20 +1322,42 @@ void VideoSetForceFullRedraw(void) //=========================================================================== -DWORD VideoGetSnapshot(SS_IO_Video* pSS) +void VideoSetSnapshot_v1(const UINT AltCharSet, const UINT VideoMode) { - pSS->bAltCharSet = !(g_nAltCharSetOffset == 0); - pSS->dwVidMode = g_uVideoMode; - return 0; + g_nAltCharSetOffset = !AltCharSet ? 0 : 256; + g_uVideoMode = VideoMode; } -//=========================================================================== +// -DWORD VideoSetSnapshot(SS_IO_Video* pSS) +#define SS_YAML_KEY_ALTCHARSET "Alt Char Set" +#define SS_YAML_KEY_VIDEOMODE "Video Mode" +#define SS_YAML_KEY_CYCLESTHISFRAME "Cycles This Frame" + +static std::string VideoGetSnapshotStructName(void) { - g_nAltCharSetOffset = !pSS->bAltCharSet ? 0 : 256; - g_uVideoMode = pSS->dwVidMode; - return 0; + static const std::string name("Video"); + return name; +} + +void VideoSaveSnapshot(YamlSaveHelper& yamlSaveHelper) +{ + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", VideoGetSnapshotStructName().c_str()); + yamlSaveHelper.SaveBool(SS_YAML_KEY_ALTCHARSET, g_nAltCharSetOffset ? true : false); + yamlSaveHelper.SaveHexUint32(SS_YAML_KEY_VIDEOMODE, g_uVideoMode); + yamlSaveHelper.SaveUint(SS_YAML_KEY_CYCLESTHISFRAME, g_dwCyclesThisFrame); +} + +void VideoLoadSnapshot(YamlLoadHelper& yamlLoadHelper) +{ + if (!yamlLoadHelper.GetSubMap(VideoGetSnapshotStructName())) + return; + + g_nAltCharSetOffset = yamlLoadHelper.LoadBool(SS_YAML_KEY_ALTCHARSET) ? 256 : 0; + g_uVideoMode = yamlLoadHelper.LoadUint(SS_YAML_KEY_VIDEOMODE); + g_dwCyclesThisFrame = yamlLoadHelper.LoadUint(SS_YAML_KEY_CYCLESTHISFRAME); + + yamlLoadHelper.PopMap(); } //=========================================================================== diff --git a/source/Video.h b/source/Video.h index ab935426..7bad49f7 100644 --- a/source/Video.h +++ b/source/Video.h @@ -152,12 +152,11 @@ struct WinBmpHeader4_t extern HBITMAP g_hLogoBitmap; -extern COLORREF g_nMonochromeRGB; // saved -extern uint32_t g_uVideoMode ; -extern DWORD g_eVideoType ; // saved -extern DWORD g_uHalfScanLines; // saved +extern COLORREF g_nMonochromeRGB; // saved to Registry +extern uint32_t g_uVideoMode; +extern DWORD g_eVideoType; // saved to Registry +extern DWORD g_uHalfScanLines; // saved to Registry extern uint8_t *g_pFramebufferbits; -extern int g_nAltCharSetOffset; // alternate character set typedef bool (*VideoUpdateFuncPtr_t)(int,int,int,int,int); @@ -177,7 +176,6 @@ void VideoReinitialize (); void VideoResetState (); WORD VideoGetScannerAddress(bool* pbVblBar_OUT, const DWORD uExecutedCycles); bool VideoGetVbl(DWORD uExecutedCycles); -void VideoEndOfVideoFrame(void); bool VideoGetSW80COL(void); bool VideoGetSWDHIRES(void); @@ -190,6 +188,10 @@ bool VideoGetSWAltCharSet(void); void VideoSetForceFullRedraw(void); +void VideoSetSnapshot_v1(const UINT AltCharSet, const UINT VideoMode); +void VideoSaveSnapshot(class YamlSaveHelper& yamlSaveHelper); +void VideoLoadSnapshot(class YamlLoadHelper& yamlLoadHelper); + int _Video_SetupBanks( bool bBank2 ); bool Update40ColCell (int x, int y, int xpixel, int ypixel, int offset); bool Update80ColCell (int x, int y, int xpixel, int ypixel, int offset); diff --git a/source/YamlHelper.cpp b/source/YamlHelper.cpp new file mode 100644 index 00000000..883e5982 --- /dev/null +++ b/source/YamlHelper.cpp @@ -0,0 +1,482 @@ +/* +AppleWin : An Apple //e emulator for Windows + +Copyright (C) 1994-1996, Michael O'Brien +Copyright (C) 1999-2001, Oliver Schmidt +Copyright (C) 2002-2005, Tom Charlesworth +Copyright (C) 2006-2015, Tom Charlesworth, Michael Pohoreski + +AppleWin is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +AppleWin is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with AppleWin; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "StdAfx.h" + +#include "Log.h" +#include "YamlHelper.h" + +int YamlHelper::InitParser(const char* pPathname) +{ + m_hFile = fopen(pPathname, "r"); + if (m_hFile == NULL) + { + return 0; + } + + if (!yaml_parser_initialize(&m_parser)) + { + return 0; + } + + yaml_parser_set_input_file(&m_parser, m_hFile); + + return 1; +} + +void YamlHelper::FinaliseParser(void) +{ + if (m_hFile) + fclose(m_hFile); + + m_hFile = NULL; +} + +void YamlHelper::GetNextEvent(bool bInMap /*= false*/) +{ + if (!yaml_parser_parse(&m_parser, &m_newEvent)) + { + //printf("Parser error %d\n", m_parser.error); + throw std::string("Parser error"); + } +} + +int YamlHelper::GetScalar(std::string& scalar) +{ + int res = 1; + bool bDone = false; + + while (!bDone) + { + GetNextEvent(); + + switch(m_newEvent.type) + { + case YAML_SCALAR_EVENT: + scalar = m_scalarName = (const char*)m_newEvent.data.scalar.value; + res = 1; + bDone = true; + break; + case YAML_SEQUENCE_END_EVENT: + res = 0; + bDone = true; + break; + case YAML_MAPPING_END_EVENT: + res = 0; + bDone = true; + break; + case YAML_STREAM_END_EVENT: + res = 0; + bDone = true; + break; + } + } + + return res; +} + +void YamlHelper::GetMapStartEvent(void) +{ + GetNextEvent(); + + if (m_newEvent.type != YAML_MAPPING_START_EVENT) + { + //printf("Unexpected yaml event (%d)\n", m_newEvent.type); + throw std::string("Unexpected yaml event"); + } +} + +int YamlHelper::ParseMap(MapYaml& mapYaml) +{ + mapYaml.clear(); + + const char*& pValue = (const char*&) m_newEvent.data.scalar.value; + + bool bKey = true; + char* pKey = NULL; + int res = 1; + bool bDone = false; + + while (!bDone) + { + GetNextEvent(true); + + switch(m_newEvent.type) + { + case YAML_STREAM_END_EVENT: + res = 0; + bDone = true; + break; + case YAML_MAPPING_START_EVENT: + { + MapValue mapValue; + mapValue.value = ""; + mapValue.subMap = new MapYaml; + mapYaml[std::string(pKey)] = mapValue; + res = ParseMap(*mapValue.subMap); + if (!res) + throw std::string("ParseMap: premature end of file during map parsing"); + bKey = true; // possibly more key,value pairs in this map + } + break; + case YAML_MAPPING_END_EVENT: + bDone = true; + break; + case YAML_SCALAR_EVENT: + if (bKey) + { + pKey = _strdup(pValue); + } + else + { + MapValue mapValue; + mapValue.value = pValue; + mapValue.subMap = NULL; + mapYaml[std::string(pKey)] = mapValue; + delete [] pKey; pKey = NULL; + } + + bKey = bKey ? false : true; + break; + case YAML_SEQUENCE_START_EVENT: + case YAML_SEQUENCE_END_EVENT: + throw std::string("ParseMap: Sequence event unsupported"); + } + } + + if (pKey) + delete [] pKey; + + return res; +} + +std::string YamlHelper::GetMapValue(MapYaml& mapYaml, const std::string key, bool& bFound) +{ + MapYaml::const_iterator iter = mapYaml.find(key); + if (iter == mapYaml.end() || iter->second.subMap != NULL) + { + bFound = false; // not found + return ""; + } + + std::string value = iter->second.value; + + mapYaml.erase(iter); + + bFound = true; + return value; +} + +bool YamlHelper::GetSubMap(MapYaml** mapYaml, const std::string key) +{ + MapYaml::const_iterator iter = (*mapYaml)->find(key); + if (iter == (*mapYaml)->end() || iter->second.subMap == NULL) + { + return false; // not found + } + + *mapYaml = iter->second.subMap; + return true; +} + +void YamlHelper::GetMapRemainder(std::string& mapName, MapYaml& mapYaml) +{ + for (MapYaml::iterator iter = mapYaml.begin(); iter != mapYaml.end(); ++iter) + { + if (iter->second.subMap) + { + std::string subMapName(iter->first); + GetMapRemainder(subMapName, *iter->second.subMap); + delete iter->second.subMap; + } + else + { + const char* pKey = iter->first.c_str(); + LogOutput("%s: Unknown key (%s)\n", mapName.c_str(), pKey); + LogFileOutput("%s: Unknown key (%s)\n", mapName.c_str(), pKey); + } + } + + mapYaml.clear(); +} + +// + +void YamlHelper::MakeAsciiToHexTable(void) +{ + memset(m_AsciiToHex, -1, sizeof(m_AsciiToHex)); + + for (int i = '0'; i<= '9'; i++) + m_AsciiToHex[i] = i - '0'; + + for (int i = 'A'; i<= 'F'; i++) + m_AsciiToHex[i] = i - 'A' + 0xA; + + for (int i = 'a'; i<= 'f'; i++) + m_AsciiToHex[i] = i - 'a' + 0xA; +} + +void YamlHelper::LoadMemory(MapYaml& mapYaml, const LPBYTE pMemBase, const size_t kAddrSpaceSize) +{ + for (MapYaml::iterator it = mapYaml.begin(); it != mapYaml.end(); ++it) + { + const char* pKey = it->first.c_str(); + UINT addr = strtoul(pKey, NULL, 16); + if (addr >= kAddrSpaceSize) + throw std::string("Memory: line address too big: " + it->first); + + LPBYTE pDst = (LPBYTE) (pMemBase + addr); + const LPBYTE pDstEnd = (LPBYTE) (pMemBase + kAddrSpaceSize); + + if (it->second.subMap) + throw std::string("Memory: unexpected sub-map"); + + const char* pValue = it->second.value.c_str(); + size_t len = strlen(pValue); + if (len & 1) + throw std::string("Memory: hex data must be an even number of nibbles on line address: " + it->first); + + for (UINT i = 0; i= pDstEnd) + throw std::string("Memory: hex data overflowed address space on line address: " + it->first); + + BYTE ah = m_AsciiToHex[ (BYTE)(*pValue++) ]; + BYTE al = m_AsciiToHex[ (BYTE)(*pValue++) ]; + if ((ah | al) & 0x80) + throw std::string("Memory: hex data contains illegal character on line address: " + it->first); + + *pDst++ = (ah<<4) | al; + } + } + + mapYaml.clear(); +} + +//------------------------------------- + +INT YamlLoadHelper::LoadInt(const std::string key) +{ + bool bFound; + std::string value = m_yamlHelper.GetMapValue(*m_pMapYaml, key, bFound); + if (value == "") + { + m_bDoGetMapRemainder = false; + throw std::string(m_currentMapName + ": Missing: " + key); + } + return strtol(value.c_str(), NULL, 0); +} + +UINT YamlLoadHelper::LoadUint(const std::string key) +{ + bool bFound; + std::string value = m_yamlHelper.GetMapValue(*m_pMapYaml, key, bFound); + if (value == "") + { + m_bDoGetMapRemainder = false; + throw std::string(m_currentMapName + ": Missing: " + key); + } + return strtoul(value.c_str(), NULL, 0); +} + +UINT64 YamlLoadHelper::LoadUint64(const std::string key) +{ + bool bFound; + std::string value = m_yamlHelper.GetMapValue(*m_pMapYaml, key, bFound); + if (value == "") + { + m_bDoGetMapRemainder = false; + throw std::string(m_currentMapName + ": Missing: " + key); + } + return _strtoui64(value.c_str(), NULL, 0); +} + +bool YamlLoadHelper::LoadBool(const std::string key) +{ + bool bFound; + std::string value = m_yamlHelper.GetMapValue(*m_pMapYaml, key, bFound); + if (value == "true") + return true; + else if (value == "false") + return false; + m_bDoGetMapRemainder = false; + throw std::string(m_currentMapName + ": Missing: " + key); +} + +std::string YamlLoadHelper::LoadString_NoThrow(const std::string& key, bool& bFound) +{ + std::string value = m_yamlHelper.GetMapValue(*m_pMapYaml, key, bFound); + return value; +} + +std::string YamlLoadHelper::LoadString(const std::string& key) +{ + bool bFound; + std::string value = LoadString_NoThrow(key, bFound); + if (!bFound) + { + m_bDoGetMapRemainder = false; + throw std::string(m_currentMapName + ": Missing: " + key); + } + return value; +} + +void YamlLoadHelper::LoadMemory(const LPBYTE pMemBase, const size_t size) +{ + m_yamlHelper.LoadMemory(*m_pMapYaml, pMemBase, size); +} + +//------------------------------------- + +void YamlSaveHelper::Save(const char* format, ...) +{ + fwrite(m_szIndent, 1, m_indent, m_hFile); + + va_list vl; + va_start(vl, format); + vfprintf(m_hFile, format, vl); + va_end(vl); +} + +void YamlSaveHelper::SaveInt(const char* key, int value) +{ + Save("%s: %d\n", key, value); +} + +void YamlSaveHelper::SaveUint(const char* key, UINT value) +{ + Save("%s: %u\n", key, value); +} + +void YamlSaveHelper::SaveHexUint4(const char* key, UINT value) +{ + Save("%s: 0x%01X\n", key, value); +} + +void YamlSaveHelper::SaveHexUint8(const char* key, UINT value) +{ + Save("%s: 0x%02X\n", key, value); +} + +void YamlSaveHelper::SaveHexUint12(const char* key, UINT value) +{ + Save("%s: 0x%03X\n", key, value); +} + +void YamlSaveHelper::SaveHexUint16(const char* key, UINT value) +{ + Save("%s: 0x%04X\n", key, value); +} + +void YamlSaveHelper::SaveHexUint32(const char* key, UINT value) +{ + Save("%s: 0x%08X\n", key, value); +} + +void YamlSaveHelper::SaveHexUint64(const char* key, UINT64 value) +{ + Save("%s: 0x%016llX\n", key, value); +} + +void YamlSaveHelper::SaveBool(const char* key, bool value) +{ + Save("%s: %s\n", key, value ? "true" : "false"); +} + +void YamlSaveHelper::SaveString(const char* key, const char* value) +{ + Save("%s: %s\n", key, (value[0] != 0) ? value : "\"\""); +} + +// Pre: uMemSize must be multiple of 8 +void YamlSaveHelper::SaveMemory(const LPBYTE pMemBase, const UINT uMemSize) +{ + if (uMemSize & 7) + throw std::string("Memory: size must be multiple of 8"); + + const UINT kIndent = m_indent; + + const UINT kStride = 64; + const char szHex[] = "0123456789ABCDEF"; + + size_t lineSize = kIndent+6+2*kStride+2; // "AAAA: 00010203...3F\n\00" = 6+ 2*64 +2 + char* const pLine = new char [lineSize]; + + for(DWORD dwOffset = 0x0000; dwOffset < uMemSize; dwOffset+=kStride) + { + char* pDst = pLine; + for (UINT i=0; i>12)&0xf ]; + *pDst++ = szHex[ (dwOffset>>8)&0xf ]; + *pDst++ = szHex[ (dwOffset>>4)&0xf ]; + *pDst++ = szHex[ dwOffset&0xf ]; + *pDst++ = ':'; + *pDst++ = ' '; + + LPBYTE pMem = pMemBase + dwOffset; + + for (UINT i=0; i= uMemSize) // Support short final line (still multiple of 8 bytes) + { + lineSize = lineSize - 2*kStride + 2*i; + break; + } + + BYTE d; + d = *pMem++; *pDst++ = szHex[d>>4]; *pDst++ = szHex[d&0xf]; + d = *pMem++; *pDst++ = szHex[d>>4]; *pDst++ = szHex[d&0xf]; + d = *pMem++; *pDst++ = szHex[d>>4]; *pDst++ = szHex[d&0xf]; + d = *pMem++; *pDst++ = szHex[d>>4]; *pDst++ = szHex[d&0xf]; + + d = *pMem++; *pDst++ = szHex[d>>4]; *pDst++ = szHex[d&0xf]; + d = *pMem++; *pDst++ = szHex[d>>4]; *pDst++ = szHex[d&0xf]; + d = *pMem++; *pDst++ = szHex[d>>4]; *pDst++ = szHex[d&0xf]; + d = *pMem++; *pDst++ = szHex[d>>4]; *pDst++ = szHex[d&0xf]; + } + + *pDst++ = '\n'; + *pDst = 0; // For debugger + + fwrite(pLine, 1, lineSize-1, m_hFile); // -1 so don't write null terminator + } + + delete [] pLine; +} + +void YamlSaveHelper::FileHdr(UINT version) +{ + fprintf(m_hFile, "%s:\n", SS_YAML_KEY_FILEHDR); + m_indent = 2; + SaveString(SS_YAML_KEY_TAG, SS_YAML_VALUE_AWSS); + SaveInt(SS_YAML_KEY_VERSION, version); +} + +void YamlSaveHelper::UnitHdr(std::string type, UINT version) +{ + fprintf(m_hFile, "\n%s:\n", SS_YAML_KEY_UNIT); + m_indent = 2; + SaveString(SS_YAML_KEY_TYPE, type.c_str()); + SaveInt(SS_YAML_KEY_VERSION, version); +} diff --git a/source/YamlHelper.h b/source/YamlHelper.h new file mode 100644 index 00000000..31e871ca --- /dev/null +++ b/source/YamlHelper.h @@ -0,0 +1,266 @@ +#pragma once + +#include "yaml.h" + +#define SS_YAML_KEY_FILEHDR "File_hdr" +#define SS_YAML_KEY_TAG "Tag" +#define SS_YAML_KEY_VERSION "Version" +#define SS_YAML_KEY_UNIT "Unit" +#define SS_YAML_KEY_TYPE "Type" +#define SS_YAML_KEY_CARD "Card" +#define SS_YAML_KEY_STATE "State" + +#define SS_YAML_VALUE_AWSS "AppleWin Save State" + +struct MapValue; +typedef std::map MapYaml; + +struct MapValue +{ + std::string value; + MapYaml* subMap; +}; + +class YamlHelper +{ +friend class YamlLoadHelper; // YamlLoadHelper can access YamlHelper's private members + +public: + YamlHelper(void) : + m_hFile(NULL) + { + MakeAsciiToHexTable(); + } + + ~YamlHelper(void) + { + if (m_hFile) + fclose(m_hFile); + } + + int InitParser(const char* pPathname); + void FinaliseParser(void); + + int GetScalar(std::string& scalar); + void GetMapStartEvent(void); + +private: + void GetNextEvent(bool bInMap = false); + int ParseMap(MapYaml& mapYaml); + std::string GetMapValue(MapYaml& mapYaml, const std::string key, bool& bFound); + void LoadMemory(MapYaml& mapYaml, const LPBYTE pMemBase, const size_t kAddrSpaceSize); + bool GetSubMap(MapYaml** mapYaml, const std::string key); + void GetMapRemainder(std::string& mapName, MapYaml& mapYaml); + + void MakeAsciiToHexTable(void); + + yaml_parser_t m_parser; + yaml_event_t m_newEvent; + + std::string m_scalarName; + + FILE* m_hFile; + char m_AsciiToHex[256]; + + MapYaml m_mapYaml; +}; + +// ----- + +class YamlLoadHelper +{ +public: + YamlLoadHelper(YamlHelper& yamlHelper) + : m_yamlHelper(yamlHelper), + m_pMapYaml(&yamlHelper.m_mapYaml), + m_bIteratingOverMap(false), + m_bDoGetMapRemainder(true), + m_topLevelMapName(yamlHelper.m_scalarName), + m_currentMapName(m_topLevelMapName) + { + if (!m_yamlHelper.ParseMap(yamlHelper.m_mapYaml)) + { + m_bDoGetMapRemainder = false; + throw std::string(m_currentMapName + ": Failed to parse map"); + } + } + + ~YamlLoadHelper(void) + { + if (m_bDoGetMapRemainder) + m_yamlHelper.GetMapRemainder(m_topLevelMapName, m_yamlHelper.m_mapYaml); + } + + INT LoadInt(const std::string key); + UINT LoadUint(const std::string key); + UINT64 LoadUint64(const std::string key); + bool LoadBool(const std::string key); + std::string LoadString_NoThrow(const std::string& key, bool& bFound); + std::string LoadString(const std::string& key); + void LoadMemory(const LPBYTE pMemBase, const size_t size); + + bool GetSubMap(const std::string key) + { + YamlStackItem item = {m_pMapYaml, m_currentMapName}; + m_stackMap.push(item); + bool res = m_yamlHelper.GetSubMap(&m_pMapYaml, key); + if (!res) + m_stackMap.pop(); + else + m_currentMapName = key; + return res; + } + + void PopMap(void) + { + if (m_stackMap.empty()) + return; + + YamlStackItem item = m_stackMap.top(); + m_stackMap.pop(); + + m_pMapYaml = item.pMapYaml; + m_currentMapName = item.mapName; + } + + std::string GetMapNextSlotNumber(void) + { + if (!m_bIteratingOverMap) + { + m_iter = m_pMapYaml->begin(); + m_bIteratingOverMap = true; + } + + if (m_iter == m_pMapYaml->end()) + { + m_bIteratingOverMap = false; + return ""; + } + + std::string scalar = m_iter->first; + ++m_iter; + return scalar; + } + +private: + YamlHelper& m_yamlHelper; + MapYaml* m_pMapYaml; + bool m_bDoGetMapRemainder; + + struct YamlStackItem + { + MapYaml* pMapYaml; + std::string mapName; + }; + std::stack m_stackMap; + + std::string m_topLevelMapName; + std::string m_currentMapName; + + bool m_bIteratingOverMap; + MapYaml::iterator m_iter; +}; + +// ----- + +class YamlSaveHelper +{ +public: + YamlSaveHelper(std::string pathname) : + m_hFile(NULL), + m_indent(0) + { + m_hFile = fopen(pathname.c_str(), "wt"); + + // todo: handle ERROR_ALREADY_EXISTS - ask if user wants to replace existing file + // - at this point any old file will have been truncated to zero + + if(m_hFile == NULL) + throw std::string("Save error"); + + _tzset(); + time_t ltime; + time(<ime); + char timebuf[26]; + errno_t err = ctime_s(timebuf, sizeof(timebuf), <ime); // includes newline at end of string + fprintf(m_hFile, "# Date-stamp: %s\n", err == 0 ? timebuf : "Error: Datestamp\n\n"); + + fprintf(m_hFile, "---\n"); + + // + + memset(m_szIndent, ' ', kMaxIndent); + } + + ~YamlSaveHelper() + { + if (m_hFile) + { + fprintf(m_hFile, "...\n"); + fclose(m_hFile); + } + } + + void Save(const char* format, ...); + + void SaveInt(const char* key, int value); + void SaveUint(const char* key, UINT value); + void SaveHexUint4(const char* key, UINT value); + void SaveHexUint8(const char* key, UINT value); + void SaveHexUint12(const char* key, UINT value); + void SaveHexUint16(const char* key, UINT value); + void SaveHexUint32(const char* key, UINT value); + void SaveHexUint64(const char* key, UINT64 value); + void SaveBool(const char* key, bool value); + void SaveString(const char* key, const char* value); + void SaveMemory(const LPBYTE pMemBase, const UINT uMemSize); + + class Label + { + public: + Label(YamlSaveHelper& rYamlSaveHelper, const char* format, ...) : + yamlSaveHelper(rYamlSaveHelper) + { + fwrite(yamlSaveHelper.m_szIndent, 1, yamlSaveHelper.m_indent, yamlSaveHelper.m_hFile); + + va_list vl; + va_start(vl, format); + vfprintf(yamlSaveHelper.m_hFile, format, vl); + va_end(vl); + + yamlSaveHelper.m_indent += 2; + _ASSERT(yamlSaveHelper.m_indent < yamlSaveHelper.kMaxIndent); + } + + ~Label(void) + { + yamlSaveHelper.m_indent -= 2; + _ASSERT(yamlSaveHelper.m_indent >= 0); + } + + YamlSaveHelper& yamlSaveHelper; + }; + + class Slot : public Label + { + public: + Slot(YamlSaveHelper& rYamlSaveHelper, std::string type, UINT slot, UINT version) : + Label(rYamlSaveHelper, "%d:\n", slot) + { + rYamlSaveHelper.Save("%s: %s\n", SS_YAML_KEY_CARD, type.c_str()); + rYamlSaveHelper.Save("%s: %d\n", SS_YAML_KEY_VERSION, version); + } + + ~Slot(void) {} + }; + + void FileHdr(UINT version); + void UnitHdr(std::string type, UINT version); + +private: + FILE* m_hFile; + + int m_indent; + static const UINT kMaxIndent = 50*2; + char m_szIndent[kMaxIndent]; +}; diff --git a/source/Z80VICE/z80.cpp b/source/Z80VICE/z80.cpp index fe8cdfe6..7738cb40 100644 --- a/source/Z80VICE/z80.cpp +++ b/source/Z80VICE/z80.cpp @@ -29,6 +29,7 @@ #include "..\AppleWin.h" #include "..\CPU.h" #include "..\Memory.h" +#include "..\YamlHelper.h" #undef IN // Defined in windef.h @@ -86,16 +87,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 +167,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 +468,9 @@ static void export_registers(void) /* ------------------------------------------------------------------------- */ +// [AppleWin-TC] Z80 IRQs not supported + +#if 0 /* Interrupt handling. */ #define DO_INTERRUPT(int_kind) \ @@ -533,6 +541,7 @@ static void export_registers(void) } \ } \ } while (0) +#endif /* ------------------------------------------------------------------------- */ @@ -6330,7 +6339,7 @@ DWORD z80_mainloop(ULONG uTotalCycles, ULONG uExecutedCycles) //cpu_int_status->num_dma_per_opcode = 0; // [AppleWin-TC] Not used - if (g_ActiveCPU != CPU_Z80) // [AppleWin-TC] + if (GetActiveCpu() != CPU_Z80) // [AppleWin-TC] break; //} while (!dma_request); @@ -6422,3 +6431,139 @@ void z80_WRMEM(WORD Addr, BYTE Value) } CpuWrite( addr, Value, ConvertZ80TStatesTo6502Cycles(maincpu_clk) ); } + +//=========================================================================== + +#define SS_YAML_VALUE_CARD_Z80 "Z80" + +#define SS_YAML_KEY_REGA "A" +#define SS_YAML_KEY_REGB "B" +#define SS_YAML_KEY_REGC "C" +#define SS_YAML_KEY_REGD "D" +#define SS_YAML_KEY_REGE "E" +#define SS_YAML_KEY_REGF "F" +#define SS_YAML_KEY_REGH "H" +#define SS_YAML_KEY_REGL "L" +#define SS_YAML_KEY_REGIX "IX" +#define SS_YAML_KEY_REGIY "IY" +#define SS_YAML_KEY_REGSP "SP" +#define SS_YAML_KEY_REGPC "PC" +#define SS_YAML_KEY_REGI "I" +#define SS_YAML_KEY_REGR "R" +#define SS_YAML_KEY_IFF1 "IFF1" +#define SS_YAML_KEY_IFF2 "IFF2" +#define SS_YAML_KEY_IM_MODE "IM Mode" +#define SS_YAML_KEY_REGA2 "A'" +#define SS_YAML_KEY_REGB2 "B'" +#define SS_YAML_KEY_REGC2 "C'" +#define SS_YAML_KEY_REGD2 "D'" +#define SS_YAML_KEY_REGE2 "E'" +#define SS_YAML_KEY_REGF2 "F'" +#define SS_YAML_KEY_REGH2 "H'" +#define SS_YAML_KEY_REGL2 "L'" +#define SS_YAML_KEY_ACTIVE "Active" + +std::string Z80_GetSnapshotCardName(void) +{ + static const std::string name(SS_YAML_VALUE_CARD_Z80); + return name; +} + +void Z80_SaveSnapshot(class YamlSaveHelper& yamlSaveHelper, const UINT uSlot) +{ + YamlSaveHelper::Slot slot(yamlSaveHelper, Z80_GetSnapshotCardName(), uSlot, 1); // fixme: object should know its slot + + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); + + // 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 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. + // + + yamlSaveHelper.Save("%s: %d\n", SS_YAML_KEY_ACTIVE, GetActiveCpu() == CPU_Z80 ? 1 : 0); + + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGA, reg_a); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGB, reg_b); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGC, reg_c); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGD, reg_d); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGE, reg_e); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGF, reg_f); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGH, reg_h); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGL, reg_l); + yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_REGIX, ((USHORT)reg_ixh<<8)|(USHORT)reg_ixl); + yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_REGIY, ((USHORT)reg_iyh<<8)|(USHORT)reg_iyl); + yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_REGSP, reg_sp); + yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_REGPC, (USHORT)z80_reg_pc); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGI, reg_i); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGR, reg_r); + + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_IFF1, iff1); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_IFF2, iff2); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_IM_MODE, im_mode); + + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGA2, reg_a2); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGB2, reg_b2); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGC2, reg_c2); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGD2, reg_d2); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGE2, reg_e2); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGF2, reg_f2); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGH2, reg_h2); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGL2, reg_l2); +} + +bool Z80_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT uSlot, UINT version) +{ + if (uSlot != 4 && uSlot != 5) // fixme + throw std::string("Card: wrong slot"); + + if (version != 1) + throw std::string("Card: wrong version"); + + reg_a = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGA); + reg_b = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGB); + reg_c = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGC); + reg_d = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGD); + reg_e = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGE); + reg_f = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGF); + reg_h = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGH); + reg_l = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGL); + USHORT IX = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGIX); + reg_ixh = IX >> 8; + reg_ixl = IX & 0xFF; + USHORT IY = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGIY); + reg_iyh = IY >> 8; + reg_iyl = IY & 0xFF; + reg_sp = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGSP); + z80_reg_pc = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGPC); + reg_i = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGI); + reg_r = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGR); + + iff1 = yamlLoadHelper.LoadUint(SS_YAML_KEY_IFF1); + iff2 = yamlLoadHelper.LoadUint(SS_YAML_KEY_IFF2); + im_mode = yamlLoadHelper.LoadUint(SS_YAML_KEY_IM_MODE); + + reg_a2 = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGA2); + reg_b2 = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGB2); + reg_c2 = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGC2); + reg_d2 = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGD2); + reg_e2 = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGE2); + reg_f2 = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGF2); + reg_h2 = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGH2); + reg_l2 = yamlLoadHelper.LoadUint(SS_YAML_KEY_REGL2); + + export_registers(); + + if ( yamlLoadHelper.LoadUint(SS_YAML_KEY_ACTIVE) ) + SetActiveCpu(CPU_Z80); // Support MS SoftCard in multiple slots (only one Z80 can be active at any one time) + + return true; +} diff --git a/source/Z80VICE/z80regs.h b/source/Z80VICE/z80regs.h index 025d08fc..54c59e81 100644 --- a/source/Z80VICE/z80regs.h +++ b/source/Z80VICE/z80regs.h @@ -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 diff --git a/source/z80emu.cpp b/source/z80emu.cpp index 932711e3..01542099 100644 --- a/source/z80emu.cpp +++ b/source/z80emu.cpp @@ -16,6 +16,7 @@ #include "StdAfx.h" #include "AppleWin.h" +#include "CPU.h" #include "Memory.h" #include "z80emu.h" @@ -30,7 +31,7 @@ BYTE __stdcall CPMZ80_IONull(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULON BYTE __stdcall CPMZ80_IOWrite(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULONG nCyclesLeft) { if ((uAddr & 0xFF00) == (0xC000 + (g_uCPMZ80Slot << 8))) - g_ActiveCPU = (g_ActiveCPU == CPU_6502) ? CPU_Z80 : CPU_6502; + SetActiveCpu( GetActiveCpu() == CPU_Z80 ? GetMainCpu() : CPU_Z80 ); return IO_Null(PC, uAddr, bWrite, uValue, nCyclesLeft); } diff --git a/source/z80emu.h b/source/z80emu.h index 18d20504..3b256f0a 100644 --- a/source/z80emu.h +++ b/source/z80emu.h @@ -14,3 +14,8 @@ // Protótipos void ConfigureSoftcard(LPBYTE pCxRomPeripheral, UINT uSlot); + +// NB. These are in z80.cpp: +std::string Z80_GetSnapshotCardName(void); +void Z80_SaveSnapshot(class YamlSaveHelper& yamlSaveHelper, const UINT uSlot); +bool Z80_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT uSlot, UINT version);