mirror of
https://github.com/ctm/executor.git
synced 2024-05-29 06:41:34 +00:00
236 lines
5.6 KiB
C
236 lines
5.6 KiB
C
/* Copyright 1989, 1990, 1995 by Abacus Research and
|
|
* Development, Inc. All rights reserved.
|
|
*/
|
|
|
|
#if !defined (OMIT_RCSID_STRINGS)
|
|
char ROMlib_rcsid_vbl[] =
|
|
"$Id: vbl.c 63 2004-12-24 18:19:43Z ctm $";
|
|
#endif
|
|
|
|
/* Forward declarations in VRetraceMgr.h (DO NOT DELETE THIS LINE) */
|
|
|
|
#include "rsys/common.h"
|
|
#include "OSUtil.h"
|
|
#include "TimeMgr.h"
|
|
#include "VRetraceMgr.h"
|
|
#include "DeviceMgr.h"
|
|
#include "SoundDvr.h"
|
|
#include "OSEvent.h"
|
|
#include "ToolboxEvent.h"
|
|
|
|
#include "rsys/pstuff.h"
|
|
#include "rsys/vbl.h"
|
|
#include "rsys/time.h"
|
|
#include "rsys/hook.h"
|
|
|
|
#include "rsys/soundopts.h"
|
|
#include "rsys/prefs.h"
|
|
|
|
|
|
typedef enum
|
|
{
|
|
CLOCKOFF = 0,
|
|
CLOCKTEMPON,
|
|
CLOCKON,
|
|
CLOCKTEMPONSOUND,
|
|
CLOCKONSOUND,
|
|
}
|
|
clockstatus_t;
|
|
|
|
PUBLIC int ROMlib_clock = CLOCKOFF;
|
|
|
|
/*
|
|
* ROMlib_vcatch is called by the time manager, hence it doesn't need to
|
|
* block signals
|
|
*/
|
|
|
|
/*
|
|
* NOTE: we put a shim in the VBL queue, because Prince of Persia
|
|
* has a bug in it that overlooks the first element in the queue
|
|
* when it's looking for itself! We put in a magic ptr value we
|
|
* can recognize in case some bozo actually ever tries to call it.
|
|
* Note, however, that VInstall fills this in with a pointer to
|
|
* a m68k RTS instruction, just to be safe.
|
|
*/
|
|
|
|
VBLTask vblshim = { 0, CWC (vType), (ProcPtr) CLC (0xAEDCBA98), 0, 0 };
|
|
|
|
PRIVATE TMTask vbltm;
|
|
|
|
#define VBUSY (1 << 6)
|
|
|
|
A0 (PUBLIC, void, C_ROMlib_vcatch)
|
|
{
|
|
VBLTaskPtr vp, next;
|
|
ULONGINT old_ticks, new_ticks, ticks_elapsed;
|
|
LONGINT msecs_to_next_tick;
|
|
CCRElement saved_ccnz, saved_ccn, saved_ccc, saved_ccv, saved_ccx;
|
|
M68kReg saved_regs[16];
|
|
|
|
/* We save the 68k registers away. This isn't necessary if we can
|
|
* only be called from the time manager, since it has already saved
|
|
* all of the registers.
|
|
*/
|
|
memcpy (saved_regs, &cpu_state.regs, sizeof saved_regs);
|
|
saved_ccnz = cpu_state.ccnz;
|
|
saved_ccn = cpu_state.ccn;
|
|
saved_ccc = cpu_state.ccc;
|
|
saved_ccv = cpu_state.ccv;
|
|
saved_ccx = cpu_state.ccx;
|
|
|
|
EM_A7 = (EM_A7 - 32) & ~3; /* Might as well long-align it. */
|
|
|
|
/* Save the old Ticks value & compute new value. */
|
|
old_ticks = CL (Ticks);
|
|
new_ticks = C_TickCount ();
|
|
ticks_elapsed = new_ticks - old_ticks;
|
|
|
|
/* Compute the milliseconds until Ticks changes again.
|
|
* Here we rely on the fact that 1000 / 60 == 50 / 3, to avoid overflow.
|
|
*/
|
|
msecs_to_next_tick = (((new_ticks + 1) * 50 + 2) / 3) - msecs_elapsed ();
|
|
if (msecs_to_next_tick <= 0)
|
|
msecs_to_next_tick = 1;
|
|
|
|
PrimeTime ((QElemPtr) &vbltm, msecs_to_next_tick);
|
|
|
|
for (vp = (VBLTaskPtr) MR (VBLQueue.qHead); vp; vp = next)
|
|
{
|
|
INTEGER old_vbl_count, new_vbl_count;
|
|
|
|
next = (VBLTaskPtr) MR (vp->qLink);
|
|
|
|
/* Blow off the Prince of Persia shim. */
|
|
if (vp == &vblshim)
|
|
/*-->*/ continue;
|
|
|
|
/* Account for possible missed ticks by possibly subtracting
|
|
* off more than one tick from the VBL count. */
|
|
old_vbl_count = CW (vp->vblCount);
|
|
new_vbl_count = old_vbl_count - ticks_elapsed;
|
|
if (old_vbl_count > 0 && new_vbl_count < 0)
|
|
new_vbl_count = 0; /* Only compensate for zero crossings. */
|
|
|
|
vp->vblCount = CW (new_vbl_count);
|
|
if (new_vbl_count == 0)
|
|
{
|
|
VBLQueue.qFlags |= CWC (VBUSY);
|
|
ROMlib_hook (vbl_number);
|
|
|
|
/* No need to save/restore syn68k regs here; we do that
|
|
* outside the loop.
|
|
*/
|
|
|
|
EM_A0 = (LONGINT) (long) US_TO_SYN68K_CHECK0(vp);
|
|
EM_A1 = (LONGINT) CL ((long) vp->vblAddr);
|
|
|
|
CALL_EMULATOR ((syn68k_addr_t) EM_A1);
|
|
|
|
VBLQueue.qFlags &= CWC (~VBUSY);
|
|
if (vp->vblCount == CWC (0))
|
|
Dequeue ((QElemPtr) vp, &VBLQueue);
|
|
}
|
|
}
|
|
|
|
memcpy (&cpu_state.regs, saved_regs, sizeof saved_regs);
|
|
cpu_state.ccnz = saved_ccnz;
|
|
cpu_state.ccn = saved_ccn;
|
|
cpu_state.ccc = saved_ccc;
|
|
cpu_state.ccv = saved_ccv;
|
|
cpu_state.ccx = saved_ccx;
|
|
}
|
|
|
|
PRIVATE void
|
|
startclock (void)
|
|
{
|
|
vbltm.tmAddr = RM ((ProcPtr) P_ROMlib_vcatch);
|
|
InsTime ((QElemPtr) &vbltm);
|
|
PrimeTime ((QElemPtr) &vbltm, 17);
|
|
/* don't adjust ROMlib_clock; it could be temporary */
|
|
}
|
|
|
|
PRIVATE void
|
|
stopclock (void)
|
|
{
|
|
if (!VBLQueue.qTail)
|
|
{
|
|
RmvTime ((QElemPtr) &vbltm);
|
|
ROMlib_clock = CLOCKOFF;
|
|
}
|
|
else
|
|
ROMlib_clock = CLOCKTEMPON;
|
|
}
|
|
|
|
A1 (PUBLIC, void, ROMlib_clockonoff, LONGINT, onoroff)
|
|
{
|
|
if (onoroff)
|
|
{
|
|
if (ROMlib_clock == CLOCKOFF)
|
|
startclock ();
|
|
ROMlib_clock = CLOCKON;
|
|
}
|
|
else
|
|
stopclock ();
|
|
}
|
|
|
|
A2 (PUBLIC trap, OSErrRET, SlotVInstall,
|
|
VBLTaskPtr, vtaskp,
|
|
INTEGER, slot)
|
|
{
|
|
return VInstall (vtaskp);
|
|
}
|
|
|
|
A1 (PUBLIC trap, OSErrRET, VInstall, VBLTaskPtr, vtaskp)
|
|
{
|
|
static unsigned short m68k_rts = CWC (0x4E75); /* RTS */
|
|
|
|
vtaskp->vblCount = CW (CW (vtaskp->vblCount) + CW (vtaskp->vblPhase));
|
|
if (vtaskp->qType == CWC ((INTEGER) vType))
|
|
{
|
|
if (!VBLQueue.qHead)
|
|
{
|
|
vblshim.vblAddr = (ProcPtr) RM (&m68k_rts); /* legal 68k code. */
|
|
Enqueue ((QElemPtr) &vblshim, &VBLQueue);
|
|
}
|
|
Enqueue ((QElemPtr) vtaskp, &VBLQueue);
|
|
if (ROMlib_clock == CLOCKOFF)
|
|
{
|
|
ROMlib_clock = CLOCKTEMPON;
|
|
startclock ();
|
|
}
|
|
/*-->*/ return noErr;
|
|
}
|
|
else
|
|
return vTypErr;
|
|
}
|
|
|
|
A2 (PUBLIC trap, OSErrRET, SlotVRemove,
|
|
VBLTaskPtr, vtaskp,
|
|
INTEGER, slot)
|
|
{
|
|
return VRemove (vtaskp);
|
|
}
|
|
|
|
A1 (PUBLIC trap, OSErrRET, VRemove, VBLTaskPtr, vtaskp)
|
|
{
|
|
if (vtaskp->qType == CWC ((INTEGER) vType))
|
|
{
|
|
Dequeue ((QElemPtr) vtaskp, &VBLQueue);
|
|
if ((VBLTaskPtr) MR (VBLQueue.qHead) == &vblshim
|
|
&& (VBLTaskPtr) MR (VBLQueue.qTail) == &vblshim)
|
|
{
|
|
Dequeue ((QElemPtr) &vblshim, &VBLQueue);
|
|
if (ROMlib_clock == CLOCKTEMPON)
|
|
stopclock ();
|
|
}
|
|
/*-->*/ return noErr;
|
|
}
|
|
else
|
|
return vTypErr;
|
|
}
|
|
|
|
A0 (PUBLIC, QHdrPtr, GetVBLQHdr)
|
|
{
|
|
return &VBLQueue;
|
|
}
|