// Funções: //=========================================================================== void ContinueExecution () { static DWORD dwVideoUpdateTick = 0; static BOOL pageflipping = 0; //? int nNumCyclesPerFrame = 23191; DWORD nCyclesToExecute; DWORD executedcycles; DWORD CLKS_PER_MS; BOOL diskspinning; BOOL screenupdated; BOOL systemidle; fullspeed = ( (speed == SPEED_MAX) || (GetKeyState(VK_SCROLL) < 0) || (ColarRapido && KeybIsPasting()) || (DiskIsSpinning() && enhancedisk)); if(fullspeed) { Timer_StopTimer(); } else { Timer_StartTimer((ULONG)((double)nNumCyclesPerFrame / g_fMHz)); } nCyclesToExecute = nNumCyclesPerFrame + g_nCpuCyclesFeedback; executedcycles = CpuExecute(nCyclesToExecute); cyclenum = executedcycles; // Atualizações: KeybAtualiza(executedcycles); DiskUpdatePosition(executedcycles); JoyUpdatePosition(executedcycles); // VideoUpdateVbl(executedcycles, 0); /* TO DO: nearrefresh */ // HDAtualiza(executedcycles); // IDEAtualiza(executedcycles); // TKClockAtualiza(executedcycles); TapeAtualiza(executedcycles); // CommUpdate(executedcycles); ImpressoraAtualiza(executedcycles); SpkrUpdate(executedcycles); CLKS_PER_MS = (DWORD)g_fCurrentCLK6502 / 1000; emulmsec_frac += executedcycles; if(emulmsec_frac > CLKS_PER_MS) { emulmsec += emulmsec_frac / CLKS_PER_MS; emulmsec_frac %= CLKS_PER_MS; } // // DETERMINE WHETHER THE SCREEN WAS UPDATED, THE DISK WAS SPINNING, // OR THE KEYBOARD I/O PORTS WERE BEING EXCESSIVELY QUERIED THIS CLOCKTICK VideoCheckPage(0); diskspinning = DiskIsSpinning(); screenupdated = VideoHasRefreshed(); systemidle = 0; if(screenupdated) pageflipping = 3; // // IF A TWENTIETH OF A SECOND HAS ELAPSED AND THE SCREEN HAS NOT BEEN // UPDATED BUT IT APPEARS TO NEED UPDATING, THEN REFRESH IT if(mode != MODE_LOGO) { const DWORD _50ms = 50; // 50ms == 20Hz DWORD dwCyclesPerScreenUpdate = _50ms * (DWORD) (g_fCurrentCLK6502 / 1000.0); if((GetTickCount() - dwVideoUpdateTick) > _50ms) { static BOOL anyupdates = 0; static DWORD lastcycles = 0; static BOOL lastupdates[2] = {0,0}; dwVideoUpdateTick = GetTickCount(); anyupdates |= screenupdated; if ((cumulativecycles-lastcycles) >= dwCyclesPerScreenUpdate) { lastcycles = cumulativecycles; if ((!anyupdates) && (!lastupdates[0]) && (!lastupdates[1]) && VideoApparentlyDirty()) { static DWORD lasttime = 0; DWORD currtime = GetTickCount(); VideoCheckPage(1); if ((!fullspeed) || (currtime-lasttime >= (DWORD)((graphicsmode || !systemidle) ? 100 : 25))) { VideoRefreshScreen(); lasttime = currtime; } screenupdated = 1; } lastupdates[1] = lastupdates[0]; lastupdates[0] = anyupdates; anyupdates = 0; if (pageflipping) pageflipping--; } } } if(!fullspeed) { Timer_WaitTimer(); } }
void ContinueExecution() { static BOOL pageflipping = 0; //? const double fUsecPerSec = 1.e6; #if 1 const UINT nExecutionPeriodUsec = 1000; // 1.0ms // const UINT nExecutionPeriodUsec = 100; // 0.1ms const double fExecutionPeriodClks = g_fCurrentCLK6502 * ((double)nExecutionPeriodUsec / fUsecPerSec); #else const double fExecutionPeriodClks = 1800.0; const UINT nExecutionPeriodUsec = (UINT) (fUsecPerSec * (fExecutionPeriodClks / g_fCurrentCLK6502)); #endif // bool bScrollLock_FullSpeed = g_uScrollLockToggle ? g_bScrollLock_FullSpeed : (GetKeyState(VK_SCROLL) < 0); g_bFullSpeed = ( (g_dwSpeed == SPEED_MAX) || bScrollLock_FullSpeed || (DiskIsSpinning() && enhancedisk && !Spkr_IsActive() && !MB_IsActive()) ); if(g_bFullSpeed) { // Don't call Spkr_Mute() - will get speaker clicks MB_Mute(); SysClk_StopTimer(); g_nCpuCyclesFeedback = 0; // For the case when this is a big -ve number } else { // Don't call Spkr_Demute() MB_Demute(); SysClk_StartTimerUsec(nExecutionPeriodUsec); } // int nCyclesToExecute = (int) fExecutionPeriodClks + g_nCpuCyclesFeedback; if(nCyclesToExecute < 0) nCyclesToExecute = 0; DWORD dwExecutedCycles = CpuExecute(nCyclesToExecute); g_dwCyclesThisFrame += dwExecutedCycles; // cyclenum = dwExecutedCycles; DiskUpdatePosition(dwExecutedCycles); JoyUpdatePosition(); VideoUpdateVbl(g_dwCyclesThisFrame); SpkrUpdate(cyclenum); sg_SSC.CommUpdate(cyclenum); PrintUpdate(cyclenum); // const DWORD CLKS_PER_MS = (DWORD)g_fCurrentCLK6502 / 1000; emulmsec_frac += dwExecutedCycles; if(emulmsec_frac > CLKS_PER_MS) { emulmsec += emulmsec_frac / CLKS_PER_MS; emulmsec_frac %= CLKS_PER_MS; } // // DETERMINE WHETHER THE SCREEN WAS UPDATED, THE DISK WAS SPINNING, // OR THE KEYBOARD I/O PORTS WERE BEING EXCESSIVELY QUERIED THIS CLOCKTICK VideoCheckPage(0); BOOL screenupdated = VideoHasRefreshed(); BOOL systemidle = 0; //(KeybGetNumQueries() > (clockgran << 2)); // && (!ranfinegrain); // TO DO if(screenupdated) pageflipping = 3; // if(g_dwCyclesThisFrame >= dwClksPerFrame) { g_dwCyclesThisFrame -= dwClksPerFrame; if(g_nAppMode != MODE_LOGO) { VideoUpdateFlash(); static BOOL anyupdates = 0; static DWORD lastcycles = 0; static BOOL lastupdates[2] = {0,0}; anyupdates |= screenupdated; // lastcycles = cumulativecycles; if ((!anyupdates) && (!lastupdates[0]) && (!lastupdates[1]) && VideoApparentlyDirty()) { VideoCheckPage(1); static DWORD lasttime = 0; DWORD currtime = GetTickCount(); if ((!g_bFullSpeed) || (currtime-lasttime >= (DWORD)((graphicsmode || !systemidle) ? 100 : 25))) { VideoRefreshScreen(); lasttime = currtime; } screenupdated = 1; } lastupdates[1] = lastupdates[0]; lastupdates[0] = anyupdates; anyupdates = 0; if (pageflipping) pageflipping--; } MB_EndOfVideoFrame(); } // if(!g_bFullSpeed) { SysClk_WaitTimer(); #if DBG_CALC_FREQ if(g_nPerfFreq) { QueryPerformanceCounter((LARGE_INTEGER*)&nTime1); LONGLONG nTimeDiff = nTime1 - nTime0; double fTime = (double)nTimeDiff / (double)(LONGLONG)g_nPerfFreq; g_fDbg[g_nIdx] = fTime; g_nIdx = (g_nIdx+1) & (MAX_CNT-1); g_fMeanPeriod = 0.0; for(UINT n=0; n<MAX_CNT; n++) g_fMeanPeriod += g_fDbg[n]; g_fMeanPeriod /= (double)MAX_CNT; g_fMeanFreq = 1.0 / g_fMeanPeriod; } #endif } }
void EmulatorThread::run() { // Load PC from Reset Vector CpuInitialize(); lcdoffshift0flag = false; //g_stp = 1; // test #ifndef FAKENMI unsigned int nmistart = GetTickCount(); #endif gThreadFlags &= 0xFFFEu; // Remove 0x01 from gThreadFlags (stack related) #ifdef AUTOTEST unsigned totalline = 0; // TODO: long long enablelogging = false; #endif while(fKeeping) { #if 1 const unsigned spdc1016freq = GlobalSetting.SPDC1016Frequency; #endif #ifdef FAMENMI twohznmicycle = spdc1016freq / 2; #endif while (batchcount >= 0 && fKeeping) { #ifdef AUTOTEST totalline++; TryTest(totalline); #endif // AUTOTEST #ifdef LOGASM #ifdef AUTOTEST if (enablelogging) { #endif #ifdef HANDYPSP LogDisassembly(mPC, NULL); #else LogDisassembly(regs.pc, NULL); #endif // HANDYPSP #ifdef AUTOTEST } #endif // AUTOTEST #endif // LOGASM if (matrixupdated) { matrixupdated = false; AppendLog("keypadmatrix updated."); } nmicount++; // MERGEASM // 2Hz NMI // TODO: use batchcount as NMI source #ifdef FAKENMI if (nmicount % 400000 == 0) { nmicount = 0; // MERGEASM //if (twohznmicycle < 0) { // twohznmicycle = spdc1016freq / 2; // reset #else // in CC800 hardware, NMI is generated by 32.768k crystal, but spdc1016 use RC oscillator so cycle/NMI can be mismatched. unsigned int dummynow = GetTickCount(); if (dummynow - nmistart >= 500) { nmistart += 500; #endif //g_nmi = 0; // next CpuExecute will execute two instructions gThreadFlags |= 0x08; // Add NMIFlag } // NMI > IRQ if ((gThreadFlags & 0x08) != 0) { gThreadFlags &= 0xFFF7u; // remove 0x08 NMI Flag // FIXME: NO MORE REVERSE g_nmi = TRUE; // next CpuExecute will execute two instructions qDebug("ggv wanna NMI."); //fprintf(stderr, "ggv wanna NMI.\n"); gDeadlockCounter--; // wrong behavior of wqxsim #ifdef HANDYPSP } else if (((PS() & AF_INTERRUPT) == 0) && ((gThreadFlags & TF_IRQFLAG) != 0)) { #else } else if (((regs.ps & 0x4) == 0) && ((gThreadFlags & 0x10) != 0)) { #endif gThreadFlags &= 0xFFEFu; // remove 0x10 IRQ Flag g_irq = TRUE; // B flag (AF_BREAK) will remove in CpuExecute qDebug("ggv wanna IRQ."); gDeadlockCounter--; // wrong behavior of wqxsim } DWORD CpuTicks = CpuExecute(); totalcycle += CpuTicks; twohznmicycle -= CpuTicks; // add checks for reset, IRQ, NMI, and other pin signals if (lastTicket == 0) { lastTicket = GetTickCount(); } gDeadlockCounter++; if (gDeadlockCounter == 6000) { // overflowed gDeadlockCounter = 0; if ((gThreadFlags & 0x80u) == 0) { // CheckTimerbaseAndEnableIRQnEXIE1 CheckTimebaseAndEnableIRQnEXIE1(); if (timer0started) { // mayDestAddr == 5 in ReadRegister // mayBaseTable have 0x100 elements? //increment = mayBasetable[mayDestAddr]; // mayBaseTable[5] == 3 //t0overflow = (unsigned int)(increment + mayPreviousTimer0Value) < 0xFF; //mayPreviousTimer0Value += increment; //if ( !t0overflow ) //{ // mayPreviousTimer0Value = 0; // Turnoff2HzNMIMaskAddIRQFlag(); //} int increment = 3; prevtimer0value += increment; if (prevtimer0value >= 0xFFu) { prevtimer0value = 0; Turnoff2HzNMIMaskAddIRQFlag(); } } } else { // RESET fixedram0000[io01_int_enable] |= 0x1; // TIMER A INTERRUPT ENABLE fixedram0000[io02_timer0_val] |= 0x1; // [io01+1] Timer0 bit1 = 1 gThreadFlags &= 0xFF7F; // remove 0x80 | 0x10 #ifdef HANDYPSP mPC = *(unsigned short*)&pmemmap[mapE000][0x1FFC]; #else regs.pc = *(unsigned short*)&pmemmap[mapE000][0x1FFC]; #endif } } else { if (timer0started) { // mayDestAddr == 5 in ReadRegister // mayBaseTable have 0x100 elements? int increment = 3; prevtimer0value += increment; if (prevtimer0value >= 0xFFu) { prevtimer0value = 0; Turnoff2HzNMIMaskAddIRQFlag(); } } } //if (timer0started) { // fixedram0000[io02_timer0_val] = fixedram0000[io02_timer0_val] + 1; //} //if (timer1started) { // fixedram0000[io03_timer1_val] = fixedram0000[io03_timer1_val] + 1; //} // TODO: dynamic re-measure if (measured == false && totalcycle % spdc1016freq < 10 && totalcycle > spdc1016freq) { measured = true; #if 0 // fixed rate on device // realworld time = 106 #ifdef HANDYPSP batchlimiter = spdc1016freq / 88; // 12*10=120ms #else batchlimiter = spdc1016freq / 4; #endif batchcount = batchlimiter; #else if (totalcycle < spdc1016freq * 2) { // first loop check! // spdc1016 executed one second in fullspeed virtual timeline unsigned long long realworldtime = GetTickCount() - lastTicket; // should less than 1000ms lastTicket = GetTickCount(); //double virtual100ms = realworldtime / 100.0; qDebug("realworldtime:%llu", realworldtime); fprintf(stderr, "realworldtime:%llu\n", realworldtime); if (realworldtime > 1000) { // TODO: device may slower than simulator // in my test iPad I get 3528/3779/3630 msec to finish one sdpc1016freq loop // we should make screen refresh at least twice per real world second or screen will never been updated // 1000->500 2000->250 4000->125 batchlimiter = 500 * spdc1016freq / realworldtime; if (remeasure) { qDebug("remeasure on batchlimiter: %u", batchlimiter); fprintf(stderr, "remeasure on batchlimiter: %u\n", batchlimiter); measured = false; totalcycle = 0; remeasure--; } batchcount = batchlimiter; } else if (batchlimiter == 0) { // 1000 - realworldtime = overflow time, overflow time / 10 = sleepcount, freq / sleepcount = batchcount //batchlimiter = spdc1016freq / ((1000 - realworldtime) / 10); sleepcount = (1000 - realworldtime) / sleepgap; batchlimiter = spdc1016freq * sleepgap / (1000 - realworldtime); } else { // wrong path? // sleep(0) is less than 10ms, but we'd never go here } batchcount = batchlimiter; } else { // totalcycle > spdc1016freq * 2 // TODO: check once more } #endif // TARGET_IPHONE_SIMULATOR } // measured == false && totalcycle % spdc1016freq < 10 && totalcycle > spdc1016freq if (totalcycle % spdc1016freq > 10 && totalcycle > spdc1016freq) { // FIXME: bug on slow device //measured = false; } if (batchlimiter != 0) { batchcount -= CpuTicks; } //usleep(10); //Sleep(0); } if (memcmp(&fixedram0000[0x9C0], fLCDBuffer, 160*80/8) != 0) { memcpy(fLCDBuffer, &fixedram0000[0x9C0], 160*80/8); qDebug("lcdBufferChanged"); fprintf(stderr, "lcdBufferChanged\n"); emit lcdBufferChanged(new QByteArray((const char*)fLCDBuffer, 160*80/8)); } Sleep(10); // SleepGap. 10ms = 10us if (batchlimiter > 0) { batchcount = batchlimiter; } else { batchcount = spdc1016freq * 2; // dirty fix } } //this->deleteLater(); } void EmulatorThread::StopKeeping() { fKeeping = false; } #ifdef AUTOTEST void EmulatorThread::TryTest( unsigned line ) { // Network if (line == 1024000) { keypadmatrix[1][6] = 1; CheckLCDOffShift0HotkeyAndEnableWatchDog(); } if (line == 1064000) { keypadmatrix[1][6] = 0; CheckLCDOffShift0HotkeyAndEnableWatchDog(); } // Down if (line == 1224000) { keypadmatrix[6][3] = 1; CheckLCDOffShift0HotkeyAndEnableWatchDog(); } if (line == 1264000) { keypadmatrix[6][3] = 0; CheckLCDOffShift0HotkeyAndEnableWatchDog(); } // Enter if (line == 1424000) { keypadmatrix[6][5] = 1; CheckLCDOffShift0HotkeyAndEnableWatchDog(); enablelogging = true; } if (line == 1524000) { keypadmatrix[6][5] = 0; CheckLCDOffShift0HotkeyAndEnableWatchDog(); } // Splash if (line == 4724000) { keypadmatrix[6][5] = 1; CheckLCDOffShift0HotkeyAndEnableWatchDog(); } if (line == 4764000) { keypadmatrix[6][5] = 0; CheckLCDOffShift0HotkeyAndEnableWatchDog(); } } #endif void CheckLCDOffShift0HotkeyAndEnableWatchDog() { //// may check hotkey press //if ( gLcdoffShift0Flag ) //{ // if ( keypadmatrix1[6] || keypadmatrix1[7] ) // { // // Line6 Dict Card // // Line7 on/off // EnableWatchDogFlag(); // 0x80 // gLcdoffShift0Flag = 0; // } //} //else //{ // // Set lcdoffshift0flag only when keypadmatrix3 == 0xFB // if ( keypadmatrix1[7] == 0xFBu ) // gLcdoffShift0Flag = 1; //} matrixupdated = true; if (lcdoffshift0flag) { // we don't have invert bit for row6,7 //bool row67down = false; for (int y = 0; y < 2; y++) { for (int x = 0; x < 8; x++) { if (keypadmatrix[y][x] == 1) { //row6,7down = true; EnableWatchDogFlag(); lcdoffshift0flag = false; return; } } } } else { if (keypadmatrix[0][2] == 1) { lcdoffshift0flag = true; // this flag is used for UI? (IO05_ClockControl) } } }
void ContinueExecution() { static BOOL pageflipping = 0; //? const double fUsecPerSec = 1.e6; #if 1 const UINT nExecutionPeriodUsec = 1000; // 1.0ms // const UINT nExecutionPeriodUsec = 100; // 0.1ms const double fExecutionPeriodClks = g_fCurrentCLK6502 * ((double)nExecutionPeriodUsec / fUsecPerSec); #else const double fExecutionPeriodClks = 1800.0; const UINT nExecutionPeriodUsec = (UINT) (fUsecPerSec * (fExecutionPeriodClks / g_fCurrentCLK6502)); #endif // bool bScrollLock_FullSpeed = g_uScrollLockToggle ? g_bScrollLock_FullSpeed : (GetKeyState(VK_SCROLL) < 0); g_bFullSpeed = ( (g_dwSpeed == SPEED_MAX) || bScrollLock_FullSpeed || (DiskIsSpinning() && enhancedisk && !Spkr_IsActive() && !MB_IsActive()) ); if(g_bFullSpeed) { // Don't call Spkr_Mute() - will get speaker clicks MB_Mute(); SysClk_StopTimer(); #ifdef USE_SPEECH_API g_Speech.Reset(); // TODO: Put this on a timer (in emulated cycles)... otherwise CATALOG cuts out #endif g_nCpuCyclesFeedback = 0; // For the case when this is a big -ve number // Switch to normal priority so that APPLEWIN process doesn't hog machine! //. EG: No disk in Drive-1, and boot Apple: Windows will start to crawl! SetPriorityNormal(); } else { // Don't call Spkr_Demute() MB_Demute(); SysClk_StartTimerUsec(nExecutionPeriodUsec); // Switch to higher priority, eg. for audio (BUG #015394) SetPriorityAboveNormal(); } #ifdef WS_VIDEO wsVideoNewDirtyRect.ulx = FRAMEBUFFER_W; wsVideoNewDirtyRect.uly = FRAMEBUFFER_H; wsVideoNewDirtyRect.lrx = 0; wsVideoNewDirtyRect.lry = 0; #endif // int nCyclesToExecute = (int) fExecutionPeriodClks + g_nCpuCyclesFeedback; if(nCyclesToExecute < 0) nCyclesToExecute = 0; DWORD dwExecutedCycles = CpuExecute(nCyclesToExecute); g_dwCyclesThisFrame += dwExecutedCycles; // cyclenum = dwExecutedCycles; DiskUpdatePosition(dwExecutedCycles); JoyUpdatePosition(); SpkrUpdate(cyclenum); sg_SSC.CommUpdate(cyclenum); PrintUpdate(cyclenum); // const DWORD CLKS_PER_MS = (DWORD)g_fCurrentCLK6502 / 1000; emulmsec_frac += dwExecutedCycles; if(emulmsec_frac > CLKS_PER_MS) { emulmsec += emulmsec_frac / CLKS_PER_MS; emulmsec_frac %= CLKS_PER_MS; } #ifdef WS_VIDEO if (wsVideoNewDirtyRect.lrx > wsVideoNewDirtyRect.ulx) { if (wsVideoNewDirtyRect.ulx < wsVideoAllDirtyRect.ulx) wsVideoAllDirtyRect.ulx = wsVideoNewDirtyRect.ulx; if (wsVideoNewDirtyRect.uly < wsVideoAllDirtyRect.uly) wsVideoAllDirtyRect.uly = wsVideoNewDirtyRect.uly; if (wsVideoNewDirtyRect.lrx > wsVideoAllDirtyRect.lrx) wsVideoAllDirtyRect.lrx = wsVideoNewDirtyRect.lrx; if (wsVideoNewDirtyRect.lry > wsVideoAllDirtyRect.lry) wsVideoAllDirtyRect.lry = wsVideoNewDirtyRect.lry; } if(g_dwCyclesThisFrame >= dwClksPerFrame) { g_dwCyclesThisFrame -= dwClksPerFrame; wsVideoRefresh(); } #else // // DETERMINE WHETHER THE SCREEN WAS UPDATED, THE DISK WAS SPINNING, // OR THE KEYBOARD I/O PORTS WERE BEING EXCESSIVELY QUERIED THIS CLOCKTICK VideoCheckPage(0); BOOL screenupdated = VideoHasRefreshed(); BOOL systemidle = 0; //(KeybGetNumQueries() > (clockgran << 2)); // && (!ranfinegrain); // TO DO if(screenupdated) pageflipping = 3; // if(g_dwCyclesThisFrame >= dwClksPerFrame) { g_dwCyclesThisFrame -= dwClksPerFrame; if(g_nAppMode != MODE_LOGO) { VideoUpdateFlash(); static BOOL anyupdates = 0; static DWORD lastcycles = 0; static BOOL lastupdates[2] = {0,0}; anyupdates |= screenupdated; // lastcycles = cumulativecycles; if ((!anyupdates) && (!lastupdates[0]) && (!lastupdates[1]) && VideoApparentlyDirty()) { VideoCheckPage(1); static DWORD lasttime = 0; DWORD currtime = GetTickCount(); if ((!g_bFullSpeed) || (currtime-lasttime >= (DWORD)((g_bGraphicsMode || !systemidle) ? 100 : 25))) { VideoRefreshScreen(); lasttime = currtime; } screenupdated = 1; } lastupdates[1] = lastupdates[0]; lastupdates[0] = anyupdates; anyupdates = 0; if (pageflipping) pageflipping--; } MB_EndOfVideoFrame(); } // #endif // ifndef WS_VIDEO if(!g_bFullSpeed) { SysClk_WaitTimer(); #if DBG_CALC_FREQ if(g_nPerfFreq) { QueryPerformanceCounter((LARGE_INTEGER*)&nTime1); LONGLONG nTimeDiff = nTime1 - nTime0; double fTime = (double)nTimeDiff / (double)(LONGLONG)g_nPerfFreq; g_fDbg[g_nIdx] = fTime; g_nIdx = (g_nIdx+1) & (MAX_CNT-1); g_fMeanPeriod = 0.0; for(UINT n=0; n<MAX_CNT; n++) g_fMeanPeriod += g_fDbg[n]; g_fMeanPeriod /= (double)MAX_CNT; g_fMeanFreq = 1.0 / g_fMeanPeriod; } #endif } }
void ContinueExecution(void) { const double fUsecPerSec = 1.e6; #if 1 const UINT nExecutionPeriodUsec = 1000; // 1.0ms // const UINT nExecutionPeriodUsec = 100; // 0.1ms const double fExecutionPeriodClks = g_fCurrentCLK6502 * ((double)nExecutionPeriodUsec / fUsecPerSec); #else const double fExecutionPeriodClks = 1800.0; const UINT nExecutionPeriodUsec = (UINT) (fUsecPerSec * (fExecutionPeriodClks / g_fCurrentCLK6502)); #endif // bool bScrollLock_FullSpeed = sg_PropertySheet.GetScrollLockToggle() ? g_bScrollLock_FullSpeed : (GetKeyState(VK_SCROLL) < 0); g_bFullSpeed = ( (g_dwSpeed == SPEED_MAX) || bScrollLock_FullSpeed || (DiskIsSpinning() && enhancedisk && !Spkr_IsActive() && !MB_IsActive()) ); if (g_bFullSpeed) { // Don't call Spkr_Mute() - will get speaker clicks MB_Mute(); SysClk_StopTimer(); #ifdef USE_SPEECH_API g_Speech.Reset(); // TODO: Put this on a timer (in emulated cycles)... otherwise CATALOG cuts out #endif g_nCpuCyclesFeedback = 0; // For the case when this is a big -ve number // Switch to normal priority so that APPLEWIN process doesn't hog machine! //. EG: No disk in Drive-1, and boot Apple: Windows will start to crawl! SetPriorityNormal(); } else { // Don't call Spkr_Demute() MB_Demute(); SysClk_StartTimerUsec(nExecutionPeriodUsec); // Switch to higher priority, eg. for audio (BUG #015394) SetPriorityAboveNormal(); } // int nCyclesToExecute = (int) fExecutionPeriodClks + g_nCpuCyclesFeedback; if (nCyclesToExecute < 0) nCyclesToExecute = 0; DWORD dwExecutedCycles = CpuExecute(nCyclesToExecute); g_dwCyclesThisFrame += dwExecutedCycles; // cyclenum = dwExecutedCycles; DiskUpdatePosition(dwExecutedCycles); JoyUpdatePosition(); SpkrUpdate(cyclenum); sg_SSC.CommUpdate(cyclenum); PrintUpdate(cyclenum); // const DWORD CLKS_PER_MS = (DWORD)g_fCurrentCLK6502 / 1000; emulmsec_frac += dwExecutedCycles; if (emulmsec_frac > CLKS_PER_MS) { emulmsec += emulmsec_frac / CLKS_PER_MS; emulmsec_frac %= CLKS_PER_MS; } // DETERMINE WHETHER THE SCREEN WAS UPDATED THIS CLOCKTICK static BOOL anyupdates = 0; VideoCheckPage(0); // force=0 anyupdates |= VideoHasRefreshed(); // Only called from here. Returns & clears 'hasrefreshed' flag // if (g_dwCyclesThisFrame >= dwClksPerFrame) { g_dwCyclesThisFrame -= dwClksPerFrame; VideoUpdateFlash(); static BOOL lastupdates[2] = {0,0}; if (!anyupdates && !lastupdates[0] && !lastupdates[1] && VideoApparentlyDirty()) { VideoCheckPage(1); // force=1 static DWORD lasttime = 0; DWORD currtime = GetTickCount(); if ((!g_bFullSpeed) || (currtime-lasttime >= (DWORD)(g_bGraphicsMode ? 100 : 25))) { VideoRefreshScreen(); lasttime = currtime; } } lastupdates[1] = lastupdates[0]; lastupdates[0] = anyupdates; anyupdates = 0; MB_EndOfVideoFrame(); } // if (!g_bFullSpeed) { SysClk_WaitTimer(); #if DBG_CALC_FREQ if (g_nPerfFreq) { QueryPerformanceCounter((LARGE_INTEGER*)&nTime1); LONGLONG nTimeDiff = nTime1 - nTime0; double fTime = (double)nTimeDiff / (double)(LONGLONG)g_nPerfFreq; g_fDbg[g_nIdx] = fTime; g_nIdx = (g_nIdx+1) & (MAX_CNT-1); g_fMeanPeriod = 0.0; for(UINT n=0; n<MAX_CNT; n++) g_fMeanPeriod += g_fDbg[n]; g_fMeanPeriod /= (double)MAX_CNT; g_fMeanFreq = 1.0 / g_fMeanPeriod; } #endif } }