/* * timer.c * * This file is part of Emu48 * * Copyright (C) 1995 Sebastien Carlier * */ #include "pch.h" #include "Emu48.h" BOOL bAccurateTimer = TRUE; UINT uT1Period = 62; static BOOL bStarted = FALSE; static UINT uT1TimerId = 0; static UINT uT2TimerId = 0; static DWORD dwT1Ticks = 0; static DWORD dwT2Init = 0; static DWORD dwT2Step = 0; static DWORD dwT2Ticks = 0; static __inline MAX(int a, int b) {return (a>b)?a:b;} static void CALLBACK TimeProc(UINT uEventId, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2); static VOID CheckT1() { _ASSERT(bStarted); if ((Chipset.t1&8) == 0) { Chipset.IORam[0x2E] &= 0x7; // clear bit 3 return; } if (Chipset.IORam[0x2E]&4) { // T1 -> Wake Up if (Chipset.Shutdn) { ResumeThread(hThread); Chipset.IORam[0x2E] &= 0xB; // clear bit 2 Chipset.IORam[0x2E] |= 0x8; // set bit 3 } } if (Chipset.IORam[0x2E]&2) { // T1 -> Interrupt Chipset.IORam[0x2E] |= 0x8; // set bit 3 Chipset.SoftInt = TRUE; bInterrupt=TRUE; } return; } static VOID CheckT2() { _ASSERT(bStarted); if ((Chipset.t2&0x80000000) == 0) { Chipset.IORam[0x2F] &= 7; // clear bit 3 return; } if (Chipset.IORam[0x2F]&4) { // T2 -> Wake Up if (Chipset.Shutdn) { ResumeThread(hThread); Chipset.IORam[0x2F] &= 0xB; // clear bit 2 Chipset.IORam[0x2F] |= 0x8; // set bit 3 } } if (Chipset.IORam[0x2F]&2) { // T2 -> Interrupt Chipset.IORam[0x2F] |= 0x8; // set bit 3 Chipset.SoftInt = TRUE; bInterrupt=TRUE; } return; } static VOID RescheduleT2() { _ASSERT(uT2TimerId == 0); dwT2Init = timeGetTime(); dwT2Ticks = dwT2Init; uT2TimerId = timeSetEvent(MAX(16,Chipset.t2>>3),0,(LPTIMECALLBACK)&TimeProc,2,TIME_ONESHOT); return; } static VOID AbortT2() { _ASSERT(uT2TimerId != 0); uT2TimerId = 0; timeKillEvent(uT2TimerId); return; } static void CALLBACK TimeProc(UINT uEventId, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) { if (!bStarted) return; if ((uT1TimerId!=0) && (uEventId == uT1TimerId)) { Chipset.t1 = (Chipset.t1-1)&0xF; CheckT1(); return; } if ((uT2TimerId!=0) && (uEventId == uT2TimerId)) { uT2TimerId = 0; Chipset.t2 = 0xFFFFFFFF; CheckT2(); RescheduleT2(); return; } return; UNREFERENCED_PARAMETER(uMsg); } VOID StartTimers() { if (bStarted) return; if (Chipset.IORam[0x2F]&1) { bStarted = TRUE; if (bAccurateTimer) { MMRESULT uResult; uResult = timeBeginPeriod(1); if (uResult!=TIMERR_NOERROR) bAccurateTimer=FALSE; } uT1TimerId = timeSetEvent(uT1Period,0,(LPTIMECALLBACK)&TimeProc,1,TIME_PERIODIC); RescheduleT2(); } return; } VOID StopTimers() { if (!bStarted) return; Chipset.t2 = ReadT2(); if (uT1TimerId != 0) { timeKillEvent(uT1TimerId); uT1TimerId = 0; } if (uT2TimerId != 0) AbortT2(); bStarted = FALSE; if (bAccurateTimer) { timeEndPeriod(1); } return; } DWORD ReadT2() { DWORD dwT2; if (!bStarted) { dwT2 = Chipset.t2; } else { DWORD dwNow = timeGetTime(); if (dwNow == dwT2Ticks) { if (dwT2Step < 7) dwT2Step++; return Chipset.t2-(8*(dwNow-dwT2Init)+dwT2Step); } dwT2Step = 0; dwT2Ticks = dwNow; dwT2 = Chipset.t2-8*(dwNow-dwT2Init); } return dwT2; } VOID SetT2(DWORD dwValue) { if (!bStarted) { Chipset.t2 = dwValue; return; } if (uT2TimerId != 0) AbortT2(); Chipset.t2 = dwValue; CheckT2(); RescheduleT2(); return; } BYTE ReadT1() { return Chipset.t1; } VOID SetT1(BYTE byValue) { Chipset.t1 = byValue&0xF; CheckT1(); return; }