Merge pull request #230 from AppleWin/main_loop_refactor

Main loop refactor -- code cleanup looks good !
This commit is contained in:
Michael 2014-09-18 15:07:51 -07:00
commit 3e22d07951
13 changed files with 244 additions and 273 deletions

View File

@ -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<MAX_CNT; n++)
g_fMeanPeriod += g_fDbg[n];
g_fMeanPeriod /= (double)MAX_CNT;
g_fMeanFreq = 1.0 / g_fMeanPeriod;
}
#endif
}
}
@ -985,11 +912,6 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int)
LogFileOutput("AppleWin version: %s\n", VERSIONSTRING);
#if DBG_CALC_FREQ
QueryPerformanceFrequency((LARGE_INTEGER*)&g_nPerfFreq);
if(g_fh) fprintf(g_fh, "Performance frequency = %d\n",g_nPerfFreq);
#endif
//-----
// Initialize COM - so we can use CoCreateInstance

View File

@ -13,9 +13,6 @@ extern TCHAR *g_pAppTitle;
extern eApple2Type g_Apple2Type;
extern DWORD cumulativecycles;
extern DWORD cyclenum;
extern DWORD emulmsec;
extern bool g_bFullSpeed;
//Pravets 8A/C only variables

View File

@ -176,16 +176,18 @@ void RequestDebugger()
*
***/
unsigned __int64 g_nCycleIrqStart;
unsigned __int64 g_nCycleIrqEnd;
UINT g_nCycleIrqTime;
#ifdef _DEBUG
static unsigned __int64 g_nCycleIrqStart;
static unsigned __int64 g_nCycleIrqEnd;
static UINT g_nCycleIrqTime;
UINT g_nIdx = 0;
const UINT BUFFER_SIZE = 4096; // 80 secs
UINT g_nBuffer[BUFFER_SIZE];
UINT g_nMean = 0;
UINT g_nMin = 0xFFFFFFFF;
UINT g_nMax = 0;
static UINT g_nIdx = 0;
static const UINT BUFFER_SIZE = 4096; // 80 secs
static UINT g_nBuffer[BUFFER_SIZE];
static UINT g_nMean = 0;
static UINT g_nMin = 0xFFFFFFFF;
static UINT g_nMax = 0;
#endif
static __forceinline void DoIrqProfiling(DWORD uCycles)
{
@ -352,7 +354,9 @@ static __forceinline void NMI(ULONG& uExecutedCycles, UINT& uExtraCycles, BOOL&
{
// NMI signals are only serviced once
g_bNmiFlank = FALSE;
#ifdef _DEBUG
g_nCycleIrqStart = g_nCumulativeCycles + uExecutedCycles;
#endif
PUSH(regs.pc >> 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);
//

View File

@ -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);

View File

@ -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:

View File

@ -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
}

View File

@ -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;
}
}
}
//===========================================================================

View File

@ -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();

View File

@ -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;

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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
//

View File

@ -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 );