2019-07-22 22:50:34 -04:00
|
|
|
/*
|
|
|
|
PROGMAIN.c
|
|
|
|
|
|
|
|
Copyright (C) 2009 Bernd Schmidt, Philip Cummins, Paul C. Pratt
|
|
|
|
|
|
|
|
You can redistribute this file and/or modify it under the terms
|
|
|
|
of version 2 of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation. You should have received a copy
|
|
|
|
of the license along with this file; see the file COPYING.
|
|
|
|
|
|
|
|
This file is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
license for more details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
PROGram MAIN.
|
|
|
|
*/
|
|
|
|
|
2020-03-03 15:13:19 -05:00
|
|
|
#include <string.h>
|
2020-03-03 13:31:11 -05:00
|
|
|
#include "SYSDEPNS.h"
|
|
|
|
|
|
|
|
#include "UI/MYOSGLUE.h"
|
|
|
|
#include "EMCONFIG.h"
|
|
|
|
#include "GLOBGLUE.h"
|
|
|
|
#include "HW/M68K/M68KITAB.h"
|
|
|
|
#include "HW/M68K/MINEM68K.h"
|
|
|
|
#include "HW/VIA/VIAEMDEV.h"
|
|
|
|
#include "HW/VIA/VIA2EMDV.h"
|
|
|
|
#include "HW/DISK/IWMEMDEV.h"
|
|
|
|
#include "HW/SCC/SCCEMDEV.h"
|
|
|
|
#include "HW/RTC/RTCEMDEV.h"
|
|
|
|
#include "PATCHES/ROMEMDEV.h"
|
|
|
|
#include "HW/SCSI/SCSIEMDV.h"
|
|
|
|
#include "HW/DISK/SONYEMDV.h"
|
|
|
|
#include "HW/SCREEN/SCRNEMDV.h"
|
|
|
|
#include "HW/VIDCARD/VIDEMDEV.h"
|
|
|
|
#include "HW/KBRD/KBRDEMDV.h"
|
|
|
|
#include "HW/POWERMAN/PMUEMDEV.h"
|
|
|
|
#include "HW/ADB/ADBEMDEV.h"
|
|
|
|
#include "HW/SOUND/ASCEMDEV.h"
|
|
|
|
#include "HW/SOUND/SNDEMDEV.h"
|
|
|
|
#include "HW/MOUSE/MOUSEMDV.h"
|
2019-07-22 22:50:34 -04:00
|
|
|
|
|
|
|
#include "PROGMAIN.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
ReportAbnormalID unused 0x1002 - 0x10FF
|
|
|
|
*/
|
|
|
|
|
2020-03-03 13:31:11 -05:00
|
|
|
const bool _EmVIA2 = false;
|
|
|
|
const bool _EmRTC = true;
|
|
|
|
const bool _EmVidCard = false;
|
|
|
|
const bool _EmClassicKbrd = true;
|
|
|
|
const bool _EmPMU = false;
|
|
|
|
const bool _EmMMU = false;
|
|
|
|
const bool _EmASC = false;
|
|
|
|
const bool _EmADB = false;
|
|
|
|
|
2020-03-03 15:13:19 -05:00
|
|
|
// Let's define a bunch of function structure thingies
|
|
|
|
|
|
|
|
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(*array))
|
|
|
|
|
|
|
|
typedef struct DevMethods {
|
|
|
|
bool (*init)(void);
|
|
|
|
void (*reset)(void);
|
|
|
|
void (*starttick)(void);
|
|
|
|
void (*endtick)(void);
|
|
|
|
void (*timebegin)(void);
|
|
|
|
void (*timeend)(void);
|
|
|
|
} DevMethods_t;
|
|
|
|
|
|
|
|
const DevMethods_t DEVICES[] = {
|
|
|
|
// RTC
|
|
|
|
{
|
|
|
|
.init = EmRTC ? RTC_Init : NULL,
|
|
|
|
.reset = NULL,
|
|
|
|
.starttick = NULL,
|
|
|
|
.endtick = NULL,
|
|
|
|
.timebegin = NULL,
|
|
|
|
.timeend = NULL,
|
|
|
|
},
|
|
|
|
// ROM
|
|
|
|
{
|
|
|
|
.init = ROM_Init,
|
|
|
|
.reset = NULL,
|
|
|
|
.starttick = NULL,
|
|
|
|
.endtick = NULL,
|
|
|
|
.timebegin = NULL,
|
|
|
|
.timeend = NULL,
|
|
|
|
},
|
|
|
|
// Memory
|
|
|
|
{
|
|
|
|
.init = AddrSpac_Init,
|
|
|
|
.reset = Memory_Reset,
|
|
|
|
.starttick = NULL,
|
|
|
|
.endtick = NULL,
|
|
|
|
.timebegin = NULL,
|
|
|
|
.timeend = NULL,
|
|
|
|
},
|
|
|
|
// ICT
|
|
|
|
{
|
|
|
|
.init = NULL,
|
|
|
|
.reset = ICT_Zap,
|
|
|
|
.starttick = NULL,
|
|
|
|
.endtick = NULL,
|
|
|
|
.timebegin = NULL,
|
|
|
|
.timeend = NULL,
|
|
|
|
},
|
|
|
|
// IWM
|
|
|
|
{
|
|
|
|
.init = NULL,
|
|
|
|
.reset = IWM_Reset,
|
|
|
|
.starttick = NULL,
|
|
|
|
.endtick = NULL,
|
|
|
|
.timebegin = NULL,
|
|
|
|
.timeend = NULL,
|
|
|
|
},
|
|
|
|
// SCC
|
|
|
|
{
|
|
|
|
.init = NULL,
|
|
|
|
.reset = SCC_Reset,
|
|
|
|
.starttick = NULL,
|
|
|
|
.endtick = NULL,
|
|
|
|
.timebegin = NULL,
|
|
|
|
.timeend = NULL,
|
|
|
|
},
|
|
|
|
// SCSI
|
|
|
|
{
|
|
|
|
.init = NULL,
|
|
|
|
.reset = SCSI_Reset,
|
|
|
|
.starttick = NULL,
|
|
|
|
.endtick = NULL,
|
|
|
|
.timebegin = NULL,
|
|
|
|
.timeend = NULL,
|
|
|
|
},
|
|
|
|
// VIA1
|
|
|
|
{
|
|
|
|
.init = NULL,
|
|
|
|
.reset = VIA1_Zap,
|
|
|
|
.starttick = NULL,
|
|
|
|
.endtick = NULL,
|
|
|
|
.timebegin = VIA1_ExtraTimeBegin,
|
|
|
|
.timeend = VIA1_ExtraTimeEnd,
|
|
|
|
},
|
|
|
|
// VIA2
|
|
|
|
{
|
|
|
|
.init = NULL,
|
|
|
|
.reset = EmVIA2 ? VIA2_Zap : NULL,
|
|
|
|
.starttick = NULL,
|
|
|
|
.endtick = NULL,
|
|
|
|
.timebegin = EmVIA2 ? VIA2_ExtraTimeBegin : NULL,
|
|
|
|
.timeend = EmVIA2 ? VIA2_ExtraTimeEnd : NULL,
|
|
|
|
},
|
|
|
|
// Sony disk drive
|
|
|
|
{
|
|
|
|
.init = NULL,
|
|
|
|
.reset = Sony_Reset,
|
|
|
|
.starttick = Sony_Update,
|
|
|
|
.endtick = NULL,
|
|
|
|
.timebegin = NULL,
|
|
|
|
.timeend = NULL,
|
|
|
|
},
|
|
|
|
// Extn
|
|
|
|
{
|
|
|
|
.init = NULL,
|
|
|
|
.reset = Extn_Reset,
|
|
|
|
.starttick = NULL,
|
|
|
|
.endtick = NULL,
|
|
|
|
.timebegin = NULL,
|
|
|
|
.timeend = NULL,
|
|
|
|
},
|
|
|
|
// m68k
|
|
|
|
{
|
|
|
|
.init = NULL,
|
|
|
|
.reset = m68k_reset,
|
|
|
|
.starttick = NULL,
|
|
|
|
.endtick = NULL,
|
|
|
|
.timebegin = NULL,
|
|
|
|
.timeend = NULL,
|
|
|
|
},
|
|
|
|
// Mouse
|
|
|
|
{
|
|
|
|
.init = NULL,
|
|
|
|
.reset = NULL,
|
|
|
|
.starttick = Mouse_Update,
|
|
|
|
.endtick = Mouse_EndTickNotify,
|
|
|
|
.timebegin = NULL,
|
|
|
|
.timeend = NULL,
|
|
|
|
},
|
|
|
|
// Classic Keyboard
|
|
|
|
{
|
|
|
|
.init = NULL,
|
|
|
|
.reset = NULL,
|
|
|
|
.starttick = EmClassicKbrd ? KeyBoard_Update : NULL,
|
|
|
|
.endtick = NULL,
|
|
|
|
.timebegin = NULL,
|
|
|
|
.timeend = NULL,
|
|
|
|
},
|
|
|
|
// ADB
|
|
|
|
{
|
|
|
|
.init = NULL,
|
|
|
|
.reset = NULL,
|
|
|
|
.starttick = EmADB ? ADB_Update : NULL,
|
|
|
|
.endtick = NULL,
|
|
|
|
.timebegin = NULL,
|
|
|
|
.timeend = NULL,
|
|
|
|
},
|
|
|
|
// LocalTalk
|
|
|
|
/*{
|
|
|
|
.init = NULL,
|
|
|
|
.reset = NULL,
|
|
|
|
.starttick = EmLocalTalk ? LocalTalkTick : NULL,
|
|
|
|
.endtick = NULL,
|
|
|
|
.timebegin = NULL,
|
|
|
|
.timeend = NULL,
|
|
|
|
},*/
|
|
|
|
// Video card
|
|
|
|
{
|
|
|
|
.init = EmVidCard ? Vid_Init : NULL,
|
|
|
|
.reset = NULL,
|
|
|
|
.starttick = EmVidCard ? Vid_Update : NULL,
|
|
|
|
.endtick = NULL,
|
|
|
|
.timebegin = NULL,
|
|
|
|
.timeend = NULL,
|
|
|
|
},
|
|
|
|
// Screen
|
|
|
|
{
|
|
|
|
.init = NULL,
|
|
|
|
.reset = NULL,
|
|
|
|
.starttick = Sixtieth_PulseNtfy, // VBlank interrupt
|
|
|
|
.endtick = Screen_EndTickNotify,
|
|
|
|
.timebegin = NULL,
|
|
|
|
.timeend = NULL,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2019-07-22 22:50:34 -04:00
|
|
|
LOCALPROC EmulatedHardwareZap(void)
|
|
|
|
{
|
2020-03-03 15:13:19 -05:00
|
|
|
int i;
|
|
|
|
for ( i = 0; i < ARRAY_SIZE(DEVICES); i++ ) {
|
|
|
|
if (DEVICES[i].reset != NULL) { DEVICES[i].reset(); }
|
|
|
|
}
|
2019-07-22 22:50:34 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
LOCALPROC DoMacReset(void)
|
|
|
|
{
|
|
|
|
Sony_EjectAllDisks();
|
|
|
|
EmulatedHardwareZap();
|
|
|
|
}
|
|
|
|
|
|
|
|
LOCALPROC InterruptReset_Update(void)
|
|
|
|
{
|
2020-02-11 00:34:32 -05:00
|
|
|
SetInterruptButton(false);
|
2019-07-22 22:50:34 -04:00
|
|
|
/*
|
|
|
|
in case has been set. so only stays set
|
|
|
|
for 60th of a second.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (WantMacInterrupt) {
|
2020-02-11 00:34:32 -05:00
|
|
|
SetInterruptButton(true);
|
|
|
|
WantMacInterrupt = false;
|
2019-07-22 22:50:34 -04:00
|
|
|
}
|
|
|
|
if (WantMacReset) {
|
|
|
|
DoMacReset();
|
2020-02-11 00:34:32 -05:00
|
|
|
WantMacReset = false;
|
2019-07-22 22:50:34 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
LOCALPROC SubTickNotify(int SubTick)
|
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
dbglog_writeCStr("ending sub tick ");
|
|
|
|
dbglog_writeNum(SubTick);
|
|
|
|
dbglog_writeReturn();
|
|
|
|
#endif
|
|
|
|
#if EmASC
|
2020-03-03 13:31:11 -05:00
|
|
|
ASC_SubTick(SubTick);
|
2019-07-22 22:50:34 -04:00
|
|
|
#else
|
2020-02-10 22:56:58 -05:00
|
|
|
#if SoundEnabled && (CurEmMd != kEmMd_PB100)
|
2019-07-22 22:50:34 -04:00
|
|
|
MacSound_SubTick(SubTick);
|
|
|
|
#else
|
|
|
|
UnusedParam(SubTick);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2020-02-10 22:56:58 -05:00
|
|
|
#define CyclesScaledPerTick (130240UL * ClockMult * kCycleScale)
|
2019-07-22 22:50:34 -04:00
|
|
|
#define CyclesScaledPerSubTick (CyclesScaledPerTick / kNumSubTicks)
|
|
|
|
|
2020-02-10 22:46:59 -05:00
|
|
|
LOCALVAR uint16_t SubTickCounter;
|
2019-07-22 22:50:34 -04:00
|
|
|
|
|
|
|
LOCALPROC SubTickTaskDo(void)
|
|
|
|
{
|
|
|
|
SubTickNotify(SubTickCounter);
|
|
|
|
++SubTickCounter;
|
|
|
|
if (SubTickCounter < (kNumSubTicks - 1)) {
|
|
|
|
/*
|
|
|
|
final SubTick handled by SubTickTaskEnd,
|
|
|
|
since CyclesScaledPerSubTick * kNumSubTicks
|
|
|
|
might not equal CyclesScaledPerTick.
|
|
|
|
*/
|
|
|
|
|
|
|
|
ICT_add(kICT_SubTick, CyclesScaledPerSubTick);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
LOCALPROC SubTickTaskStart(void)
|
|
|
|
{
|
|
|
|
SubTickCounter = 0;
|
|
|
|
ICT_add(kICT_SubTick, CyclesScaledPerSubTick);
|
|
|
|
}
|
|
|
|
|
|
|
|
LOCALPROC SubTickTaskEnd(void)
|
|
|
|
{
|
|
|
|
SubTickNotify(kNumSubTicks - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
LOCALPROC SixtiethSecondNotify(void)
|
|
|
|
{
|
2020-03-03 15:13:19 -05:00
|
|
|
int i;
|
2019-07-22 22:50:34 -04:00
|
|
|
#if dbglog_HAVE && 0
|
|
|
|
dbglog_WriteNote("begin new Sixtieth");
|
|
|
|
#endif
|
|
|
|
InterruptReset_Update();
|
2020-03-03 15:13:19 -05:00
|
|
|
for ( i = 0; i < ARRAY_SIZE(DEVICES); i++ ) {
|
|
|
|
if (DEVICES[i].starttick != NULL) { DEVICES[i].starttick(); }
|
|
|
|
}
|
2019-07-22 22:50:34 -04:00
|
|
|
|
|
|
|
SubTickTaskStart();
|
|
|
|
}
|
|
|
|
|
|
|
|
LOCALPROC SixtiethEndNotify(void)
|
|
|
|
{
|
2020-03-03 15:13:19 -05:00
|
|
|
int i;
|
2019-07-22 22:50:34 -04:00
|
|
|
SubTickTaskEnd();
|
2020-03-03 15:13:19 -05:00
|
|
|
for ( i = 0; i < ARRAY_SIZE(DEVICES); i++ ) {
|
|
|
|
if (DEVICES[i].endtick != NULL) { DEVICES[i].endtick(); }
|
|
|
|
}
|
2019-07-22 22:50:34 -04:00
|
|
|
#if dbglog_HAVE && 0
|
|
|
|
dbglog_WriteNote("end Sixtieth");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
LOCALPROC ExtraTimeBeginNotify(void)
|
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
dbglog_writeCStr("begin extra time");
|
|
|
|
dbglog_writeReturn();
|
|
|
|
#endif
|
|
|
|
VIA1_ExtraTimeBegin();
|
2020-03-03 13:31:11 -05:00
|
|
|
if (_EmVIA2) { VIA2_ExtraTimeBegin(); }
|
2019-07-22 22:50:34 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
LOCALPROC ExtraTimeEndNotify(void)
|
|
|
|
{
|
|
|
|
VIA1_ExtraTimeEnd();
|
2020-03-03 13:31:11 -05:00
|
|
|
if (_EmVIA2) { VIA2_ExtraTimeEnd(); }
|
2019-07-22 22:50:34 -04:00
|
|
|
#if 0
|
|
|
|
dbglog_writeCStr("end extra time");
|
|
|
|
dbglog_writeReturn();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
GLOBALPROC EmulationReserveAlloc(void)
|
|
|
|
{
|
|
|
|
ReserveAllocOneBlock(&RAM,
|
2020-02-11 00:34:32 -05:00
|
|
|
kRAM_Size + RAMSafetyMarginFudge, 5, false);
|
2019-07-22 22:50:34 -04:00
|
|
|
#if EmVidCard
|
2020-03-03 13:31:11 -05:00
|
|
|
ReserveAllocOneBlock(&VidROM, kVidROM_Size, 5, false);
|
2019-07-22 22:50:34 -04:00
|
|
|
#endif
|
|
|
|
#if IncludeVidMem
|
|
|
|
ReserveAllocOneBlock(&VidMem,
|
2020-02-11 00:34:32 -05:00
|
|
|
kVidMemRAM_Size + RAMSafetyMarginFudge, 5, true);
|
2019-07-22 22:50:34 -04:00
|
|
|
#endif
|
|
|
|
#if SmallGlobals
|
|
|
|
MINEM68K_ReserveAlloc();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2020-02-11 00:34:32 -05:00
|
|
|
LOCALFUNC bool InitEmulation(void)
|
2019-07-22 22:50:34 -04:00
|
|
|
{
|
2020-03-03 15:13:19 -05:00
|
|
|
int i;
|
|
|
|
for ( i = 0; i < ARRAY_SIZE(DEVICES); i++ ) {
|
|
|
|
if (DEVICES[i].init != NULL) {
|
|
|
|
bool retval = DEVICES[i].init();
|
|
|
|
if (retval == false) { return false; }
|
|
|
|
}
|
|
|
|
}
|
2020-03-03 13:31:11 -05:00
|
|
|
|
2020-03-03 15:13:19 -05:00
|
|
|
EmulatedHardwareZap();
|
|
|
|
return true;
|
2019-07-22 22:50:34 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
LOCALPROC ICT_DoTask(int taskid)
|
|
|
|
{
|
|
|
|
switch (taskid) {
|
|
|
|
case kICT_SubTick:
|
|
|
|
SubTickTaskDo();
|
|
|
|
break;
|
|
|
|
#if EmClassicKbrd
|
|
|
|
case kICT_Kybd_ReceiveEndCommand:
|
|
|
|
DoKybd_ReceiveEndCommand();
|
|
|
|
break;
|
|
|
|
case kICT_Kybd_ReceiveCommand:
|
|
|
|
DoKybd_ReceiveCommand();
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#if EmADB
|
|
|
|
case kICT_ADB_NewState:
|
|
|
|
ADB_DoNewState();
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#if EmPMU
|
|
|
|
case kICT_PMU_Task:
|
|
|
|
PMU_DoTask();
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
case kICT_VIA1_Timer1Check:
|
|
|
|
VIA1_DoTimer1Check();
|
|
|
|
break;
|
|
|
|
case kICT_VIA1_Timer2Check:
|
|
|
|
VIA1_DoTimer2Check();
|
|
|
|
break;
|
|
|
|
#if EmVIA2
|
|
|
|
case kICT_VIA2_Timer1Check:
|
|
|
|
VIA2_DoTimer1Check();
|
|
|
|
break;
|
|
|
|
case kICT_VIA2_Timer2Check:
|
|
|
|
VIA2_DoTimer2Check();
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
ReportAbnormalID(0x1001, "unknown taskid in ICT_DoTask");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
LOCALPROC ICT_DoCurrentTasks(void)
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
uimr m = ICTactive;
|
|
|
|
|
|
|
|
while (0 != m) {
|
|
|
|
if (0 != (m & 1)) {
|
|
|
|
if (i >= kNumICTs) {
|
|
|
|
/* shouldn't happen */
|
|
|
|
ICTactive &= ((1 << kNumICTs) - 1);
|
|
|
|
m = 0;
|
|
|
|
} else if (ICTwhen[i] == NextiCount) {
|
|
|
|
ICTactive &= ~ (1 << i);
|
|
|
|
#ifdef _VIA_Debug
|
|
|
|
fprintf(stderr, "doing task %d, %d\n", NextiCount, i);
|
|
|
|
#endif
|
|
|
|
ICT_DoTask(i);
|
|
|
|
|
|
|
|
/*
|
|
|
|
A Task may set the time of
|
|
|
|
any task, including itself.
|
|
|
|
But it cannot set any task
|
|
|
|
to execute immediately, so
|
|
|
|
one pass is sufficient.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
++i;
|
|
|
|
m >>= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-10 22:46:59 -05:00
|
|
|
LOCALFUNC uint32_t ICT_DoGetNext(uint32_t maxn)
|
2019-07-22 22:50:34 -04:00
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
uimr m = ICTactive;
|
2020-02-10 22:46:59 -05:00
|
|
|
uint32_t v = maxn;
|
2019-07-22 22:50:34 -04:00
|
|
|
|
|
|
|
while (0 != m) {
|
|
|
|
if (0 != (m & 1)) {
|
|
|
|
if (i >= kNumICTs) {
|
|
|
|
/* shouldn't happen */
|
|
|
|
m = 0;
|
|
|
|
} else {
|
2020-02-10 22:46:59 -05:00
|
|
|
uint32_t d = ICTwhen[i] - NextiCount;
|
2019-07-22 22:50:34 -04:00
|
|
|
/* at this point d must be > 0 */
|
|
|
|
if (d < v) {
|
|
|
|
#ifdef _VIA_Debug
|
|
|
|
fprintf(stderr, "coming task %d, %d, %d\n",
|
|
|
|
NextiCount, i, d);
|
|
|
|
#endif
|
|
|
|
v = d;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
++i;
|
|
|
|
m >>= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2020-02-10 22:46:59 -05:00
|
|
|
LOCALPROC m68k_go_nCycles_1(uint32_t n)
|
2019-07-22 22:50:34 -04:00
|
|
|
{
|
2020-02-10 22:46:59 -05:00
|
|
|
uint32_t n2;
|
|
|
|
uint32_t StopiCount = NextiCount + n;
|
2019-07-22 22:50:34 -04:00
|
|
|
do {
|
|
|
|
ICT_DoCurrentTasks();
|
|
|
|
n2 = ICT_DoGetNext(n);
|
|
|
|
#if dbglog_HAVE && 0
|
|
|
|
dbglog_StartLine();
|
|
|
|
dbglog_writeCStr("before m68k_go_nCycles, NextiCount:");
|
|
|
|
dbglog_writeHex(NextiCount);
|
|
|
|
dbglog_writeCStr(", n2:");
|
|
|
|
dbglog_writeHex(n2);
|
|
|
|
dbglog_writeCStr(", n:");
|
|
|
|
dbglog_writeHex(n);
|
|
|
|
dbglog_writeReturn();
|
|
|
|
#endif
|
|
|
|
NextiCount += n2;
|
|
|
|
m68k_go_nCycles(n2);
|
|
|
|
n = StopiCount - NextiCount;
|
|
|
|
} while (n != 0);
|
|
|
|
}
|
|
|
|
|
2020-02-10 22:46:59 -05:00
|
|
|
LOCALVAR uint32_t ExtraSubTicksToDo = 0;
|
2019-07-22 22:50:34 -04:00
|
|
|
|
|
|
|
LOCALPROC DoEmulateOneTick(void)
|
|
|
|
{
|
|
|
|
#if EnableAutoSlow
|
|
|
|
{
|
2020-02-10 22:46:59 -05:00
|
|
|
uint32_t NewQuietTime = QuietTime + 1;
|
2019-07-22 22:50:34 -04:00
|
|
|
|
|
|
|
if (NewQuietTime > QuietTime) {
|
|
|
|
/* if not overflow */
|
|
|
|
QuietTime = NewQuietTime;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#if EnableAutoSlow
|
|
|
|
{
|
2020-02-10 22:46:59 -05:00
|
|
|
uint32_t NewQuietSubTicks = QuietSubTicks + kNumSubTicks;
|
2019-07-22 22:50:34 -04:00
|
|
|
|
|
|
|
if (NewQuietSubTicks > QuietSubTicks) {
|
|
|
|
/* if not overflow */
|
|
|
|
QuietSubTicks = NewQuietSubTicks;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
SixtiethSecondNotify();
|
|
|
|
|
|
|
|
m68k_go_nCycles_1(CyclesScaledPerTick);
|
|
|
|
|
|
|
|
SixtiethEndNotify();
|
|
|
|
|
2020-02-10 22:46:59 -05:00
|
|
|
if ((uint8_t) -1 == SpeedValue) {
|
|
|
|
ExtraSubTicksToDo = (uint32_t) -1;
|
2019-07-22 22:50:34 -04:00
|
|
|
} else {
|
2020-02-10 22:46:59 -05:00
|
|
|
uint32_t ExtraAdd = (kNumSubTicks << SpeedValue) - kNumSubTicks;
|
|
|
|
uint32_t ExtraLimit = ExtraAdd << 3;
|
2019-07-22 22:50:34 -04:00
|
|
|
|
|
|
|
ExtraSubTicksToDo += ExtraAdd;
|
|
|
|
if (ExtraSubTicksToDo > ExtraLimit) {
|
|
|
|
ExtraSubTicksToDo = ExtraLimit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-11 00:34:32 -05:00
|
|
|
LOCALFUNC bool MoreSubTicksToDo(void)
|
2019-07-22 22:50:34 -04:00
|
|
|
{
|
2020-02-11 00:34:32 -05:00
|
|
|
bool v = false;
|
2019-07-22 22:50:34 -04:00
|
|
|
|
|
|
|
if (ExtraTimeNotOver() && (ExtraSubTicksToDo > 0)) {
|
|
|
|
#if EnableAutoSlow
|
|
|
|
if ((QuietSubTicks >= 16384)
|
|
|
|
&& (QuietTime >= 34)
|
|
|
|
&& ! WantNotAutoSlow)
|
|
|
|
{
|
|
|
|
ExtraSubTicksToDo = 0;
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
2020-02-11 00:34:32 -05:00
|
|
|
v = true;
|
2019-07-22 22:50:34 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOCALPROC DoEmulateExtraTime(void)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
DoEmulateExtraTime is used for
|
|
|
|
anything over emulation speed
|
|
|
|
of 1x. It periodically calls
|
|
|
|
ExtraTimeNotOver and stops
|
|
|
|
when this returns false (or it
|
|
|
|
is finished with emulating the
|
|
|
|
extra time).
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (MoreSubTicksToDo()) {
|
|
|
|
ExtraTimeBeginNotify();
|
|
|
|
do {
|
|
|
|
#if EnableAutoSlow
|
|
|
|
{
|
2020-02-10 22:46:59 -05:00
|
|
|
uint32_t NewQuietSubTicks = QuietSubTicks + 1;
|
2019-07-22 22:50:34 -04:00
|
|
|
|
|
|
|
if (NewQuietSubTicks > QuietSubTicks) {
|
|
|
|
/* if not overflow */
|
|
|
|
QuietSubTicks = NewQuietSubTicks;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
m68k_go_nCycles_1(CyclesScaledPerSubTick);
|
|
|
|
--ExtraSubTicksToDo;
|
|
|
|
} while (MoreSubTicksToDo());
|
|
|
|
ExtraTimeEndNotify();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-10 22:46:59 -05:00
|
|
|
LOCALVAR uint32_t CurEmulatedTime = 0;
|
2019-07-22 22:50:34 -04:00
|
|
|
/*
|
|
|
|
The number of ticks that have been
|
|
|
|
emulated so far.
|
|
|
|
|
|
|
|
That is, the number of times
|
|
|
|
"DoEmulateOneTick" has been called.
|
|
|
|
*/
|
|
|
|
|
|
|
|
LOCALPROC RunEmulatedTicksToTrueTime(void)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
The general idea is to call DoEmulateOneTick
|
|
|
|
once per tick.
|
|
|
|
|
|
|
|
But if emulation is lagging, we'll try to
|
|
|
|
catch up by calling DoEmulateOneTick multiple
|
|
|
|
times, unless we're too far behind, in
|
|
|
|
which case we forget it.
|
|
|
|
|
|
|
|
If emulating one tick takes longer than
|
|
|
|
a tick we don't want to sit here
|
|
|
|
forever. So the maximum number of calls
|
|
|
|
to DoEmulateOneTick is determined at
|
|
|
|
the beginning, rather than just
|
|
|
|
calling DoEmulateOneTick until
|
|
|
|
CurEmulatedTime >= TrueEmulatedTime.
|
|
|
|
*/
|
|
|
|
|
2020-02-10 22:46:59 -05:00
|
|
|
int8_t n = OnTrueTime - CurEmulatedTime;
|
2019-07-22 22:50:34 -04:00
|
|
|
|
|
|
|
if (n > 0) {
|
|
|
|
DoEmulateOneTick();
|
|
|
|
++CurEmulatedTime;
|
|
|
|
|
|
|
|
DoneWithDrawingForTick();
|
|
|
|
|
|
|
|
if (n > 8) {
|
|
|
|
/* emulation not fast enough */
|
|
|
|
n = 8;
|
|
|
|
CurEmulatedTime = OnTrueTime - n;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ExtraTimeNotOver() && (--n > 0)) {
|
|
|
|
/* lagging, catch up */
|
|
|
|
|
2020-02-11 00:34:32 -05:00
|
|
|
EmVideoDisable = true;
|
2019-07-22 22:50:34 -04:00
|
|
|
|
|
|
|
do {
|
|
|
|
DoEmulateOneTick();
|
|
|
|
++CurEmulatedTime;
|
|
|
|
} while (ExtraTimeNotOver()
|
|
|
|
&& (--n > 0));
|
|
|
|
|
2020-02-11 00:34:32 -05:00
|
|
|
EmVideoDisable = false;
|
2019-07-22 22:50:34 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
EmLagTime = n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
LOCALPROC MainEventLoop(void)
|
|
|
|
{
|
|
|
|
for (; ; ) {
|
|
|
|
WaitForNextTick();
|
|
|
|
if (ForceMacOff) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
RunEmulatedTicksToTrueTime();
|
|
|
|
|
|
|
|
DoEmulateExtraTime();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GLOBALPROC ProgramMain(void)
|
|
|
|
{
|
|
|
|
if (InitEmulation())
|
|
|
|
{
|
|
|
|
MainEventLoop();
|
|
|
|
}
|
|
|
|
}
|