/* * 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); }