1 /*****************************************************************************
2 ** $Source: /cygdrive/d/Private/_SVNROOT/bluemsx/blueMSX/Src/Emulator/Emulator.c,v $
3 **
4 ** $Revision: 1.67 $
5 **
6 ** $Date: 2009-07-18 14:35:59 $
7 **
8 ** More info: http://www.bluemsx.com
9 **
10 ** Copyright (C) 2003-2006 Daniel Vik
11 **
12 ** This program is free software; you can redistribute it and/or modify
13 ** it under the terms of the GNU General Public License as published by
14 ** the Free Software Foundation; either version 2 of the License, or
15 ** (at your option) any later version.
16 **
17 ** This program is distributed in the hope that it will be useful,
18 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ** GNU General Public License for more details.
21 **
22 ** You should have received a copy of the GNU General Public License
23 ** along with this program; if not, write to the Free Software
24 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 **
26 ******************************************************************************
27 */
28 #include "Emulator.h"
29 #include "MsxTypes.h"
30 #include "Debugger.h"
31 #include "Board.h"
32 #include "FileHistory.h"
33 #include "Switches.h"
34 #include "Led.h"
35 #include "Machine.h"
36 #include "InputEvent.h"
37 
38 #include "ArchThread.h"
39 #include "ArchEvent.h"
40 #include "ArchTimer.h"
41 #include "ArchSound.h"
42 #include "ArchMidi.h"
43 
44 #include "JoystickPort.h"
45 #include "ArchInput.h"
46 #include "ArchDialog.h"
47 #include "ArchNotifications.h"
48 #include <math.h>
49 #include <string.h>
50 
51 static int WaitForSync(int maxSpeed, int breakpointHit);
52 
53 static void*  emuThread;
54 #ifndef WII
55 static void*  emuSyncEvent;
56 #endif
57 static void*  emuStartEvent;
58 #ifndef WII
59 static void*  emuTimer;
60 #endif
61 static int    emuExitFlag;
62 static UInt32 emuSysTime = 0;
63 static UInt32 emuFrequency = 3579545;
64 int           emuMaxSpeed = 0;
65 int           emuPlayReverse = 0;
66 int           emuMaxEmuSpeed = 0; // Max speed issued by emulation
67 static char   emuStateName[512];
68 static volatile int      emuSuspendFlag;
69 static volatile EmuState emuState = EMU_STOPPED;
70 static volatile int      emuSingleStep = 0;
71 static Properties* properties;
72 static Mixer* mixer;
73 static BoardDeviceInfo deviceInfo;
74 static Machine* machine;
75 static int lastScreenMode;
76 
77 static int emuFrameskipCounter = 0;
78 
79 static UInt32 emuTimeIdle       = 0;
80 static UInt32 emuTimeTotal      = 1;
81 static UInt32 emuTimeOverflow   = 0;
82 static UInt32 emuUsageCurrent   = 0;
83 static UInt32 emuCpuSpeed       = 0;
84 static UInt32 emuCpuUsage       = 0;
85 static int    enableSynchronousUpdate = 1;
86 
87 #if 0
88 
89 #define LOG_SIZE (10 * 1000000)
90 UInt32 logentry[LOG_SIZE];
91 
92 int logindex;
93 int logwrapped;
94 
95 void dolog(int slot, int sslot, int wr, UInt16 addr, UInt8 val)
96 {
97     logentry[logindex++] = (slot << 26) | (sslot << 24) | ((UInt32)val << 16) | addr | (wr ? (1 << 31) : 0);
98     if (logindex == LOG_SIZE) {
99         logindex = 0;
100         logwrapped++;
101     }
102 }
103 
104 void clearlog()
105 {
106     logwrapped = 0;
107     logindex = 0;
108 }
109 
110 void savelog()
111 {
112     int totalSize = LOG_SIZE;
113     int lastPct = -1;
114     int cnt = 0;
115     FILE * f = fopen("bluemsxlog.txt", "w+");
116     int i = 0;
117     if (logwrapped == 0 && logindex == 0) {
118         return;
119     }
120 
121     if (logwrapped) {
122         i = logindex;
123     }
124     else {
125         totalSize = logindex;
126     }
127 
128     printf("Saving log for slot 1\n");
129 
130     do {
131         UInt32 v = logentry[i];
132         int newPct = ++cnt * 100 / totalSize;
133         char rw = (v >> 31) ? 'W' : 'R';
134 
135         if (newPct != lastPct) {
136             printf("\r%d%%",newPct);
137             lastPct = newPct;
138         }
139         fprintf(f, "%c(%d:%d) %.4x: %.2x\n", rw, (v>>26)&3, (v>>24)&3,v & 0xffff, (v >> 16) & 0xff);
140 
141         if (++i == LOG_SIZE) {
142             i = 0;
143         }
144     } while (i != logindex);
145     printf("\n");
146     fclose(f);
147 }
148 #else
149 #define clearlog()
150 #define savelog()
151 #endif
152 
emuCalcCpuUsage()153 static void emuCalcCpuUsage() {
154     static UInt32 oldSysTime = 0;
155     static UInt32 oldAverage = 0;
156     static UInt32 cnt = 0;
157     UInt32 newSysTime;
158     UInt32 emuTimeAverage;
159 
160     if (emuTimeTotal < 10) {
161         return;
162     }
163     newSysTime = archGetSystemUpTime(1000);
164     emuTimeAverage = 100 * (emuTimeTotal - emuTimeIdle) / (emuTimeTotal / 10);
165 
166     emuTimeOverflow = emuTimeAverage > 940;
167 
168     if ((cnt++ & 0x1f) == 0) {
169         UInt32 usageAverage = emuUsageCurrent * 100 / (newSysTime - oldSysTime) * emuFrequency / 3579545;
170         if (usageAverage > 98 && usageAverage < 102) {
171             usageAverage = 100;
172         }
173 
174         if (usageAverage >= 10000) {
175             usageAverage = 0;
176         }
177 
178         emuCpuSpeed = usageAverage;
179         emuCpuUsage = emuTimeAverage;
180     }
181 
182     oldSysTime      = newSysTime;
183     emuUsageCurrent = 0;
184     emuTimeIdle     = 0;
185     emuTimeTotal    = 1;
186 }
187 
emuUseSynchronousUpdate()188 static int emuUseSynchronousUpdate()
189 {
190     if (properties->emulation.syncMethod == P_EMU_SYNCIGNORE) {
191         return properties->emulation.syncMethod;
192     }
193 
194     if (properties->emulation.speed == 50 &&
195         enableSynchronousUpdate &&
196         emulatorGetMaxSpeed() == 0)
197     {
198         return properties->emulation.syncMethod;
199     }
200     return P_EMU_SYNCAUTO;
201 }
202 
203 
emulatorGetCpuSpeed()204 UInt32 emulatorGetCpuSpeed() {
205     return emuCpuSpeed;
206 }
207 
emulatorGetCpuUsage()208 UInt32 emulatorGetCpuUsage() {
209     return emuCpuUsage;
210 }
211 
emuEnableSynchronousUpdate(int enable)212 void emuEnableSynchronousUpdate(int enable)
213 {
214     enableSynchronousUpdate = enable;
215 }
216 
emulatorInit(Properties * theProperties,Mixer * theMixer)217 void emulatorInit(Properties* theProperties, Mixer* theMixer)
218 {
219     properties = theProperties;
220     mixer      = theMixer;
221 }
222 
emulatorExit()223 void emulatorExit()
224 {
225     properties = NULL;
226     mixer      = NULL;
227 }
228 
229 
emulatorGetState()230 EmuState emulatorGetState() {
231     return emuState;
232 }
233 
emulatorSetState(EmuState state)234 void emulatorSetState(EmuState state) {
235     if (state == EMU_RUNNING) {
236         archSoundResume();
237         archMidiEnable(1);
238     }
239     else {
240         archSoundSuspend();
241         archMidiEnable(0);
242     }
243     if (state == EMU_STEP) {
244         state = EMU_RUNNING;
245         emuSingleStep = 1;
246     }
247     if (state == EMU_STEP_BACK) {
248         EmuState oldState = state;
249         state = EMU_RUNNING;
250         if (!boardRewindOne()) {
251             state = oldState;
252         }
253 
254     }
255     emuState = state;
256 }
257 
258 
emulatorGetSyncPeriod()259 int emulatorGetSyncPeriod() {
260 #ifdef NO_HIRES_TIMERS
261     return 10;
262 #else
263     return properties->emulation.syncMethod == P_EMU_SYNCAUTO ||
264            properties->emulation.syncMethod == P_EMU_SYNCNONE ? 2 : 1;
265 #endif
266 }
267 
268 #ifndef WII
timerCallback(void * timer)269 static int timerCallback(void* timer) {
270     if (properties == NULL) {
271         return 1;
272     }
273     else {
274         static UInt32 frameCount = 0;
275         static UInt32 oldSysTime = 0;
276         static UInt32 refreshRate = 50;
277         UInt32 framePeriod = (properties->video.frameSkip + 1) * 1000;
278         UInt32 syncPeriod = emulatorGetSyncPeriod();
279         UInt32 sysTime = archGetSystemUpTime(1000);
280         UInt32 diffTime = sysTime - oldSysTime;
281         int syncMethod = emuUseSynchronousUpdate();
282 
283         if (diffTime == 0) {
284             return 0;
285         }
286 
287         oldSysTime = sysTime;
288 
289         // Update display
290         frameCount += refreshRate * diffTime;
291         if (frameCount >= framePeriod) {
292             frameCount %= framePeriod;
293             if (emuState == EMU_RUNNING) {
294                 refreshRate = boardGetRefreshRate();
295 
296                 if (syncMethod == P_EMU_SYNCAUTO || syncMethod == P_EMU_SYNCNONE) {
297                     archUpdateEmuDisplay(0);
298                 }
299             }
300         }
301 
302         if (syncMethod == P_EMU_SYNCTOVBLANKASYNC) {
303             archUpdateEmuDisplay(syncMethod);
304         }
305 
306         // Update emulation
307         archEventSet(emuSyncEvent);
308     }
309 
310     return 1;
311 }
312 
timerCallback_global(void * timer)313 int timerCallback_global(void* timer) {
314    timerCallback(timer);
315 }
316 
317 #endif
318 
getDeviceInfo(BoardDeviceInfo * deviceInfo)319 static void getDeviceInfo(BoardDeviceInfo* deviceInfo)
320 {
321     int i;
322 
323     for (i = 0; i < PROP_MAX_CARTS; i++) {
324         strcpy(properties->media.carts[i].fileName, deviceInfo->carts[i].name);
325         strcpy(properties->media.carts[i].fileNameInZip, deviceInfo->carts[i].inZipName);
326         // Don't save rom type
327         // properties->media.carts[i].type = deviceInfo->carts[i].type;
328         updateExtendedRomName(i, properties->media.carts[i].fileName, properties->media.carts[i].fileNameInZip);
329     }
330 
331     for (i = 0; i < PROP_MAX_DISKS; i++) {
332         strcpy(properties->media.disks[i].fileName, deviceInfo->disks[i].name);
333         strcpy(properties->media.disks[i].fileNameInZip, deviceInfo->disks[i].inZipName);
334         updateExtendedDiskName(i, properties->media.disks[i].fileName, properties->media.disks[i].fileNameInZip);
335     }
336 
337     for (i = 0; i < PROP_MAX_TAPES; i++) {
338         strcpy(properties->media.tapes[i].fileName, deviceInfo->tapes[i].name);
339         strcpy(properties->media.tapes[i].fileNameInZip, deviceInfo->tapes[i].inZipName);
340         updateExtendedCasName(i, properties->media.tapes[i].fileName, properties->media.tapes[i].fileNameInZip);
341     }
342 
343     properties->emulation.vdpSyncMode      = deviceInfo->video.vdpSyncMode;
344 
345 }
346 
setDeviceInfo(BoardDeviceInfo * deviceInfo)347 static void setDeviceInfo(BoardDeviceInfo* deviceInfo)
348 {
349     int i;
350 
351     for (i = 0; i < PROP_MAX_CARTS; i++) {
352         deviceInfo->carts[i].inserted =  strlen(properties->media.carts[i].fileName);
353         deviceInfo->carts[i].type = properties->media.carts[i].type;
354         strcpy(deviceInfo->carts[i].name, properties->media.carts[i].fileName);
355         strcpy(deviceInfo->carts[i].inZipName, properties->media.carts[i].fileNameInZip);
356     }
357 
358     for (i = 0; i < PROP_MAX_DISKS; i++) {
359         deviceInfo->disks[i].inserted =  strlen(properties->media.disks[i].fileName);
360         strcpy(deviceInfo->disks[i].name, properties->media.disks[i].fileName);
361         strcpy(deviceInfo->disks[i].inZipName, properties->media.disks[i].fileNameInZip);
362     }
363 
364     for (i = 0; i < PROP_MAX_TAPES; i++) {
365         deviceInfo->tapes[i].inserted =  strlen(properties->media.tapes[i].fileName);
366         strcpy(deviceInfo->tapes[i].name, properties->media.tapes[i].fileName);
367         strcpy(deviceInfo->tapes[i].inZipName, properties->media.tapes[i].fileNameInZip);
368     }
369 
370     deviceInfo->video.vdpSyncMode = properties->emulation.vdpSyncMode;
371 }
372 
373 static int emulationStartFailure = 0;
374 
emulatorPauseCb(void)375 static void emulatorPauseCb(void)
376 {
377     emulatorSetState(EMU_PAUSED);
378     debuggerNotifyEmulatorPause();
379 }
380 
emulatorThread()381 static void emulatorThread() {
382     int frequency;
383     int success = 0;
384     int reversePeriod = 0;
385     int reverseBufferCnt = 0;
386 
387     emulatorSetFrequency(properties->emulation.speed, &frequency);
388 
389     switchSetFront(properties->emulation.frontSwitch);
390     switchSetPause(properties->emulation.pauseSwitch);
391     switchSetAudio(properties->emulation.audioSwitch);
392 
393     if (properties->emulation.reverseEnable && properties->emulation.reverseMaxTime > 0) {
394         reversePeriod = 50;
395         reverseBufferCnt = properties->emulation.reverseMaxTime * 1000 / reversePeriod;
396     }
397     success = boardRun(machine,
398                        &deviceInfo,
399                        mixer,
400                        *emuStateName ? emuStateName : NULL,
401                        frequency,
402                        reversePeriod,
403                        reverseBufferCnt,
404                        WaitForSync);
405 
406     ledSetAll(0);
407     emuState = EMU_STOPPED;
408 
409 #ifndef WII
410     archTimerDestroy(emuTimer);
411 #endif
412 
413     if (!success) {
414         emulationStartFailure = 1;
415     }
416 
417     archEventSet(emuStartEvent);
418 }
419 //extern int xxxx;
420 
emulatorStart(const char * stateName)421 void emulatorStart(const char* stateName) {
422         dbgEnable();
423 
424     archEmulationStartNotification();
425 //xxxx = 0;
426     emulatorResume();
427 
428     emuExitFlag = 0;
429 
430     mixerIsChannelTypeActive(mixer, MIXER_CHANNEL_MOONSOUND, 1);
431     mixerIsChannelTypeActive(mixer, MIXER_CHANNEL_YAMAHA_SFG, 1);
432     mixerIsChannelTypeActive(mixer, MIXER_CHANNEL_MSXAUDIO, 1);
433     mixerIsChannelTypeActive(mixer, MIXER_CHANNEL_MSXMUSIC, 1);
434     mixerIsChannelTypeActive(mixer, MIXER_CHANNEL_SCC, 1);
435 
436 
437     properties->emulation.pauseSwitch = 0;
438     switchSetPause(properties->emulation.pauseSwitch);
439 
440     machine = machineCreate(properties->emulation.machineName);
441 
442     if (machine == NULL) {
443         archShowStartEmuFailDialog();
444         archEmulationStopNotification();
445         emuState = EMU_STOPPED;
446         archEmulationStartFailure();
447         return;
448     }
449 
450     boardSetMachine(machine);
451 
452 #ifndef NO_TIMERS
453 #ifndef WII
454     emuSyncEvent  = archEventCreate(0);
455 #endif
456     emuStartEvent = archEventCreate(0);
457 #ifndef WII
458     emuTimer = archCreateTimer(emulatorGetSyncPeriod(), timerCallback);
459 #endif
460 #endif
461 
462     setDeviceInfo(&deviceInfo);
463 
464     inputEventReset();
465 
466     archSoundResume();
467     archMidiEnable(1);
468 
469     emuState = EMU_PAUSED;
470     emulationStartFailure = 0;
471     strcpy(emuStateName, stateName ? stateName : "");
472 
473     clearlog();
474 
475 #ifdef SINGLE_THREADED
476     emuState = EMU_RUNNING;
477     emulatorThread();
478 
479     if (emulationStartFailure) {
480         archEmulationStopNotification();
481         emuState = EMU_STOPPED;
482         archEmulationStartFailure();
483     }
484 #else
485     emuThread = archThreadCreate(emulatorThread, THREAD_PRIO_HIGH);
486 
487     archEventWait(emuStartEvent, 3000);
488 
489     if (emulationStartFailure) {
490         archEmulationStopNotification();
491         emuState = EMU_STOPPED;
492         archEmulationStartFailure();
493     }
494     if (emuState != EMU_STOPPED) {
495         getDeviceInfo(&deviceInfo);
496 
497         boardSetYm2413Oversampling(properties->sound.chip.ym2413Oversampling);
498         boardSetY8950Oversampling(properties->sound.chip.y8950Oversampling);
499         boardSetMoonsoundOversampling(properties->sound.chip.moonsoundOversampling);
500 
501         strcpy(properties->emulation.machineName, machine->name);
502 
503         debuggerNotifyEmulatorStart();
504 
505         emuState = EMU_RUNNING;
506     }
507 #endif
508 }
509 
emulatorStop()510 void emulatorStop() {
511     if (emuState == EMU_STOPPED) {
512         return;
513     }
514 
515     debuggerNotifyEmulatorStop();
516 
517     emuState = EMU_STOPPED;
518 
519     do {
520         archThreadSleep(10);
521     } while (!emuSuspendFlag);
522 
523     emuExitFlag = 1;
524 #ifndef WII
525     archEventSet(emuSyncEvent);
526 #endif
527     archSoundSuspend();
528     archThreadJoin(emuThread, 3000);
529     archMidiEnable(0);
530     machineDestroy(machine);
531     archThreadDestroy(emuThread);
532 #ifndef WII
533     archEventDestroy(emuSyncEvent);
534 #endif
535     archEventDestroy(emuStartEvent);
536 
537     // Reset active indicators in mixer
538     mixerIsChannelTypeActive(mixer, MIXER_CHANNEL_MOONSOUND, 1);
539     mixerIsChannelTypeActive(mixer, MIXER_CHANNEL_YAMAHA_SFG, 1);
540     mixerIsChannelTypeActive(mixer, MIXER_CHANNEL_MSXAUDIO, 1);
541     mixerIsChannelTypeActive(mixer, MIXER_CHANNEL_MSXMUSIC, 1);
542     mixerIsChannelTypeActive(mixer, MIXER_CHANNEL_SCC, 1);
543 
544     archEmulationStopNotification();
545 
546     dbgDisable();
547     dbgPrint();
548     savelog();
549 }
550 
551 
552 
emulatorSetFrequency(int logFrequency,int * frequency)553 void emulatorSetFrequency(int logFrequency, int* frequency) {
554     emuFrequency = (int)(3579545 * pow(2.0, (logFrequency - 50) / 15.0515));
555 
556     if (frequency != NULL) {
557         *frequency  = emuFrequency;
558     }
559 
560     boardSetFrequency(emuFrequency);
561 }
562 
emulatorSuspend()563 void emulatorSuspend() {
564     if (emuState == EMU_RUNNING) {
565         emuState = EMU_SUSPENDED;
566         do {
567             archThreadSleep(10);
568         } while (!emuSuspendFlag);
569         archSoundSuspend();
570         archMidiEnable(0);
571     }
572 }
573 
emulatorResume()574 void emulatorResume() {
575     if (emuState == EMU_SUSPENDED) {
576         emuSysTime = 0;
577 
578         archSoundResume();
579         archMidiEnable(1);
580         emuState = EMU_RUNNING;
581         archUpdateEmuDisplay(0);
582     }
583 }
584 
emulatorGetCurrentScreenMode()585 int emulatorGetCurrentScreenMode()
586 {
587     return lastScreenMode;
588 }
589 
emulatorRestart()590 void emulatorRestart() {
591     Machine* machine = machineCreate(properties->emulation.machineName);
592 
593     emulatorStop();
594     if (machine != NULL) {
595         boardSetMachine(machine);
596         machineDestroy(machine);
597     }
598 }
599 
emulatorRestartSound()600 void emulatorRestartSound() {
601     emulatorSuspend();
602     archSoundDestroy();
603     archSoundCreate(mixer, 44100, properties->sound.bufSize, properties->sound.stereo ? 2 : 1);
604     emulatorResume();
605 }
606 
emulatorGetCpuOverflow()607 int emulatorGetCpuOverflow() {
608     int overflow = emuTimeOverflow;
609     emuTimeOverflow = 0;
610     return overflow;
611 }
612 
emulatorSetMaxSpeed(int enable)613 void emulatorSetMaxSpeed(int enable) {
614     emuMaxSpeed = enable;
615 }
616 
emulatorGetMaxSpeed()617 int  emulatorGetMaxSpeed() {
618     return emuMaxSpeed;
619 }
620 
emulatorPlayReverse(int enable)621 void emulatorPlayReverse(int enable)
622 {
623     if (enable) {
624         archSoundSuspend();
625     }
626     else {
627         archSoundResume();
628     }
629     emuPlayReverse = enable;
630 }
631 
emulatorGetPlayReverse()632 int  emulatorGetPlayReverse()
633 {
634     return emuPlayReverse;
635 }
636 
emulatorResetMixer()637 void emulatorResetMixer() {
638     // Reset active indicators in mixer
639     mixerIsChannelTypeActive(mixer, MIXER_CHANNEL_MOONSOUND, 1);
640     mixerIsChannelTypeActive(mixer, MIXER_CHANNEL_YAMAHA_SFG, 1);
641     mixerIsChannelTypeActive(mixer, MIXER_CHANNEL_MSXAUDIO, 1);
642     mixerIsChannelTypeActive(mixer, MIXER_CHANNEL_MSXMUSIC, 1);
643     mixerIsChannelTypeActive(mixer, MIXER_CHANNEL_SCC, 1);
644     mixerIsChannelTypeActive(mixer, MIXER_CHANNEL_PCM, 1);
645     mixerIsChannelTypeActive(mixer, MIXER_CHANNEL_IO, 1);
646 }
647 
emulatorSyncScreen()648 int emulatorSyncScreen()
649 {
650     int rv = 0;
651     emuFrameskipCounter--;
652     if (emuFrameskipCounter < 0) {
653         rv = archUpdateEmuDisplay(properties->emulation.syncMethod);
654         if (rv) {
655             emuFrameskipCounter = properties->video.frameSkip;
656         }
657     }
658     return rv;
659 }
660 
661 
RefreshScreen(int screenMode)662 void RefreshScreen(int screenMode) {
663 
664     lastScreenMode = screenMode;
665 
666     if (emuUseSynchronousUpdate() == P_EMU_SYNCFRAMES && emuState == EMU_RUNNING) {
667         emulatorSyncScreen();
668     }
669 }
670 
671 #ifndef NO_TIMERS
672 
673 #ifdef WII
674 
WaitForSync(int maxSpeed,int breakpointHit)675 static int WaitForSync(int maxSpeed, int breakpointHit)
676 {
677     UInt32 diffTime;
678 
679     emuMaxEmuSpeed = maxSpeed;
680 
681     emuSuspendFlag = 1;
682 
683     archPollInput();
684 
685     if (emuState != EMU_RUNNING) {
686         archEventSet(emuStartEvent);
687         archThreadSleep(100);
688         emuSuspendFlag = 0;
689         return emuExitFlag ? -1 : 0;
690     }
691 
692     emuSuspendFlag = 0;
693 
694     if (emuSingleStep) {
695         diffTime = 0;
696     }else{
697         diffTime = 20;
698     }
699 
700     if (emuMaxSpeed || emuMaxEmuSpeed) {
701         diffTime *= 10;
702     }
703 
704     return emuExitFlag ? -1 : diffTime;
705 }
706 
707 #else
708 
WaitReverse()709 int WaitReverse()
710 {
711     boardEnableSnapshots(0);
712 
713     for (;;) {
714         UInt32 sysTime = archGetSystemUpTime(1000);
715         UInt32 diffTime = sysTime - emuSysTime;
716         if (diffTime >= 50) {
717             emuSysTime = sysTime;
718             break;
719         }
720         archEventWait(emuSyncEvent, -1);
721     }
722 
723     boardRewind();
724 
725     return -60;
726 }
727 
WaitForSync(int maxSpeed,int breakpointHit)728 static int WaitForSync(int maxSpeed, int breakpointHit) {
729     UInt32 li1;
730     UInt32 li2;
731     static UInt32 tmp = 0;
732     static UInt32 cnt = 0;
733     UInt32 sysTime;
734     UInt32 diffTime;
735     UInt32 syncPeriod;
736     static int overflowCount = 0;
737     static UInt32 kbdPollCnt = 0;
738 
739     if (emuPlayReverse && properties->emulation.reverseEnable) {
740         return WaitReverse();
741     }
742 
743     boardEnableSnapshots(1);
744 
745     emuMaxEmuSpeed = maxSpeed;
746 
747     syncPeriod = emulatorGetSyncPeriod();
748     li1 = archGetHiresTimer();
749 
750     emuSuspendFlag = 1;
751 
752     if (emuSingleStep) {
753         debuggerNotifyEmulatorPause();
754         emuSingleStep = 0;
755         emuState = EMU_PAUSED;
756         archSoundSuspend();
757         archMidiEnable(0);
758     }
759 
760     if (breakpointHit) {
761         debuggerNotifyEmulatorPause();
762         emuState = EMU_PAUSED;
763         archSoundSuspend();
764         archMidiEnable(0);
765     }
766 
767     if (emuState != EMU_RUNNING) {
768         archEventSet(emuStartEvent);
769         emuSysTime = 0;
770     }
771 
772 #ifdef SINGLE_THREADED
773     emuExitFlag |= archPollEvent();
774 #endif
775 
776     if (((++kbdPollCnt & 0x03) >> 1) == 0) {
777        archPollInput();
778     }
779 
780     if (emuUseSynchronousUpdate() == P_EMU_SYNCTOVBLANK) {
781         overflowCount += emulatorSyncScreen() ? 0 : 1;
782         while ((!emuExitFlag && emuState != EMU_RUNNING) || overflowCount > 0) {
783             archEventWait(emuSyncEvent, -1);
784 #ifdef NO_TIMERS
785             while (timerCallback(NULL) == 0) emuExitFlag |= archPollEvent();
786 #endif
787             overflowCount--;
788         }
789     }
790     else {
791         do {
792 #ifdef NO_TIMERS
793             while (timerCallback(NULL) == 0) emuExitFlag |= archPollEvent();
794 #endif
795             archEventWait(emuSyncEvent, -1);
796             if (((emuMaxSpeed || emuMaxEmuSpeed) && !emuExitFlag) || overflowCount > 0) {
797 #ifdef NO_TIMERS
798                 while (timerCallback(NULL) == 0) emuExitFlag |= archPollEvent();
799 #endif
800                 archEventWait(emuSyncEvent, -1);
801             }
802             overflowCount = 0;
803         } while (!emuExitFlag && emuState != EMU_RUNNING);
804     }
805 
806     emuSuspendFlag = 0;
807     li2 = archGetHiresTimer();
808 
809     emuTimeIdle  += li2 - li1;
810     emuTimeTotal += li2 - tmp;
811     tmp = li2;
812 
813     sysTime = archGetSystemUpTime(1000);
814     diffTime = sysTime - emuSysTime;
815     emuSysTime = sysTime;
816 
817     if (emuSingleStep) {
818         diffTime = 0;
819     }
820 
821     if ((++cnt & 0x0f) == 0) {
822         emuCalcCpuUsage(NULL);
823     }
824 
825     overflowCount = emulatorGetCpuOverflow() ? 1 : 0;
826 #ifdef NO_HIRES_TIMERS
827     if (diffTime > 50U) {
828         overflowCount = 1;
829         diffTime = 0;
830     }
831 #else
832     if (diffTime > 100U) {
833         overflowCount = 1;
834         diffTime = 0;
835     }
836 #endif
837     if (emuMaxSpeed || emuMaxEmuSpeed) {
838         diffTime *= 10;
839         if (diffTime > 20 * syncPeriod) {
840             diffTime =  20 * syncPeriod;
841         }
842     }
843 
844     emuUsageCurrent += diffTime;
845 
846     return emuExitFlag ? -99 : diffTime;
847 }
848 #endif
849 
850 #else
851 
852 #ifdef WIN32
853 #include <windows.h>
854 
getHiresTimer()855 UInt32 getHiresTimer() {
856     static LONGLONG hfFrequency = 0;
857     LARGE_INTEGER li;
858 
859     if (!hfFrequency) {
860         if (QueryPerformanceFrequency(&li)) {
861             hfFrequency = li.QuadPart;
862         }
863         else {
864             return 0;
865         }
866     }
867 
868     QueryPerformanceCounter(&li);
869 
870     return (DWORD)(li.QuadPart * 1000000 / hfFrequency);
871 }
872 #else
873 #define getHiresTimer archGetHiresTimer
874 #endif
875 #if 1
876 
877 extern void switch_to_main_thread(void);
878 
WaitForSync(int maxSpeed,int breakpointHit)879 static int WaitForSync(int maxSpeed, int breakpointHit) {
880 
881    static float time_fraction = 0.0;
882    if (time_fraction > 1.0)
883       time_fraction -= 1.0;
884 
885    switch_to_main_thread();
886 
887    time_fraction += (1000.0 / 60.0) - 16.0;
888 
889    return 16 + time_fraction;
890 }
891 
892 #else
893 
894 static UInt32 busy, total, oldTime;
895 
WaitForSync(int maxSpeed,int breakpointHit)896 static int WaitForSync(int maxSpeed, int breakpointHit) {
897     emuSuspendFlag = 1;
898 
899     busy += getHiresTimer() - oldTime;
900 
901     emuExitFlag |= archPollEvent();
902 
903     archPollInput();
904 
905     do {
906         for (;;) {
907             UInt32 sysTime = archGetSystemUpTime(1000);
908             UInt32 diffTime = sysTime - emuSysTime;
909             emuExitFlag |= archPollEvent();
910             if (diffTime < 10) {
911                 continue;
912             }
913             emuSysTime += 10;
914             if (diffTime > 30) {
915                 emuSysTime = sysTime;
916             }
917             break;
918         }
919     } while (!emuExitFlag && emuState != EMU_RUNNING);
920 
921 
922     emuSuspendFlag = 0;
923 
924     total += getHiresTimer() - oldTime;
925     oldTime = getHiresTimer();
926 #if 0
927     if (total >= 1000000) {
928         UInt32 pct = 10000 * busy / total;
929         printf("CPU Usage = %d.%d%%\n", pct / 100, pct % 100);
930         total = 0;
931         busy = 0;
932     }
933 #endif
934 
935     return emuExitFlag ? -1 : 10;
936 }
937 #endif
938 
939 
940 #endif // #ifndef NO_TIMERS
941 
942