Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
d9f1bfb12a
7 changed files with 97 additions and 25 deletions
|
@ -8,8 +8,13 @@ https://github.com/AppleWin/AppleWin/issues/new
|
|||
|
||||
Tom Charlesworth
|
||||
|
||||
1.28.7.0 - 15 Jun 2019
|
||||
----------------------
|
||||
. [Bug #654] Fix for Sather's "Little Text Window" not rendering correctly.
|
||||
. [Bug #654] Fix for 6522 TIMER1's period to be N+2 cycles.
|
||||
|
||||
1.28.6.0 - 1 Jun 2019
|
||||
|
||||
1.28.6.0 - 2 Jun 2019
|
||||
---------------------
|
||||
. [Bug #651] Cycle-accurate interrupts:
|
||||
- Interrupts sources are checked after every opcode (full-speed after every 40 opcodes).
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#define APPLEWIN_VERSION 1,28,6,0
|
||||
#define APPLEWIN_VERSION 1,28,7,0
|
||||
|
||||
#define xstr(a) str(a)
|
||||
#define str(a) #a
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -125,6 +125,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
static int g_nHiresPage = 1;
|
||||
static int g_nTextPage = 1;
|
||||
|
||||
static bool g_bDelayVideoMode = false;
|
||||
static uint32_t g_uNewVideoModeFlags = 0;
|
||||
|
||||
// Understanding the Apple II, Timing Generation and the Video Scanner, Pg 3-11
|
||||
// Vertical Scanning
|
||||
// Horizontal Scanning
|
||||
|
@ -1852,7 +1855,7 @@ uint16_t NTSC_VideoGetScannerAddress ( const ULONG uExecutedCycles )
|
|||
const uint16_t currVideoClockHorz = g_nVideoClockHorz;
|
||||
|
||||
// Required for ANSI STORY (end credits) vert scrolling mid-scanline mixed mode: DGR80, TEXT80, DGR80
|
||||
g_nVideoClockHorz -= 2;
|
||||
g_nVideoClockHorz -= 1;
|
||||
if ((SHORT)g_nVideoClockHorz < 0)
|
||||
{
|
||||
g_nVideoClockHorz += VIDEO_SCANNER_MAX_HORZ;
|
||||
|
@ -1884,8 +1887,15 @@ void NTSC_SetVideoTextMode( int cols )
|
|||
}
|
||||
|
||||
//===========================================================================
|
||||
void NTSC_SetVideoMode( uint32_t uVideoModeFlags )
|
||||
void NTSC_SetVideoMode( uint32_t uVideoModeFlags, bool bDelay/*=false*/ )
|
||||
{
|
||||
if (bDelay)
|
||||
{
|
||||
g_bDelayVideoMode = true;
|
||||
g_uNewVideoModeFlags = uVideoModeFlags;
|
||||
return;
|
||||
}
|
||||
|
||||
g_nVideoMixed = uVideoModeFlags & VF_MIXED;
|
||||
g_nVideoCharSet = VideoGetSWAltCharSet() ? 1 : 0;
|
||||
|
||||
|
@ -2227,7 +2237,19 @@ static void VideoUpdateCycles( int cyclesLeftToUpdate )
|
|||
//===========================================================================
|
||||
void NTSC_VideoUpdateCycles( long cycles6502 )
|
||||
{
|
||||
_ASSERT(cycles6502 < VIDEO_SCANNER_6502_CYCLES); // Use NTSC_VideoRedrawWholeScreen() instead
|
||||
_ASSERT(cycles6502 && cycles6502 < VIDEO_SCANNER_6502_CYCLES); // Use NTSC_VideoRedrawWholeScreen() instead
|
||||
|
||||
if (g_bDelayVideoMode)
|
||||
{
|
||||
VideoUpdateCycles(1); // Video mode change is delayed by 1 cycle
|
||||
|
||||
g_bDelayVideoMode = false;
|
||||
NTSC_SetVideoMode(g_uNewVideoModeFlags);
|
||||
|
||||
cycles6502--;
|
||||
if (!cycles6502)
|
||||
return;
|
||||
}
|
||||
|
||||
VideoUpdateCycles(cycles6502);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
extern uint32_t g_nChromaSize;
|
||||
|
||||
// Prototypes (Public) ________________________________________________
|
||||
extern void NTSC_SetVideoMode( uint32_t uVideoModeFlags );
|
||||
extern void NTSC_SetVideoMode( uint32_t uVideoModeFlags, bool bDelay=false );
|
||||
extern void NTSC_SetVideoStyle();
|
||||
extern void NTSC_SetVideoTextMode( int cols );
|
||||
extern uint32_t*NTSC_VideoGetChromaTable( bool bHueTypeMonochrome, bool bMonitorTypeColorTV );
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -675,7 +675,7 @@ BYTE VideoSetMode(WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles)
|
|||
if (!IS_APPLE2)
|
||||
RGB_SetVideoMode(address);
|
||||
|
||||
NTSC_SetVideoMode( g_uVideoMode );
|
||||
NTSC_SetVideoMode( g_uVideoMode, true );
|
||||
|
||||
return MemReadFloatingBus(uExecutedCycles);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue