Merge remote-tracking branch 'upstream/master' into ntsc
This commit is contained in:
commit
6f0a71a330
9 changed files with 113 additions and 37 deletions
|
@ -9,12 +9,19 @@ https://github.com/AppleWin/AppleWin/issues/new
|
||||||
Tom Charlesworth
|
Tom Charlesworth
|
||||||
|
|
||||||
|
|
||||||
1.29.5.0 - 11 Nov 2019
|
1.29.6.0 - 18 Nov 2019
|
||||||
----------------------
|
----------------------
|
||||||
|
. [Bug #724] Fixed so that 6502 interrupt is delayed by 1 opcode when interrupt occurs on last cycle of opcode.
|
||||||
|
- fixes French Touch's "Mad Effect" & "Mad Effect #2" demos.
|
||||||
. [Bug #711] Fixed Mockingboard initial "stretched" music playback (regression introduced at 1.28.7.0).
|
. [Bug #711] Fixed Mockingboard initial "stretched" music playback (regression introduced at 1.28.7.0).
|
||||||
. [Bug #707] Fixed ADTPro (running under AppleWin) not working with real COM ports.
|
. [Bug #707] Fixed ADTPro (running under AppleWin) not working with real COM ports.
|
||||||
|
. [Bug #701] Fixed 6522's TIMER being out-of-sync with 6502.
|
||||||
|
. [Bug #699] Fixed French Touch's "Mad Effect". See #656, #701, #724.
|
||||||
. [Bug #680] Fixed video tearing (eg. for FT's "Scroll Scroll Scroll" & "Mad Effect #2").
|
. [Bug #680] Fixed video tearing (eg. for FT's "Scroll Scroll Scroll" & "Mad Effect #2").
|
||||||
. [Bug #659] Fix for Applied Engineering's Phasor song player (noisy playback) (regression introduced at 1.26.3.4).
|
. [Bug #659] Fix for Applied Engineering's Phasor song player (noisy playback) (regression introduced at 1.26.3.4).
|
||||||
|
. [Bug #656] Changed so only TEXT ($C050/1) and MIXED ($C052/3) have a 1 cycle delay (extension to 1.28.8.0).
|
||||||
|
- fixes French Touch's "Mad Effect" demo.
|
||||||
|
- fixed Deater's "Cycle-count Megademo" (vertical GR grey line shouldn't be visible between GR & HGR video).
|
||||||
. [Bug #652] Fixed 6522's TIMER to underflow at 0x0000 -> 0xFFFF
|
. [Bug #652] Fixed 6522's TIMER to underflow at 0x0000 -> 0xFFFF
|
||||||
- and T1C=0x0000 now correctly underflows on next cycle.
|
- and T1C=0x0000 now correctly underflows on next cycle.
|
||||||
. [Bug #435] COM ports above COM9 weren't available from the UI.
|
. [Bug #435] COM ports above COM9 weren't available from the UI.
|
||||||
|
@ -23,6 +30,7 @@ Tom Charlesworth
|
||||||
. [PR #694] Debugger: Symbol loading: Fix random crash upon start up.
|
. [PR #694] Debugger: Symbol loading: Fix random crash upon start up.
|
||||||
. Fixed crash with debug command line switches: -m and -no-mb.
|
. Fixed crash with debug command line switches: -m and -no-mb.
|
||||||
|
|
||||||
|
(1.29.5.0 - skipped)
|
||||||
|
|
||||||
1.29.4.0 - 24 Oct 2019
|
1.29.4.0 - 24 Oct 2019
|
||||||
----------------------
|
----------------------
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#define APPLEWIN_VERSION 1,29,5,0
|
#define APPLEWIN_VERSION 1,29,6,0
|
||||||
|
|
||||||
#define xstr(a) str(a)
|
#define xstr(a) str(a)
|
||||||
#define str(a) #a
|
#define str(a) #a
|
||||||
|
|
|
@ -143,6 +143,8 @@ static volatile UINT32 g_bmIRQ = 0;
|
||||||
static volatile UINT32 g_bmNMI = 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 eCpuType g_MainCPU = CPU_65C02;
|
static eCpuType g_MainCPU = CPU_65C02;
|
||||||
|
@ -403,10 +405,23 @@ static __forceinline void NMI(ULONG& uExecutedCycles, BOOL& flagc, BOOL& flagn,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NB. No need to save to save-state, as IRQ() follows CheckInterruptSources(), and IRQ() always sets it to false.
|
||||||
|
static bool g_irqOnLastOpcodeCycle = false;
|
||||||
|
|
||||||
static __forceinline void IRQ(ULONG& uExecutedCycles, BOOL& flagc, BOOL& flagn, BOOL& flagv, BOOL& flagz)
|
static __forceinline void IRQ(ULONG& uExecutedCycles, BOOL& flagc, BOOL& flagn, BOOL& flagv, BOOL& flagz)
|
||||||
{
|
{
|
||||||
if(g_bmIRQ && !(regs.ps & AF_INTERRUPT))
|
if(g_bmIRQ && !(regs.ps & AF_INTERRUPT))
|
||||||
{
|
{
|
||||||
|
// if 6522 interrupt occurs on opcode's last cycle, then defer IRQ by 1 opcode
|
||||||
|
if (g_irqOnLastOpcodeCycle && !g_irqDefer1Opcode)
|
||||||
|
{
|
||||||
|
g_irqOnLastOpcodeCycle = false;
|
||||||
|
g_irqDefer1Opcode = true; // if INT occurs again on next opcode, then do NOT defer
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_irqDefer1Opcode = false;
|
||||||
|
|
||||||
// IRQ signals are deasserted when a specific r/w operation is done on device
|
// IRQ signals are deasserted when a specific r/w operation is done on device
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
g_nCycleIrqStart = g_nCumulativeCycles + uExecutedCycles;
|
g_nCycleIrqStart = g_nCumulativeCycles + uExecutedCycles;
|
||||||
|
@ -420,6 +435,8 @@ static __forceinline void IRQ(ULONG& uExecutedCycles, BOOL& flagc, BOOL& flagn,
|
||||||
UINT uExtraCycles = 0; // Needed for CYC(a) macro
|
UINT uExtraCycles = 0; // Needed for CYC(a) macro
|
||||||
CYC(7)
|
CYC(7)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_irqOnLastOpcodeCycle = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int IRQ_CHECK_OPCODE_FULL_SPEED = 40; // ~128 cycles (assume 3 cycles per opcode)
|
const int IRQ_CHECK_OPCODE_FULL_SPEED = 40; // ~128 cycles (assume 3 cycles per opcode)
|
||||||
|
@ -435,7 +452,9 @@ static __forceinline void CheckInterruptSources(ULONG uExecutedCycles, const boo
|
||||||
g_fullSpeedOpcodeCount = IRQ_CHECK_OPCODE_FULL_SPEED;
|
g_fullSpeedOpcodeCount = IRQ_CHECK_OPCODE_FULL_SPEED;
|
||||||
}
|
}
|
||||||
|
|
||||||
MB_UpdateCycles(uExecutedCycles);
|
if (MB_UpdateCycles(uExecutedCycles))
|
||||||
|
g_irqOnLastOpcodeCycle = true;
|
||||||
|
|
||||||
if (sg_Mouse.IsActive())
|
if (sg_Mouse.IsActive())
|
||||||
sg_Mouse.SetVBlank( !VideoGetVblBar(uExecutedCycles) );
|
sg_Mouse.SetVBlank( !VideoGetVblBar(uExecutedCycles) );
|
||||||
}
|
}
|
||||||
|
@ -536,11 +555,10 @@ DWORD CpuExecute(const DWORD uCycles, const bool bVideoUpdate)
|
||||||
// >0 : Do multi-opcode emulation
|
// >0 : Do multi-opcode emulation
|
||||||
const DWORD uExecutedCycles = InternalCpuExecute(uCycles, bVideoUpdate);
|
const DWORD uExecutedCycles = InternalCpuExecute(uCycles, bVideoUpdate);
|
||||||
|
|
||||||
|
// NB. Required for normal-speed (even though 6522 is updated after every opcode), as may've finished on IRQ()
|
||||||
MB_UpdateCycles(uExecutedCycles); // Update 6522s (NB. Do this before updating g_nCumulativeCycles below)
|
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
|
// NB. Ensures that 6522 regs are up-to-date for any potential save-state
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
const UINT nRemainingCycles = uExecutedCycles - g_nCyclesExecuted;
|
const UINT nRemainingCycles = uExecutedCycles - g_nCyclesExecuted;
|
||||||
g_nCumulativeCycles += nRemainingCycles;
|
g_nCumulativeCycles += nRemainingCycles;
|
||||||
|
|
||||||
|
@ -665,6 +683,8 @@ void CpuReset()
|
||||||
|
|
||||||
regs.bJammed = 0;
|
regs.bJammed = 0;
|
||||||
|
|
||||||
|
g_irqDefer1Opcode = false;
|
||||||
|
|
||||||
SetActiveCpu( GetMainCpu() );
|
SetActiveCpu( GetMainCpu() );
|
||||||
z80_reset();
|
z80_reset();
|
||||||
}
|
}
|
||||||
|
@ -678,7 +698,8 @@ void CpuReset()
|
||||||
#define SS_YAML_KEY_REGP "P"
|
#define SS_YAML_KEY_REGP "P"
|
||||||
#define SS_YAML_KEY_REGS "S"
|
#define SS_YAML_KEY_REGS "S"
|
||||||
#define SS_YAML_KEY_REGPC "PC"
|
#define SS_YAML_KEY_REGPC "PC"
|
||||||
#define SS_YAML_KEY_CUMULATIVECYCLES "Cumulative Cycles"
|
#define SS_YAML_KEY_CUMULATIVE_CYCLES "Cumulative Cycles"
|
||||||
|
#define SS_YAML_KEY_IRQ_DEFER_1_OPCODE "Defer IRQ By 1 Opcode"
|
||||||
|
|
||||||
#define SS_YAML_VALUE_6502 "6502"
|
#define SS_YAML_VALUE_6502 "6502"
|
||||||
#define SS_YAML_VALUE_65C02 "65C02"
|
#define SS_YAML_VALUE_65C02 "65C02"
|
||||||
|
@ -701,10 +722,11 @@ void CpuSaveSnapshot(YamlSaveHelper& yamlSaveHelper)
|
||||||
yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGP, regs.ps);
|
yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGP, regs.ps);
|
||||||
yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGS, (BYTE) regs.sp);
|
yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_REGS, (BYTE) regs.sp);
|
||||||
yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_REGPC, regs.pc);
|
yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_REGPC, regs.pc);
|
||||||
yamlSaveHelper.SaveHexUint64(SS_YAML_KEY_CUMULATIVECYCLES, g_nCumulativeCycles);
|
yamlSaveHelper.SaveHexUint64(SS_YAML_KEY_CUMULATIVE_CYCLES, g_nCumulativeCycles);
|
||||||
|
yamlSaveHelper.SaveBool(SS_YAML_KEY_IRQ_DEFER_1_OPCODE, g_irqDefer1Opcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CpuLoadSnapshot(YamlLoadHelper& yamlLoadHelper)
|
void CpuLoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version)
|
||||||
{
|
{
|
||||||
if (!yamlLoadHelper.GetSubMap(CpuGetSnapshotStructName()))
|
if (!yamlLoadHelper.GetSubMap(CpuGetSnapshotStructName()))
|
||||||
return;
|
return;
|
||||||
|
@ -725,7 +747,10 @@ void CpuLoadSnapshot(YamlLoadHelper& yamlLoadHelper)
|
||||||
|
|
||||||
CpuIrqReset();
|
CpuIrqReset();
|
||||||
CpuNmiReset();
|
CpuNmiReset();
|
||||||
g_nCumulativeCycles = yamlLoadHelper.LoadUint64(SS_YAML_KEY_CUMULATIVECYCLES);
|
g_nCumulativeCycles = yamlLoadHelper.LoadUint64(SS_YAML_KEY_CUMULATIVE_CYCLES);
|
||||||
|
|
||||||
|
if (version >= 5)
|
||||||
|
g_irqDefer1Opcode = yamlLoadHelper.LoadBool(SS_YAML_KEY_IRQ_DEFER_1_OPCODE);
|
||||||
|
|
||||||
yamlLoadHelper.PopMap();
|
yamlLoadHelper.PopMap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ void CpuNmiAssert(eIRQSRC Device);
|
||||||
void CpuNmiDeassert(eIRQSRC Device);
|
void CpuNmiDeassert(eIRQSRC Device);
|
||||||
void CpuReset ();
|
void CpuReset ();
|
||||||
void CpuSaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
|
void CpuSaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
|
||||||
void CpuLoadSnapshot(class YamlLoadHelper& yamlLoadHelper);
|
void CpuLoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT version);
|
||||||
|
|
||||||
BYTE CpuRead(USHORT addr, ULONG uExecutedCycles);
|
BYTE CpuRead(USHORT addr, ULONG uExecutedCycles);
|
||||||
void CpuWrite(USHORT addr, BYTE a, ULONG uExecutedCycles);
|
void CpuWrite(USHORT addr, BYTE a, ULONG uExecutedCycles);
|
||||||
|
|
|
@ -129,6 +129,10 @@ struct SY6522_AY8910
|
||||||
SSI263A SpeechChip;
|
SSI263A SpeechChip;
|
||||||
MockingboardUnitState_e state; // Where a unit is a 6522+AY8910 pair
|
MockingboardUnitState_e state; // Where a unit is a 6522+AY8910 pair
|
||||||
MockingboardUnitState_e stateB; // Phasor: 6522 & 2nd AY8910
|
MockingboardUnitState_e stateB; // Phasor: 6522 & 2nd AY8910
|
||||||
|
|
||||||
|
// NB. No need to save to save-state, as it will be done immediately after opcode completes in MB_UpdateCycles()
|
||||||
|
bool bLoadT1C; // Load T1C with T1L after opcode completes
|
||||||
|
bool bLoadT2C; // Load T2C with T2L after opcode completes
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -433,7 +437,7 @@ static void SY6522_Write(BYTE nDevice, BYTE nReg, BYTE nValue)
|
||||||
UpdateIFR(pMB, IxR_TIMER1);
|
UpdateIFR(pMB, IxR_TIMER1);
|
||||||
|
|
||||||
pMB->sy6522.TIMER1_LATCH.h = nValue;
|
pMB->sy6522.TIMER1_LATCH.h = nValue;
|
||||||
pMB->sy6522.TIMER1_COUNTER.w = pMB->sy6522.TIMER1_LATCH.w;
|
pMB->bLoadT1C = true;
|
||||||
|
|
||||||
StartTimer1(pMB);
|
StartTimer1(pMB);
|
||||||
CpuAdjustIrqCheck(pMB->sy6522.TIMER1_LATCH.w); // Sync IRQ check timeout with 6522 counter underflow - GH#608
|
CpuAdjustIrqCheck(pMB->sy6522.TIMER1_LATCH.w); // Sync IRQ check timeout with 6522 counter underflow - GH#608
|
||||||
|
@ -529,7 +533,8 @@ static BYTE SY6522_Read(BYTE nDevice, BYTE nReg)
|
||||||
nValue = pMB->sy6522.DDRA;
|
nValue = pMB->sy6522.DDRA;
|
||||||
break;
|
break;
|
||||||
case 0x04: // TIMER1L_COUNTER
|
case 0x04: // TIMER1L_COUNTER
|
||||||
nValue = pMB->sy6522.TIMER1_COUNTER.l;
|
// NB. GH#701 (T1C:=0xFFFF, LDA T1C_L, A==0xFC)
|
||||||
|
nValue = (pMB->sy6522.TIMER1_COUNTER.w - 3) & 0xff; // -3 to compensate for the (assumed) 4-cycle STA 6522.T1C_H
|
||||||
UpdateIFR(pMB, IxR_TIMER1);
|
UpdateIFR(pMB, IxR_TIMER1);
|
||||||
break;
|
break;
|
||||||
case 0x05: // TIMER1H_COUNTER
|
case 0x05: // TIMER1H_COUNTER
|
||||||
|
@ -1541,7 +1546,8 @@ void MB_Reset() // CTRL+RESET or power-cycle
|
||||||
|
|
||||||
static BYTE __stdcall MB_Read(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULONG nExecutedCycles)
|
static BYTE __stdcall MB_Read(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULONG nExecutedCycles)
|
||||||
{
|
{
|
||||||
MB_UpdateCycles(nExecutedCycles);
|
if (g_bFullSpeed)
|
||||||
|
MB_UpdateCycles(nExecutedCycles);
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
if(!IS_APPLE2 && MemCheckINTCXROM())
|
if(!IS_APPLE2 && MemCheckINTCXROM())
|
||||||
|
@ -1604,7 +1610,8 @@ static BYTE __stdcall MB_Read(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULO
|
||||||
|
|
||||||
static BYTE __stdcall MB_Write(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULONG nExecutedCycles)
|
static BYTE __stdcall MB_Write(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULONG nExecutedCycles)
|
||||||
{
|
{
|
||||||
MB_UpdateCycles(nExecutedCycles);
|
if (g_bFullSpeed)
|
||||||
|
MB_UpdateCycles(nExecutedCycles);
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
if(!IS_APPLE2 && MemCheckINTCXROM())
|
if(!IS_APPLE2 && MemCheckINTCXROM())
|
||||||
|
@ -1794,6 +1801,9 @@ void MB_PeriodicUpdate(UINT executedCycles)
|
||||||
|
|
||||||
static bool CheckTimerUnderflowAndIrq(USHORT& timerCounter, int& timerIrqDelay, const USHORT nClocks, bool* pTimerUnderflow=NULL)
|
static bool CheckTimerUnderflowAndIrq(USHORT& timerCounter, int& timerIrqDelay, const USHORT nClocks, bool* pTimerUnderflow=NULL)
|
||||||
{
|
{
|
||||||
|
if (nClocks == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
int oldTimer = timerCounter;
|
int oldTimer = timerCounter;
|
||||||
int timer = timerCounter;
|
int timer = timerCounter;
|
||||||
timer -= nClocks;
|
timer -= nClocks;
|
||||||
|
@ -1803,23 +1813,21 @@ static bool CheckTimerUnderflowAndIrq(USHORT& timerCounter, int& timerIrqDelay,
|
||||||
|
|
||||||
if (timerIrqDelay) // Deal with any previous counter underflow which didn't yet result in an IRQ
|
if (timerIrqDelay) // Deal with any previous counter underflow which didn't yet result in an IRQ
|
||||||
{
|
{
|
||||||
timerIrqDelay -= nClocks;
|
_ASSERT(timerIrqDelay == 1);
|
||||||
if (timerIrqDelay <= 0)
|
timerIrqDelay = 0;
|
||||||
{
|
timerIrq = true;
|
||||||
timerIrqDelay = 0;
|
// if LATCH is very small then could underflow for every opcode...
|
||||||
timerIrq = true;
|
|
||||||
}
|
|
||||||
// don't re-underflow if TIMER = 0xFFFF or 0xFFFE (so just return)
|
|
||||||
}
|
}
|
||||||
else if (oldTimer >= 0 && timer < 0) // Underflow occurs for 0x0000 -> 0xFFFF
|
|
||||||
|
if (oldTimer >= 0 && timer < 0) // Underflow occurs for 0x0000 -> 0xFFFF
|
||||||
{
|
{
|
||||||
if (pTimerUnderflow)
|
if (pTimerUnderflow)
|
||||||
*pTimerUnderflow = true; // Just for Willy Byte!
|
*pTimerUnderflow = true; // Just for Willy Byte!
|
||||||
|
|
||||||
if (timer < -2)
|
if (timer <= -2) // TIMER = 0xFFFE (or less)
|
||||||
timerIrq = true;
|
timerIrq = true;
|
||||||
else // TIMER = 0xFFFF or 0xFFFE
|
else // TIMER = 0xFFFF
|
||||||
timerIrqDelay = 3 + timer; // ...so 2 or 1 cycles until IRQ
|
timerIrqDelay = 1; // ...so 1 cycle until IRQ
|
||||||
}
|
}
|
||||||
|
|
||||||
return timerIrq;
|
return timerIrq;
|
||||||
|
@ -1828,24 +1836,45 @@ static bool CheckTimerUnderflowAndIrq(USHORT& timerCounter, int& timerIrqDelay,
|
||||||
// Called by:
|
// Called by:
|
||||||
// . CpuExecute() every ~1000 @ 1MHz
|
// . CpuExecute() every ~1000 @ 1MHz
|
||||||
// . CheckInterruptSources() every opcode (or every 40 opcodes at full-speed)
|
// . CheckInterruptSources() every opcode (or every 40 opcodes at full-speed)
|
||||||
// . MB_Read() / MB_Write()
|
// . MB_Read() / MB_Write() (only for full-speed)
|
||||||
void MB_UpdateCycles(ULONG uExecutedCycles)
|
bool MB_UpdateCycles(ULONG uExecutedCycles)
|
||||||
{
|
{
|
||||||
if (g_SoundcardType == CT_Empty)
|
if (g_SoundcardType == CT_Empty)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
CpuCalcCycles(uExecutedCycles);
|
CpuCalcCycles(uExecutedCycles);
|
||||||
UINT64 uCycles = g_nCumulativeCycles - g_uLastCumulativeCycles;
|
UINT64 uCycles = g_nCumulativeCycles - g_uLastCumulativeCycles;
|
||||||
|
if (uCycles == 0)
|
||||||
|
return false; // Likely when called from CpuExecute()
|
||||||
|
_ASSERT(uCycles > 1);
|
||||||
|
|
||||||
|
const bool isOpcode = (uCycles > 1 && uCycles <= 7); // todo: better to pass in a flag?
|
||||||
|
|
||||||
g_uLastCumulativeCycles = g_nCumulativeCycles;
|
g_uLastCumulativeCycles = g_nCumulativeCycles;
|
||||||
_ASSERT(uCycles < 0x10000);
|
_ASSERT(uCycles < 0x10000);
|
||||||
USHORT nClocks = (USHORT) uCycles;
|
USHORT nClocks = (USHORT) uCycles;
|
||||||
|
|
||||||
|
bool bIrqOnLastOpcodeCycle = false;
|
||||||
|
|
||||||
for (int i=0; i<NUM_SY6522; i++)
|
for (int i=0; i<NUM_SY6522; i++)
|
||||||
{
|
{
|
||||||
SY6522_AY8910* pMB = &g_MB[i];
|
SY6522_AY8910* pMB = &g_MB[i];
|
||||||
|
|
||||||
bool bTimer1Underflow = false; // Just for Willy Byte!
|
bool bTimer1Underflow = false; // Just for Willy Byte!
|
||||||
const bool bTimer1Irq = CheckTimerUnderflowAndIrq(pMB->sy6522.TIMER1_COUNTER.w, pMB->sy6522.timer1IrqDelay, nClocks, &bTimer1Underflow);
|
bool bTimer1Irq = false;
|
||||||
|
bool bTimer1IrqOnLastCycle = false;
|
||||||
|
|
||||||
|
if (isOpcode)
|
||||||
|
{
|
||||||
|
bTimer1Irq = CheckTimerUnderflowAndIrq(pMB->sy6522.TIMER1_COUNTER.w, pMB->sy6522.timer1IrqDelay, nClocks-1, &bTimer1Underflow);
|
||||||
|
bTimer1IrqOnLastCycle = CheckTimerUnderflowAndIrq(pMB->sy6522.TIMER1_COUNTER.w, pMB->sy6522.timer1IrqDelay, 1, &bTimer1Underflow);
|
||||||
|
bTimer1Irq = bTimer1Irq || bTimer1IrqOnLastCycle;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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);
|
const bool bTimer2Irq = CheckTimerUnderflowAndIrq(pMB->sy6522.TIMER2_COUNTER.w, pMB->sy6522.timer2IrqDelay, nClocks);
|
||||||
|
|
||||||
if (!pMB->bTimer1Active && bTimer1Underflow)
|
if (!pMB->bTimer1Active && bTimer1Underflow)
|
||||||
|
@ -1864,6 +1893,7 @@ void MB_UpdateCycles(ULONG uExecutedCycles)
|
||||||
if (pMB->bTimer1Active && bTimer1Irq)
|
if (pMB->bTimer1Active && bTimer1Irq)
|
||||||
{
|
{
|
||||||
UpdateIFR(pMB, 0, IxR_TIMER1);
|
UpdateIFR(pMB, 0, IxR_TIMER1);
|
||||||
|
bIrqOnLastOpcodeCycle = true;
|
||||||
|
|
||||||
MB_Update();
|
MB_Update();
|
||||||
|
|
||||||
|
@ -1880,6 +1910,9 @@ void MB_UpdateCycles(ULONG uExecutedCycles)
|
||||||
// - Ultima4/5 change ACCESS_TIMER1 after a couple of IRQs into tune
|
// - 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 += 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)
|
pMB->sy6522.TIMER1_COUNTER.w += 2; // GH#652: account for extra 2 cycles (Rockwell, Fig.16: period=N+2cycles)
|
||||||
|
// EG. T1C=0xFFFE, T1L=0x0001
|
||||||
|
// . T1C += T1L = 0xFFFF
|
||||||
|
// . T1C += 2 = 0x0001
|
||||||
if (pMB->sy6522.TIMER1_COUNTER.w > pMB->sy6522.TIMER1_LATCH.w)
|
if (pMB->sy6522.TIMER1_COUNTER.w > pMB->sy6522.TIMER1_LATCH.w)
|
||||||
{
|
{
|
||||||
if (pMB->sy6522.TIMER1_LATCH.w)
|
if (pMB->sy6522.TIMER1_LATCH.w)
|
||||||
|
@ -1891,6 +1924,12 @@ void MB_UpdateCycles(ULONG uExecutedCycles)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pMB->bLoadT1C)
|
||||||
|
{
|
||||||
|
pMB->bLoadT1C = false;
|
||||||
|
pMB->sy6522.TIMER1_COUNTER.w = pMB->sy6522.TIMER1_LATCH.w;
|
||||||
|
}
|
||||||
|
|
||||||
if (pMB->bTimer2Active && bTimer2Irq)
|
if (pMB->bTimer2Active && bTimer2Irq)
|
||||||
{
|
{
|
||||||
UpdateIFR(pMB, 0, IxR_TIMER2);
|
UpdateIFR(pMB, 0, IxR_TIMER2);
|
||||||
|
@ -1913,6 +1952,8 @@ void MB_UpdateCycles(ULONG uExecutedCycles)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return bIrqOnLastOpcodeCycle;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
|
@ -11,7 +11,7 @@ void MB_Demute();
|
||||||
void MB_StartOfCpuExecute();
|
void MB_StartOfCpuExecute();
|
||||||
void MB_PeriodicUpdate(UINT executedCycles);
|
void MB_PeriodicUpdate(UINT executedCycles);
|
||||||
void MB_CheckIRQ();
|
void MB_CheckIRQ();
|
||||||
void MB_UpdateCycles(ULONG uExecutedCycles);
|
bool MB_UpdateCycles(ULONG uExecutedCycles);
|
||||||
SS_CARDTYPE MB_GetSoundcardType();
|
SS_CARDTYPE MB_GetSoundcardType();
|
||||||
bool MB_IsActive();
|
bool MB_IsActive();
|
||||||
DWORD MB_GetVolume();
|
DWORD MB_GetVolume();
|
||||||
|
|
|
@ -116,7 +116,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
static int g_nHiresPage = 1;
|
static int g_nHiresPage = 1;
|
||||||
static int g_nTextPage = 1;
|
static int g_nTextPage = 1;
|
||||||
|
|
||||||
static bool g_bDelayVideoMode = false;
|
static bool g_bDelayVideoMode = false; // NB. No need to save to save-state, as it will be done immediately after opcode completes in NTSC_VideoUpdateCycles()
|
||||||
static uint32_t g_uNewVideoModeFlags = 0;
|
static uint32_t g_uNewVideoModeFlags = 0;
|
||||||
|
|
||||||
// Understanding the Apple II, Timing Generation and the Video Scanner, Pg 3-11
|
// Understanding the Apple II, Timing Generation and the Video Scanner, Pg 3-11
|
||||||
|
|
|
@ -68,7 +68,8 @@ static YamlHelper yamlHelper;
|
||||||
// v2: Extended: keyboard (added 'Key Waiting'), memory (LC mem type for II/II+, inverted MF_INTCXROM bit)
|
// v2: Extended: keyboard (added 'Key Waiting'), memory (LC mem type for II/II+, inverted MF_INTCXROM bit)
|
||||||
// v3: Extended: memory (added 'AnnunciatorN')
|
// v3: Extended: memory (added 'AnnunciatorN')
|
||||||
// v4: Extended: video (added 'Video Refresh Rate')
|
// v4: Extended: video (added 'Video Refresh Rate')
|
||||||
#define UNIT_APPLE2_VER 4
|
// v5: Extended: cpu (added 'Defer IRQ By 1 Opcode')
|
||||||
|
#define UNIT_APPLE2_VER 5
|
||||||
|
|
||||||
#define UNIT_SLOTS_VER 1
|
#define UNIT_SLOTS_VER 1
|
||||||
|
|
||||||
|
@ -214,7 +215,7 @@ static void ParseUnitApple2(YamlLoadHelper& yamlLoadHelper, UINT version)
|
||||||
SetApple2Type( ParseApple2Type(model) ); // NB. Sets default main CPU type
|
SetApple2Type( ParseApple2Type(model) ); // NB. Sets default main CPU type
|
||||||
m_ConfigNew.m_Apple2Type = GetApple2Type();
|
m_ConfigNew.m_Apple2Type = GetApple2Type();
|
||||||
|
|
||||||
CpuLoadSnapshot(yamlLoadHelper); // NB. Overrides default main CPU type
|
CpuLoadSnapshot(yamlLoadHelper, version); // NB. Overrides default main CPU type
|
||||||
m_ConfigNew.m_CpuType = GetMainCpu();
|
m_ConfigNew.m_CpuType = GetMainCpu();
|
||||||
|
|
||||||
JoyLoadSnapshot(yamlLoadHelper);
|
JoyLoadSnapshot(yamlLoadHelper);
|
||||||
|
@ -390,7 +391,7 @@ static void Snapshot_LoadState_v2(void)
|
||||||
m_ConfigNew.m_bEnableHDD = false;
|
m_ConfigNew.m_bEnableHDD = false;
|
||||||
//m_ConfigNew.m_bEnableTheFreezesF8Rom = ?; // todo: when support saving config
|
//m_ConfigNew.m_bEnableTheFreezesF8Rom = ?; // todo: when support saving config
|
||||||
|
|
||||||
MemReset();
|
MemReset(); // Also calls CpuInitialize()
|
||||||
PravetsReset();
|
PravetsReset();
|
||||||
sg_Disk2Card.Reset();
|
sg_Disk2Card.Reset();
|
||||||
HD_Reset();
|
HD_Reset();
|
||||||
|
|
|
@ -660,9 +660,10 @@ BYTE VideoSetMode(WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles)
|
||||||
if (!IS_APPLE2)
|
if (!IS_APPLE2)
|
||||||
RGB_SetVideoMode(address);
|
RGB_SetVideoMode(address);
|
||||||
|
|
||||||
bool delay = true;
|
// Only 1-cycle delay for VF_TEXT & VF_MIXED mode changes (GH#656)
|
||||||
if ((oldVideoMode ^ g_uVideoMode) & VF_PAGE2)
|
bool delay = false;
|
||||||
delay = false; // PAGE2 flag changed state, so no 1 cycle delay (GH#656)
|
if ((oldVideoMode ^ g_uVideoMode) & (VF_TEXT|VF_MIXED))
|
||||||
|
delay = true;
|
||||||
|
|
||||||
NTSC_SetVideoMode( g_uVideoMode, delay );
|
NTSC_SetVideoMode( g_uVideoMode, delay );
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue