emu48-mirror/sources/Emu48/ENGINE.C

380 lines
11 KiB
C
Raw Normal View History

2024-03-19 22:24:30 +01:00
/*
* 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);
}