380 lines
11 KiB
C
380 lines
11 KiB
C
|
/*
|
||
|
* engine.c
|
||
|
*
|
||
|
* This file is part of Emu48
|
||
|
*
|
||
|
* Copyright (C) 1995 Sebastien Carlier
|
||
|
*
|
||
|
*/
|
||
|
#include "pch.h"
|
||
|
#include "Emu48.h"
|
||
|
#include "Serial.h"
|
||
|
|
||
|
// HST bits
|
||
|
#define XM 1
|
||
|
#define SB 2
|
||
|
#define SR 4
|
||
|
#define MP 8
|
||
|
|
||
|
#pragma intrinsic(memset,memcpy)
|
||
|
|
||
|
#define w Chipset
|
||
|
#define PCHANGED ((void)(F_s[0]=w.P,F_l[1]=w.P+1))
|
||
|
#define GOYES3 {if(w.carry)goto o_goyes3;else{w.pc+=2;continue;}}
|
||
|
#define GOYES5 {if(w.carry)goto o_goyes5;else{w.pc+=2;continue;}}
|
||
|
#define INTERRUPT ((void)(w.SoftInt=TRUE,bInterrupt=TRUE))
|
||
|
|
||
|
#define SAMPLE 16384 // 23.04.98 cg, new, speed adjust sample frequency
|
||
|
|
||
|
// 23.04.98 cg, new, cpu cycles for interval
|
||
|
#define T2CYCLES ((cCurrentRomType=='S')?dwSXCycles:dwGXCycles)
|
||
|
|
||
|
//#define FASTPTR(d) (RMap[d>>12]+(d&0xFFF))
|
||
|
static __inline LPBYTE FASTPTR(DWORD d)
|
||
|
{
|
||
|
// 17.12.98 cg, bugfix, code is running in IO area as well
|
||
|
if ((Chipset.IOCfig)&&((d&0xFFFC0)==Chipset.IOBase))
|
||
|
return Chipset.IORam+d-Chipset.IOBase;
|
||
|
|
||
|
return RMap[d>>12]+(d&0xFFF);
|
||
|
}
|
||
|
|
||
|
#include "Ops.h"
|
||
|
|
||
|
BOOL bInterrupt = FALSE;
|
||
|
UINT nState = 1;
|
||
|
UINT nNextState = 0;
|
||
|
BOOL bKeySlow = FALSE; // 18.11.98 cg, new, slow down for key emulation
|
||
|
CHIPSET Chipset;
|
||
|
|
||
|
char szSerialWire[16]; // 20.05.98 cg, new, devicename for wire port
|
||
|
char szSerialIr[16]; // 20.05.98 cg, new, devicename for IR port
|
||
|
|
||
|
DWORD dwSXCycles = 82; // 23.04.98 cg, new, SX cpu cycles in interval
|
||
|
DWORD dwGXCycles = 123; // 23.04.98 cg, new, GX cpu cycles in interval
|
||
|
|
||
|
static BOOL bCommInit = FALSE; // 17.05.98 cg, new, COM port not open
|
||
|
static BOOL bRealSpeed = FALSE; // 23.04.98 cg, new, enable/disable real speed
|
||
|
|
||
|
static DWORD dwOldCyc; // 23.04.98 cg, new, cpu cycles at last event
|
||
|
static DWORD dwSpeedRef; // 23.04.98 cg, new, timer value at last event
|
||
|
static DWORD dwTickRef; // 23.04.98 cg, new, sample timer ticks
|
||
|
|
||
|
static __inline VOID CheckSerial(VOID) // 17.05.98 cg, new function
|
||
|
// 25.02.99 cg, changed, inline coded now
|
||
|
{
|
||
|
if (ioc_acc) // IOC changed
|
||
|
{
|
||
|
ioc_acc = FALSE;
|
||
|
|
||
|
// COM port closed and serial on
|
||
|
if (bCommInit == FALSE && (Chipset.IORam[IO_CTRL] & SON) != 0)
|
||
|
{
|
||
|
CommOpen(szSerialWire,szSerialIr); // open COM ports
|
||
|
bCommInit = CommConnect() != PORT_CLOSE;
|
||
|
}
|
||
|
|
||
|
// COM port opend and serial off
|
||
|
if (bCommInit == TRUE && (Chipset.IORam[IO_CTRL] & SON) == 0)
|
||
|
{
|
||
|
CommClose(); // close COM port
|
||
|
bCommInit = FALSE;
|
||
|
}
|
||
|
|
||
|
// Interrupt on recv buffer full and receive buffer full
|
||
|
if ((Chipset.IORam[IO_CTRL] & ERBF) && (Chipset.IORam[RCS] & RBF))
|
||
|
{
|
||
|
Chipset.Shutdn = FALSE;
|
||
|
INTERRUPT;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static __inline VOID AdjustSpeed(VOID) // 23.04.98 cg, new, adjust emulation speed
|
||
|
// 25.02.99 cg, changed, inline coded now
|
||
|
{
|
||
|
if (bRealSpeed || bKeySlow) // 18.11.98 cg, changed, slow down
|
||
|
{
|
||
|
// cycles elapsed for next check
|
||
|
if (Chipset.cycles-dwOldCyc >= (DWORD) T2CYCLES)
|
||
|
{
|
||
|
LARGE_INTEGER lAct;
|
||
|
do
|
||
|
{
|
||
|
BOOL bErr = QueryPerformanceCounter(&lAct);
|
||
|
_ASSERT(bErr); // no high-resolution performance counter
|
||
|
}
|
||
|
while(lAct.LowPart-dwSpeedRef <= dwTickRef);
|
||
|
|
||
|
dwOldCyc += T2CYCLES; // adjust cycles reference
|
||
|
dwSpeedRef += dwTickRef; // adjust reference time
|
||
|
}
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
static VOID AdjKeySpeed(VOID) // 05.07.98 cg, new, slow down key repeat
|
||
|
// 18.11.98 cg, bugfix, slow down whole emulation,
|
||
|
// when key pressed
|
||
|
{
|
||
|
WORD i;
|
||
|
BOOL bKey;
|
||
|
|
||
|
if (bRealSpeed) return; // no need to slow down
|
||
|
|
||
|
bKey = FALSE; // search for a pressed key
|
||
|
for (i = 0;i < sizeof(Chipset.Keyboard_Row) / sizeof(Chipset.Keyboard_Row[0]) && !bKey;++i)
|
||
|
bKey = (Chipset.Keyboard_Row[i] != 0);
|
||
|
|
||
|
if (!bKeySlow && bKey) // key pressed, init variables
|
||
|
{
|
||
|
LARGE_INTEGER lTime; // sample timer ticks
|
||
|
dwOldCyc = Chipset.cycles; // save reference cycles
|
||
|
QueryPerformanceCounter(&lTime); // get timer ticks
|
||
|
dwSpeedRef = lTime.LowPart; // save reference time
|
||
|
}
|
||
|
bKeySlow = bKey; // save new state
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
VOID SetSpeed(BOOL bAdjust) // 23.04.98 cg, new, set emulation speed
|
||
|
{
|
||
|
if (bAdjust) // 15.05.98 cg, changed, switch to real speed
|
||
|
{
|
||
|
LARGE_INTEGER lTime; // sample timer ticks
|
||
|
dwOldCyc = Chipset.cycles; // save reference cycles
|
||
|
QueryPerformanceCounter(&lTime); // get timer ticks
|
||
|
dwSpeedRef = lTime.LowPart; // save reference time
|
||
|
}
|
||
|
bRealSpeed = bAdjust; // 15.05.98 cg, bugfix, save emulation speed
|
||
|
}
|
||
|
|
||
|
VOID UpdateKdnBit(VOID) // 25.02.99 cg, new, update KDN bit
|
||
|
{
|
||
|
if (Chipset.intk && Chipset.cycles - Chipset.dwKdnCycles > (DWORD) T2CYCLES * 16)
|
||
|
IOBit(0x19,8,Chipset.in != 0);
|
||
|
}
|
||
|
|
||
|
BOOL WaitForSleepState(VOID) // 16.06.98 cg, new, wait for cpu SHUTDN then sleep state
|
||
|
{
|
||
|
DWORD dwRefTime = timeGetTime();
|
||
|
|
||
|
// wait for the SHUTDN command with 1.5 sec timeout
|
||
|
while (timeGetTime() - dwRefTime < 1500L && !Chipset.Shutdn)
|
||
|
Sleep(0);
|
||
|
|
||
|
if (Chipset.Shutdn) // not timeout, cpu is down
|
||
|
SwitchToState(3); // go to sleep state
|
||
|
|
||
|
return 3 != nNextState; // state not changed, emulator was busy
|
||
|
}
|
||
|
|
||
|
UINT SwitchToState(UINT nNewState)
|
||
|
{
|
||
|
UINT nOldState = nState;
|
||
|
|
||
|
if (nState == nNewState) return nOldState;
|
||
|
switch (nState)
|
||
|
{
|
||
|
case 0: // Run
|
||
|
switch (nNewState)
|
||
|
{
|
||
|
case 1: // -> Invalid
|
||
|
nNextState = 1;
|
||
|
if (Chipset.Shutdn)
|
||
|
ResumeThread(hThread);
|
||
|
else
|
||
|
bInterrupt = TRUE;
|
||
|
while (nState!=nNextState) Sleep(0);
|
||
|
UpdateWindowStatus();
|
||
|
break;
|
||
|
case 2: // -> Return
|
||
|
nNextState = 1;
|
||
|
if (Chipset.Shutdn)
|
||
|
ResumeThread(hThread);
|
||
|
else
|
||
|
bInterrupt = TRUE;
|
||
|
while (nState!=nNextState) Sleep(0);
|
||
|
nNextState = 2;
|
||
|
ResumeThread(hThread);
|
||
|
while (nState!=nNextState) Sleep(0);
|
||
|
UpdateWindowStatus();
|
||
|
break;
|
||
|
case 3: // -> Sleep
|
||
|
nNextState = 3;
|
||
|
if (Chipset.Shutdn)
|
||
|
ResumeThread(hThread);
|
||
|
else
|
||
|
bInterrupt = TRUE;
|
||
|
while (nState!=nNextState) Sleep(0);
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case 1: // Invalid
|
||
|
switch (nNewState)
|
||
|
{
|
||
|
case 0: // -> Run
|
||
|
nNextState = 0;
|
||
|
bInterrupt = FALSE;
|
||
|
// 16.05.98 cg, bugfix, wait until thread is down, then resume
|
||
|
while (ResumeThread(hThread)==0) Sleep(0);
|
||
|
// ResumeThread(hThread);
|
||
|
while (nState!=nNextState) Sleep(0);
|
||
|
UpdateWindowStatus();
|
||
|
break;
|
||
|
case 2: // -> Return
|
||
|
nNextState = 2;
|
||
|
// 16.05.98 cg, bugfix, wait until thread is down, then resume
|
||
|
while (ResumeThread(hThread)==0) Sleep(0);
|
||
|
// ResumeThread(hThread);
|
||
|
while (nState!=nNextState) Sleep(0);
|
||
|
break;
|
||
|
case 3: // -> Sleep
|
||
|
nNextState = 3;
|
||
|
// 16.05.98 cg, bugfix, wait until thread is down, then resume
|
||
|
while (ResumeThread(hThread)==0) Sleep(0);
|
||
|
// ResumeThread(hThread);
|
||
|
while (nState!=nNextState) Sleep(0);
|
||
|
UpdateWindowStatus();
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case 3: // Sleep
|
||
|
switch (nNewState)
|
||
|
{
|
||
|
case 0: // -> Run
|
||
|
nNextState = 0;
|
||
|
if (Chipset.Shutdn) bInterrupt=TRUE;
|
||
|
// 16.05.98 cg, bugfix, wait until thread is down, then resume
|
||
|
while (ResumeThread(hThread)==0) Sleep(0);
|
||
|
// ResumeThread(hThread);
|
||
|
//while (nState!=nNextState) Sleep(0);
|
||
|
break;
|
||
|
case 1: // -> Invalid
|
||
|
nNextState = 1;
|
||
|
// 16.05.98 cg, bugfix, wait until thread is down, then resume
|
||
|
while (ResumeThread(hThread)==0) Sleep(0);
|
||
|
// ResumeThread(hThread);
|
||
|
while (nState!=nNextState) Sleep(0);
|
||
|
UpdateWindowStatus();
|
||
|
break;
|
||
|
case 2: // -> Return
|
||
|
nNextState = 1;
|
||
|
// 16.05.98 cg, bugfix, wait until thread is down, then resume
|
||
|
while (ResumeThread(hThread)==0) Sleep(0);
|
||
|
// ResumeThread(hThread);
|
||
|
while (nState!=nNextState) Sleep(0);
|
||
|
nNextState = 2;
|
||
|
// 16.05.98 cg, bugfix, wait until thread is down, then resume
|
||
|
while (ResumeThread(hThread)==0) Sleep(0);
|
||
|
// ResumeThread(hThread);
|
||
|
while (nState!=nNextState) Sleep(0);
|
||
|
UpdateWindowStatus();
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
return nOldState;
|
||
|
}
|
||
|
|
||
|
UINT WorkerThread(LPVOID pParam)
|
||
|
{
|
||
|
LARGE_INTEGER lDummyInt; // 23.04.98 cg, new, sample timer ticks
|
||
|
QueryPerformanceFrequency(&lDummyInt); // 23.04.98 cg, new, init timer ticks
|
||
|
lDummyInt.QuadPart /= SAMPLE; // 23.04.98 cg, new, calculate sample ticks
|
||
|
dwTickRef = lDummyInt.LowPart; // 23.04.98 cg, new, sample timer ticks
|
||
|
_ASSERT(dwTickRef); // 23.04.98 cg, new, tick resolution error
|
||
|
|
||
|
loop:
|
||
|
while (nNextState == 1) // go into invalid state
|
||
|
{
|
||
|
CommClose(); // 17.05.98 cg, new, close COM port
|
||
|
bCommInit = FALSE; // 17.05.98 cg, new, COM port not open
|
||
|
nState = 1; // in invalid state
|
||
|
SuspendThread(hThread); // sleep thread
|
||
|
if (nNextState == 2) // go into return state
|
||
|
{
|
||
|
nState = 2; // in return state
|
||
|
return 0; // kill thread
|
||
|
}
|
||
|
ioc_acc = TRUE; // 17.05.98 cg, new, test if UART on
|
||
|
}
|
||
|
while (nNextState == 0)
|
||
|
{
|
||
|
if (nState!=0)
|
||
|
{
|
||
|
nState = 0;
|
||
|
if (Chipset.type == 'S')
|
||
|
{
|
||
|
Chipset.cards_status &= 0x5;
|
||
|
if (pbyPort2) Chipset.cards_status |= 0x2;
|
||
|
if (bPort2Writeable) Chipset.cards_status |= 0x8;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Chipset.cards_status &= 0xA;
|
||
|
if (pbyPort2) Chipset.cards_status |= 0x1;
|
||
|
if (bPort2Writeable) Chipset.cards_status |= 0x4;
|
||
|
}
|
||
|
UpdateDisplayPointers();
|
||
|
UpdateMainDisplay();
|
||
|
UpdateMenuDisplay();
|
||
|
UpdateAnnunciators();
|
||
|
// 23.04.98 cg, new, init speed reference
|
||
|
dwOldCyc = Chipset.cycles;
|
||
|
QueryPerformanceCounter(&lDummyInt);
|
||
|
dwSpeedRef = lDummyInt.LowPart;
|
||
|
// 23.04.98 cg, end of init
|
||
|
StartTimers();
|
||
|
}
|
||
|
PCHANGED;
|
||
|
while (!bInterrupt)
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
LPBYTE I = FASTPTR(w.pc);
|
||
|
#include "Fetch.h"
|
||
|
#include "Opcodes.h"
|
||
|
}
|
||
|
while(0); // 23.04.98 cg, workaround for continue
|
||
|
|
||
|
CheckSerial(); // 17.05.98 cg, serial support
|
||
|
AdjustSpeed(); // 23.04.98 cg, adjust emulation speed
|
||
|
}
|
||
|
if (Chipset.Shutdn)
|
||
|
{
|
||
|
bInterrupt = FALSE;
|
||
|
SuspendThread(hThread);
|
||
|
Chipset.Shutdn = FALSE;
|
||
|
// 23.04.98 cg, new, init speed reference
|
||
|
dwOldCyc = Chipset.cycles;
|
||
|
QueryPerformanceCounter(&lDummyInt);
|
||
|
dwSpeedRef = lDummyInt.LowPart;
|
||
|
// 23.04.98 cg, end of init
|
||
|
}
|
||
|
if (Chipset.SoftInt)
|
||
|
{
|
||
|
bInterrupt = FALSE;
|
||
|
Chipset.SoftInt = FALSE;
|
||
|
if (Chipset.inte)
|
||
|
{
|
||
|
Chipset.inte = FALSE;
|
||
|
rstkpush(Chipset.pc);
|
||
|
Chipset.pc = 0xf;
|
||
|
}
|
||
|
}
|
||
|
if (nNextState != 0)
|
||
|
{
|
||
|
StopTimers();
|
||
|
Chipset.cards_status &= (Chipset.type=='S')?0x5:0xA;
|
||
|
}
|
||
|
}
|
||
|
while (nNextState == 3) // go into sleep state
|
||
|
{
|
||
|
nState = 3; // in sleep state
|
||
|
SuspendThread(hThread); // sleep thread
|
||
|
}
|
||
|
goto loop;
|
||
|
UNREFERENCED_PARAMETER(pParam);
|
||
|
}
|