/* 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 "Core.h" #include "CardManager.h" #include "CPU.h" #include "Interface.h" #include "Log.h" #include "Memory.h" #include "Pravets.h" #include "Speaker.h" #include "Registry.h" #include "SynchronousEventManager.h" #ifdef USE_SPEECH_API #include "Speech.h" #endif static UINT16 g_OldAppleWinVersion[4] = { 0 }; UINT16 g_AppleWinVersion[4] = { 0 }; std::string g_VERSIONSTRING = "xx.yy.zz.ww"; std::string g_pAppTitle; eApple2Type g_Apple2Type = A2TYPE_APPLE2EENHANCED; bool g_bFullSpeed = false; //================================================= AppMode_e g_nAppMode = MODE_LOGO; std::string g_sStartDir; // NB. AppleWin.exe maybe relative to this! (GH#663) std::string g_sProgramDir; // Directory of where AppleWin executable resides std::string g_sCurrentDir; // Also Starting Dir. Debugger uses this when load/save std::string g_sBuiltinSymbolsDir; // Alternate directory for built-in debug symbols bool g_bRestart = false; bool g_bDisableDirectInput = false; bool g_bDisableDirectSound = false; bool g_bDisableDirectSoundMockingboard = false; DWORD g_dwSpeed = SPEED_NORMAL; // Affected by Config dialog's speed slider bar double g_fCurrentCLK6502 = CLK_6502_NTSC; // Affected by Config dialog's speed slider bar static double g_fMHz = 1.0; // Affected by Config dialog's speed slider bar int g_nCpuCyclesFeedback = 0; DWORD g_dwCyclesThisFrame = 0; int g_nMemoryClearType = MIP_FF_FF_00_00; // Note: -1 = random MIP in Memory.cpp MemReset() SynchronousEventManager g_SynchronousEventMgr; HANDLE g_hCustomRomF8 = INVALID_HANDLE_VALUE; // Cmd-line specified custom F8 ROM at $F800..$FFFF bool g_bCustomRomF8Failed = false; // Set if custom F8 ROM file failed HANDLE g_hCustomRom = INVALID_HANDLE_VALUE; // Cmd-line specified custom ROM at $C000..$FFFF(16KiB) or $D000..$FFFF(12KiB) bool g_bCustomRomFailed = false; // Set if custom ROM file failed bool g_bEnableSpeech = false; #ifdef USE_SPEECH_API CSpeech g_Speech; #endif //=========================================================================== #ifdef LOG_PERF_TIMINGS static UINT64 g_timeTotal = 0; UINT64 g_timeCpu = 0; UINT64 g_timeVideo = 0; // part of timeCpu UINT64 g_timeMB_Timer = 0; // part of timeCpu UINT64 g_timeMB_NoTimer = 0; UINT64 g_timeSpeaker = 0; static UINT64 g_timeVideoRefresh = 0; void LogPerfTimings(void) { if (g_timeTotal) { UINT64 cpu = g_timeCpu - g_timeVideo - g_timeMB_Timer; UINT64 video = g_timeVideo + g_timeVideoRefresh; UINT64 spkr = g_timeSpeaker; UINT64 mb = g_timeMB_Timer + g_timeMB_NoTimer; UINT64 audio = spkr + mb; UINT64 other = g_timeTotal - g_timeCpu - g_timeSpeaker - g_timeMB_NoTimer - g_timeVideoRefresh; LogOutput("Perf breakdown:\n"); LogOutput(". CPU %% = %6.2f\n", (double)cpu / (double)g_timeTotal * 100.0); LogOutput(". Video %% = %6.2f\n", (double)video / (double)g_timeTotal * 100.0); LogOutput("... NTSC %% = %6.2f\n", (double)g_timeVideo / (double)g_timeTotal * 100.0); LogOutput("... refresh %% = %6.2f\n", (double)g_timeVideoRefresh / (double)g_timeTotal * 100.0); LogOutput(". Audio %% = %6.2f\n", (double)audio / (double)g_timeTotal * 100.0); LogOutput("... Speaker %% = %6.2f\n", (double)spkr / (double)g_timeTotal * 100.0); LogOutput("... MB %% = %6.2f\n", (double)mb / (double)g_timeTotal * 100.0); LogOutput(". Other %% = %6.2f\n", (double)other / (double)g_timeTotal * 100.0); LogOutput(". TOTAL %% = %6.2f\n", (double)(cpu+video+audio+other) / (double)g_timeTotal * 100.0); } } #endif //=========================================================================== static DWORD dwLogKeyReadTickStart; static bool bLogKeyReadDone = false; void LogFileTimeUntilFirstKeyReadReset(void) { #ifdef LOG_PERF_TIMINGS LogPerfTimings(); #endif if (!g_fh) return; dwLogKeyReadTickStart = GetTickCount(); bLogKeyReadDone = false; } // Log the time from emulation restart/reboot until the first key read: BIT $C000 // . AZTEC.DSK (DOS 3.3) does prior LDY $C000 reads, but the BIT $C000 is at the "Press any key" message // . Phasor1.dsk / ProDOS 1.1.1: PC=E797: B1 50: LDA ($50),Y / "Select an Option:" message // . Rescue Raiders v1.3,v1.5: PC=895: LDA $C000 / boot to intro void LogFileTimeUntilFirstKeyRead(void) { if (!g_fh || bLogKeyReadDone) return; if ( (mem[regs.pc-3] != 0x2C) // AZTEC: bit $c000 && !((regs.pc-2) == 0xE797 && mem[regs.pc-2] == 0xB1 && mem[regs.pc-1] == 0x50) // Phasor1: lda ($50),y && !((regs.pc-3) == 0x0895 && mem[regs.pc-3] == 0xAD) // Rescue Raiders v1.3,v1.5: lda $c000 ) return; DWORD dwTime = GetTickCount() - dwLogKeyReadTickStart; LogFileOutput("Time from emulation reboot until first $C000 access: %d msec\n", dwTime); bLogKeyReadDone = true; } //--------------------------------------------------------------------------- eApple2Type GetApple2Type(void) { return g_Apple2Type; } void SetApple2Type(eApple2Type type) { g_Apple2Type = type; SetMainCpuDefault(type); } const UINT16* GetOldAppleWinVersion(void) { return g_OldAppleWinVersion; } CardManager& GetCardMgr(void) { static CardManager g_CardMgr; // singleton return g_CardMgr; } //=========================================================================== double Get6502BaseClock(void) { return (GetVideo().GetVideoRefreshRate() == VR_50HZ) ? CLK_6502_PAL : CLK_6502_NTSC; } void SetCurrentCLK6502(void) { static DWORD dwPrevSpeed = (DWORD) -1; static VideoRefreshRate_e prevVideoRefreshRate = VR_NONE; if (dwPrevSpeed == g_dwSpeed && GetVideo().GetVideoRefreshRate() == prevVideoRefreshRate) return; dwPrevSpeed = g_dwSpeed; prevVideoRefreshRate = GetVideo().GetVideoRefreshRate(); // SPEED_MIN = 0 = 0.50 MHz // SPEED_NORMAL = 10 = 1.00 MHz // 20 = 2.00 MHz // SPEED_MAX-1 = 39 = 3.90 MHz // SPEED_MAX = 40 = ???? MHz (run full-speed, /g_fCurrentCLK6502/ is ignored) if(g_dwSpeed < SPEED_NORMAL) g_fMHz = 0.5 + (double)g_dwSpeed * 0.05; else g_fMHz = (double)g_dwSpeed / 10.0; g_fCurrentCLK6502 = Get6502BaseClock() * g_fMHz; // // Now re-init modules that are dependent on /g_fCurrentCLK6502/ // SpkrReinitialize(); GetCardMgr().GetMockingboardCardMgr().ReinitializeClock(); } void UseClockMultiplier(double clockMultiplier) { if (clockMultiplier == 0.0) return; if (clockMultiplier < 1.0) { if (clockMultiplier < 0.5) clockMultiplier = 0.5; g_dwSpeed = (ULONG)((clockMultiplier - 0.5) * 20); // [0.5..0.9] -> [0..9] } else { g_dwSpeed = (ULONG)(clockMultiplier * 10); if (g_dwSpeed >= SPEED_MAX) g_dwSpeed = SPEED_MAX - 1; } SetCurrentCLK6502(); } void SetAppleWinVersion(UINT16 major, UINT16 minor, UINT16 fix, UINT16 fix_minor) { g_AppleWinVersion[0] = major; g_AppleWinVersion[1] = minor; g_AppleWinVersion[2] = fix; g_AppleWinVersion[3] = fix_minor; g_VERSIONSTRING = StrFormat("%d.%d.%d.%d", major, minor, fix, fix_minor); } bool CheckOldAppleWinVersion(void) { const int VERSIONSTRING_SIZE = 16; char szOldAppleWinVersion[VERSIONSTRING_SIZE + 1]; RegLoadString(REG_CONFIG, REGVALUE_VERSION, TRUE, szOldAppleWinVersion, VERSIONSTRING_SIZE, ""); const bool bShowAboutDlg = (g_VERSIONSTRING != szOldAppleWinVersion); // version: xx.yy.zz.ww char* p0 = szOldAppleWinVersion; int len = strlen(szOldAppleWinVersion); szOldAppleWinVersion[len] = '.'; // append a null terminator szOldAppleWinVersion[len + 1] = '\0'; for (UINT i = 0; i < 4; i++) { char* p1 = strstr(p0, "."); if (!p1) break; *p1 = 0; g_OldAppleWinVersion[i] = atoi(p0); p0 = p1 + 1; } return bShowAboutDlg; } bool SetCurrentImageDir(const std::string& pszImageDir) { g_sCurrentDir = pszImageDir; if (!g_sCurrentDir.empty() && *g_sCurrentDir.rbegin() != PATH_SEPARATOR) g_sCurrentDir += PATH_SEPARATOR; if (SetCurrentDirectory(g_sCurrentDir.c_str())) return true; return false; } Pravets& GetPravets(void) { static Pravets pravets; return pravets; }