mirror of
https://github.com/AppleWin/AppleWin.git
synced 2024-06-24 12:29:43 +00:00
6522: Underflow on 0x0001 -> 0x0000; and FRT's period is N+2 cycles (#652)
This commit is contained in:
parent
9a7424e704
commit
3fbe416424
|
@ -1737,13 +1737,46 @@ void MB_EndOfVideoFrame()
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static bool CheckTimerUnderflowAndIrq(USHORT& timerCounter, int& timerIrqDelay, const USHORT nClocks, bool* pTimerUnderflow=NULL)
|
||||
{
|
||||
int oldTimer = timerCounter; // Catch the case for 0x0000 -> -ve, as this isn't an underflow
|
||||
int timer = timerCounter;
|
||||
timer -= nClocks;
|
||||
timerCounter = (USHORT)timer;
|
||||
|
||||
bool timerIrq = false;
|
||||
|
||||
if (timerIrqDelay) // Deal with any previous counter underflow which didn't yet result in an IRQ
|
||||
{
|
||||
timerIrqDelay -= nClocks;
|
||||
if (timerIrqDelay <= 0)
|
||||
{
|
||||
timerIrqDelay = 0;
|
||||
timerIrq = true;
|
||||
}
|
||||
// don't re-underflow if TIMER = 0x0000 or 0xFFFF (so just return)
|
||||
}
|
||||
else if (oldTimer > 0 && timer <= 0) // Underflow occurs for 0x0001 -> 0x0000
|
||||
{
|
||||
if (pTimerUnderflow)
|
||||
*pTimerUnderflow = true; // Just for Willy Byte!
|
||||
|
||||
if (timer <= -2)
|
||||
timerIrq = true;
|
||||
else // TIMER = 0x0000 or 0xFFFF
|
||||
timerIrqDelay = 2 + timer; // ...so 2 or 1 cycles until IRQ
|
||||
}
|
||||
|
||||
return timerIrq;
|
||||
}
|
||||
|
||||
// Called by:
|
||||
// . CpuExecute() every ~1000 @ 1MHz
|
||||
// . CheckInterruptSources() every 128 cycles
|
||||
// . MB_Read() / MB_Write()
|
||||
void MB_UpdateCycles(ULONG uExecutedCycles)
|
||||
{
|
||||
if(g_SoundcardType == CT_Empty)
|
||||
if (g_SoundcardType == CT_Empty)
|
||||
return;
|
||||
|
||||
CpuCalcCycles(uExecutedCycles);
|
||||
|
@ -1752,19 +1785,13 @@ void MB_UpdateCycles(ULONG uExecutedCycles)
|
|||
_ASSERT(uCycles < 0x10000);
|
||||
USHORT nClocks = (USHORT) uCycles;
|
||||
|
||||
for(int i=0; i<NUM_SY6522; i++)
|
||||
for (int i=0; i<NUM_SY6522; i++)
|
||||
{
|
||||
SY6522_AY8910* pMB = &g_MB[i];
|
||||
|
||||
USHORT OldTimer1 = pMB->sy6522.TIMER1_COUNTER.w;
|
||||
USHORT OldTimer2 = pMB->sy6522.TIMER2_COUNTER.w;
|
||||
|
||||
pMB->sy6522.TIMER1_COUNTER.w -= nClocks;
|
||||
pMB->sy6522.TIMER2_COUNTER.w -= nClocks;
|
||||
|
||||
// Check for counter underflow
|
||||
bool bTimer1Underflow = (!(OldTimer1 & 0x8000) && (pMB->sy6522.TIMER1_COUNTER.w & 0x8000));
|
||||
bool bTimer2Underflow = (!(OldTimer2 & 0x8000) && (pMB->sy6522.TIMER2_COUNTER.w & 0x8000));
|
||||
bool bTimer1Underflow = false; // Just for Willy Byte!
|
||||
const bool bTimer1Irq = CheckTimerUnderflowAndIrq(pMB->sy6522.TIMER1_COUNTER.w, pMB->sy6522.timer1IrqDelay, nClocks, &bTimer1Underflow);
|
||||
const bool bTimer2Irq = CheckTimerUnderflowAndIrq(pMB->sy6522.TIMER2_COUNTER.w, pMB->sy6522.timer2IrqDelay, nClocks);
|
||||
|
||||
if (!pMB->bTimer1Active && bTimer1Underflow)
|
||||
{
|
||||
|
@ -1774,11 +1801,12 @@ void MB_UpdateCycles(ULONG uExecutedCycles)
|
|||
{
|
||||
// Fix for Willy Byte - need to confirm that 6522 really does this!
|
||||
// . It never accesses IER/IFR/TIMER1 regs to clear IRQ
|
||||
// . NB. Willy Byte doesn't work with Phasor.
|
||||
UpdateIFR(pMB, IxR_TIMER1); // Deassert the TIMER IRQ
|
||||
}
|
||||
}
|
||||
|
||||
if (pMB->bTimer1Active && bTimer1Underflow)
|
||||
if (pMB->bTimer1Active && bTimer1Irq)
|
||||
{
|
||||
UpdateIFR(pMB, 0, IxR_TIMER1);
|
||||
|
||||
|
@ -1786,7 +1814,7 @@ void MB_UpdateCycles(ULONG uExecutedCycles)
|
|||
if (g_nMBTimerDevice == i)
|
||||
MB_Update();
|
||||
|
||||
if((pMB->sy6522.ACR & RUNMODE) == RM_ONESHOT)
|
||||
if ((pMB->sy6522.ACR & RUNMODE) == RM_ONESHOT)
|
||||
{
|
||||
// One-shot mode
|
||||
// - Phasor's playback code uses one-shot mode
|
||||
|
@ -1798,6 +1826,8 @@ void MB_UpdateCycles(ULONG uExecutedCycles)
|
|||
// 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; // GH#651: account for underflowed cycles too
|
||||
pMB->sy6522.TIMER1_COUNTER.w += 2; // GH#652: account for extra 2 cycles (Rockwell, Fig.16: period=N+2cycles)
|
||||
// - or maybe the counter doesn't count down during these 2 cycles?
|
||||
if (pMB->sy6522.TIMER1_COUNTER.w > pMB->sy6522.TIMER1_LATCH.w)
|
||||
{
|
||||
if (pMB->sy6522.TIMER1_LATCH.w)
|
||||
|
@ -1809,7 +1839,7 @@ void MB_UpdateCycles(ULONG uExecutedCycles)
|
|||
}
|
||||
}
|
||||
|
||||
if (pMB->bTimer2Active && bTimer2Underflow)
|
||||
if (pMB->bTimer2Active && bTimer2Irq)
|
||||
{
|
||||
UpdateIFR(pMB, 0, IxR_TIMER2);
|
||||
|
||||
|
@ -1918,7 +1948,8 @@ void MB_GetSnapshot_v1(SS_CARD_MOCKINGBOARD_v1* const pSS, const DWORD dwSlot)
|
|||
// Unit version history:
|
||||
// 2: Added: Timer1 & Timer2 active
|
||||
// 3: Added: Unit state
|
||||
const UINT kUNIT_VERSION = 3;
|
||||
// 4: Added: 6522 timerIrqDelay
|
||||
const UINT kUNIT_VERSION = 4;
|
||||
|
||||
const UINT NUM_MB_UNITS = 2;
|
||||
const UINT NUM_PHASOR_UNITS = 2;
|
||||
|
@ -1952,6 +1983,8 @@ const UINT NUM_PHASOR_UNITS = 2;
|
|||
#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_SY6522_TIMER1_IRQ_DELAY "Timer1 IRQ Delay"
|
||||
#define SS_YAML_KEY_SY6522_TIMER2_IRQ_DELAY "Timer2 IRQ Delay"
|
||||
|
||||
#define SS_YAML_KEY_PHASOR_UNIT "Unit"
|
||||
#define SS_YAML_KEY_PHASOR_CLOCK_SCALE_FACTOR "Clock Scale Factor"
|
||||
|
@ -1979,8 +2012,10 @@ static void SaveSnapshotSY6522(YamlSaveHelper& yamlSaveHelper, SY6522& sy6522)
|
|||
yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SY6522_REG_DDRA, sy6522.DDRA);
|
||||
yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_SY6522_REG_T1_COUNTER, sy6522.TIMER1_COUNTER.w);
|
||||
yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_SY6522_REG_T1_LATCH, sy6522.TIMER1_LATCH.w);
|
||||
yamlSaveHelper.SaveUint(SS_YAML_KEY_SY6522_TIMER1_IRQ_DELAY, sy6522.timer1IrqDelay); // v4
|
||||
yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_SY6522_REG_T2_COUNTER, sy6522.TIMER2_COUNTER.w);
|
||||
yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_SY6522_REG_T2_LATCH, sy6522.TIMER2_LATCH.w);
|
||||
yamlSaveHelper.SaveUint(SS_YAML_KEY_SY6522_TIMER2_IRQ_DELAY, sy6522.timer2IrqDelay); // v4
|
||||
yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SY6522_REG_SERIAL_SHIFT, sy6522.SERIAL_SHIFT);
|
||||
yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SY6522_REG_ACR, sy6522.ACR);
|
||||
yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SY6522_REG_PCR, sy6522.PCR);
|
||||
|
@ -2032,7 +2067,7 @@ void MB_SaveSnapshot(YamlSaveHelper& yamlSaveHelper, const UINT uSlot)
|
|||
}
|
||||
}
|
||||
|
||||
static void LoadSnapshotSY6522(YamlLoadHelper& yamlLoadHelper, SY6522& sy6522)
|
||||
static void LoadSnapshotSY6522(YamlLoadHelper& yamlLoadHelper, SY6522& sy6522, UINT version)
|
||||
{
|
||||
if (!yamlLoadHelper.GetSubMap(SS_YAML_KEY_SY6522))
|
||||
throw std::string("Card: Expected key: ") + std::string(SS_YAML_KEY_SY6522);
|
||||
|
@ -2052,6 +2087,14 @@ static void LoadSnapshotSY6522(YamlLoadHelper& yamlLoadHelper, SY6522& sy6522)
|
|||
sy6522.IER = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_IER);
|
||||
sy6522.ORA_NO_HS = 0; // Not saved
|
||||
|
||||
sy6522.timer1IrqDelay = sy6522.timer2IrqDelay = 0;
|
||||
|
||||
if (version >= 4)
|
||||
{
|
||||
sy6522.timer1IrqDelay = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_TIMER1_IRQ_DELAY);
|
||||
sy6522.timer2IrqDelay = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_TIMER2_IRQ_DELAY);
|
||||
}
|
||||
|
||||
yamlLoadHelper.PopMap();
|
||||
}
|
||||
|
||||
|
@ -2094,7 +2137,7 @@ bool MB_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version)
|
|||
if (!yamlLoadHelper.GetSubMap(unit))
|
||||
throw std::string("Card: Expected key: ") + std::string(unit);
|
||||
|
||||
LoadSnapshotSY6522(yamlLoadHelper, pMB->sy6522);
|
||||
LoadSnapshotSY6522(yamlLoadHelper, pMB->sy6522, version);
|
||||
AY8910_LoadSnapshot(yamlLoadHelper, nDeviceNum, std::string(""));
|
||||
LoadSnapshotSSI263(yamlLoadHelper, pMB->SpeechChip);
|
||||
|
||||
|
@ -2216,7 +2259,7 @@ bool Phasor_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version
|
|||
if (!yamlLoadHelper.GetSubMap(unit))
|
||||
throw std::string("Card: Expected key: ") + std::string(unit);
|
||||
|
||||
LoadSnapshotSY6522(yamlLoadHelper, pMB->sy6522);
|
||||
LoadSnapshotSY6522(yamlLoadHelper, pMB->sy6522, version);
|
||||
AY8910_LoadSnapshot(yamlLoadHelper, nDeviceNum+0, std::string("-A"));
|
||||
AY8910_LoadSnapshot(yamlLoadHelper, nDeviceNum+1, std::string("-B"));
|
||||
LoadSnapshotSSI263(yamlLoadHelper, pMB->SpeechChip);
|
||||
|
|
|
@ -115,6 +115,8 @@ struct SY6522
|
|||
IWORD TIMER1_LATCH;
|
||||
IWORD TIMER2_COUNTER;
|
||||
IWORD TIMER2_LATCH;
|
||||
int timer1IrqDelay;
|
||||
int timer2IrqDelay;
|
||||
//
|
||||
BYTE SERIAL_SHIFT; // $0A
|
||||
BYTE ACR; // $0B - Auxiliary Control Register
|
||||
|
|
Loading…
Reference in New Issue
Block a user