diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 16380883..765ed3f5 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -47,6 +47,7 @@ add_library(appleii SHARED linux/duplicates/Joystick.cpp linux/duplicates/Frame.cpp linux/duplicates/SerialComms.cpp + linux/duplicates/Applewin.cpp Z80VICE/z80.cpp Z80VICE/z80mem.cpp diff --git a/source/frontends/ncurses/main.cpp b/source/frontends/ncurses/main.cpp index e9d1bf16..93044230 100644 --- a/source/frontends/ncurses/main.cpp +++ b/source/frontends/ncurses/main.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include @@ -37,8 +36,10 @@ namespace bool createMissingDisks; std::string snapshot; int memclear; + bool log; bool benchmark; bool headless; + bool ntsc; bool saveConfigurationOnExit; bool run; // false if options include "-h" @@ -70,7 +71,9 @@ namespace po::options_description emulatorDesc("Emulator"); emulatorDesc.add_options() + ("log", "Log to AppleWin.log") ("headless,hl", "Headless: disable video") + ("ntsc,nt", "NTSC: execute NTSC code") ("benchmark,b", "Benchmark emulator"); desc.add(emulatorDesc); @@ -113,6 +116,8 @@ namespace options.benchmark = vm.count("benchmark") > 0; options.headless = vm.count("headless") > 0; + options.log = vm.count("log") > 0; + options.ntsc = vm.count("ntsc") > 0; return true; } @@ -128,7 +133,7 @@ namespace } } - bool ContinueExecution(const bool updateVideo) + bool ContinueExecution(const EmulatorOptions & options) { const auto start = std::chrono::steady_clock::now(); @@ -144,7 +149,9 @@ namespace const DWORD uCyclesToExecute = fExecutionPeriodClks; - const bool bVideoUpdate = false; + const bool bVideoUpdate = options.ntsc; + g_bFullSpeed = !bVideoUpdate; + const DWORD uActualCyclesExecuted = CpuExecute(uCyclesToExecute, bVideoUpdate); g_dwCyclesThisFrame += uActualCyclesExecuted; @@ -156,6 +163,12 @@ namespace { case KEY_F(2): { + g_bRestart = false; + return false; + } + case KEY_F(3): + { + g_bRestart = true; return false; } case KEY_F(12): @@ -173,35 +186,39 @@ namespace const UINT dwClksPerFrame = NTSC_GetCyclesPerFrame(); if (g_dwCyclesThisFrame >= dwClksPerFrame) { - g_dwCyclesThisFrame -= dwClksPerFrame; - if (updateVideo) + g_dwCyclesThisFrame = g_dwCyclesThisFrame % dwClksPerFrame; + if (!options.headless) { VideoRedrawScreen(); } } - const auto end = std::chrono::steady_clock::now(); - const auto diff = end - start; - const long us = std::chrono::duration_cast(diff).count(); - - const double coeff = exp(-0.000001 * nExecutionPeriodUsec); // 0.36 after 1 second - - g_relativeSpeed = g_relativeSpeed * coeff + double(us) / double(nExecutionPeriodUsec) * (1.0 - coeff); - - if (!sg_Disk2Card.IsConditionForFullSpeed()) + if (!options.headless) { - if (us < nExecutionPeriodUsec) + const auto end = std::chrono::steady_clock::now(); + const auto diff = end - start; + const long us = std::chrono::duration_cast(diff).count(); + + const double coeff = exp(-0.000001 * nExecutionPeriodUsec); // 0.36 after 1 second + + g_relativeSpeed = g_relativeSpeed * coeff + double(us) / double(nExecutionPeriodUsec) * (1.0 - coeff); + + if (!sg_Disk2Card.IsConditionForFullSpeed()) { - usleep(nExecutionPeriodUsec - us); + if (us < nExecutionPeriodUsec) + { + usleep(nExecutionPeriodUsec - us); + } } } return true; } - void EnterMessageLoop(const bool updateVideo) + void EnterMessageLoop(const EmulatorOptions & options) { - while (ContinueExecution(updateVideo)) + LogFileTimeUntilFirstKeyReadReset(); + while (ContinueExecution(options)) { } } @@ -238,9 +255,6 @@ namespace int foo(int argc, const char * argv []) { - g_fh = fopen("/tmp/applewin.txt", "w"); - setbuf(g_fh, NULL); - EmulatorOptions options; options.memclear = g_nMemoryClearType; const bool run = getEmulatorOptions(argc, argv, options); @@ -248,6 +262,11 @@ namespace if (!run) return 1; + if (options.log) + { + LogInit(); + } + InitializeRegistry("applen.conf"); g_nMemoryClearType = options.memclear; @@ -296,11 +315,10 @@ namespace if (options.benchmark) { VideoBenchmark(&VideoRedrawScreen); - g_bRestart = false; } else { - EnterMessageLoop(!options.headless); + EnterMessageLoop(options); } sg_Mouse.Uninitialize(); sg_Mouse.Reset(); diff --git a/source/frontends/ncurses/world.cpp b/source/frontends/ncurses/world.cpp index 44672c2f..1de38198 100644 --- a/source/frontends/ncurses/world.cpp +++ b/source/frontends/ncurses/world.cpp @@ -369,7 +369,7 @@ void FrameRefreshStatus(int x, bool) void NVideoInitialize() { - VideoReinitialize(); + VideoInitialize(); setlocale(LC_ALL, ""); initscr(); @@ -540,6 +540,7 @@ BYTE KeybGetKeycode () BYTE KeybReadData() { + LogFileTimeUntilFirstKeyRead(); return nextKey; } diff --git a/source/linux/data.h b/source/linux/data.h index b93591da..a89eb25f 100644 --- a/source/linux/data.h +++ b/source/linux/data.h @@ -7,3 +7,6 @@ void SetWindowTitle(); void getScreenData(uint8_t * & data, int & width, int & height, int & sx, int & sy, int & sw, int & sh); extern int g_nAltCharSetOffset; // alternate character set + +void LogFileTimeUntilFirstKeyReadReset(void); +void LogFileTimeUntilFirstKeyRead(void); diff --git a/source/linux/duplicates/Applewin.cpp b/source/linux/duplicates/Applewin.cpp new file mode 100644 index 00000000..5e2d564b --- /dev/null +++ b/source/linux/duplicates/Applewin.cpp @@ -0,0 +1,40 @@ +#include "StdAfx.h" +#include "Memory.h" +#include "Log.h" +#include "Common.h" +#include "CPU.h" + +static bool bLogKeyReadDone = false; +static DWORD dwLogKeyReadTickStart; + +void LogFileTimeUntilFirstKeyReadReset(void) +{ + 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; +} diff --git a/source/linux/windows/time.cpp b/source/linux/windows/time.cpp index dd646343..397a1f59 100644 --- a/source/linux/windows/time.cpp +++ b/source/linux/windows/time.cpp @@ -19,6 +19,15 @@ DWORD timeGetTime() return now.tv_usec / 1000; } +/// Returns the number of ticks since an undefined time (usually system startup). +DWORD GetTickCount() +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + const uint64_t ticks = (uint64_t)(ts.tv_nsec / 1000000) + ((uint64_t)ts.tv_sec * 1000ull); + return ticks; +} + void GetLocalTime(SYSTEMTIME *t) { timespec ts; diff --git a/source/linux/windows/time.h b/source/linux/windows/time.h index 27103a0f..a6fe724d 100644 --- a/source/linux/windows/time.h +++ b/source/linux/windows/time.h @@ -26,4 +26,5 @@ int GetDateFormat(LCID Locale, DWORD dwFlags, CONST SYSTEMTIME *lpDate, LPCSTR l int GetTimeFormat(LCID Locale, DWORD dwFlags, CONST SYSTEMTIME *lpTime, LPCSTR lpFormat, LPSTR lpTimeStr, int cchTime); DWORD timeGetTime(); +DWORD GetTickCount(); void GetLocalTime(SYSTEMTIME *t);