diff --git a/source/Applewin.cpp b/source/Applewin.cpp index dd210225..a4d5ee05 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -35,6 +35,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "DiskImage.h" #include "Frame.h" #include "Harddisk.h" +#include "Joystick.h" #include "Log.h" #include "Memory.h" #include "Mockingboard.h" @@ -61,10 +62,6 @@ TCHAR *g_pAppTitle = TITLE_APPLE_2E_ENHANCED; eApple2Type g_Apple2Type = A2TYPE_APPLE2EENHANCED; -DWORD cumulativecycles = 0; // Wraps after ~1hr 9mins -DWORD cyclenum = 0; // Used by SpkrToggle() for non-wave sound -DWORD emulmsec = 0; -static DWORD emulmsec_frac = 0; bool g_bFullSpeed = false; //Pravets 8A/C variables @@ -78,7 +75,6 @@ HINSTANCE g_hInstance = (HINSTANCE)0; AppMode_e g_nAppMode = MODE_LOGO; static bool g_bLoadedSaveState = false; -static int lastmode = MODE_LOGO; TCHAR g_sProgramDir[MAX_PATH] = TEXT(""); // Directory of where AppleWin executable resides TCHAR g_sDebugDir [MAX_PATH] = TEXT(""); // TODO: Not currently used TCHAR g_sScreenShotDir[MAX_PATH] = TEXT(""); // TODO: Not currently used @@ -117,17 +113,6 @@ CSpeech g_Speech; //=========================================================================== -#define DBG_CALC_FREQ 0 -#if DBG_CALC_FREQ -const UINT MAX_CNT = 256; -double g_fDbg[MAX_CNT]; -UINT g_nIdx = 0; -double g_fMeanPeriod,g_fMeanFreq; -ULONGLONG g_nPerfFreq = 0; -#endif - -//--------------------------------------------------------------------------- - bool GetLoadedSaveStateFlag(void) { return g_bLoadedSaveState; @@ -229,86 +214,28 @@ void ContinueExecution(void) if (nCyclesToExecute < 0) nCyclesToExecute = 0; - DWORD dwExecutedCycles = CpuExecute(nCyclesToExecute); - g_dwCyclesThisFrame += dwExecutedCycles; + const DWORD uActualCyclesExecuted = CpuExecute(nCyclesToExecute); + g_dwCyclesThisFrame += uActualCyclesExecuted; - // + DiskUpdatePosition(uActualCyclesExecuted); + JoyUpdateButtonLatch(nExecutionPeriodUsec); // Button latch time is independent of CPU clock frequency - cyclenum = dwExecutedCycles; - - DiskUpdatePosition(dwExecutedCycles); - JoyUpdatePosition(); - - SpkrUpdate(cyclenum); - sg_SSC.CommUpdate(cyclenum); - PrintUpdate(cyclenum); - - // - - const DWORD CLKS_PER_MS = (DWORD)g_fCurrentCLK6502 / 1000; - - emulmsec_frac += dwExecutedCycles; - if (emulmsec_frac > CLKS_PER_MS) - { - emulmsec += emulmsec_frac / CLKS_PER_MS; - emulmsec_frac %= CLKS_PER_MS; - } - - // DETERMINE WHETHER THE SCREEN WAS UPDATED THIS CLOCKTICK - static BOOL anyupdates = 0; - VideoCheckPage(0); // force=0 - anyupdates |= VideoHasRefreshed(); // Only called from here. Returns & clears 'hasrefreshed' flag + SpkrUpdate(uActualCyclesExecuted); + sg_SSC.CommUpdate(uActualCyclesExecuted); + PrintUpdate(uActualCyclesExecuted); // if (g_dwCyclesThisFrame >= dwClksPerFrame) { g_dwCyclesThisFrame -= dwClksPerFrame; - VideoUpdateFlash(); - - static BOOL lastupdates[2] = {0,0}; - if (!anyupdates && !lastupdates[0] && !lastupdates[1] && VideoApparentlyDirty()) - { - VideoCheckPage(1); // force=1 - static DWORD lasttime = 0; - DWORD currtime = GetTickCount(); - if ((!g_bFullSpeed) || - (currtime-lasttime >= (DWORD)(g_bGraphicsMode ? 100 : 25))) - { - VideoRefreshScreen(); - lasttime = currtime; - } - } - - lastupdates[1] = lastupdates[0]; - lastupdates[0] = anyupdates; - anyupdates = 0; - + VideoEndOfVideoFrame(); MB_EndOfVideoFrame(); } - // - if (!g_bFullSpeed) { SysClk_WaitTimer(); - -#if DBG_CALC_FREQ - if (g_nPerfFreq) - { - QueryPerformanceCounter((LARGE_INTEGER*)&nTime1); - LONGLONG nTimeDiff = nTime1 - nTime0; - double fTime = (double)nTimeDiff / (double)(LONGLONG)g_nPerfFreq; - - g_fDbg[g_nIdx] = fTime; - g_nIdx = (g_nIdx+1) & (MAX_CNT-1); - g_fMeanPeriod = 0.0; - for(UINT n=0; n> 8) PUSH(regs.pc & 0xFF) EF_TO_AF @@ -369,7 +373,9 @@ static __forceinline void IRQ(ULONG& uExecutedCycles, UINT& uExtraCycles, BOOL& if(g_bmIRQ && !(regs.ps & AF_INTERRUPT)) { // IRQ signals are deasserted when a specific r/w operation is done on device +#ifdef _DEBUG g_nCycleIrqStart = g_nCumulativeCycles + uExecutedCycles; +#endif PUSH(regs.pc >> 8) PUSH(regs.pc & 0xFF) EF_TO_AF @@ -465,6 +471,29 @@ ULONG CpuGetCyclesThisVideoFrame(const ULONG nExecutedCycles) } #endif +//--------------------------------------------------------------------------- + +static DWORD g_dwEmulationTime_ms = 0; + +static void UpdateEmulationTime(const DWORD dwExecutedCycles) +{ + static DWORD dwEmulationTimeFrac_clks = 0; + + const DWORD CLKS_PER_MS = (DWORD)g_fCurrentCLK6502 / 1000; + + dwEmulationTimeFrac_clks += dwExecutedCycles; + if (dwEmulationTimeFrac_clks > CLKS_PER_MS) + { + g_dwEmulationTime_ms += dwEmulationTimeFrac_clks / CLKS_PER_MS; + dwEmulationTimeFrac_clks %= CLKS_PER_MS; + } +} + +DWORD CpuGetEmulationTime_ms(void) +{ + return g_dwEmulationTime_ms; +} + //=========================================================================== DWORD CpuExecute(const DWORD uCycles) @@ -479,6 +508,7 @@ DWORD CpuExecute(const DWORD uCycles) const DWORD uExecutedCycles = InternalCpuExecute(uCycles); MB_UpdateCycles(uExecutedCycles); // Update 6522s (NB. Do this before updating g_nCumulativeCycles below) + UpdateEmulationTime(uExecutedCycles); // diff --git a/source/CPU.h b/source/CPU.h index 2e21591b..58c5d886 100644 --- a/source/CPU.h +++ b/source/CPU.h @@ -31,3 +31,5 @@ DWORD CpuSetSnapshot(SS_CPU6502* pSS); BYTE CpuRead(USHORT addr, ULONG uExecutedCycles); void CpuWrite(USHORT addr, BYTE a, ULONG uExecutedCycles); + +DWORD CpuGetEmulationTime_ms(void); diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index 92b7e7f9..40b8d8a4 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -4711,9 +4711,9 @@ size_t Util_GetTextScreen ( char* &pText_ ) g_nTextScreen = 0; memset( pBeg, 0, sizeof( g_aTextScreen ) ); - int bBank2 = g_bVideoDisplayPage2; - LPBYTE g_pTextBank1 = MemGetAuxPtr (0x400 << (int)bBank2); - LPBYTE g_pTextBank0 = MemGetMainPtr(0x400 << (int)bBank2); + unsigned int uBank2 = VideoGetSWPAGE2() ? 1 : 0; + LPBYTE g_pTextBank1 = MemGetAuxPtr (0x400 << uBank2); + LPBYTE g_pTextBank0 = MemGetMainPtr(0x400 << uBank2); for( int y = 0; y < 24; y++ ) { @@ -4724,7 +4724,7 @@ size_t Util_GetTextScreen ( char* &pText_ ) { char c; // TODO: FormatCharTxtCtrl() ? - if ( g_bVideoMode & VF_80COL ) + if ( VideoGetSW80COL() ) { // AUX c = g_pTextBank1[ nAddressStart ] & 0x7F; c = RemapChar(c); @@ -4792,7 +4792,7 @@ int CmdTextSave (int nArgs) _tcscpy( g_sMemoryLoadSaveFileName, g_aArgs[ 1 ].sArg ); else { - if( g_bVideoMode & VF_80COL ) + if( VideoGetSW80COL() ) sprintf( g_sMemoryLoadSaveFileName, "AppleWin_Text80.txt" ); else sprintf( g_sMemoryLoadSaveFileName, "AppleWin_Text40.txt" ); @@ -5997,11 +5997,11 @@ Update_t _ViewOutput( ViewVideoPage_t iPage, VideoUpdateFuncPtr_t pfUpdate ); Update_t _ViewOutput( ViewVideoPage_t iPage, VideoUpdateFuncPtr_t pfUpdate ) { - g_VideoForceFullRedraw = true; + VideoSetForceFullRedraw(); _Video_Dirty(); switch( iPage ) { - case VIEW_PAGE_X: _Video_SetupBanks( g_bVideoDisplayPage2 ); break; // Page Current + case VIEW_PAGE_X: _Video_SetupBanks( VideoGetSWPAGE2() ); break; // Page Current case VIEW_PAGE_1: _Video_SetupBanks( false ); break; // Page 1 case VIEW_PAGE_2: _Video_SetupBanks( true ); break; // Page 2 ! default: diff --git a/source/Debugger/Debugger_Display.cpp b/source/Debugger/Debugger_Display.cpp index e0b88ed1..7fd183bd 100644 --- a/source/Debugger/Debugger_Display.cpp +++ b/source/Debugger/Debugger_Display.cpp @@ -2735,38 +2735,38 @@ void DrawSoftSwitches( int iSoftSwitch ) // GR / TEXT // GRAPH/TEXT // TEXT ON/OFF - sprintf( sText, !(g_bVideoMode & VF_TEXT) ? "GR / ----" : "-- / TEXT" ); + sprintf( sText, !VideoGetSWTEXT() ? "GR / ----" : "-- / TEXT" ); PrintTextCursorY( sText, rect ); // $C052 / $C053 = MIXEDOFF/MIXEDON = SW.MIXCLR/SW.MIXSET // FULL/MIXED // MIX OFF/ON - sprintf( sText, !(g_bVideoMode & VF_MIXED) ? "FULL/-----" : "----/MIXED" ); + sprintf( sText, !VideoGetSWMIXED() ? "FULL/-----" : "----/MIXED" ); PrintTextCursorY( sText, rect ); // $C054 / $C055 = PAGE1/PAGE2 = PAGE2OFF/PAGE2ON = SW.LOWSCR/SW.HISCR // PAGE 1 / 2 - sprintf( sText, !(g_bVideoMode & VF_PAGE2) ? "PAGE 1 / -" : "PAGE - / 2" ); + sprintf( sText, !VideoGetSWPAGE2() ? "PAGE 1 / -" : "PAGE - / 2" ); PrintTextCursorY( sText, rect ); // $C056 / $C057 LORES/HIRES = HIRESOFF/HIRESON = SW.LORES/SW.HIRES // LO / HIRES // LO / ----- // -- / HIRES - sprintf( sText, !(g_bVideoMode & VF_HIRES) ? "LO /-- RES" : "---/HI RES" ); + sprintf( sText, !VideoGetSWHIRES() ? "LO /-- RES" : "---/HI RES" ); PrintTextCursorY( sText, rect ); PrintTextCursorY( "", rect ); // Extended soft switches - sprintf( sText, !(g_bVideoMode & VF_80COL) ? "40 / -- COL" : "-- / 80 COL" ); + sprintf( sText, !VideoGetSW80COL() ? "40 / -- COL" : "-- / 80 COL" ); PrintTextCursorY( sText, rect ); - sprintf(sText, (g_nAltCharSetOffset == 0) ? "ASCII/-----" : "-----/MOUSE" ); + sprintf(sText, VideoGetSWAltCharSet() ? "ASCII/-----" : "-----/MOUSE" ); PrintTextCursorY( sText, rect ); // 280/560 HGR - sprintf(sText, !(g_bVideoMode & VF_DHIRES) ? "HGR / ----" : "--- / DHGR" ); + sprintf(sText, !VideoGetSWDHIRES() ? "HGR / ----" : "--- / DHGR" ); PrintTextCursorY( sText, rect ); #else //SOFTSWITCH_OLD // See: VideoSetMode() @@ -2778,25 +2778,25 @@ void DrawSoftSwitches( int iSoftSwitch ) bool bSet; // $C050 / $C051 = TEXTOFF/TEXTON = SW.TXTCLR/SW.TXTSET - bSet = !(g_bVideoMode & VF_TEXT); + bSet = !VideoGetSWTEXT(); _DrawSoftSwitch( rect, 0xC050, bSet, NULL, "GR.", "TEXT" ); // $C052 / $C053 = MIXEDOFF/MIXEDON = SW.MIXCLR/SW.MIXSET // FULL/MIXED // MIX OFF/ON - bSet = !(g_bVideoMode & VF_MIXED); + bSet = !VideoGetSWMIXED(); _DrawSoftSwitch( rect, 0xC052, bSet, NULL, "FULL", "MIX" ); // $C054 / $C055 = PAGE1/PAGE2 = PAGE2OFF/PAGE2ON = SW.LOWSCR/SW.HISCR // PAGE 1 / 2 - bSet = !(g_bVideoMode & VF_PAGE2); + bSet = !VideoGetSWPAGE2(); _DrawSoftSwitch( rect, 0xC054, bSet, "PAGE ", "1", "2" ); // $C056 / $C057 LORES/HIRES = HIRESOFF/HIRESON = SW.LORES/SW.HIRES // LO / HIRES // LO / ----- // -- / HIRES - bSet = !(g_bVideoMode & VF_HIRES); + bSet = !VideoGetSWHIRES(); _DrawSoftSwitch( rect, 0xC056, bSet, NULL, "LO", "HI", "RES" ); DebuggerSetColorBG( DebuggerGetColor( BG_INFO )); @@ -2805,20 +2805,20 @@ void DrawSoftSwitches( int iSoftSwitch ) // 280/560 HGR // C05E = ON, C05F = OFF - bSet = (g_bVideoMode & VF_DHIRES) ? true : false; + bSet = VideoGetSWDHIRES(); _DrawSoftSwitch( rect, 0xC05E, bSet, NULL, "DHGR", "HGR" ); // Extended soft switches // C00C = off, C00D = on - bSet = !(g_bVideoMode & VF_80COL); + bSet = !VideoGetSW80COL(); _DrawSoftSwitch( rect, 0xC00C, bSet, "Col", "40", "80" ); // C00E = off, C00F = on - bSet = (g_nAltCharSetOffset == 0); + bSet = VideoGetSWAltCharSet(); _DrawSoftSwitch( rect, 0xC00E, bSet, NULL, "ASC", "MOUS" ); // ASCII/MouseText // C000 = 80STOREOFF, C001 = 80STOREON - bSet = !(g_bVideoMode & VF_MASK2); + bSet = !VideoGetSW80STORE(); _DrawSoftSwitch( rect, 0xC000, bSet, "80Sto", "0", "1" ); #endif // SOFTSWITCH_OLD } diff --git a/source/Joystick.cpp b/source/Joystick.cpp index 3b232378..00141aa5 100644 --- a/source/Joystick.cpp +++ b/source/Joystick.cpp @@ -45,7 +45,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Configuration\PropertySheet.h" -#define BUTTONTIME 5000 // TODO: Describe this magic number +#define BUTTONTIME 5000 // This is the latch (debounce) time in usecs for the joystick buttons enum {DEVICE_NONE=0, DEVICE_JOYSTICK, DEVICE_KEYBOARD, DEVICE_MOUSE}; @@ -82,7 +82,7 @@ static POINT keyvalue[9] = {{PDL_MIN,PDL_MAX}, {PDL_CENTRAL,PDL_MAX}, {PDL {PDL_MIN,PDL_CENTRAL},{PDL_CENTRAL,PDL_CENTRAL},{PDL_MAX,PDL_CENTRAL}, {PDL_MIN,PDL_MIN}, {PDL_CENTRAL,PDL_MIN}, {PDL_MAX,PDL_MIN}}; -static DWORD buttonlatch[3] = {0,0,0}; +static int buttonlatch[3] = {0,0,0}; static BOOL joybutton[3] = {0,0,0}; static int joyshrx[2] = {8,8}; @@ -703,11 +703,19 @@ void JoySetPosition(int xvalue, int xrange, int yvalue, int yrange) } //=========================================================================== -void JoyUpdatePosition() + +// Update the latch (debounce) time for each button +void JoyUpdateButtonLatch(const UINT nExecutionPeriodUsec) { - if (buttonlatch[0]) --buttonlatch[0]; - if (buttonlatch[1]) --buttonlatch[1]; - if (buttonlatch[2]) --buttonlatch[2]; + for (UINT i=0; i<3; i++) + { + if (buttonlatch[i]) + { + buttonlatch[i] -= nExecutionPeriodUsec; + if (buttonlatch[i] < 0) + buttonlatch[i] = 0; + } + } } //=========================================================================== diff --git a/source/Joystick.h b/source/Joystick.h index 32cfeb72..9889c2c9 100644 --- a/source/Joystick.h +++ b/source/Joystick.h @@ -15,7 +15,7 @@ void JoyReset(); void JoySetButton(eBUTTON,eBUTTONSTATE); BOOL JoySetEmulationType(HWND,DWORD,int, const bool bMousecardActive); void JoySetPosition(int,int,int,int); -void JoyUpdatePosition(); +void JoyUpdateButtonLatch(const UINT nExecutionPeriodUsec); BOOL JoyUsingMouse(); BOOL JoyUsingKeyboard(); BOOL JoyUsingKeyboardCursors(); diff --git a/source/Memory.cpp b/source/Memory.cpp index 25f00c92..f1a19fd9 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -88,7 +88,7 @@ MEMORY MANAGEMENT SOFT SWITCHES $C005 W RAMWRTON Write enable aux memory from $0200-$BFFF $C006 W INTCXROMOFF Enable slot ROM from $C100-$CFFF $C007 W INTCXROMON Enable main ROM from $C100-$CFFF - $C008 W ALZTPOFF Enable main memory from $0000-$01FF & avl BSR + $C008 W ALTZPOFF Enable main memory from $0000-$01FF & avl BSR $C009 W ALTZPON Enable aux memory from $0000-$01FF & avl BSR $C00A W SLOTC3ROMOFF Enable main ROM from $C300-$C3FF $C00B W SLOTC3ROMON Enable slot ROM from $C300-$C3FF @@ -1074,13 +1074,6 @@ void MemDestroy () //=========================================================================== -bool MemGet80Store() -{ - return SW_80STORE != 0; -} - -//=========================================================================== - bool MemCheckSLOTCXROM() { return SW_SLOTCXROM ? true : false; diff --git a/source/Memory.h b/source/Memory.h index 55ff2065..c418422c 100644 --- a/source/Memory.h +++ b/source/Memory.h @@ -38,7 +38,6 @@ extern UINT g_uMaxExPages; // user requested ram pages (from cmd line) void RegisterIoHandler(UINT uSlot, iofunction IOReadC0, iofunction IOWriteC0, iofunction IOReadCx, iofunction IOWriteCx, LPVOID lpSlotParameter, BYTE* pExpansionRom); void MemDestroy (); -bool MemGet80Store(); bool MemCheckSLOTCXROM(); LPBYTE MemGetAuxPtr(const WORD); LPBYTE MemGetMainPtr(const WORD); diff --git a/source/Speaker.cpp b/source/Speaker.cpp index 288c9c60..3608ecd6 100644 --- a/source/Speaker.cpp +++ b/source/Speaker.cpp @@ -479,7 +479,9 @@ BYTE __stdcall SpkrToggle (WORD, WORD, BYTE, BYTE, ULONG nCyclesLeft) if (lastcyclenum) { toggles++; - DWORD delta = cyclenum-lastcyclenum; + //DWORD delta = cyclenum-lastcyclenum; // [TC: 14/09/2014] Looks broken, since 'cyclenum' is cycles executed in previous call to CpuExecute() + CpuCalcCycles(nCyclesLeft); + DWORD delta = (DWORD)g_nCumulativeCycles - lastcyclenum; // DETERMINE WHETHER WE ARE PLAYING A SOUND EFFECT if (directio && @@ -493,7 +495,8 @@ BYTE __stdcall SpkrToggle (WORD, WORD, BYTE, BYTE, ULONG nCyclesLeft) lastdelta[0] = delta; totaldelta += delta; } - lastcyclenum = cyclenum; + //lastcyclenum = cyclenum; + lastcyclenum = (DWORD)g_nCumulativeCycles; } @@ -610,7 +613,7 @@ void SpkrUpdate_Timer() nSamplesUsed = Spkr_SubmitWaveBuffer_FullSpeed(g_pSpeakerBuffer, g_nBufferIdx); _ASSERT(nSamplesUsed <= g_nBufferIdx); - memmove(g_pSpeakerBuffer, &g_pSpeakerBuffer[nSamplesUsed], g_nBufferIdx-nSamplesUsed); // FIXME-TC: _Size * 2 + memmove(g_pSpeakerBuffer, &g_pSpeakerBuffer[nSamplesUsed], g_nBufferIdx-nSamplesUsed); // FIXME-TC: _Size * 2 (GH#213?) g_nBufferIdx -= nSamplesUsed; } } diff --git a/source/Video.cpp b/source/Video.cpp index 9060d26e..404d0d94 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -197,13 +197,24 @@ const BYTE DoubleHiresPalIndex[16] = { const int SRCOFFS_DHIRES = (SRCOFFS_HIRES + 512); // 1168 const int SRCOFFS_TOTAL = (SRCOFFS_DHIRES + 2560); // 3278 - #define SW_80COL (g_bVideoMode & VF_80COL) - #define SW_DHIRES (g_bVideoMode & VF_DHIRES) - #define SW_HIRES (g_bVideoMode & VF_HIRES) - #define SW_MASK2 (g_bVideoMode & VF_MASK2) - #define SW_MIXED (g_bVideoMode & VF_MIXED) - #define SW_PAGE2 (g_bVideoMode & VF_PAGE2) - #define SW_TEXT (g_bVideoMode & VF_TEXT) + enum VideoFlag_e + { + VF_80COL = 0x00000001, + VF_DHIRES = 0x00000002, + VF_HIRES = 0x00000004, + VF_80STORE= 0x00000008, + VF_MIXED = 0x00000010, + VF_PAGE2 = 0x00000020, + VF_TEXT = 0x00000040 + }; + + #define SW_80COL (g_uVideoMode & VF_80COL) + #define SW_DHIRES (g_uVideoMode & VF_DHIRES) + #define SW_HIRES (g_uVideoMode & VF_HIRES) + #define SW_80STORE (g_uVideoMode & VF_80STORE) + #define SW_MIXED (g_uVideoMode & VF_MIXED) + #define SW_PAGE2 (g_uVideoMode & VF_PAGE2) + #define SW_TEXT (g_uVideoMode & VF_TEXT) #define SETSOURCEPIXEL(x,y,c) g_aSourceStartofLine[(y)][(x)] = (c) @@ -261,24 +272,20 @@ static BYTE colormixbuffer[6]; static WORD colormixmap[6][6][6]; // - int g_nAltCharSetOffset = 0; // alternate character set +static int g_nAltCharSetOffset = 0; // alternate character set - bool g_bVideoDisplayPage2 = 0; - /*bool*/ UINT g_VideoForceFullRedraw = 1; +static /*bool*/ UINT g_VideoForceFullRedraw = 1; static LPBYTE framebufferaddr = (LPBYTE)0; static LONG g_nFrameBufferPitch = 0; -BOOL g_bGraphicsMode = 0; -static BOOL hasrefreshed = 0; -static DWORD lastpageflip = 0; COLORREF monochrome = RGB(0xC0,0xC0,0xC0); static BOOL rebuiltsource = 0; static LPBYTE vidlastmem = NULL; - int g_bVideoMode = VF_TEXT; +static UINT g_uVideoMode = VF_TEXT; DWORD g_eVideoType = VT_COLOR_TVEMU; - DWORD g_uHalfScanLines = true; // drop 50% scan lines for a more authentic look + DWORD g_uHalfScanLines = 1; // drop 50% scan lines for a more authentic look static bool g_bTextFlashState = false; @@ -1924,8 +1931,8 @@ BOOL VideoApparentlyDirty () return 1; DWORD address = (SW_HIRES && !SW_TEXT) - ? (0x20 << (int)g_bVideoDisplayPage2) - : (0x04 << (int)g_bVideoDisplayPage2); + ? (0x20 << (SW_PAGE2 ? 1 : 0)) + : (0x04 << (SW_PAGE2 ? 1 : 0)); DWORD length = (SW_HIRES && !SW_TEXT) ? 0x20 : 0x4; while (length--) if (*(memdirty+(address++)) & 2) @@ -1933,12 +1940,12 @@ BOOL VideoApparentlyDirty () // - bool bCharFlashing = false; - // Scan visible text page for any flashing chars if((SW_TEXT || SW_MIXED) && (g_nAltCharSetOffset == 0)) { - BYTE* pnMemText = MemGetMainPtr(0x400 << (int)g_bVideoDisplayPage2); + BYTE* pTextBank0 = MemGetMainPtr(0x400 << (SW_PAGE2 ? 1 : 0)); + BYTE* pTextBank1 = MemGetAuxPtr (0x400 << (SW_PAGE2 ? 1 : 0)); + const bool b80Col = SW_80COL; // Scan 8 long-lines of 120 chars (at 128 char offsets): // . Skip 8-char holes in TEXT @@ -1946,19 +1953,20 @@ BOOL VideoApparentlyDirty () { for(UINT x=0; x<40*3; x++) { - BYTE ch = pnMemText[y*128+x]; + BYTE ch = pTextBank0[y*128+x]; if((ch >= 0x40) && (ch <= 0x7F)) + return 1; + + if (b80Col) { - bCharFlashing = true; - break; + ch = pTextBank1[y*128+x]; + if((ch >= 0x40) && (ch <= 0x7F)) + return 1; } } } } - if(bCharFlashing) - return 1; - return 0; } @@ -1981,7 +1989,7 @@ void VideoBenchmark () { // GOING ON, CHANGING HALF OF THE BYTES IN THE VIDEO BUFFER EACH FRAME TO // SIMULATE THE ACTIVITY OF AN AVERAGE GAME DWORD totaltextfps = 0; - g_bVideoMode = VF_TEXT; + g_uVideoMode = VF_TEXT; FillMemory(mem+0x400,0x400,0x14); VideoRedrawScreen(); DWORD milliseconds = GetTickCount(); @@ -2003,7 +2011,7 @@ void VideoBenchmark () { // GOING ON, CHANGING HALF OF THE BYTES IN THE VIDEO BUFFER EACH FRAME TO // SIMULATE THE ACTIVITY OF AN AVERAGE GAME DWORD totalhiresfps = 0; - g_bVideoMode = VF_HIRES; + g_uVideoMode = VF_HIRES; FillMemory(mem+0x2000,0x2000,0x14); VideoRedrawScreen(); milliseconds = GetTickCount(); @@ -2099,7 +2107,7 @@ void VideoBenchmark () { DWORD executedcycles = CpuExecute(103); cycles -= executedcycles; DiskUpdatePosition(executedcycles); - JoyUpdatePosition(); + JoyUpdateButtonLatch(executedcycles); } } if (cycle & 1) @@ -2154,25 +2162,6 @@ BYTE VideoCheckMode (WORD, WORD address, BYTE, BYTE, ULONG uExecutedCycles) //=========================================================================== -// Check if we should call VideoRefreshScreen() based on unexpected page -// - Only called from 2 places in main ContinueExecution() loop -void VideoCheckPage(BOOL force) -{ - const bool bUnexpectedPage = (g_bVideoDisplayPage2 != (SW_PAGE2 != 0)); - //_ASSERT(!bUnexpectedPage); // [TC] Q: When does this happen? A: EG. When page-flipping && Scroll-Lock is pressed - - if (bUnexpectedPage && // Unexpected page && - (force || (emulmsec-lastpageflip > 500))) // force || >500ms since last flip - { - g_bVideoDisplayPage2 = (SW_PAGE2 != 0); - VideoRefreshScreen(); - hasrefreshed = 1; - lastpageflip = emulmsec; - } -} - -//=========================================================================== - /* // Drol expects = 80 68DE A5 02 LDX #02 @@ -2384,13 +2373,6 @@ void VideoDisplayLogo () DeleteObject(font); } -//=========================================================================== -BOOL VideoHasRefreshed () { - BOOL result = hasrefreshed; - hasrefreshed = 0; - return result; -} - //=========================================================================== void VideoRealizePalette(HDC dc) { @@ -2483,8 +2465,9 @@ static void DebugRefresh(char uDebugFlag) { static DWORD uLastRefreshTime = 0; - const DWORD uTimeBetweenRefreshes = uLastRefreshTime ? emulmsec - uLastRefreshTime : 0; - uLastRefreshTime = emulmsec; + const DWORD dwEmuTime_ms = CpuGetEmulationTime_ms(); + const DWORD uTimeBetweenRefreshes = uLastRefreshTime ? dwEmuTime_ms - uLastRefreshTime : 0; + uLastRefreshTime = dwEmuTime_ms; if (!uTimeBetweenRefreshes) return; // 1st time in func @@ -2505,7 +2488,7 @@ VideoUpdateFuncPtr_t VideoRefreshScreen () // IN THE FRAME BUFFER. MARK CELLS IN WHICH REDRAWING HAS TAKEN PLACE AS // DIRTY. _Video_Dirty(); - _Video_SetupBanks( g_bVideoDisplayPage2 ); + _Video_SetupBanks( SW_PAGE2 != 0 ); VideoUpdateFuncPtr_t pfUpdate = SW_TEXT ? SW_80COL @@ -2694,15 +2677,8 @@ void VideoReinitialize () void VideoResetState () { g_nAltCharSetOffset = 0; - g_bVideoDisplayPage2 = 0; - g_bVideoMode = VF_TEXT; + g_uVideoMode = VF_TEXT; g_VideoForceFullRedraw = 1; - -#if 0 // Debug HGR2 without having to exec 6502 code - g_bVideoDisplayPage2 = 1; - g_bVideoMode = VF_TEXT | VF_HIRES; -#endif - } @@ -2711,53 +2687,46 @@ BYTE VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles) { address &= 0xFF; DWORD oldpage2 = SW_PAGE2; - int oldvalue = g_nAltCharSetOffset+(int)(g_bVideoMode & ~(VF_MASK2 | VF_PAGE2)); - switch (address) { - case 0x00: g_bVideoMode &= ~VF_MASK2; break; - case 0x01: g_bVideoMode |= VF_MASK2; break; - case 0x0C: if (!IS_APPLE2) g_bVideoMode &= ~VF_80COL; break; - case 0x0D: if (!IS_APPLE2) g_bVideoMode |= VF_80COL; break; + int oldvalue = g_nAltCharSetOffset+(int)(g_uVideoMode & ~(VF_80STORE | VF_PAGE2)); + + switch (address) + { + case 0x00: g_uVideoMode &= ~VF_80STORE; break; + case 0x01: g_uVideoMode |= VF_80STORE; break; + case 0x0C: if (!IS_APPLE2) g_uVideoMode &= ~VF_80COL; break; + case 0x0D: if (!IS_APPLE2) g_uVideoMode |= VF_80COL; break; case 0x0E: if (!IS_APPLE2) g_nAltCharSetOffset = 0; break; // Alternate char set off case 0x0F: if (!IS_APPLE2) g_nAltCharSetOffset = 256; break; // Alternate char set on - case 0x50: g_bVideoMode &= ~VF_TEXT; break; - case 0x51: g_bVideoMode |= VF_TEXT; break; - case 0x52: g_bVideoMode &= ~VF_MIXED; break; - case 0x53: g_bVideoMode |= VF_MIXED; break; - case 0x54: g_bVideoMode &= ~VF_PAGE2; break; - case 0x55: g_bVideoMode |= VF_PAGE2; break; - case 0x56: g_bVideoMode &= ~VF_HIRES; break; - case 0x57: g_bVideoMode |= VF_HIRES; break; - case 0x5E: if (!IS_APPLE2) g_bVideoMode |= VF_DHIRES; break; - case 0x5F: if (!IS_APPLE2) g_bVideoMode &= ~VF_DHIRES; break; + case 0x50: g_uVideoMode &= ~VF_TEXT; break; + case 0x51: g_uVideoMode |= VF_TEXT; break; + case 0x52: g_uVideoMode &= ~VF_MIXED; break; + case 0x53: g_uVideoMode |= VF_MIXED; break; + case 0x54: g_uVideoMode &= ~VF_PAGE2; break; + case 0x55: g_uVideoMode |= VF_PAGE2; break; + case 0x56: g_uVideoMode &= ~VF_HIRES; break; + case 0x57: g_uVideoMode |= VF_HIRES; break; + case 0x5E: if (!IS_APPLE2) g_uVideoMode |= VF_DHIRES; break; + case 0x5F: if (!IS_APPLE2) g_uVideoMode &= ~VF_DHIRES; break; } - if (SW_MASK2) - g_bVideoMode &= ~VF_PAGE2; - if (oldvalue != g_nAltCharSetOffset+(int)(g_bVideoMode & ~(VF_MASK2 | VF_PAGE2))) { - g_bGraphicsMode = !SW_TEXT; - g_VideoForceFullRedraw = 1; - } - if (g_bFullSpeed && oldpage2 && !SW_PAGE2) { - static DWORD lasttime = 0; - DWORD currtime = GetTickCount(); - if (currtime-lasttime >= 20) - lasttime = currtime; - else - oldpage2 = SW_PAGE2; + + if (SW_80STORE) + g_uVideoMode &= ~VF_PAGE2; + + if (oldvalue != g_nAltCharSetOffset+(int)(g_uVideoMode & ~(VF_80STORE | VF_PAGE2))) + { + g_VideoForceFullRedraw = 1; } if (oldpage2 != SW_PAGE2) { - g_bVideoDisplayPage2 = (SW_PAGE2 != 0); if (!g_VideoForceFullRedraw) { #if 1 VideoRefreshScreen(); - hasrefreshed = 1; #else g_VideoForceFullRedraw = 1; // GH#129,GH204: Defer the redraw until the main ContinueExecution() loop (TODO: What effect does this have on other games?) #endif } - lastpageflip = emulmsec; } return MemReadFloatingBus(uExecutedCycles); @@ -2766,7 +2735,7 @@ BYTE VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles) //=========================================================================== // Called at 60Hz (every 16.666ms) -void VideoUpdateFlash() +static void VideoUpdateFlash() { static UINT nTextFlashCnt = 0; @@ -2788,17 +2757,81 @@ void VideoUpdateFlash() //=========================================================================== -bool VideoGetSW80COL() +// Called from main-loop every 17030 cycles (ie. 60Hz when CPU = 1MHz) +void VideoEndOfVideoFrame(void) +{ + VideoUpdateFlash(); // TODO: Flash rate should be constant (regardless of CPU speed) + + if (!VideoApparentlyDirty()) + return; + + // Apple II is not page flipping... + + static DWORD dwLastTime = 0; + DWORD dwCurrTime = GetTickCount(); + if (!g_bFullSpeed || + (dwCurrTime-dwLastTime >= 100)) // FullSpeed: update every 100ms + { + VideoRefreshScreen(); + dwLastTime = dwCurrTime; + } +} + +//=========================================================================== + +bool VideoGetSW80COL(void) { return SW_80COL ? true : false; } +bool VideoGetSWDHIRES(void) +{ + return SW_DHIRES ? true : false; +} + +bool VideoGetSWHIRES(void) +{ + return SW_HIRES ? true : false; +} + +bool VideoGetSW80STORE(void) +{ + return SW_80STORE ? true : false; +} + +bool VideoGetSWMIXED(void) +{ + return SW_MIXED ? true : false; +} + +bool VideoGetSWPAGE2(void) +{ + return SW_PAGE2 ? true : false; +} + +bool VideoGetSWTEXT(void) +{ + return SW_TEXT ? true : false; +} + +bool VideoGetSWAltCharSet(void) +{ + return g_nAltCharSetOffset == 0; +} + +//=========================================================================== + +void VideoSetForceFullRedraw(void) +{ + g_VideoForceFullRedraw = 1; +} + //=========================================================================== DWORD VideoGetSnapshot(SS_IO_Video* pSS) { pSS->bAltCharSet = !(g_nAltCharSetOffset == 0); - pSS->dwVidMode = g_bVideoMode; + pSS->dwVidMode = g_uVideoMode; return 0; } @@ -2807,13 +2840,7 @@ DWORD VideoGetSnapshot(SS_IO_Video* pSS) DWORD VideoSetSnapshot(SS_IO_Video* pSS) { g_nAltCharSetOffset = !pSS->bAltCharSet ? 0 : 256; - g_bVideoMode = pSS->dwVidMode; - - // - - g_bGraphicsMode = !SW_TEXT; - g_bVideoDisplayPage2 = (SW_PAGE2 != 0); - + g_uVideoMode = pSS->dwVidMode; return 0; } @@ -2831,8 +2858,8 @@ WORD VideoGetScannerAddress(bool* pbVblBar_OUT, const DWORD uExecutedCycles) // machine state switches // int nHires = (SW_HIRES && !SW_TEXT) ? 1 : 0; - int nPage2 = (SW_PAGE2) ? 1 : 0; - int n80Store = (MemGet80Store()) ? 1 : 0; + int nPage2 = SW_PAGE2 ? 1 : 0; + int n80Store = SW_80STORE ? 1 : 0; // calculate video parameters according to display standard // diff --git a/source/Video.h b/source/Video.h index afee07c5..9aa270b9 100644 --- a/source/Video.h +++ b/source/Video.h @@ -19,17 +19,6 @@ extern TCHAR g_aVideoChoices[]; extern char *g_apVideoModeDesc[ NUM_VIDEO_MODES ]; - enum VideoFlag_e - { - VF_80COL = 0x00000001, - VF_DHIRES = 0x00000002, - VF_HIRES = 0x00000004, - VF_MASK2 = 0x00000008, - VF_MIXED = 0x00000010, - VF_PAGE2 = 0x00000020, - VF_TEXT = 0x00000040 - }; - enum AppleFont_e { // 40-Column mode is 1x Zoom (default) @@ -57,15 +46,11 @@ enum AppleFont_e extern HBITMAP g_hLogoBitmap; -extern BOOL g_bGraphicsMode; extern COLORREF monochrome; // saved extern DWORD g_eVideoType; // saved extern DWORD g_uHalfScanLines; // saved extern LPBYTE g_pFramebufferbits; -extern int g_nAltCharSetOffset; -extern int g_bVideoMode; // g_bVideoMode - typedef bool (*VideoUpdateFuncPtr_t)(int,int,int,int,int); // Prototypes _______________________________________________________ @@ -74,12 +59,10 @@ void CreateColorMixMap(); BOOL VideoApparentlyDirty (); void VideoBenchmark (); -void VideoCheckPage (BOOL); void VideoChooseColor (); void VideoDestroy (); void VideoDrawLogoBitmap(HDC hDstDC, int xoff, int yoff, int srcw, int srch, int scale); void VideoDisplayLogo (); -BOOL VideoHasRefreshed (); void VideoInitialize (); void VideoRealizePalette (HDC); VideoUpdateFuncPtr_t VideoRedrawScreen (UINT); @@ -89,15 +72,22 @@ void VideoReinitialize (); void VideoResetState (); WORD VideoGetScannerAddress(bool* pbVblBar_OUT, const DWORD uExecutedCycles); bool VideoGetVbl(DWORD uExecutedCycles); -void VideoUpdateFlash(); -bool VideoGetSW80COL(); +void VideoEndOfVideoFrame(void); + +bool VideoGetSW80COL(void); +bool VideoGetSWDHIRES(void); +bool VideoGetSWHIRES(void); +bool VideoGetSW80STORE(void); +bool VideoGetSWMIXED(void); +bool VideoGetSWPAGE2(void); +bool VideoGetSWTEXT(void); +bool VideoGetSWAltCharSet(void); + +void VideoSetForceFullRedraw(void); + DWORD VideoGetSnapshot(SS_IO_Video* pSS); DWORD VideoSetSnapshot(SS_IO_Video* pSS); - -extern bool g_bVideoDisplayPage2; -extern /*bool*/ UINT g_VideoForceFullRedraw; - void _Video_Dirty(); void _Video_RedrawScreen( VideoUpdateFuncPtr_t update, bool bMixed = false ); void _Video_SetupBanks( bool bBank2 );