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