this repo has no description
1/*
2 PROGMAIN.c
3
4 Copyright (C) 2009 Bernd Schmidt, Philip Cummins, Paul C. Pratt
5
6 You can redistribute this file and/or modify it under the terms
7 of version 2 of the GNU General Public License as published by
8 the Free Software Foundation. You should have received a copy
9 of the license along with this file; see the file COPYING.
10
11 This file is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 license for more details.
15*/
16
17/*
18 PROGram MAIN.
19*/
20
21#include "PICOMMON.h"
22#include "MINEM68K.h"
23#if EmVIA1
24#include "VIAEMDEV.h"
25#endif
26#if EmVIA2
27#include "VIA2EMDV.h"
28#endif
29#include "IWMEMDEV.h"
30#include "SCCEMDEV.h"
31#if EmRTC
32#include "RTCEMDEV.h"
33#endif
34#include "ROMEMDEV.h"
35#include "SCSIEMDV.h"
36#include "SONYEMDV.h"
37#include "SCRNEMDV.h"
38
39#if EmVidCard
40#include "VIDEMDEV.h"
41#endif
42
43#if EmClassicKbrd
44#include "KBRDEMDV.h"
45#elif EmPMU
46#include "PMUEMDEV.h"
47#else
48#include "ADBEMDEV.h"
49#endif
50
51#if EmClassicSnd
52#include "SNDEMDEV.h"
53#endif
54#if EmASC
55#include "ASCEMDEV.h"
56#endif
57
58#include "MOUSEMDV.h"
59
60
61#include "PROGMAIN.h"
62
63/*
64 ReportAbnormalID unused 0x1002 - 0x10FF
65*/
66
67LOCALPROC EmulatedHardwareZap(void)
68{
69 Memory_Reset();
70 ICT_Zap();
71 IWM_Reset();
72 SCC_Reset();
73 SCSI_Reset();
74#if EmVIA1
75 VIA1_Zap();
76#endif
77#if EmVIA2
78 VIA2_Zap();
79#endif
80 Sony_Reset();
81 Extn_Reset();
82 m68k_reset();
83}
84
85LOCALPROC DoMacReset(void)
86{
87 Sony_EjectAllDisks();
88 EmulatedHardwareZap();
89}
90
91LOCALPROC InterruptReset_Update(void)
92{
93 SetInterruptButton(falseblnr);
94 /*
95 in case has been set. so only stays set
96 for 60th of a second.
97 */
98
99 if (WantMacInterrupt) {
100 SetInterruptButton(trueblnr);
101 WantMacInterrupt = falseblnr;
102 }
103 if (WantMacReset) {
104 DoMacReset();
105 WantMacReset = falseblnr;
106 }
107}
108
109LOCALPROC SubTickNotify(int SubTick)
110{
111#if 0
112 dbglog_writeCStr("ending sub tick ");
113 dbglog_writeNum(SubTick);
114 dbglog_writeReturn();
115#endif
116#if EmClassicSnd
117 MacSound_SubTick(SubTick);
118#elif EmASC
119 ASC_SubTick(SubTick);
120#else
121 UnusedParam(SubTick);
122#endif
123}
124
125#define CyclesScaledPerTick (130240UL * kMyClockMult * kCycleScale)
126#define CyclesScaledPerSubTick (CyclesScaledPerTick / kNumSubTicks)
127
128LOCALVAR ui4r SubTickCounter;
129
130LOCALPROC SubTickTaskDo(void)
131{
132 SubTickNotify(SubTickCounter);
133 ++SubTickCounter;
134 if (SubTickCounter < (kNumSubTicks - 1)) {
135 /*
136 final SubTick handled by SubTickTaskEnd,
137 since CyclesScaledPerSubTick * kNumSubTicks
138 might not equal CyclesScaledPerTick.
139 */
140
141 ICT_add(kICT_SubTick, CyclesScaledPerSubTick);
142 }
143}
144
145LOCALPROC SubTickTaskStart(void)
146{
147 SubTickCounter = 0;
148 ICT_add(kICT_SubTick, CyclesScaledPerSubTick);
149}
150
151LOCALPROC SubTickTaskEnd(void)
152{
153 SubTickNotify(kNumSubTicks - 1);
154}
155
156LOCALPROC SixtiethSecondNotify(void)
157{
158#if dbglog_HAVE && 0
159 dbglog_WriteNote("begin new Sixtieth");
160#endif
161 Mouse_Update();
162 InterruptReset_Update();
163#if EmClassicKbrd
164 KeyBoard_Update();
165#endif
166#if EmADB
167 ADB_Update();
168#endif
169
170 Sixtieth_PulseNtfy(); /* Vertical Blanking Interrupt */
171 Sony_Update();
172
173#if EmLocalTalk
174 LocalTalkTick();
175#endif
176#if EmRTC
177 RTC_Interrupt();
178#endif
179#if EmVidCard
180 Vid_Update();
181#endif
182
183 SubTickTaskStart();
184}
185
186LOCALPROC SixtiethEndNotify(void)
187{
188 SubTickTaskEnd();
189 Mouse_EndTickNotify();
190 Screen_EndTickNotify();
191#if dbglog_HAVE && 0
192 dbglog_WriteNote("end Sixtieth");
193#endif
194}
195
196LOCALPROC ExtraTimeBeginNotify(void)
197{
198#if 0
199 dbglog_writeCStr("begin extra time");
200 dbglog_writeReturn();
201#endif
202#if EmVIA1
203 VIA1_ExtraTimeBegin();
204#endif
205#if EmVIA2
206 VIA2_ExtraTimeBegin();
207#endif
208}
209
210LOCALPROC ExtraTimeEndNotify(void)
211{
212#if EmVIA1
213 VIA1_ExtraTimeEnd();
214#endif
215#if EmVIA2
216 VIA2_ExtraTimeEnd();
217#endif
218#if 0
219 dbglog_writeCStr("end extra time");
220 dbglog_writeReturn();
221#endif
222}
223
224GLOBALPROC EmulationReserveAlloc(void)
225{
226 ReserveAllocOneBlock(&RAM,
227 kRAM_Size + RAMSafetyMarginFudge, 5, falseblnr);
228#if EmVidCard
229 ReserveAllocOneBlock(&VidROM, kVidROM_Size, 5, falseblnr);
230#endif
231#if IncludeVidMem
232 ReserveAllocOneBlock(&VidMem,
233 kVidMemRAM_Size + RAMSafetyMarginFudge, 5, trueblnr);
234#endif
235#if SmallGlobals
236 MINEM68K_ReserveAlloc();
237#endif
238}
239
240LOCALFUNC blnr InitEmulation(void)
241{
242#if EmRTC
243 if (RTC_Init())
244#endif
245 if (ROM_Init())
246#if EmVidCard
247 if (Vid_Init())
248#endif
249 if (AddrSpac_Init())
250 {
251 EmulatedHardwareZap();
252 return trueblnr;
253 }
254 return falseblnr;
255}
256
257LOCALPROC ICT_DoTask(int taskid)
258{
259 switch (taskid) {
260 case kICT_SubTick:
261 SubTickTaskDo();
262 break;
263#if EmClassicKbrd
264 case kICT_Kybd_ReceiveEndCommand:
265 DoKybd_ReceiveEndCommand();
266 break;
267 case kICT_Kybd_ReceiveCommand:
268 DoKybd_ReceiveCommand();
269 break;
270#endif
271#if EmADB
272 case kICT_ADB_NewState:
273 ADB_DoNewState();
274 break;
275#endif
276#if EmPMU
277 case kICT_PMU_Task:
278 PMU_DoTask();
279 break;
280#endif
281#if EmVIA1
282 case kICT_VIA1_Timer1Check:
283 VIA1_DoTimer1Check();
284 break;
285 case kICT_VIA1_Timer2Check:
286 VIA1_DoTimer2Check();
287 break;
288#endif
289#if EmVIA2
290 case kICT_VIA2_Timer1Check:
291 VIA2_DoTimer1Check();
292 break;
293 case kICT_VIA2_Timer2Check:
294 VIA2_DoTimer2Check();
295 break;
296#endif
297 default:
298 ReportAbnormalID(0x1001, "unknown taskid in ICT_DoTask");
299 break;
300 }
301}
302
303LOCALPROC ICT_DoCurrentTasks(void)
304{
305 int i = 0;
306 uimr m = ICTactive;
307
308 while (0 != m) {
309 if (0 != (m & 1)) {
310 if (i >= kNumICTs) {
311 /* shouldn't happen */
312 ICTactive &= ((1 << kNumICTs) - 1);
313 m = 0;
314 } else if (ICTwhen[i] == NextiCount) {
315 ICTactive &= ~ (1 << i);
316#ifdef _VIA_Debug
317 fprintf(stderr, "doing task %d, %d\n", NextiCount, i);
318#endif
319 ICT_DoTask(i);
320
321 /*
322 A Task may set the time of
323 any task, including itself.
324 But it cannot set any task
325 to execute immediately, so
326 one pass is sufficient.
327 */
328 }
329 }
330 ++i;
331 m >>= 1;
332 }
333}
334
335LOCALFUNC ui5b ICT_DoGetNext(ui5b maxn)
336{
337 int i = 0;
338 uimr m = ICTactive;
339 ui5b v = maxn;
340
341 while (0 != m) {
342 if (0 != (m & 1)) {
343 if (i >= kNumICTs) {
344 /* shouldn't happen */
345 m = 0;
346 } else {
347 ui5b d = ICTwhen[i] - NextiCount;
348 /* at this point d must be > 0 */
349 if (d < v) {
350#ifdef _VIA_Debug
351 fprintf(stderr, "coming task %d, %d, %d\n",
352 NextiCount, i, d);
353#endif
354 v = d;
355 }
356 }
357 }
358 ++i;
359 m >>= 1;
360 }
361
362 return v;
363}
364
365LOCALPROC m68k_go_nCycles_1(ui5b n)
366{
367 ui5b n2;
368 ui5b StopiCount = NextiCount + n;
369 do {
370 ICT_DoCurrentTasks();
371 n2 = ICT_DoGetNext(n);
372#if dbglog_HAVE && 0
373 dbglog_StartLine();
374 dbglog_writeCStr("before m68k_go_nCycles, NextiCount:");
375 dbglog_writeHex(NextiCount);
376 dbglog_writeCStr(", n2:");
377 dbglog_writeHex(n2);
378 dbglog_writeCStr(", n:");
379 dbglog_writeHex(n);
380 dbglog_writeReturn();
381#endif
382 NextiCount += n2;
383 m68k_go_nCycles(n2);
384 n = StopiCount - NextiCount;
385 } while (n != 0);
386}
387
388LOCALVAR ui5b ExtraSubTicksToDo = 0;
389
390LOCALPROC DoEmulateOneTick(void)
391{
392#if EnableAutoSlow
393 {
394 ui5r NewQuietTime = QuietTime + 1;
395
396 if (NewQuietTime > QuietTime) {
397 /* if not overflow */
398 QuietTime = NewQuietTime;
399 }
400 }
401#endif
402#if EnableAutoSlow
403 {
404 ui5r NewQuietSubTicks = QuietSubTicks + kNumSubTicks;
405
406 if (NewQuietSubTicks > QuietSubTicks) {
407 /* if not overflow */
408 QuietSubTicks = NewQuietSubTicks;
409 }
410 }
411#endif
412
413 SixtiethSecondNotify();
414
415 m68k_go_nCycles_1(CyclesScaledPerTick);
416
417 SixtiethEndNotify();
418
419 if ((ui3b) -1 == SpeedValue) {
420 ExtraSubTicksToDo = (ui5b) -1;
421 } else {
422 ui5b ExtraAdd = (kNumSubTicks << SpeedValue) - kNumSubTicks;
423 ui5b ExtraLimit = ExtraAdd << 3;
424
425 ExtraSubTicksToDo += ExtraAdd;
426 if (ExtraSubTicksToDo > ExtraLimit) {
427 ExtraSubTicksToDo = ExtraLimit;
428 }
429 }
430}
431
432LOCALFUNC blnr MoreSubTicksToDo(void)
433{
434 blnr v = falseblnr;
435
436 if (ExtraTimeNotOver() && (ExtraSubTicksToDo > 0)) {
437#if EnableAutoSlow
438 if ((QuietSubTicks >= kAutoSlowSubTicks)
439 && (QuietTime >= kAutoSlowTime)
440 && ! WantNotAutoSlow)
441 {
442 ExtraSubTicksToDo = 0;
443 } else
444#endif
445 {
446 v = trueblnr;
447 }
448 }
449
450 return v;
451}
452
453LOCALPROC DoEmulateExtraTime(void)
454{
455 /*
456 DoEmulateExtraTime is used for
457 anything over emulation speed
458 of 1x. It periodically calls
459 ExtraTimeNotOver and stops
460 when this returns false (or it
461 is finished with emulating the
462 extra time).
463 */
464
465 if (MoreSubTicksToDo()) {
466 ExtraTimeBeginNotify();
467 do {
468#if EnableAutoSlow
469 {
470 ui5r NewQuietSubTicks = QuietSubTicks + 1;
471
472 if (NewQuietSubTicks > QuietSubTicks) {
473 /* if not overflow */
474 QuietSubTicks = NewQuietSubTicks;
475 }
476 }
477#endif
478 m68k_go_nCycles_1(CyclesScaledPerSubTick);
479 --ExtraSubTicksToDo;
480 } while (MoreSubTicksToDo());
481 ExtraTimeEndNotify();
482 }
483}
484
485LOCALVAR ui5b CurEmulatedTime = 0;
486 /*
487 The number of ticks that have been
488 emulated so far.
489
490 That is, the number of times
491 "DoEmulateOneTick" has been called.
492 */
493
494LOCALPROC RunEmulatedTicksToTrueTime(void)
495{
496 /*
497 The general idea is to call DoEmulateOneTick
498 once per tick.
499
500 But if emulation is lagging, we'll try to
501 catch up by calling DoEmulateOneTick multiple
502 times, unless we're too far behind, in
503 which case we forget it.
504
505 If emulating one tick takes longer than
506 a tick we don't want to sit here
507 forever. So the maximum number of calls
508 to DoEmulateOneTick is determined at
509 the beginning, rather than just
510 calling DoEmulateOneTick until
511 CurEmulatedTime >= TrueEmulatedTime.
512 */
513
514 si3b n = OnTrueTime - CurEmulatedTime;
515
516 if (n > 0) {
517 DoEmulateOneTick();
518 ++CurEmulatedTime;
519
520 DoneWithDrawingForTick();
521
522 if (n > 8) {
523 /* emulation not fast enough */
524 n = 8;
525 CurEmulatedTime = OnTrueTime - n;
526 }
527
528 if (ExtraTimeNotOver() && (--n > 0)) {
529 /* lagging, catch up */
530
531 EmVideoDisable = trueblnr;
532
533 do {
534 DoEmulateOneTick();
535 ++CurEmulatedTime;
536 } while (ExtraTimeNotOver()
537 && (--n > 0));
538
539 EmVideoDisable = falseblnr;
540 }
541
542 EmLagTime = n;
543 }
544}
545
546LOCALPROC MainEventLoop(void)
547{
548 for (; ; ) {
549 WaitForNextTick();
550 if (ForceMacOff) {
551 return;
552 }
553
554 RunEmulatedTicksToTrueTime();
555
556 DoEmulateExtraTime();
557 }
558}
559
560GLOBALPROC ProgramMain(void)
561{
562 if (InitEmulation())
563 {
564 MainEventLoop();
565 }
566}