Files
AppleWin/source/Utilities.cpp
T
Kelvin Lee 926c592f75 Replace some BOOL usages with proper bool (PR #1500)
1. Registry functions
   The set of functions are changed to consistently use bool arguments.
   The macros are changed to inline functions to improve type checking.
   RegSaveValue() are overloaded with help of templates to reduce
   typecasting at call sites. For instance, bool value would be converted
   consistently instead of relying on call sites to convert bool to int values.
2. Memory functions
   BOOL usages were unnecessary. Mostly internal usages which can simply be bool.
3. FrameBase
   Some member variables are changed to bool.
   BOOL was used because of those Registry functions.

Additional changes:
- Some expressions are forced to be bool when assigning to bool variables.
2026-06-06 14:12:42 +01:00

605 lines
18 KiB
C++

/*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
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: main
*
* Author: Various
*/
#include "StdAfx.h"
#include "Utilities.h"
#include "Core.h"
#include "CardManager.h"
#include "CPU.h"
#include "Joystick.h"
#include "Log.h"
#include "ParallelPrinter.h"
#include "Registry.h"
#include "Riff.h"
#include "SaveState.h"
#include "Speaker.h"
#include "Memory.h"
#include "Pravets.h"
#include "Keyboard.h"
#include "Interface.h"
#include "SoundCore.h"
#include "CopyProtectionDongles.h"
#include "Configuration/IPropertySheet.h"
#include "Tfe/PCapBackend.h"
#ifdef USE_SPEECH_API
#include "Speech.h"
#endif
// Backwards compatibility with AppleWin <1.24.0
static void LoadConfigOldJoystick_v1(const UINT uJoyNum)
{
uint32_t dwOldJoyType;
if (!REGLOAD(uJoyNum==0 ? REGVALUE_OLD_JOYSTICK0_EMU_TYPE1 : REGVALUE_OLD_JOYSTICK1_EMU_TYPE1, &dwOldJoyType))
return; // EG. Old AppleWin never installed
UINT uNewJoyType;
switch (dwOldJoyType)
{
case 0: // Disabled
default:
uNewJoyType = J0C_DISABLED;
break;
case 1: // PC Joystick
uNewJoyType = J0C_JOYSTICK1;
break;
case 2: // Keyboard (standard)
uNewJoyType = J0C_KEYBD_NUMPAD;
GetPropertySheet().SetJoystickCenteringControl(JOYSTICK_MODE_FLOATING);
break;
case 3: // Keyboard (centering)
uNewJoyType = J0C_KEYBD_NUMPAD;
GetPropertySheet().SetJoystickCenteringControl(JOYSTICK_MODE_CENTERING);
break;
case 4: // Mouse
uNewJoyType = J0C_MOUSE;
break;
}
JoySetJoyType(uJoyNum, uNewJoyType);
}
// Reads configuration from the registry entries
//
// NB. loadImages=false if loading a save-state from cmd-line afterwards
// - Registry images may have been deleted from disk, so avoid the MessageBox
void LoadConfiguration(bool loadImages)
{
uint32_t dwComputerType = 0;
eApple2Type apple2Type = A2TYPE_APPLE2EENHANCED;
if (REGLOAD(REGVALUE_APPLE2_TYPE, &dwComputerType))
{
const uint32_t dwLoadedComputerType = dwComputerType;
if ( (dwComputerType >= A2TYPE_MAX) ||
(dwComputerType >= A2TYPE_UNDEFINED && dwComputerType < A2TYPE_CLONE) ||
(dwComputerType >= A2TYPE_CLONE_A2_MAX && dwComputerType < A2TYPE_CLONE_A2E) )
dwComputerType = A2TYPE_APPLE2EENHANCED;
// Remap the bad Pravets models (before AppleWin v1.26)
if (dwComputerType == A2TYPE_BAD_PRAVETS82) dwComputerType = A2TYPE_PRAVETS82;
if (dwComputerType == A2TYPE_BAD_PRAVETS8M) dwComputerType = A2TYPE_PRAVETS8M;
// Remap the bad Pravets models (at AppleWin v1.26) - GH#415
if (dwComputerType == A2TYPE_CLONE) dwComputerType = A2TYPE_PRAVETS82;
if (dwLoadedComputerType != dwComputerType)
{
std::string strText = StrFormat("Unsupported Apple2Type(%d). Changing to %d", dwLoadedComputerType, dwComputerType);
LogFileOutput("%s\n", strText.c_str());
GetFrame().FrameMessageBox(strText.c_str(),
"Load Configuration",
MB_ICONSTOP | MB_SETFOREGROUND);
GetPropertySheet().ConfigSaveApple2Type((eApple2Type)dwComputerType);
}
apple2Type = (eApple2Type) dwComputerType;
}
else if (REGLOAD(REGVALUE_OLD_APPLE2_TYPE, &dwComputerType)) // Support older AppleWin registry entries
{
switch (dwComputerType)
{
// NB. No A2TYPE_APPLE2E (this is correct)
case 0: apple2Type = A2TYPE_APPLE2; break;
case 1: apple2Type = A2TYPE_APPLE2PLUS; break;
case 2: apple2Type = A2TYPE_APPLE2EENHANCED; break;
default: apple2Type = A2TYPE_APPLE2EENHANCED; break;
}
}
SetApple2Type(apple2Type);
//
uint32_t dwMainCpuType;
REGLOAD_DEFAULT(REGVALUE_CPU_TYPE, &dwMainCpuType, CPU_65C02);
if (dwMainCpuType != CPU_6502 && dwMainCpuType != CPU_65C02)
dwMainCpuType = CPU_65C02;
SetMainCpu((eCpuType)dwMainCpuType);
//
uint32_t dwJoyType;
if (REGLOAD(REGVALUE_JOYSTICK0_EMU_TYPE, &dwJoyType))
JoySetJoyType(JN_JOYSTICK0, dwJoyType);
else if (REGLOAD(REGVALUE_OLD_JOYSTICK0_EMU_TYPE2, &dwJoyType)) // GH#434
JoySetJoyType(JN_JOYSTICK0, dwJoyType);
else
LoadConfigOldJoystick_v1(JN_JOYSTICK0);
if (REGLOAD(REGVALUE_JOYSTICK1_EMU_TYPE, &dwJoyType))
JoySetJoyType(JN_JOYSTICK1, dwJoyType);
else if (REGLOAD(REGVALUE_OLD_JOYSTICK1_EMU_TYPE2, &dwJoyType)) // GH#434
JoySetJoyType(JN_JOYSTICK1, dwJoyType);
else
LoadConfigOldJoystick_v1(JN_JOYSTICK1);
uint32_t copyProtectionDongleType;
std::string regSection = RegGetConfigSlotSection(GAME_IO_CONNECTOR);
if (RegLoadValue(regSection.c_str(), REGVALUE_GAME_IO_TYPE, true, &copyProtectionDongleType))
SetCopyProtectionDongleType((DONGLETYPE)copyProtectionDongleType);
else
SetCopyProtectionDongleType(DT_EMPTY);
REGLOAD_DEFAULT(REGVALUE_EMULATION_SPEED, &g_dwSpeed, SPEED_NORMAL);
GetVideo().Config_Load_Video();
SetCurrentCLK6502(); // Pre: g_dwSpeed && Config_Load_Video()->SetVideoRefreshRate()
//
uint32_t dwTmp = 0;
if(REGLOAD(REGVALUE_FS_SHOW_SUBUNIT_STATUS, &dwTmp))
GetFrame().SetFullScreenShowSubunitStatus(dwTmp ? true : false);
if (REGLOAD(REGVALUE_SHOW_DISKII_STATUS, &dwTmp))
GetFrame().SetWindowedModeShowDiskiiStatus(dwTmp ? true : false);
if(REGLOAD(REGVALUE_THE_FREEZES_F8_ROM, &dwTmp))
GetPropertySheet().SetTheFreezesF8Rom(dwTmp);
if(REGLOAD(REGVALUE_SAVE_STATE_ON_EXIT, &dwTmp))
SetSaveStateOnExit(dwTmp ? true : false);
if(REGLOAD(REGVALUE_PDL_XTRIM, &dwTmp))
JoySetTrim((short)dwTmp, true);
if(REGLOAD(REGVALUE_PDL_YTRIM, &dwTmp))
JoySetTrim((short)dwTmp, false);
if(REGLOAD(REGVALUE_SCROLLLOCK_TOGGLE, &dwTmp))
GetPropertySheet().SetScrollLockToggle(dwTmp);
if(REGLOAD(REGVALUE_CURSOR_CONTROL, &dwTmp))
GetPropertySheet().SetJoystickCursorControl(dwTmp);
if(REGLOAD(REGVALUE_AUTOFIRE, &dwTmp))
GetPropertySheet().SetAutofire(dwTmp);
if(REGLOAD(REGVALUE_SWAP_BUTTONS_0_AND_1, &dwTmp))
GetPropertySheet().SetButtonsSwapState(dwTmp ? true : false);
if(REGLOAD(REGVALUE_CENTERING_CONTROL, &dwTmp))
GetPropertySheet().SetJoystickCenteringControl(dwTmp);
if(REGLOAD(REGVALUE_MOUSE_CROSSHAIR, &dwTmp))
GetPropertySheet().SetMouseShowCrosshair(dwTmp);
if(REGLOAD(REGVALUE_MOUSE_RESTRICT_TO_WINDOW, &dwTmp))
GetPropertySheet().SetMouseRestrictToWindow(dwTmp);
//
char szFilename[MAX_PATH];
//
for (UINT slot = SLOT0; slot < NUM_SLOTS; slot++)
{
std::string regSection = RegGetConfigSlotSection(slot);
if (RegLoadValue(regSection.c_str(), REGVALUE_CARD_TYPE, true, &dwTmp))
{
if (slot == SLOT0)
SetExpansionMemType((SS_CARDTYPE)dwTmp, false);
else
GetCardMgr().Insert(slot, (SS_CARDTYPE)dwTmp, false);
}
else // new install or legacy (AppleWin 1.30.3 or earlier)
{
// New install:
GetCardMgr().Insert(slot, GetCardMgr().QueryDefaultCardForSlot(slot, GetApple2Type()));
// Legacy:
if (slot == SLOT3)
{
RegLoadString(REG_CONFIG, REGVALUE_UTHERNET_INTERFACE, true, szFilename, MAX_PATH, "");
// copy it to the new location
PCapBackend::SetRegistryInterface(slot, szFilename);
uint32_t tfeEnabled;
REGLOAD_DEFAULT(REGVALUE_UTHERNET_ACTIVE, &tfeEnabled, 0);
GetCardMgr().Insert(SLOT3, tfeEnabled ? CT_Uthernet : CT_Empty);
}
else if (slot == SLOT4 && REGLOAD(REGVALUE_SLOT4, &dwTmp))
GetCardMgr().Insert(SLOT4, (SS_CARDTYPE)dwTmp);
else if (slot == SLOT5 && REGLOAD(REGVALUE_SLOT5, &dwTmp))
GetCardMgr().Insert(SLOT5, (SS_CARDTYPE)dwTmp);
else if (slot == SLOT7 && REGLOAD(REGVALUE_HDD_ENABLED, &dwTmp) && dwTmp == 1) // GH#1015
GetCardMgr().Insert(SLOT7, CT_GenericHDD);
}
}
// Aux slot
if (IsAppleIIe(GetApple2Type()))
{
std::string regSection = RegGetConfigSlotSection(SLOT_AUX);
if (RegLoadValue(regSection.c_str(), REGVALUE_CARD_TYPE, true, &dwTmp))
{
SS_CARDTYPE type = (SS_CARDTYPE)dwTmp;
const bool noUpdateRegistry = false;
GetCardMgr().InsertAux(type, noUpdateRegistry);
SetExpansionMemType(type, noUpdateRegistry);
RegLoadValue(regSection.c_str(), REGVALUE_AUX_NUM_BANKS, true, &dwTmp, kDefaultExMemoryBanksRealRW3);
SetRamWorksMemorySize(dwTmp, noUpdateRegistry);
}
else // new install or legacy
{
const bool noUpdateRegistry = false;
GetCardMgr().InsertAux(CT_Extended80Col, noUpdateRegistry);
}
}
if (REGLOAD(REGVALUE_MASTER_VOLUME, &dwTmp) || // Try MASTER_VOLUME
REGLOAD(REGVALUE_SPKR_VOLUME, &dwTmp)) // ...else try older SPKR_VOLUME
{
SpkrSetVolume(dwTmp, GetPropertySheet().GetVolumeMax());
GetCardMgr().GetMockingboardCardMgr().SetVolume(dwTmp, GetPropertySheet().GetVolumeMax());
}
// Load save-state pathname *before* inserting any harddisk/disk images (for both init & reinit cases)
// NB. inserting harddisk/disk can change snapshot pathname
RegLoadString(REG_CONFIG, REGVALUE_SAVESTATE_FILENAME, true, szFilename, MAX_PATH, ""); // Can be pathname or just filename
Snapshot_SetFilename(szFilename); // If not in Registry than default will be used (ie. g_sCurrentDir + default filename)
//
RegLoadString(REG_PREFS, REGVALUE_PREF_HDV_START_DIR, true, szFilename, MAX_PATH, "");
if (szFilename[0] == '\0')
GetCurrentDirectory(sizeof(szFilename), szFilename);
SetCurrentImageDir(szFilename);
if (loadImages)
{
for (UINT slot = SLOT1; slot < NUM_SLOTS; slot++)
{
if (GetCardMgr().QuerySlot(slot) == CT_GenericHDD)
{
HarddiskInterfaceCard& card = dynamic_cast<HarddiskInterfaceCard&>(GetCardMgr().GetRef(slot));
for (UINT i = HARDDISK_1; i < NUM_HARDDISKS; i++)
{
card.LoadLastDiskImage(i);
}
}
}
}
//
// Current/Starting Dir is the "root" of where the user keeps their disk images
RegLoadString(REG_PREFS, REGVALUE_PREF_START_DIR, true, szFilename, MAX_PATH, "");
if (szFilename[0] == '\0')
GetCurrentDirectory(sizeof(szFilename), szFilename);
SetCurrentImageDir(szFilename);
if (loadImages)
GetCardMgr().GetDisk2CardMgr().LoadLastDiskImage();
// Do this after populating the slots with Disk II controller(s)
uint32_t dwEnhanceDisk;
REGLOAD_DEFAULT(REGVALUE_ENHANCE_DISK_SPEED, &dwEnhanceDisk, 1);
GetCardMgr().GetDisk2CardMgr().SetEnhanceDisk(dwEnhanceDisk ? true : false);
//
if (GetCardMgr().IsParallelPrinterCardInstalled())
GetCardMgr().GetParallelPrinterCard()->GetRegistryConfig();
//
if (REGLOAD(REGVALUE_WINDOW_SCALE, &dwTmp))
GetFrame().SetViewportScale(dwTmp);
if (REGLOAD(REGVALUE_CONFIRM_REBOOT, &dwTmp))
GetFrame().g_bConfirmReboot = !!dwTmp;
}
static std::string GetFullPath(LPCSTR szFileName)
{
std::string strPathName;
if (szFileName[0] == PATH_SEPARATOR || szFileName[1] == ':')
{
// Abs pathname
strPathName = szFileName;
}
else
{
// Rel pathname (GH#663)
strPathName = g_sStartDir;
strPathName.append(szFileName);
}
return strPathName;
}
static void SetCurrentDir(const std::string & pathname)
{
// Due to the order HDDs/disks are inserted, then s7 insertions take priority over s6 & s5; and d2 takes priority over d1:
// . if -s6[dN] and -hN are specified, then g_sCurrentDir will be set to the HDD image's path
// . if -s5[dN] and -s6[dN] are specified, then g_sCurrentDir will be set to the s6 image's path
// . if -[sN]d1 and -[sN]d2 are specified, then g_sCurrentDir will be set to the d2 image's path
// This is purely dependent on the current order of InsertFloppyDisks() & InsertHardDisks() - ie. very brittle!
// . better to use -current-dir to be explicit
std::size_t found = pathname.find_last_of(PATH_SEPARATOR);
std::string path = pathname.substr(0, found);
SetCurrentImageDir(path);
}
static bool DoDiskInsert(const UINT slot, const int nDrive, LPCSTR szFileName)
{
Disk2InterfaceCard& card = dynamic_cast<Disk2InterfaceCard&>(GetCardMgr().GetRef(slot));
if (szFileName[0] == '\0')
{
card.EjectDisk(nDrive);
return true;
}
std::string strPathName = GetFullPath(szFileName);
if (strPathName.empty()) return false;
ImageError_e Error = card.InsertDisk(nDrive, strPathName, IMAGE_USE_FILES_WRITE_PROTECT_STATUS, IMAGE_DONT_CREATE);
bool res = (Error == eIMAGE_ERROR_NONE);
if (res)
SetCurrentDir(strPathName);
return res;
}
static bool DoHardDiskInsert(const UINT slot, const int nDrive, LPCSTR szFileName)
{
HarddiskInterfaceCard& card = dynamic_cast<HarddiskInterfaceCard&>(GetCardMgr().GetRef(slot));
if (szFileName[0] == '\0')
{
card.Unplug(nDrive);
return true;
}
std::string strPathName = GetFullPath(szFileName);
if (strPathName.empty()) return false;
BOOL bRes = card.Insert(nDrive, strPathName);
bool res = (bRes == TRUE);
if (res)
SetCurrentDir(strPathName);
return res;
}
void InsertFloppyDisks(const UINT slot, LPCSTR szImageName_drive[NUM_DRIVES], bool driveConnected[NUM_DRIVES], bool& bBoot)
{
// If no FDDs then just return (and don't insert an FDC into this slot)
bool res = true;
for (UINT i = DRIVE_1; i < NUM_DRIVES; i++)
res &= szImageName_drive[i] == NULL;
if (res)
return;
if (GetCardMgr().QuerySlot(slot) != CT_Disk2)
GetCardMgr().Insert(slot, CT_Disk2); // Enable the Floppy drive controller card
res = true;
for (UINT i = DRIVE_1; i < NUM_DRIVES; i++)
{
if (!driveConnected[i])
{
dynamic_cast<Disk2InterfaceCard&>(GetCardMgr().GetRef(slot)).UnplugDrive(i);
}
else if (szImageName_drive[i])
{
res = DoDiskInsert(slot, i, szImageName_drive[i]);
LogFileOutput("Init: S%d, DoDiskInsert(D%d), res=%d\n", slot, i+1, res);
if (i == DRIVE_1)
{
GetFrame().FrameRefreshStatus(DRAW_LEDS | DRAW_BUTTON_DRIVES | DRAW_DISK_STATUS); // floppy activity LEDs and floppy buttons
bBoot = true;
}
}
}
if (!res)
GetFrame().FrameMessageBox("Failed to insert floppy disk(s) - see log file", "Warning", MB_ICONASTERISK | MB_OK);
}
void InsertHardDisks(const UINT slot, LPCSTR szImageName_harddisk[NUM_HARDDISKS], bool& bBoot)
{
// If no HDDs then just return (and don't insert an HDC into this slot)
bool res = true;
for (UINT i = HARDDISK_1; i < NUM_HARDDISKS; i++)
res &= szImageName_harddisk[i] == NULL;
if (res)
return;
if (GetCardMgr().QuerySlot(slot) != CT_GenericHDD)
GetCardMgr().Insert(slot, CT_GenericHDD); // Enable the Harddisk controller card
res = true;
for (UINT i = HARDDISK_1; i < NUM_HARDDISKS; i++)
{
if (szImageName_harddisk[i])
{
res &= DoHardDiskInsert(slot, i, szImageName_harddisk[i]);
LogFileOutput("Init: DoHardDiskInsert(HDD-%d), res=%d\n", i, res);
if (i == HARDDISK_1)
{
GetFrame().FrameRefreshStatus(DRAW_LEDS | DRAW_DISK_STATUS); // harddisk activity LED
bBoot = true;
}
}
}
if (!res)
GetFrame().FrameMessageBox("Failed to insert harddisk(s) - see log file", "Warning", MB_ICONASTERISK | MB_OK);
}
void GetAppleWindowTitle()
{
switch (g_Apple2Type)
{
default:
case A2TYPE_APPLE2: g_pAppTitle = TITLE_APPLE_2; break;
case A2TYPE_APPLE2PLUS: g_pAppTitle = TITLE_APPLE_2_PLUS; break;
case A2TYPE_APPLE2JPLUS: g_pAppTitle = TITLE_APPLE_2_JPLUS; break;
case A2TYPE_APPLE2E: g_pAppTitle = TITLE_APPLE_2E; break;
case A2TYPE_APPLE2EENHANCED: g_pAppTitle = TITLE_APPLE_2E_ENHANCED; break;
case A2TYPE_PRAVETS82: g_pAppTitle = TITLE_PRAVETS_82; break;
case A2TYPE_PRAVETS8M: g_pAppTitle = TITLE_PRAVETS_8M; break;
case A2TYPE_PRAVETS8A: g_pAppTitle = TITLE_PRAVETS_8A; break;
case A2TYPE_TK30002E: g_pAppTitle = TITLE_TK3000_2E; break;
case A2TYPE_BASE64A: g_pAppTitle = TITLE_BASE64A; break;
}
#if _DEBUG
g_pAppTitle += " *DEBUG* ";
#endif
if (g_nAppMode == MODE_LOGO)
return;
g_pAppTitle += " - ";
if (GetVideo().IsVideoStyle(VS_HALF_SCANLINES))
g_pAppTitle += " 50% ";
g_pAppTitle += GetVideo().VideoGetAppWindowTitle();
if (GetCardMgr().GetDisk2CardMgr().IsAnyFirmware13Sector())
g_pAppTitle += " (S6-13) ";
if (g_hCustomRomF8 != INVALID_HANDLE_VALUE)
g_pAppTitle += " (custom rom)";
else if (GetPropertySheet().GetTheFreezesF8Rom() && IsApple2PlusOrClone(GetApple2Type()))
g_pAppTitle += " (The Freeze's non-autostart F8 rom)";
switch (g_nAppMode)
{
case MODE_PAUSED: g_pAppTitle += std::string(" [") + TITLE_PAUSED + "]"; break;
case MODE_STEPPING: g_pAppTitle += std::string(" [") + TITLE_STEPPING + "]"; break;
}
}
//===========================================================================
// CtrlReset() vs ResetMachineState():
// . CPU:
// Ctrl+Reset : 6502.sp=-3 / CpuReset()
// Power cycle: 6502.sp=0x1ff / CpuInitialize()
// . Disk][:
// Ctrl+Reset : if motor-on, then motor-off but continue to spin for 1s
// Power cycle: motor-off & immediately stop spinning
// todo: consolidate CtrlReset() and ResetMachineState()
void ResetMachineState()
{
LogFileOutput("Apple II power-cycle\n");
GetCardMgr().Reset(true);
g_bFullSpeed = 0; // Might've hit reset in middle of InternalCpuExecute() - so beep may get (partially) muted
MemReset(); // calls CpuInitialize(), CNoSlotClock.Reset()
GetPravets().Reset();
if (GetCardMgr().QuerySlot(SLOT6) == CT_Disk2)
dynamic_cast<Disk2InterfaceCard&>(GetCardMgr().GetRef(SLOT6)).Boot();
GetVideo().VideoResetState();
KeybReset();
JoyReset();
SpkrReset();
SetActiveCpu(GetMainCpu());
#ifdef USE_SPEECH_API
g_Speech.Reset();
#endif
SoundCore_SetFade(FADE_NONE);
LogFileTimeUntilFirstKeyReadReset();
}
//===========================================================================
/*
* In comments, UTAII is an abbreviation for a reference to "Understanding the Apple II" by James Sather
*/
// todo: consolidate CtrlReset() and ResetMachineState()
void CtrlReset()
{
if (IsAppleIIeOrAbove(GetApple2Type()))
{
// NB. RamWorks III manual (v1.41, pg 45):
// "The bank select register is initialized to zero on a power-up, but not after a reset."
// For A][ & A][+, reset doesn't reset the LC switches (UTAII:5-29)
// TODO: What about Saturn cards? Presumably the same as the A][ & A][+ slot0 LC?
MemResetPaging();
// For A][ & A][+, reset doesn't reset the video mode (UTAII:4-4)
GetVideo().VideoResetState(); // Switch Alternate char set off
}
if (IsAppleIIeOrAbove(GetApple2Type()) || IsCopamBase64A(GetApple2Type()))
{
// For A][ & A][+, reset doesn't reset the annunciators (UTAIIe:I-5)
// Base 64A: on RESET does reset to ROM page 0 (GH#807)
MemAnnunciatorReset();
}
GetPravets().Reset();
GetCardMgr().Reset(false);
KeybReset();
#ifdef USE_SPEECH_API
g_Speech.Reset();
#endif
CpuReset();
GetFrame().g_bFreshReset = true;
}