Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 20 additions & 16 deletions source/6522.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ void SY6522::Reset(const bool powerCycle)
StopTimer1();
StopTimer2();

m_timer1IrqDelay = m_timer2IrqDelay = 0;
m_timer1IrqDelay = m_timer2IrqDelay = false;
}

//---------------------------------------------------------------------------
Expand Down Expand Up @@ -215,9 +215,9 @@ void SY6522::Write(BYTE nReg, BYTE nValue)
m_regs.IER |= nValue;
}
if (m_syncEvent[0])
m_syncEvent[0]->m_canAssertIRQ = (m_regs.IER & IxR_TIMER1) ? true : false;
m_syncEvent[0]->m_canAssertIRQ = (m_regs.IER & IxR_TIMER1);
if (m_syncEvent[1])
m_syncEvent[1]->m_canAssertIRQ = (m_regs.IER & IxR_TIMER2) ? true : false;
m_syncEvent[1]->m_canAssertIRQ = (m_regs.IER & IxR_TIMER2);
UpdateIFR(0);
break;
}
Expand All @@ -239,7 +239,7 @@ void SY6522::UpdateTimer2(USHORT clocks)

//-----------------------------------------------------------------------------

bool SY6522::CheckTimerUnderflow(USHORT& counter, int& timerIrqDelay, const USHORT clocks)
bool SY6522::CheckTimerUnderflow(USHORT& counter, bool& timerIrqDelay, const USHORT clocks) const
{
if (clocks == 0)
return false;
Expand All @@ -253,8 +253,8 @@ bool SY6522::CheckTimerUnderflow(USHORT& counter, int& timerIrqDelay, const USHO

if (timerIrqDelay) // Deal with any previous counter underflow which didn't yet result in an IRQ
{
_ASSERT(timerIrqDelay == 1);
timerIrqDelay = 0;
_ASSERT(timerIrqDelay);
timerIrqDelay = false;
timerIrq = true;
// if LATCH is very small then could underflow for every opcode...
}
Expand All @@ -266,22 +266,22 @@ bool SY6522::CheckTimerUnderflow(USHORT& counter, int& timerIrqDelay, const USHO
if (timer <= -3) // TIMER = 0xFFFD (or less)
timerIrq = true;
else // TIMER = 0xFFFF or 0xFFFE
timerIrqDelay = 1; // ...so 1 or 2 cycles until IRQ
timerIrqDelay = true; // ...so 1 or 2 cycles until IRQ
}
else
{
if (timer <= -2) // TIMER = 0xFFFE (or less)
timerIrq = true;
else // TIMER = 0xFFFF
timerIrqDelay = 1; // ...so 1 cycle until IRQ
timerIrqDelay = true; // ...so 1 cycle until IRQ
}

}

return timerIrq;
}

int SY6522::OnTimer1Underflow(USHORT& counter)
bool SY6522::OnTimer1Underflow(USHORT& counter) const
{
int timer = (int)(short)(counter);
if (m_isMegaAudio)
Expand All @@ -296,15 +296,15 @@ int SY6522::OnTimer1Underflow(USHORT& counter)
timer += (m_regs.TIMER1_LATCH.w + kExtraTimerCycles); // GH#651: account for underflowed cycles / GH#652: account for extra 2 cycles
}
counter = (USHORT)timer;
return (timer < 0) ? 1 : 0; // timer1IrqDelay
return (timer < 0); // timer1IrqDelay
}

//-----------------------------------------------------------------------------

USHORT SY6522::GetTimer1Counter(BYTE reg)
{
USHORT counter = m_regs.TIMER1_COUNTER.w; // NB. don't update the real T1C
int timerIrqDelay = m_timer1IrqDelay; // NB. don't update the real timer1IrqDelay
bool timerIrqDelay = m_timer1IrqDelay; // NB. don't update the real timer1IrqDelay
const UINT opcodeCycleAdjust = GetOpcodeCyclesForRead(reg) - 1; // to compensate for the 4/5/6 cycle read opcode
if (CheckTimerUnderflow(counter, timerIrqDelay, opcodeCycleAdjust))
OnTimer1Underflow(counter);
Expand All @@ -320,15 +320,15 @@ USHORT SY6522::GetTimer2Counter(BYTE reg)
bool SY6522::IsTimer1Underflowed(BYTE reg)
{
USHORT counter = m_regs.TIMER1_COUNTER.w; // NB. don't update the real T1C
int timerIrqDelay = m_timer1IrqDelay; // NB. don't update the real timer1IrqDelay
bool timerIrqDelay = m_timer1IrqDelay; // NB. don't update the real timer1IrqDelay
const UINT opcodeCycleAdjust = GetOpcodeCyclesForRead(reg); // to compensate for the 4/5/6 cycle read opcode
return CheckTimerUnderflow(counter, timerIrqDelay, opcodeCycleAdjust);
}

bool SY6522::IsTimer2Underflowed(BYTE reg)
{
USHORT counter = m_regs.TIMER2_COUNTER.w; // NB. don't update the real T2C
int timerIrqDelay = m_timer2IrqDelay; // NB. don't update the real timer2IrqDelay
bool timerIrqDelay = m_timer2IrqDelay; // NB. don't update the real timer2IrqDelay
const UINT opcodeCycleAdjust = GetOpcodeCyclesForRead(reg); // to compensate for the 4/5/6 cycle read opcode
return CheckTimerUnderflow(counter, timerIrqDelay, opcodeCycleAdjust);
}
Expand Down Expand Up @@ -641,10 +641,12 @@ void SY6522::SaveSnapshot(YamlSaveHelper& yamlSaveHelper)
yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SY6522_REG_DDRA, m_regs.DDRA);
yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_SY6522_REG_T1_COUNTER, m_regs.TIMER1_COUNTER.w);
yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_SY6522_REG_T1_LATCH, m_regs.TIMER1_LATCH.w);
// SS_YAML_KEY_SY6522_TIMER1_IRQ_DELAY is saved/loaded as Uint for backward compatibility.
yamlSaveHelper.SaveUint(SS_YAML_KEY_SY6522_TIMER1_IRQ_DELAY, m_timer1IrqDelay); // v4
yamlSaveHelper.SaveBool(SS_YAML_KEY_SY6522_TIMER1_ACTIVE, m_timer1Active); // v8
yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_SY6522_REG_T2_COUNTER, m_regs.TIMER2_COUNTER.w);
yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_SY6522_REG_T2_LATCH, m_regs.TIMER2_LATCH.w);
// SS_YAML_KEY_SY6522_TIMER2_IRQ_DELAY is saved/loaded as Uint for backward compatibility.
yamlSaveHelper.SaveUint(SS_YAML_KEY_SY6522_TIMER2_IRQ_DELAY, m_timer2IrqDelay); // v4
yamlSaveHelper.SaveBool(SS_YAML_KEY_SY6522_TIMER2_ACTIVE, m_timer2Active); // v8
yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SY6522_REG_SERIAL_SHIFT, m_regs.SERIAL_SHIFT);
Expand Down Expand Up @@ -675,10 +677,12 @@ void SY6522::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version)
m_regs.IER = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_REG_IER);
m_regs.ORA_NO_HS = 0; // Not saved

m_timer1IrqDelay = m_timer2IrqDelay = 0;
m_timer1IrqDelay = m_timer2IrqDelay = false;

if (version >= 4)
{
// SS_YAML_KEY_SY6522_TIMER1_IRQ_DELAY|SS_YAML_KEY_SY6522_TIMER2_IRQ_DELAY are
// saved/loaded as Uint for backward compatibility.
m_timer1IrqDelay = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_TIMER1_IRQ_DELAY);
m_timer2IrqDelay = yamlLoadHelper.LoadUint(SS_YAML_KEY_SY6522_TIMER2_IRQ_DELAY);
}
Expand Down Expand Up @@ -721,14 +725,14 @@ void SY6522::SetTimersActiveFromSnapshot(bool timer1Active, bool timer2Active, U
{
SyncEvent* syncEvent = m_syncEvent[0];
syncEvent->SetCycles(GetRegT1C() + kExtraTimerCycles); // NB. use COUNTER, not LATCH
syncEvent->m_canAssertIRQ = (m_regs.IER & IxR_TIMER1) ? true : false;
syncEvent->m_canAssertIRQ = (m_regs.IER & IxR_TIMER1);
g_SynchronousEventMgr.Insert(syncEvent);
}
if (IsTimer2Active())
{
SyncEvent* syncEvent = m_syncEvent[1];
syncEvent->SetCycles(GetRegT2C() + kExtraTimerCycles); // NB. use COUNTER, not LATCH
syncEvent->m_canAssertIRQ = (m_regs.IER & IxR_TIMER2) ? true : false;
syncEvent->m_canAssertIRQ = (m_regs.IER & IxR_TIMER2);
g_SynchronousEventMgr.Insert(syncEvent);
}
}
18 changes: 9 additions & 9 deletions source/6522.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,14 @@ class SY6522
_ASSERT(0);
return 0;
}
BYTE GetBusViewOfORB() { return m_regs.ORB & m_regs.DDRB; } // Return how the AY8913 sees ORB on the bus (ie. not CPU's view which will be OR'd with !DDRB)
USHORT GetRegT1C() { return m_regs.TIMER1_COUNTER.w; }
USHORT GetRegT2C() { return m_regs.TIMER2_COUNTER.w; }
BYTE GetBusViewOfORB() const { return (m_regs.ORB & m_regs.DDRB); } // Return how the AY8913 sees ORB on the bus (ie. not CPU's view which will be OR'd with !DDRB)
USHORT GetRegT1C() const { return m_regs.TIMER1_COUNTER.w; }
USHORT GetRegT2C() const { return m_regs.TIMER2_COUNTER.w; }
void GetRegs(BYTE regs[SIZE_6522_REGS]) { memcpy(&regs[0], (BYTE*)&m_regs, SIZE_6522_REGS); } // For debugger
void SetRegIRA(BYTE reg) { m_regs.ORA = reg; }
bool IsTimer1IrqDelay() { return m_timer1IrqDelay ? true : false; }
bool IsTimer1IrqDelay() const { return m_timer1IrqDelay; }
void SetBusBeingDriven(bool state) { m_isBusDriven = state; }
bool IsBad() { return m_bad6522; }
bool IsBad() const { return m_bad6522; }

BYTE Read(BYTE nReg);
void Write(BYTE nReg, BYTE nValue);
Expand Down Expand Up @@ -92,8 +92,8 @@ class SY6522
bool IsTimer1Underflowed(BYTE reg);
bool IsTimer2Underflowed(BYTE reg);

bool CheckTimerUnderflow(USHORT& counter, int& timerIrqDelay, const USHORT clocks);
int OnTimer1Underflow(USHORT& counter);
bool CheckTimerUnderflow(USHORT& counter, bool& timerIrqDelay, const USHORT clocks) const;
bool OnTimer1Underflow(USHORT& counter) const;

UINT GetOpcodeCyclesForRead(BYTE reg);
UINT GetOpcodeCyclesForWrite(BYTE reg);
Expand Down Expand Up @@ -144,8 +144,8 @@ class SY6522

Regs m_regs;

int m_timer1IrqDelay;
int m_timer2IrqDelay;
bool m_timer1IrqDelay;
bool m_timer2IrqDelay;
bool m_timer1Active;
bool m_timer2Active;

Expand Down
68 changes: 64 additions & 4 deletions source/AY8910.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ AY8913::AY8913()
memset(sound_ay_registers, 0, sizeof(sound_ay_registers));
init();
m_fCurrentCLK_AY8910 = g_fCurrentCLK6502;
m_type = AY_3_8913;
};


Expand Down Expand Up @@ -763,8 +764,24 @@ BYTE AY8913::sound_ay_read( int reg )
case 10:
val &= 31;
break;
case 7: // ENABLE
if (m_type == AY_3_8912)
val &= 0x7f;
if (m_type == AY_3_8913)
val &= 0x3f;
break;
case 14: // PORTA
if (m_type == AY_3_8913)
val = 14; // reg doesn't exist, so bus just returns reg number
break;
case 15: // PORTB
if (m_type == AY_3_8912 || m_type == AY_3_8913)
val = 15; // reg doesn't exist, so bus just returns reg number
}

if (m_type == AY_Empty)
val = 0xff;

return val;
}

Expand All @@ -776,6 +793,9 @@ BYTE AY8913::sound_ay_read( int reg )
*/
void AY8913::sound_ay_write( int reg, int val, libspectrum_dword now )
{
if (m_type == AY_Empty)
return;

if( ay_change_count < AY_CHANGE_MAX ) {
ay_change[ ay_change_count ].tstates = now;
ay_change[ ay_change_count ].reg = ( reg & 15 );
Expand Down Expand Up @@ -1009,8 +1029,10 @@ sound_beeper( int is_tape, int on )

//

#define SS_YAML_KEY_AY8910 "AY8910"
#define SS_YAML_KEY_AY8910_v14 "AY8910" // v14
#define SS_YAML_KEY_AY891x "AY891x" // v15+

#define SS_YAML_KEY_TYPE "Type" // v15+
#define SS_YAML_KEY_TONE0_TICK "Tone0 Tick"
#define SS_YAML_KEY_TONE1_TICK "Tone1 Tick"
#define SS_YAML_KEY_TONE2_TICK "Tone2 Tick"
Expand Down Expand Up @@ -1051,11 +1073,37 @@ sound_beeper( int is_tape, int on )
#define SS_YAML_KEY_CHANGE "Change"
#define SS_YAML_VALUE_CHANGE_FORMAT "%d, %d, 0x%1X, 0x%02X"

std::string AY8913::Type2String()
{
if (m_type == AY_Empty) return "Empty";
if (m_type == AY_3_8910) return "AY-3-8910";
if (m_type == AY_3_8912) return "AY-3-8912";
if (m_type == AY_3_8913) return "AY-3-8913";
if (m_type == YM2149F) return "YM2149F";
_ASSERT(0);
return "AY-3-8913";
}

AY891xType AY8913::String2Type(std::string type)
{
if (type == "Empty") return AY_Empty;
if (type == "AY-3-8910") return AY_3_8910;
if (type == "AY-3-8912") return AY_3_8912;
if (type == "AY-3-8913") return AY_3_8913;
if (type == "YM2149F") return YM2149F;
_ASSERT(0);
return AY_3_8913;
}

void AY8913::SaveSnapshot(YamlSaveHelper& yamlSaveHelper, const std::string& suffix)
{
std::string unit = std::string(SS_YAML_KEY_AY8910) + suffix;
std::string unit = std::string(SS_YAML_KEY_AY891x) + suffix;
YamlSaveHelper::Label label(yamlSaveHelper, "%s:\n", unit.c_str());

yamlSaveHelper.SaveString(SS_YAML_KEY_TYPE, Type2String());
if (m_type == AY_Empty)
return;

yamlSaveHelper.SaveUint(SS_YAML_KEY_TONE0_TICK, ay_tone_tick[0]);
yamlSaveHelper.SaveUint(SS_YAML_KEY_TONE1_TICK, ay_tone_tick[1]);
yamlSaveHelper.SaveUint(SS_YAML_KEY_TONE2_TICK, ay_tone_tick[2]);
Expand Down Expand Up @@ -1106,12 +1154,24 @@ void AY8913::SaveSnapshot(YamlSaveHelper& yamlSaveHelper, const std::string& suf
}
}

bool AY8913::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, const std::string& suffix)
bool AY8913::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, const std::string& suffix, UINT version)
{
std::string unit = std::string(SS_YAML_KEY_AY8910) + suffix;
std::string unit = (version >= 15 ? std::string(SS_YAML_KEY_AY891x)
: std::string(SS_YAML_KEY_AY8910_v14)) + suffix;
if (!yamlLoadHelper.GetSubMap(unit))
throw std::runtime_error("Card: Expected key: " + unit);

m_type = AY_3_8913;
if (version >= 15)
{
m_type = String2Type(yamlLoadHelper.LoadString(SS_YAML_KEY_TYPE));
if (m_type == AY_Empty)
{
yamlLoadHelper.PopMap();
return true;
}
}

ay_tone_tick[0] = yamlLoadHelper.LoadUint(SS_YAML_KEY_TONE0_TICK);
ay_tone_tick[1] = yamlLoadHelper.LoadUint(SS_YAML_KEY_TONE1_TICK);
ay_tone_tick[2] = yamlLoadHelper.LoadUint(SS_YAML_KEY_TONE2_TICK);
Expand Down
8 changes: 7 additions & 1 deletion source/AY8910.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once

enum AY891xType {AY_Empty, AY_3_8910, AY_3_8912, AY_3_8913, YM2149F, AY_Unknown};

//-------------------------------------
// FUSE stuff

Expand Down Expand Up @@ -29,8 +31,11 @@ class AY8913
void SetFramesize(int frameSize) { sound_generator_framesiz = frameSize; }
void SetSoundBuffers(INT16** buffers) { ppSoundBuffers = buffers; }
static void SetCLK( double CLK ) { m_fCurrentCLK_AY8910 = CLK; }
void SetType(AY891xType type) { m_type = type; }
std::string Type2String();
AY891xType String2Type(std::string type);
void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper, const std::string& suffix);
bool LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, const std::string& suffix);
bool LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, const std::string& suffix, UINT version);

private:
void init();
Expand Down Expand Up @@ -72,6 +77,7 @@ class AY8913
int sound_generator_framesiz;
int sound_generator_freq;
unsigned int ay_tone_levels[16];
AY891xType m_type;

// Vars shared between all AY's
static double m_fCurrentCLK_AY8910;
Expand Down
12 changes: 6 additions & 6 deletions source/CPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ static bool g_bCritSectionValid = false; // Deleting CritialSection when not val
static CRITICAL_SECTION g_CriticalSection; // To guard /g_bmIRQ/ & /g_bmNMI/
static volatile UINT32 g_bmIRQ = 0;
static volatile UINT32 g_bmNMI = 0;
static volatile BOOL g_bNmiFlank = FALSE; // Positive going flank on NMI line
static volatile bool g_bNmiFlank = false; // Positive going flank on NMI line

static bool g_irqDefer1Opcode = false;
static bool g_interruptInLastExecutionBatch = false; // Last batch of executed cycles included an interrupt (IRQ/NMI)
Expand Down Expand Up @@ -187,7 +187,7 @@ void SetActiveCpu(eCpuType cpu)

bool IsIrqAsserted()
{
return g_bmIRQ ? true : false;
return (g_bmIRQ != 0);
}

bool Is6502InterruptEnabled()
Expand Down Expand Up @@ -319,7 +319,7 @@ void CaptureCOUT()
}
else if (ch == 0x1B) // Escape
{
bEscMode = bEscMode ? false : true; // Toggle mode
bEscMode = !bEscMode; // Toggle mode
}
else if (ch >= ' ' && ch <= '~')
{
Expand Down Expand Up @@ -405,7 +405,7 @@ static __forceinline bool NMI(ULONG& uExecutedCycles, BOOL& flagc, BOOL& flagn,
return false;

// NMI signals are only serviced once
g_bNmiFlank = FALSE;
g_bNmiFlank = false;
#ifdef _DEBUG
g_nCycleIrqStart = g_nCumulativeCycles + uExecutedCycles;
#endif
Expand Down Expand Up @@ -886,7 +886,7 @@ void CpuNmiReset()
_ASSERT(g_bCritSectionValid);
if (g_bCritSectionValid) EnterCriticalSection(&g_CriticalSection);
g_bmNMI = 0;
g_bNmiFlank = FALSE;
g_bNmiFlank = false;
if (g_bCritSectionValid) LeaveCriticalSection(&g_CriticalSection);
}

Expand All @@ -895,7 +895,7 @@ void CpuNmiAssert(eIRQSRC Device)
_ASSERT(g_bCritSectionValid);
if (g_bCritSectionValid) EnterCriticalSection(&g_CriticalSection);
if (g_bmNMI == 0) // NMI line is just becoming active
g_bNmiFlank = TRUE;
g_bNmiFlank = true;
g_bmNMI |= 1<<Device;
if (g_bCritSectionValid) LeaveCriticalSection(&g_CriticalSection);
}
Expand Down
Loading
Loading