From 297cea7d2aec892b13522f74e271c6a965409e96 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sat, 21 Oct 2017 18:47:22 +0100 Subject: [PATCH] Support polling of Mockingboard's & Phasor's 6522 IFR.Timer1 (#496) . Extended save-state (Mockingboard & Phasor: version 2) to support 6522 timer being active --- source/AY8910.cpp | 1 - source/CPU.cpp | 1 + source/Mockingboard.cpp | 130 ++++++++++++++++++++++++++-------------- source/Mockingboard.h | 5 -- 4 files changed, 85 insertions(+), 52 deletions(-) diff --git a/source/AY8910.cpp b/source/AY8910.cpp index e7f21f7d..701a958a 100644 --- a/source/AY8910.cpp +++ b/source/AY8910.cpp @@ -32,7 +32,6 @@ #include "AY8910.h" #include "Applewin.h" // For g_fh -#include "Mockingboard.h" // For g_uTimer1IrqCount #include "YamlHelper.h" /* The AY white noise RNG algorithm is based on info from MAME's ay8910.c - diff --git a/source/CPU.cpp b/source/CPU.cpp index 402ca743..f6bdc0fd 100644 --- a/source/CPU.cpp +++ b/source/CPU.cpp @@ -539,6 +539,7 @@ DWORD CpuExecute(const DWORD uCycles, const bool bVideoUpdate) const DWORD uExecutedCycles = InternalCpuExecute(uCycles, bVideoUpdate); MB_UpdateCycles(uExecutedCycles); // Update 6522s (NB. Do this before updating g_nCumulativeCycles below) + // NB. Ensures that 6522 regs are up-to-date for any potential save-state UpdateEmulationTime(uExecutedCycles); // diff --git a/source/Mockingboard.cpp b/source/Mockingboard.cpp index 4571f6cf..928b593d 100644 --- a/source/Mockingboard.cpp +++ b/source/Mockingboard.cpp @@ -122,7 +122,8 @@ struct SY6522_AY8910 SY6522 sy6522; BYTE nAY8910Number; BYTE nAYCurrentRegister; - BYTE nTimerStatus; + bool bTimer1Active; + bool bTimer2Active; SSI263A SpeechChip; }; @@ -203,13 +204,7 @@ static DWORD g_dwMaxPhonemeLen = 0; // When 6522 IRQ is *not* active use 60Hz update freq for MB voices static const double g_f6522TimerPeriod_NoIRQ = CLK_6502 / 60.0; // Constant whatever the CLK is set to -//--------------------------------------------------------------------------- - -// External global vars: -bool g_bMBTimerIrqActive = false; -#ifdef _DEBUG -UINT32 g_uTimer1IrqCount = 0; // DEBUG -#endif +static bool g_bMBTimerIrqActive = false; //--------------------------------------------------------------------------- @@ -219,33 +214,41 @@ static void Votrax_Write(BYTE nDevice, BYTE nValue); //--------------------------------------------------------------------------- -static void StartTimer(SY6522_AY8910* pMB) +static void StartTimer1(SY6522_AY8910* pMB) { -// if((pMB->nAY8910Number & 1) != SY6522_DEVICE_A) -// return; - - if((pMB->sy6522.IER & IxR_TIMER1) == 0x00) - return; - - USHORT nPeriod = pMB->sy6522.TIMER1_LATCH.w; - -// if(nPeriod <= 0xff) // Timer1L value has been written (but TIMER1H hasn't) -// return; - - pMB->nTimerStatus = 1; + pMB->bTimer1Active = true; // 6522 CLK runs at same speed as 6502 CLK - g_n6522TimerPeriod = nPeriod; + g_n6522TimerPeriod = pMB->sy6522.TIMER1_LATCH.w; + + if (pMB->sy6522.IER & IxR_TIMER1) + g_bMBTimerIrqActive = true; + + g_nMBTimerDevice = pMB->nAY8910Number; +} + +// The assumption was that timer1 was only active if IER.TIMER1=1 +// . Not true, since IFR can be polled (with IER.TIMER1=0) +static void StartTimer1_LoadStateV1(SY6522_AY8910* pMB) +{ + if ((pMB->sy6522.IER & IxR_TIMER1) == 0x00) + return; + + pMB->bTimer1Active = true; + + // 6522 CLK runs at same speed as 6502 CLK + g_n6522TimerPeriod = pMB->sy6522.TIMER1_LATCH.w; g_bMBTimerIrqActive = true; + g_nMBTimerDevice = pMB->nAY8910Number; } //----------------------------------------------------------------------------- -static void StopTimer(SY6522_AY8910* pMB) +static void StopTimer1(SY6522_AY8910* pMB) { - pMB->nTimerStatus = 0; + pMB->bTimer1Active = false; g_bMBTimerIrqActive = false; g_nMBTimerDevice = TIMERDEVICE_INVALID; } @@ -256,8 +259,8 @@ static void ResetSY6522(SY6522_AY8910* pMB) { memset(&pMB->sy6522,0,sizeof(SY6522)); - if(pMB->nTimerStatus) - StopTimer(pMB); + if (pMB->bTimer1Active) + StopTimer1(pMB); pMB->nAYCurrentRegister = 0; } @@ -398,7 +401,7 @@ static void SY6522_Write(BYTE nDevice, BYTE nReg, BYTE nValue) pMB->sy6522.TIMER1_LATCH.h = nValue; pMB->sy6522.TIMER1_COUNTER.w = pMB->sy6522.TIMER1_LATCH.w; - StartTimer(pMB); + StartTimer1(pMB); break; case 0x07: // TIMER1H_LATCH // Clear Timer1 Interrupt Flag. @@ -445,11 +448,11 @@ static void SY6522_Write(BYTE nDevice, BYTE nReg, BYTE nValue) if(pMB->sy6522.IER & IxR_TIMER1) break; - if(pMB->nTimerStatus == 0) + if (pMB->bTimer1Active == false) break; // Stop timer - StopTimer(pMB); + StopTimer1(pMB); } else { @@ -457,7 +460,7 @@ static void SY6522_Write(BYTE nDevice, BYTE nReg, BYTE nValue) nValue &= 0x7F; pMB->sy6522.IER |= nValue; UpdateIFR(pMB); - StartTimer(pMB); + StartTimer1(pMB); } break; case 0x0f: // ORA_NO_HS @@ -1656,7 +1659,10 @@ void MB_EndOfVideoFrame() //----------------------------------------------------------------------------- -// Called by CpuExecute() after every N opcodes (N = ~1000 @ 1MHz) +// Called by: +// . CpuExecute() every ~1000 @ 1MHz +// . CheckInterruptSources() every 128 cycles +// . MB_Read() / MB_Write() void MB_UpdateCycles(ULONG uExecutedCycles) { if(g_SoundcardType == CT_Empty) @@ -1682,12 +1688,8 @@ void MB_UpdateCycles(ULONG uExecutedCycles) bool bTimer1Underflow = (!(OldTimer1 & 0x8000) && (pMB->sy6522.TIMER1_COUNTER.w & 0x8000)); bool bTimer2Underflow = (!(OldTimer2 & 0x8000) && (pMB->sy6522.TIMER2_COUNTER.w & 0x8000)); - if( bTimer1Underflow && (g_nMBTimerDevice == i) && g_bMBTimerIrqActive ) + if ( bTimer1Underflow && (g_nMBTimerDevice == i) ) { -#ifdef _DEBUG - g_uTimer1IrqCount++; // DEBUG -#endif - pMB->sy6522.IFR |= IxR_TIMER1; UpdateIFR(pMB); @@ -1696,20 +1698,20 @@ void MB_UpdateCycles(ULONG uExecutedCycles) // One-shot mode // - Phasor's playback code uses one-shot mode // - Willy Byte sets to one-shot to stop the timer IRQ - StopTimer(pMB); + StopTimer1(pMB); } else { // Free-running mode // - Ultima4/5 change ACCESS_TIMER1 after a couple of IRQs into tune pMB->sy6522.TIMER1_COUNTER.w = pMB->sy6522.TIMER1_LATCH.w; - StartTimer(pMB); + StartTimer1(pMB); } MB_Update(); } else if ( bTimer1Underflow - && !g_bMBTimerIrqActive // StopTimer() has been called + && !g_bMBTimerIrqActive // StopTimer1() has been called && (pMB->sy6522.IFR & IxR_TIMER1) // IRQ && ((pMB->sy6522.ACR & RUNMODE) == RM_ONESHOT) ) // One-shot mode { @@ -1826,7 +1828,7 @@ int MB_SetSnapshot_v1(const SS_CARD_MOCKINGBOARD_v1* const pSS, const DWORD /*dw memcpy(&pMB->SpeechChip, &pSS->Unit[i].RegsSSI263, sizeof(SSI263A)); pMB->nAYCurrentRegister = pSS->Unit[i].nAYCurrentRegister; - StartTimer(pMB); // Attempt to start timer + StartTimer1_LoadStateV1(pMB); // Attempt to start timer // @@ -1919,6 +1921,8 @@ const UINT NUM_PHASOR_UNITS = 2; #define SS_YAML_KEY_TIMER1_IRQ "Timer1 IRQ Pending" #define SS_YAML_KEY_TIMER2_IRQ "Timer2 IRQ Pending" #define SS_YAML_KEY_SPEECH_IRQ "Speech IRQ Pending" +#define SS_YAML_KEY_TIMER1_ACTIVE "Timer1 Active" +#define SS_YAML_KEY_TIMER2_ACTIVE "Timer2 Active" #define SS_YAML_KEY_PHASOR_UNIT "Unit" #define SS_YAML_KEY_PHASOR_CLOCK_SCALE_FACTOR "Clock Scale Factor" @@ -1974,7 +1978,8 @@ void MB_SaveSnapshot(YamlSaveHelper& yamlSaveHelper, const UINT uSlot) UINT nDeviceNum = nMbCardNum*2; SY6522_AY8910* pMB = &g_MB[nDeviceNum]; - YamlSaveHelper::Slot slot(yamlSaveHelper, MB_GetSnapshotCardName(), uSlot, 1); // fixme: object should be just 1 Mockingboard card & it will know its slot + const UINT version = 2; + YamlSaveHelper::Slot slot(yamlSaveHelper, MB_GetSnapshotCardName(), uSlot, version); // fixme: object should be just 1 Mockingboard card & it will know its slot YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); @@ -1990,6 +1995,8 @@ void MB_SaveSnapshot(YamlSaveHelper& yamlSaveHelper, const UINT uSlot) yamlSaveHelper.Save("%s: %s # Not supported\n", SS_YAML_KEY_TIMER1_IRQ, "false"); yamlSaveHelper.Save("%s: %s # Not supported\n", SS_YAML_KEY_TIMER2_IRQ, "false"); yamlSaveHelper.Save("%s: %s # Not supported\n", SS_YAML_KEY_SPEECH_IRQ, "false"); + yamlSaveHelper.SaveBool(SS_YAML_KEY_TIMER1_ACTIVE, pMB->bTimer1Active); + yamlSaveHelper.SaveBool(SS_YAML_KEY_TIMER2_ACTIVE, pMB->bTimer2Active); nDeviceNum++; pMB++; @@ -2039,7 +2046,7 @@ bool MB_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version) if (slot != 4 && slot != 5) // fixme throw std::string("Card: wrong slot"); - if (version != 1) + if (version < 1 || version > 2) throw std::string("Card: wrong version"); AY8910UpdateSetCycles(); @@ -2067,11 +2074,25 @@ bool MB_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version) yamlLoadHelper.LoadBool(SS_YAML_KEY_TIMER2_IRQ); // Consume yamlLoadHelper.LoadBool(SS_YAML_KEY_SPEECH_IRQ); // Consume + if (version >= 2) + { + pMB->bTimer1Active = yamlLoadHelper.LoadBool(SS_YAML_KEY_TIMER1_ACTIVE); + pMB->bTimer2Active = yamlLoadHelper.LoadBool(SS_YAML_KEY_TIMER2_ACTIVE); + } + yamlLoadHelper.PopMap(); // - StartTimer(pMB); // Attempt to start timer + if (version == 1) + { + StartTimer1_LoadStateV1(pMB); // Attempt to start timer + } + else // version >= 2 + { + if (pMB->bTimer1Active) + StartTimer1(pMB); // Attempt to start timer + } // Crude - currently only support a single speech chip // FIX THIS: @@ -2110,7 +2131,8 @@ void Phasor_SaveSnapshot(YamlSaveHelper& yamlSaveHelper, const UINT uSlot) UINT nDeviceNum = 0; SY6522_AY8910* pMB = &g_MB[0]; // fixme: Phasor uses MB's slot4(2x6522), slot4(2xSSI263), but slot4+5(4xAY8910) - YamlSaveHelper::Slot slot(yamlSaveHelper, Phasor_GetSnapshotCardName(), uSlot, 1); // fixme: object should be just 1 Mockingboard card & it will know its slot + const UINT version = 2; + YamlSaveHelper::Slot slot(yamlSaveHelper, Phasor_GetSnapshotCardName(), uSlot, version); // fixme: object should be just 1 Mockingboard card & it will know its slot YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); @@ -2130,6 +2152,8 @@ void Phasor_SaveSnapshot(YamlSaveHelper& yamlSaveHelper, const UINT uSlot) yamlSaveHelper.Save("%s: %s # Not supported\n", SS_YAML_KEY_TIMER1_IRQ, "false"); yamlSaveHelper.Save("%s: %s # Not supported\n", SS_YAML_KEY_TIMER2_IRQ, "false"); yamlSaveHelper.Save("%s: %s # Not supported\n", SS_YAML_KEY_SPEECH_IRQ, "false"); + yamlSaveHelper.SaveBool(SS_YAML_KEY_TIMER1_ACTIVE, pMB->bTimer1Active); + yamlSaveHelper.SaveBool(SS_YAML_KEY_TIMER2_ACTIVE, pMB->bTimer2Active); nDeviceNum += 2; pMB++; @@ -2141,7 +2165,7 @@ bool Phasor_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version if (slot != 4) // fixme throw std::string("Card: wrong slot"); - if (version != 1) + if (version < 1 || version > 2) throw std::string("Card: wrong version"); g_PhasorClockScaleFactor = yamlLoadHelper.LoadUint(SS_YAML_KEY_PHASOR_CLOCK_SCALE_FACTOR); @@ -2172,11 +2196,25 @@ bool Phasor_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version yamlLoadHelper.LoadBool(SS_YAML_KEY_TIMER2_IRQ); // Consume yamlLoadHelper.LoadBool(SS_YAML_KEY_SPEECH_IRQ); // Consume + if (version >= 2) + { + pMB->bTimer1Active = yamlLoadHelper.LoadBool(SS_YAML_KEY_TIMER1_ACTIVE); + pMB->bTimer2Active = yamlLoadHelper.LoadBool(SS_YAML_KEY_TIMER2_ACTIVE); + } + yamlLoadHelper.PopMap(); // - StartTimer(pMB); // Attempt to start timer + if (version == 1) + { + StartTimer1_LoadStateV1(pMB); // Attempt to start timer + } + else // version >= 2 + { + if (pMB->bTimer1Active) + StartTimer1(pMB); // Attempt to start timer + } // Crude - currently only support a single speech chip // FIX THIS: diff --git a/source/Mockingboard.h b/source/Mockingboard.h index 901a9e41..0c33bc8b 100644 --- a/source/Mockingboard.h +++ b/source/Mockingboard.h @@ -1,10 +1,5 @@ #pragma once -extern bool g_bMBTimerIrqActive; -#ifdef _DEBUG -extern UINT32 g_uTimer1IrqCount; // DEBUG -#endif - void MB_Initialize(); void MB_Reinitialize(); void MB_Destroy();