this repo has no description
at main 566 lines 9.9 kB view raw
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}