From a69cfcc464a8dc8e58fcd2cea163f3626bdbeefb Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Sat, 2 May 2009 09:04:47 +0000 Subject: [PATCH] Removed VU-Skip [helps simplify the frameskipper logic] -- Use the VU Cycle Stealer hack instead for better, faster, more stable speedups of the VU1 unit. git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1114 96395faa-99c1-11dd-bbfe-3dabce05a288 --- common/include/Pcsx2Config.h | 1 - pcsx2/Counters.cpp | 18 +--- pcsx2/GS.cpp | 41 ++-------- pcsx2/GS.h | 1 - pcsx2/Linux/CpuDlg.cpp | 3 - pcsx2/Misc.cpp | 22 +++-- pcsx2/System.cpp | 3 - pcsx2/VUmicro.h | 4 - pcsx2/VUmicroMem.cpp | 15 ---- pcsx2/VifDma.cpp | 7 -- pcsx2/windows/CpuDlg.cpp | 1 - pcsx2/windows/pcsx2.rc | 38 ++++----- pcsx2/x86/ix86-32/iR5900-32.cpp | 140 +++++++++++++++----------------- 13 files changed, 105 insertions(+), 189 deletions(-) diff --git a/common/include/Pcsx2Config.h b/common/include/Pcsx2Config.h index 8c248bd521..d26587a84b 100644 --- a/common/include/Pcsx2Config.h +++ b/common/include/Pcsx2Config.h @@ -54,7 +54,6 @@ extern SessionOverrideFlags g_Session; #define PCSX2_FRAMELIMIT_NORMAL 0x000 #define PCSX2_FRAMELIMIT_LIMIT 0x400 #define PCSX2_FRAMELIMIT_SKIP 0x800 -#define PCSX2_FRAMELIMIT_VUSKIP 0xc00 #define CHECK_FRAMELIMIT (Config.Options&PCSX2_FRAMELIMIT_MASK) diff --git a/pcsx2/Counters.cpp b/pcsx2/Counters.cpp index b9b9a7c9ed..89a5cf8bd6 100644 --- a/pcsx2/Counters.cpp +++ b/pcsx2/Counters.cpp @@ -32,7 +32,6 @@ using namespace Threading; extern u8 psxhblankgate; -u32 g_vu1SkipCount; // number of frames to disable/skip VU1 static const uint EECNT_FUTURE_TARGET = 0x10000000; @@ -50,8 +49,6 @@ SyncCounter vsyncCounter; u32 nextsCounter; // records the cpuRegs.cycle value of the last call to rcntUpdate() s32 nextCounter; // delta from nextsCounter, in cycles, until the next rcntUpdate() -// VUSkip Locals and Globals - void rcntReset(int index) { counters[index].count = 0; counters[index].sCycleT = cpuRegs.cycle; @@ -264,9 +261,6 @@ u32 UpdateVSyncRate() m_iStart = GetCPUTicks(); cpuRcntSet(); - // Initialize VU Skip Stuff... - g_vu1SkipCount = 0; - return (u32)m_iTicks; } @@ -363,17 +357,7 @@ static __forceinline void VSyncEnd(u32 sCycle) iFrame++; - if( g_vu1SkipCount > 0 ) - { - gsPostVsyncEnd( false ); - AtomicDecrement( g_vu1SkipCount ); - vu1MicroEnableSkip(); - } - else - { - gsPostVsyncEnd( true ); - vu1MicroDisableSkip(); - } + gsPostVsyncEnd( true ); hwIntcIrq(INTC_VBLANK_E); // HW Irq psxVBlankEnd(); // psxCounters vBlank End diff --git a/pcsx2/GS.cpp b/pcsx2/GS.cpp index 4ff204c57d..24b440538e 100644 --- a/pcsx2/GS.cpp +++ b/pcsx2/GS.cpp @@ -165,16 +165,10 @@ void gsSetVideoRegionType( u32 isPal ) // Make sure framelimiter options are in sync with the plugin's capabilities. void gsInit() { - switch(CHECK_FRAMELIMIT) + if( (CHECK_FRAMELIMIT == PCSX2_FRAMELIMIT_SKIP) && (GSsetFrameSkip == NULL) ) { - case PCSX2_FRAMELIMIT_SKIP: - case PCSX2_FRAMELIMIT_VUSKIP: - if( GSsetFrameSkip == NULL ) - { - Config.Options &= ~PCSX2_FRAMELIMIT_MASK; - Console::WriteLn("Notice: Disabling frameskip -- GS plugin does not support it."); - } - break; + Config.Options &= ~PCSX2_FRAMELIMIT_MASK; + Console::WriteLn("Notice: Disabling frameskip -- GS plugin does not support it."); } } @@ -619,8 +613,7 @@ __forceinline void gsFrameSkip( bool forceskip ) static u8 FramesToRender = 0; static u8 FramesToSkip = 0; - if( CHECK_FRAMELIMIT != PCSX2_FRAMELIMIT_SKIP && - CHECK_FRAMELIMIT != PCSX2_FRAMELIMIT_VUSKIP ) return; + if( CHECK_FRAMELIMIT != PCSX2_FRAMELIMIT_SKIP ) return; // FrameSkip and VU-Skip Magic! // Skips a sequence of consecutive frames after a sequence of rendered frames @@ -652,14 +645,6 @@ __forceinline void gsFrameSkip( bool forceskip ) return; } - // if we've already given the EE a skipcount assignment then don't do anything more. - // Otherwise we could start compounding the issue and skips would be too long. - if( g_vu1SkipCount > 0 ) - { - //Console::Status("- Already Assigned a Skipcount.. %d", params g_vu1SkipCount ); - return; - } - if( FramesToRender == 0 ) { // -- Standard operation section -- @@ -680,20 +665,9 @@ __forceinline void gsFrameSkip( bool forceskip ) if( (m_justSkipped && (sSlowDeltaTime > m_iSlowTicks)) || (sSlowDeltaTime > m_iSlowTicks*2) ) { - //Console::Status( "Frameskip Initiated! Lateness: %d", params (int)( (sSlowDeltaTime*100) / m_iSlowTicks ) ); - - if( CHECK_FRAMELIMIT == PCSX2_FRAMELIMIT_VUSKIP ) - { - // For best results we have to wait for the EE to - // tell us when to skip, so that VU skips are synched with GS skips. - AtomicExchangeAdd( g_vu1SkipCount, yesSkipFrames+1 ); - } - else - { - GSsetFrameSkip(1); - FramesToRender = noSkipFrames+1; - FramesToSkip = yesSkipFrames; - } + GSsetFrameSkip(1); + FramesToRender = noSkipFrames+1; + FramesToSkip = yesSkipFrames; } } else @@ -771,7 +745,6 @@ void gsPostVsyncEnd( bool updategs ) void _gs_ResetFrameskip() { - g_vu1SkipCount = 0; // set to 0 so that EE will re-enable the VU at the next vblank. GSsetFrameSkip( 0 ); } diff --git a/pcsx2/GS.h b/pcsx2/GS.h index bdb84fd19a..983d13a9b1 100644 --- a/pcsx2/GS.h +++ b/pcsx2/GS.h @@ -331,7 +331,6 @@ void mfifoGIFtransfer(int qwc); int _GIFchain(); void gifMFIFOInterrupt(); -extern u32 g_vu1SkipCount; extern u32 CSRw; extern u64 m_iSlowStart; diff --git a/pcsx2/Linux/CpuDlg.cpp b/pcsx2/Linux/CpuDlg.cpp index 0fd1e7b07b..4baca1577e 100644 --- a/pcsx2/Linux/CpuDlg.cpp +++ b/pcsx2/Linux/CpuDlg.cpp @@ -39,8 +39,6 @@ void OnCpu_Ok(GtkButton *button, gpointer user_data) newopts |= PCSX2_FRAMELIMIT_LIMIT; else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(CpuDlg, "GtkRadioButton_LimitFS")))) newopts |= PCSX2_FRAMELIMIT_SKIP; - else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(CpuDlg, "GtkRadioButton_VUSkip")))) - newopts |= PCSX2_FRAMELIMIT_VUSKIP; Config.CustomFps = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(lookup_widget(CpuDlg, "CustomFPSLimit"))); Config.CustomFrameSkip = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(lookup_widget(CpuDlg, "FrameThreshold"))); @@ -88,7 +86,6 @@ void OnConf_Cpu(GtkMenuItem *menuitem, gpointer user_data) gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(CpuDlg, "GtkRadioButton_LimitNormal")), CHECK_FRAMELIMIT == PCSX2_FRAMELIMIT_NORMAL); gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(CpuDlg, "GtkRadioButton_LimitLimit")), CHECK_FRAMELIMIT == PCSX2_FRAMELIMIT_LIMIT); gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(CpuDlg, "GtkRadioButton_LimitFS")), CHECK_FRAMELIMIT == PCSX2_FRAMELIMIT_SKIP); - gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(CpuDlg, "GtkRadioButton_VUSkip")), CHECK_FRAMELIMIT == PCSX2_FRAMELIMIT_VUSKIP); sprintf(str, "Cpu Vendor: %s", cpuinfo.x86ID); gtk_label_set_text(GTK_LABEL(lookup_widget(CpuDlg, "GtkLabel_CpuVendor")), str); diff --git a/pcsx2/Misc.cpp b/pcsx2/Misc.cpp index f6a67fe6f7..d129f4ed9a 100644 --- a/pcsx2/Misc.cpp +++ b/pcsx2/Misc.cpp @@ -447,12 +447,19 @@ void CycleFrameLimit(int dir) newFrameLimit = 0; } else newFrameLimit = oldFrameLimit; - } else if (dir > 0) { - // next - newFrameLimit = (curFrameLimit + PCSX2_FRAMELIMIT_LIMIT) & PCSX2_FRAMELIMIT_MASK; - } else { - // previous - newFrameLimit = (curFrameLimit + PCSX2_FRAMELIMIT_VUSKIP) & PCSX2_FRAMELIMIT_MASK; + } + else if (dir > 0) // next + { + newFrameLimit = curFrameLimit + PCSX2_FRAMELIMIT_LIMIT; + if( newFrameLimit > PCSX2_FRAMELIMIT_SKIP ) + newFrameLimit = 0; + } + else // previous + { + if( newFrameLimit == 0 ) + newFrameLimit = PCSX2_FRAMELIMIT_SKIP; + else + newFrameLimit = curFrameLimit - PCSX2_FRAMELIMIT_LIMIT; } newOptions = (Config.Options & ~PCSX2_FRAMELIMIT_MASK) | newFrameLimit; @@ -467,7 +474,6 @@ void CycleFrameLimit(int dir) limitMsg = "Limit"; break; case PCSX2_FRAMELIMIT_SKIP: - case PCSX2_FRAMELIMIT_VUSKIP: if( GSsetFrameSkip == NULL ) { newOptions &= ~PCSX2_FRAMELIMIT_MASK; @@ -479,7 +485,7 @@ void CycleFrameLimit(int dir) // When enabling Skipping we have to make sure Skipper (GS) and Limiter (EE) // are properly synchronized. gsDynamicSkipEnable(); - limitMsg = ((newOptions & PCSX2_FRAMELIMIT_MASK) == PCSX2_FRAMELIMIT_SKIP) ? "Skip" : "VUSkip"; + limitMsg = "Skip"; } break; diff --git a/pcsx2/System.cpp b/pcsx2/System.cpp index 97b2a3b64f..3ed6d4a102 100644 --- a/pcsx2/System.cpp +++ b/pcsx2/System.cpp @@ -319,9 +319,6 @@ void SysClearExecutionCache() psxCpu->Reset(); vuMicroCpuReset(); - - // make sure the VU1 doesn't have lingering "skip" enabled. - vu1MicroDisableSkip(); } __forceinline void SysUpdate() diff --git a/pcsx2/VUmicro.h b/pcsx2/VUmicro.h index 5933338447..18bb18a384 100644 --- a/pcsx2/VUmicro.h +++ b/pcsx2/VUmicro.h @@ -123,10 +123,6 @@ extern void vu1ResetRegs(); extern void vu1ExecMicro(u32 addr); extern void vu1Exec(VURegs* VU); -extern void vu1MicroEnableSkip(); -extern void vu1MicroDisableSkip(); -extern bool vu1MicroIsSkipping(); - void VU0_UPPER_FD_00(); void VU0_UPPER_FD_01(); void VU0_UPPER_FD_10(); diff --git a/pcsx2/VUmicroMem.cpp b/pcsx2/VUmicroMem.cpp index ce2e32add1..59ed7cd653 100644 --- a/pcsx2/VUmicroMem.cpp +++ b/pcsx2/VUmicroMem.cpp @@ -38,21 +38,6 @@ static void DummyExecuteVU1Block(void) VU1.vifRegs->stat &= ~4; // also reset the bit (grandia 3 works) } -void vu1MicroEnableSkip() -{ - CpuVU1.ExecuteBlock = DummyExecuteVU1Block; -} - -void vu1MicroDisableSkip() -{ - CpuVU1.ExecuteBlock = CHECK_VU1REC ? recVU1.ExecuteBlock : intVU1.ExecuteBlock; -} - -bool vu1MicroIsSkipping() -{ - return CpuVU1.ExecuteBlock == DummyExecuteVU1Block; -} - void vuMicroCpuReset() { CpuVU0 = CHECK_VU0REC ? recVU0 : intVU0; diff --git a/pcsx2/VifDma.cpp b/pcsx2/VifDma.cpp index 8ac5b9798a..37c25ed4e3 100644 --- a/pcsx2/VifDma.cpp +++ b/pcsx2/VifDma.cpp @@ -580,13 +580,6 @@ static void VIFunpack(u32 *data, vifCode *v, unsigned int size, const unsigned i vif = &vif1; vifRow = g_vifRow1; assert(v->addr < memsize); - - if (vu1MicroIsSkipping()) - { - // don't process since the frame is dummy - vif->tag.addr += (size / (VIFfuncTable[ vif->cmd & 0xf ].gsize * vifRegs->cycle.wl)) * ((vifRegs->cycle.cl - vifRegs->cycle.wl) * 16); - return; - } } dest = (u32*)(VU->Mem + v->addr); diff --git a/pcsx2/windows/CpuDlg.cpp b/pcsx2/windows/CpuDlg.cpp index dc4c97beff..d7a334385e 100644 --- a/pcsx2/windows/CpuDlg.cpp +++ b/pcsx2/windows/CpuDlg.cpp @@ -134,7 +134,6 @@ BOOL CALLBACK CpuDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) if( SendDlgItemMessage(hW,IDC_CPU_FL_NORMAL,BM_GETCHECK,0,0) ) newopts |= PCSX2_FRAMELIMIT_NORMAL; else if( SendDlgItemMessage(hW,IDC_CPU_FL_LIMIT,BM_GETCHECK,0,0) ) newopts |= PCSX2_FRAMELIMIT_LIMIT; else if( SendDlgItemMessage(hW,IDC_CPU_FL_SKIP,BM_GETCHECK,0,0) ) newopts |= PCSX2_FRAMELIMIT_SKIP; - else if( SendDlgItemMessage(hW,IDC_CPU_FL_SKIPVU,BM_GETCHECK,0,0) ) newopts |= PCSX2_FRAMELIMIT_VUSKIP; GetDlgItemText(hW, IDC_CUSTOMFPS, cfps, 20); Config.CustomFps = atoi(cfps); diff --git a/pcsx2/windows/pcsx2.rc b/pcsx2/windows/pcsx2.rc index e5934d0551..e1013f35db 100644 --- a/pcsx2/windows/pcsx2.rc +++ b/pcsx2/windows/pcsx2.rc @@ -828,7 +828,7 @@ BEGIN CONTROL "EE Counters log",IDC_EECNTLOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,140,64,11 END -IDD_CPUDLG DIALOGEX 0, 0, 563, 321 +IDD_CPUDLG DIALOGEX 0, 0, 563, 305 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN @@ -843,13 +843,11 @@ BEGIN CONTROL "Normal - All frames are rendered as fast as possible.",IDC_CPU_FL_NORMAL, "Button",BS_AUTORADIOBUTTON | BS_MULTILINE | WS_GROUP,309,17,221,17 CONTROL "Limit - Force frames to normal speeds if too fast.\n (You can set a custom FPS limit below.)",IDC_CPU_FL_LIMIT, - "Button",BS_AUTORADIOBUTTON | BS_MULTILINE,309,33,222,15 + "Button",BS_AUTORADIOBUTTON | BS_MULTILINE,309,37,222,15 CONTROL "Frame Skip - In order to achieve normal speeds,\n some frames are skipped (fast).\n Fps displayed counts skipped frames too.",IDC_CPU_FL_SKIP, - "Button",BS_AUTORADIOBUTTON | BS_MULTILINE,309,48,221,28 - CONTROL "VU Skip - Same as 'Frame Skip', but tries to skip more.\n Artifacts might be present, but will be faster.",IDC_CPU_FL_SKIPVU, - "Button",BS_AUTORADIOBUTTON | BS_MULTILINE,309,75,220,25 - DEFPUSHBUTTON "OK",IDOK,210,298,61,14 - PUSHBUTTON "Cancel",IDCANCEL,282,298,61,14,NOT WS_TABSTOP + "Button",BS_AUTORADIOBUTTON | BS_MULTILINE,309,56,221,28 + DEFPUSHBUTTON "OK",IDOK,210,287,61,14 + PUSHBUTTON "Cancel",IDCANCEL,282,287,61,14,NOT WS_TABSTOP LTEXT "CPU Vendor",IDC_VENDORNAME,12,23,88,8 LTEXT "Family",IDC_FAMILYNAME,12,41,88,8 LTEXT "Cpu Speed",IDC_CPUSPEEDNAME,12,60,88,8 @@ -860,19 +858,19 @@ BEGIN GROUPBOX "VU Recompilers - All options are set by default",IDC_CPU_VUGROUP,7,119,265,46 LTEXT "Features",IDC_FEATURESNAME,12,78,88,8 GROUPBOX "",IDC_STATIC,7,7,265,90 - LTEXT "Custom FPS Limit (0=auto):",IDC_CUSTOM_FPS,327,113,124,12 - EDITTEXT IDC_CUSTOMFPS,456,113,53,13,ES_AUTOHSCROLL | ES_NUMBER - EDITTEXT IDC_CUSTOM_FRAMESKIP,456,130,53,13,ES_AUTOHSCROLL | ES_NUMBER - EDITTEXT IDC_CUSTOM_CONSECUTIVE_FRAMES,456,148,53,13,ES_AUTOHSCROLL | ES_NUMBER - LTEXT "Skip Frames when slower than:\n(See Note 1)",IDC_FRAMESKIP_LABEL1,327,129,106,20 - LTEXT "Consecutive Frames before skipping:\n(See Note 2)",IDC_FRAMESKIP_LABEL2,327,149,121,17 - GROUPBOX "Frame Limiting (F4 key switches the mode in-game!)",IDC_FRAMELIMIT,301,7,250,280 - GROUPBOX "Detailed Settings",IDC_FRAMELIMIT_OPTIONS,310,99,234,185 - LTEXT "*Note 1: Will only skip when slower than this fps number.\n (0 = Auto) ; (9999 = Forced-Frameskip regardless of speed.)\n (e.g. If set to 45, will only skip when slower than 45fps.)",IDC_FRAMESKIP_LABEL3,318,189,217,26 - LTEXT "*Note 2: Will render this number of consecutive frames before\n skipping the next frame. (0=default)\n (e.g. If set to 2, will render 2 frames before skipping 1.)",IDC_FRAMESKIP_LABEL4,318,216,217,25 - EDITTEXT IDC_CUSTOM_CONSECUTIVE_SKIP,456,166,53,13,ES_AUTOHSCROLL | ES_NUMBER - LTEXT "Consecutive Frames to skip:\n(See Note 3)",IDC_FRAMESKIP_LABEL5,327,167,121,17 - LTEXT "*Note 3: Will skip this number of frames before\n rendering the next sequence of frames. (0=default)\n (e.g. If set to 2, will skip 2 consecutive frames whenever its time\n to skip.)",IDC_FRAMESKIP_LABEL6,318,244,217,32 + LTEXT "Custom FPS Limit (0=auto):",IDC_CUSTOM_FPS,327,103,124,12 + EDITTEXT IDC_CUSTOMFPS,456,103,53,13,ES_AUTOHSCROLL | ES_NUMBER + EDITTEXT IDC_CUSTOM_FRAMESKIP,456,121,53,13,ES_AUTOHSCROLL | ES_NUMBER + EDITTEXT IDC_CUSTOM_CONSECUTIVE_FRAMES,456,139,53,13,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "Skip Frames when slower than:\n(See Note 1)",IDC_FRAMESKIP_LABEL1,327,119,106,20 + LTEXT "Consecutive Frames before skipping:\n(See Note 2)",IDC_FRAMESKIP_LABEL2,327,139,121,17 + GROUPBOX "Frame Limiting (F4 key switches the mode in-game!)",IDC_FRAMELIMIT,301,7,250,274 + GROUPBOX "Detailed Settings",IDC_FRAMELIMIT_OPTIONS,310,89,234,185 + LTEXT "*Note 1: Will only skip when slower than this fps number.\n (0 = Auto) ; (9999 = Forced-Frameskip regardless of speed.)\n (e.g. If set to 45, will only skip when slower than 45fps.)",IDC_FRAMESKIP_LABEL3,318,179,217,26 + LTEXT "*Note 2: Will render this number of consecutive frames before\n skipping the next frame. (0=default)\n (e.g. If set to 2, will render 2 frames before skipping 1.)",IDC_FRAMESKIP_LABEL4,318,206,217,25 + EDITTEXT IDC_CUSTOM_CONSECUTIVE_SKIP,456,157,53,13,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "Consecutive Frames to skip:\n(See Note 3)",IDC_FRAMESKIP_LABEL5,327,157,121,17 + LTEXT "*Note 3: Will skip this number of frames before\n rendering the next sequence of frames. (0=default)\n (e.g. If set to 2, will skip 2 consecutive frames whenever its time\n to skip.)",IDC_FRAMESKIP_LABEL6,318,234,217,32 END diff --git a/pcsx2/x86/ix86-32/iR5900-32.cpp b/pcsx2/x86/ix86-32/iR5900-32.cpp index d93c425de6..f3768ab66e 100644 --- a/pcsx2/x86/ix86-32/iR5900-32.cpp +++ b/pcsx2/x86/ix86-32/iR5900-32.cpp @@ -424,7 +424,7 @@ PCSX2_ALIGNED16( static u8 manual_counter[Ps2MemSize::Base >> 12] ); //////////////////////////////////////////////////// void recResetEE( void ) { - DbgCon::Status( "iR5900-32 > Resetting recompiler memory and structures." ); + Console::Status( "Issuing EE/iR5900-32 Recompiler Reset [mem/structure cleanup]" ); maxrecmem = 0; @@ -1258,7 +1258,6 @@ void recRecompile( const u32 startpc ) // if recPtr reached the mem limit reset whole mem if ( ( (uptr)recPtr - (uptr)recMem ) >= REC_CACHEMEM-0x40000 || dumplog == 0xffffffff) { - DevCon::WriteLn( "EE Recompiler data reset" ); recResetEE(); } if ( ( (uptr)recStackPtr - (uptr)recStack ) >= RECSTACK_SIZE-0x100 ) { @@ -1334,10 +1333,7 @@ void recRecompile( const u32 startpc ) willbranch3 = 1; s_nEndBlock = i; - // Log the pagesplits verbosely for now, until we see if any games are affected - // adversely by excessive splits. - DevCon::Notice( "Pagesplit @ %08X : size=%d insts", params startpc, (i-startpc) / 4 ); - + //DevCon::Notice( "Pagesplit @ %08X : size=%d insts", params startpc, (i-startpc) / 4 ); break; } @@ -1508,86 +1504,80 @@ StartRecomp: iDumpBlock(startpc, recPtr); #endif - // fixme! The following manual/protected block code can be greatly simplified now. - // It originally had to account for cross-page blocks, but we have since guaranteed - // that no block will cross a page boundary. - u32 sz = (s_nEndBlock-startpc) >> 2; u32 inpage_ptr = HWADDR(startpc); u32 inpage_sz = sz*4; - while(inpage_sz) - { - int PageType = mmap_GetRamPageInfo((u32*)PSM(inpage_ptr)); - u32 inpage_offs = inpage_ptr & 0xFFF; - u32 pgsz = std::min(0x1000 - inpage_offs, inpage_sz); + // note: blocks are guaranteed to reside within the confines of a single page. - if(PageType!=-1) + const int PageType = mmap_GetRamPageInfo((u32*)PSM(inpage_ptr)); + const u32 inpage_offs = inpage_ptr & 0xFFF; + //const u32 pgsz = std::min(0x1000 - inpage_offs, inpage_sz); + const u32 pgsz = inpage_sz; + + if(PageType!=-1) + { + if (PageType==0) { + mmap_MarkCountedRamPage(PSM(inpage_ptr),inpage_ptr&~0xFFF); + manual_page[inpage_ptr >> 12] = 0; + } + else { - if (PageType==0) { - mmap_MarkCountedRamPage(PSM(inpage_ptr),inpage_ptr&~0xFFF); - manual_page[inpage_ptr >> 12] = 0; + xMOV( ecx, inpage_ptr ); + xMOV( edx, pgsz / 4 ); + //xMOV( eax, startpc ); // uncomment this to access startpc (as eax) in dyna_block_discard + + u32 lpc = inpage_ptr; + u32 stg = pgsz; + while(stg>0) + { + xCMP( ptr32[PSM(lpc)], *(u32*)PSM(lpc) ); + xJNE( dyna_block_discard ); + + stg -= 4; + lpc += 4; + } + + // Tweakpoint! 3 is a 'magic' number representing the number of times a counted block + // is re-protected before the recompiler gives up and sets it up as an uncounted (permanent) + // manual block. Higher thresholds result in more recompilations for blocks that share code + // and data on the same page. Side effects of a lower threshold: over extended gameplay + // with several map changes, a game's overall performance could degrade. + + // (ideally, perhaps, manual_counter should be reset to 0 every few minutes?) + + if (startpc != 0x81fc0 && manual_counter[inpage_ptr >> 12] <= 3) { + + // Counted blocks add a weighted (by block size) value into manual_page each time they're + // run. If the block gets run a lot, it resets and re-protects itself in the hope + // that whatever forced it to be manually-checked before was a 1-time deal. + + // Counted blocks have a secondary threshold check in manual_counter, which forces a block + // to 'uncounted' mode if it's recompiled several time. This protects against excessive + // recompilation of blocks that reside on the same codepage as data. + + // fixme? Currently this algo is kinda dumb and results in the forced recompilation of a + // lot of blocks before it decides to mark a 'busy' page as uncounted. There might be + // be a more clever approach that could streamline this process, by doing a first-pass + // test using the vtlb memory protection (without recompilation!) to reprotect a counted + // block. But unless a new also is relatively simple in implementation, it's probably + // not worth the effort (tests show that we have lots of recompiler memory to spare, and + // that the current amount of recompilation is fairly cheap). + + xADD(ptr16[&manual_page[inpage_ptr >> 12]], sz); + xJC( dyna_page_reset ); + + // note: clearcnt is measured per-page, not per-block! + DbgCon::WriteLn( "Manual block @ %08X : size=%3d page/offs=%05X/%03X inpgsz=%d clearcnt=%d", + params startpc, sz, inpage_ptr>>12, inpage_offs, inpage_sz, manual_counter[inpage_ptr >> 12] ); } else { - xMOV( ecx, inpage_ptr ); - xMOV( edx, pgsz / 4 ); - //xMOV( eax, startpc ); // uncomment this to access startpc (as eax) in dyna_block_discard - - u32 lpc = inpage_ptr; - u32 stg = pgsz; - while(stg>0) - { - xCMP( ptr32[PSM(lpc)], *(u32*)PSM(lpc) ); - xJNE( dyna_block_discard ); - - stg -= 4; - lpc += 4; - } - - // Tweakpoint! 3 is a 'magic' number representing the number of times a counted block - // is re-protected before the recompiler gives up and sets it up as an uncounted (permanent) - // manual block. 4 definitely seemed too high, but 2 might be better? Side effects of a - // lower threshold: over extended gameplay with several map changes, a game's overall - // performance could degrade. - - // (ideally, perhaps, manual_counter should be reset to 0 every few minutes?) - - if (startpc != 0x81fc0 && manual_counter[inpage_ptr >> 12] <= 3) { - - // Counted blocks add a weighted (by block size) value into manual_page each time they're - // run. If the block gets run a lot, it resets and re-protects itself in the hope - // that whatever forced it to be manually-checked before was a 1-time deal. - - // Counted blocks have a secondary threshold check in manual_counter, which forces a block - // to 'uncounted' mode if it's recompiled several time. This protects against excessive - // recompilation of blocks that reside on the same codepage as data. - - // fixme? Currently this algo is kinda dumb and results in the forced recompilation of a - // lot of blocks before it decides to mark a 'busy' page as uncounted. There might be - // be a more clever approach that could streamline this process, by doing a first-pass - // test using the vtlb memory protection (without recompilation!) to reprotect a counted - // block. But unless a new also is relatively simple in implementation, it's probably - // not worth the effort (tests show that we have lots of recompiler memory to spare, and - // that the current amount of recompilation is fairly cheap). - - xADD(ptr16[&manual_page[inpage_ptr >> 12]], sz); - xJC( dyna_page_reset ); - - // note: clearcnt is measured per-page, not per-block! - DbgCon::WriteLn( "Manual block @ %08X : size=%3d page/offs=%05X/%03X inpgsz=%d clearcnt=%d", - params startpc, sz, inpage_ptr>>12, inpage_offs, inpage_sz, manual_counter[inpage_ptr >> 12] ); - } - else - { - DbgCon::Notice( "Uncounted Manual block @ %08X : size=%3d page/offs=%05X/%03X inpgsz=%d", - params startpc, sz, inpage_ptr>>12, inpage_offs, pgsz, inpage_sz ); - } - + DbgCon::Notice( "Uncounted Manual block @ %08X : size=%3d page/offs=%05X/%03X inpgsz=%d", + params startpc, sz, inpage_ptr>>12, inpage_offs, pgsz, inpage_sz ); } + } - inpage_ptr += pgsz; - inpage_sz -= pgsz; } // Finally: Generate x86 recompiled code!