minivmac4ios/Mini vMac/mnvm_core/PROGMAIN.c

1 line
9.8 KiB
C
Executable File

/*
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.
*/
#ifndef AllFiles
#include "SYSDEPNS.h"
#include "MYOSGLUE.h"
#include "EMCONFIG.h"
#include "GLOBGLUE.h"
#include "M68KITAB.h"
#include "MINEM68K.h"
#include "VIAEMDEV.h"
#if EmVIA2
#include "VIA2EMDV.h"
#endif
#include "IWMEMDEV.h"
#include "SCCEMDEV.h"
#if EmRTC
#include "RTCEMDEV.h"
#endif
#include "ROMEMDEV.h"
#include "SCSIEMDV.h"
#include "SONYEMDV.h"
#include "SCRNEMDV.h"
#if EmVidCard
#include "VIDEMDEV.h"
#endif
#if EmClassicKbrd
#include "KBRDEMDV.h"
#elif EmPMU
#include "PMUEMDEV.h"
#else
#include "ADBEMDEV.h"
#endif
#if EmASC
#include "ASCEMDEV.h"
#else
#if MySoundEnabled && (CurEmMd != kEmMd_PB100)
#include "SNDEMDEV.h"
#endif
#endif
#include "MOUSEMDV.h"
#endif
#include "PROGMAIN.h"
LOCALPROC EmulatedHardwareZap(void)
{
Memory_Reset();
ICT_Zap();
IWM_Reset();
SCC_Reset();
SCSI_Reset();
VIA1_Zap();
#if EmVIA2
VIA2_Zap();
#endif
Sony_Reset();
Extn_Reset();
m68k_reset();
}
LOCALPROC DoMacReset(void)
{
Sony_EjectAllDisks();
EmulatedHardwareZap();
}
LOCALPROC InterruptReset_Update(void)
{
SetInterruptButton(falseblnr);
/*
in case has been set. so only stays set
for 60th of a second.
*/
if (WantMacInterrupt) {
SetInterruptButton(trueblnr);
WantMacInterrupt = falseblnr;
}
if (WantMacReset) {
DoMacReset();
WantMacReset = falseblnr;
}
}
LOCALPROC SubTickNotify(int SubTick)
{
#if 0
dbglog_writeCStr("ending sub tick ");
dbglog_writeNum(SubTick);
dbglog_writeReturn();
#endif
#if MySoundEnabled && (CurEmMd != kEmMd_PB100)
MacSound_SubTick(SubTick);
#else
UnusedParam(SubTick);
#endif
}
#define CyclesScaledPerTick (130240UL * kMyClockMult * kCycleScale)
#define CyclesScaledPerSubTick (CyclesScaledPerTick / kNumSubTicks)
LOCALVAR ui4r SubTickCounter;
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)
{
#if dbglog_HAVE && 0
dbglog_StartLine();
dbglog_writeCStr("begin new Sixtieth");
dbglog_writeReturn();
#endif
Mouse_Update();
InterruptReset_Update();
#if EmClassicKbrd
KeyBoard_Update();
#endif
#if EmADB
ADB_Update();
#endif
Sixtieth_PulseNtfy(); /* Vertical Blanking Interrupt */
Sony_Update();
#if EmLocalTalk
LocalTalkTick();
#endif
#if EmRTC
RTC_Interrupt();
#endif
#if EmVidCard
Vid_Update();
#endif
#if EmASC
ASC_Update();
#endif
SubTickTaskStart();
}
LOCALPROC SixtiethEndNotify(void)
{
SubTickTaskEnd();
Mouse_EndTickNotify();
Screen_EndTickNotify();
#if dbglog_HAVE && 0
dbglog_StartLine();
dbglog_writeCStr("end Sixtieth");
dbglog_writeReturn();
#endif
}
LOCALPROC ExtraTimeBeginNotify(void)
{
#if 0
dbglog_writeCStr("begin extra time");
dbglog_writeReturn();
#endif
VIA1_ExtraTimeBegin();
#if EmVIA2
VIA2_ExtraTimeBegin();
#endif
}
LOCALPROC ExtraTimeEndNotify(void)
{
VIA1_ExtraTimeEnd();
#if EmVIA2
VIA2_ExtraTimeEnd();
#endif
#if 0
dbglog_writeCStr("end extra time");
dbglog_writeReturn();
#endif
}
GLOBALPROC EmulationReserveAlloc(void)
{
ReserveAllocOneBlock(&RAM,
kRAM_Size + RAMSafetyMarginFudge, 5, falseblnr);
#if EmVidCard
ReserveAllocOneBlock(&VidROM, kVidROM_Size, 5, falseblnr);
#endif
#if IncludeVidMem
ReserveAllocOneBlock(&VidMem,
kVidMemRAM_Size + RAMSafetyMarginFudge, 5, trueblnr);
#endif
#if SmallGlobals
MINEM68K_ReserveAlloc();
#endif
}
LOCALFUNC blnr InitEmulation(void)
{
#if EmRTC
if (RTC_Init())
#endif
if (ROM_Init())
#if EmVidCard
if (Vid_Init())
#endif
if (AddrSpac_Init())
{
EmulatedHardwareZap();
return trueblnr;
}
return falseblnr;
}
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:
ReportAbnormal("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;
}
}
LOCALFUNC ui5b ICT_DoGetNext(ui5b maxn)
{
int i = 0;
uimr m = ICTactive;
ui5b v = maxn;
while (0 != m) {
if (0 != (m & 1)) {
if (i >= kNumICTs) {
/* shouldn't happen */
m = 0;
} else {
ui5b d = ICTwhen[i] - NextiCount;
/* 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;
}
LOCALPROC m68k_go_nCycles_1(ui5b n)
{
ui5b n2;
ui5b StopiCount = NextiCount + n;
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);
}
LOCALVAR ui5b ExtraSubTicksToDo = 0;
LOCALPROC DoEmulateOneTick(void)
{
#if EnableAutoSlow
{
ui5r NewQuietTime = QuietTime + 1;
if (NewQuietTime > QuietTime) {
/* if not overflow */
QuietTime = NewQuietTime;
}
}
#endif
#if EnableAutoSlow
{
ui5r NewQuietSubTicks = QuietSubTicks + kNumSubTicks;
if (NewQuietSubTicks > QuietSubTicks) {
/* if not overflow */
QuietSubTicks = NewQuietSubTicks;
}
}
#endif
SixtiethSecondNotify();
m68k_go_nCycles_1(CyclesScaledPerTick);
SixtiethEndNotify();
if ((ui3b) -1 == SpeedValue) {
ExtraSubTicksToDo = (ui5b) -1;
} else {
ui5b ExtraAdd = (kNumSubTicks << SpeedValue) - kNumSubTicks;
ui5b ExtraLimit = ExtraAdd << 3;
ExtraSubTicksToDo += ExtraAdd;
if (ExtraSubTicksToDo > ExtraLimit) {
ExtraSubTicksToDo = ExtraLimit;
}
}
}
LOCALFUNC blnr MoreSubTicksToDo(void)
{
blnr v = falseblnr;
if (ExtraTimeNotOver() && (ExtraSubTicksToDo > 0)) {
#if EnableAutoSlow
if ((QuietSubTicks >= 16384)
&& (QuietTime >= 34)
&& ! WantNotAutoSlow)
{
ExtraSubTicksToDo = 0;
} else
#endif
{
v = trueblnr;
}
}
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
{
ui5r NewQuietSubTicks = QuietSubTicks + 1;
if (NewQuietSubTicks > QuietSubTicks) {
/* if not overflow */
QuietSubTicks = NewQuietSubTicks;
}
}
#endif
m68k_go_nCycles_1(CyclesScaledPerSubTick);
--ExtraSubTicksToDo;
} while (MoreSubTicksToDo());
ExtraTimeEndNotify();
}
}
LOCALVAR ui5b CurEmulatedTime = 0;
/*
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.
*/
si3b n = OnTrueTime - CurEmulatedTime;
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 */
EmVideoDisable = trueblnr;
do {
DoEmulateOneTick();
++CurEmulatedTime;
} while (ExtraTimeNotOver()
&& (--n > 0));
EmVideoDisable = falseblnr;
}
EmLagTime = n;
}
}
LOCALPROC MainEventLoop(void)
{
for (; ; ) {
WaitForNextTick();
if (ForceMacOff) {
return;
}
RunEmulatedTicksToTrueTime();
DoEmulateExtraTime();
}
}
GLOBALPROC ProgramMain(void)
{
if (InitEmulation())
{
MainEventLoop();
}
}