Added ability to merge traces cross JCC branch instructions

Makes traces longer -> emulation faster in average
This commit is contained in:
Stanislav Shwartsman 2007-12-14 20:41:09 +00:00
parent db69a25c36
commit d9a59c7a1f
5 changed files with 57 additions and 24 deletions

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: cpu.cc,v 1.189 2007-12-14 11:27:44 sshwarts Exp $
// $Id: cpu.cc,v 1.190 2007-12-14 20:41:09 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -65,7 +65,7 @@ static Bit32u iCacheMisses=0;
static Bit32u iCacheMergeTraces=0;
static Bit32u iCacheTraceLengh[BX_MAX_TRACE_LENGTH];
#define InstrICache_StatsMask 0xfffffff
#define InstrICache_StatsMask 0x3ffffff
#define InstrICache_Stats() {\
if ((iCacheLookups & InstrICache_StatsMask) == 0) { \
@ -120,7 +120,7 @@ bxICacheEntry_c* BX_CPU_C::fetchInstructionTrace(bxInstruction_c *iStorage, bx_a
// We are not so lucky, but let's be optimistic - try to build trace from
// incoming instruction bytes stream !
trace->pAddr = pAddr;
trace->writeStamp = ICacheWriteStampInvalid;
trace->writeStamp = pageWriteStamp;
trace->ilen = 0;
InstrICache_Increment(iCacheMisses);
@ -138,7 +138,7 @@ bxICacheEntry_c* BX_CPU_C::fetchInstructionTrace(bxInstruction_c *iStorage, bx_a
bxInstruction_c *i = trace->i;
for (unsigned len=0;len<max_length;len++)
for (unsigned len=0;len<max_length;len++,i++)
{
#if BX_SUPPORT_X86_64
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64)
@ -157,25 +157,33 @@ bxICacheEntry_c* BX_CPU_C::fetchInstructionTrace(bxInstruction_c *iStorage, bx_a
}
// First instruction is boundary fetch, return iStorage and leave
// the trace cache entry invalid (do not cache the instruction)
trace->writeStamp = ICacheWriteStampInvalid;
boundaryFetch(fetchPtr, remainingInPage, iStorage);
return 0;
}
// add instruction to the trace ...
unsigned iLen = i->ilen();
trace->writeStamp = pageWriteStamp;
trace->ilen++;
if (i->getStopTraceAttr()) break;
// ... and continue to the next instruction
remainingInPage -= iLen;
if (remainingInPage == 0) break;
if (remainingInPage < 15) maxFetch = remainingInPage;
fetchPtr += iLen;
pAddr += iLen;
i++;
fetchPtr += iLen;
if (mergeTraces(trace, i, pAddr)) break;
if (i->getStopTraceAttr()) {
unsigned b1 = i->b1() & 0x1f0;
if (b1 == 0x70 || b1 == 0x180) { // JCC instruction
// try cross JCC branch merge of traces
mergeTraces(trace, i+1, pAddr);
}
break;
}
// try to find a trace starting from current pAddr and merge
if (mergeTraces(trace, i+1, pAddr)) break;
}
return trace;
@ -369,6 +377,11 @@ void BX_CPU_C::cpu_loop(Bit32u max_instr_count)
while (1) {
#if BX_SUPPORT_TRACE_CACHE
// clear stop trace magic indication that probably was set by branch32/64
BX_CPU_THIS_PTR async_event &= ~BX_ASYNC_EVENT_STOP_TRACE;
#endif
// First check on events which occurred for previous instructions
// (traps) and ones which are asynchronous to the CPU
// (hardware interrupts).

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: cpu.h,v 1.387 2007-12-14 11:27:44 sshwarts Exp $
// $Id: cpu.h,v 1.388 2007-12-14 20:41:09 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -1199,7 +1199,10 @@ public: // for now...
#define BX_DEBUG_TRAP_SPECIAL (0xf8000000)
Bit32u debug_trap; // holds DR6 value (16bit) to be set as well
volatile bx_bool async_event;
volatile Bit32u async_event;
#define BX_ASYNC_EVENT_STOP_TRACE (0x80000000)
volatile bx_bool INTR;
volatile bx_bool smi_pending;
volatile bx_bool nmi_pending;

View File

@ -1,5 +1,5 @@
////////////////////////////////////////////////////////////////////////
// $Id: ctrl_xfer_pro.cc,v 1.63 2007-12-10 23:04:18 sshwarts Exp $
// $Id: ctrl_xfer_pro.cc,v 1.64 2007-12-14 20:41:09 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -139,6 +139,12 @@ BX_CPU_C::branch_near32(Bit32u new_EIP)
BX_ERROR(("branch_near: offset outside of CS limits"));
exception(BX_GP_EXCEPTION, 0, 0);
}
#if BX_SUPPORT_TRACE_CACHE
// assert magic async_event to stop trace execution
BX_CPU_THIS_PTR async_event |= BX_ASYNC_EVENT_STOP_TRACE;
#endif
EIP = new_EIP;
}
@ -170,6 +176,11 @@ BX_CPU_C::branch_near64(bxInstruction_c *i)
exception(BX_GP_EXCEPTION, 0, 0);
}
#if BX_SUPPORT_TRACE_CACHE
// assert magic async_event to stop trace execution
BX_CPU_THIS_PTR async_event |= BX_ASYNC_EVENT_STOP_TRACE;
#endif
RIP = new_RIP;
}
#endif

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: fetchdecode.cc,v 1.147 2007-12-13 18:42:31 sshwarts Exp $
// $Id: fetchdecode.cc,v 1.148 2007-12-14 20:41:09 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -1514,7 +1514,7 @@ static const BxOpcodeInfo_t BxOpcodeInfo32M[512*2] = {
/* C0 /wm */ { BxGroup2 | BxImmediate_Ib, NULL, BxOpcodeInfoG2Eb },
/* C1 /wm */ { BxGroup2 | BxImmediate_Ib, NULL, BxOpcodeInfoG2Ew },
/* C2 /wm */ { BxImmediate_Iw | BxTraceEnd, &BX_CPU_C::RETnear16_Iw },
/* C3 /wm */ { BxTraceEnd, &BX_CPU_C::RETnear16 },
/* C3 /wm */ { BxTraceEnd, &BX_CPU_C::RETnear16 },
/* C4 /wm */ { 0, &BX_CPU_C::LES_GwMp },
/* C5 /wm */ { 0, &BX_CPU_C::LDS_GwMp },
/* C6 /wm */ { BxImmediate_Ib, &BX_CPU_C::MOV_EbIbM },

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: proc_ctrl.cc,v 1.188 2007-12-14 11:27:44 sshwarts Exp $
// $Id: proc_ctrl.cc,v 1.189 2007-12-14 20:41:09 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -136,14 +136,16 @@ void BX_CPU_C::CLTS(bxInstruction_c *i)
void BX_CPU_C::INVD(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 4
invalidate_prefetch_q();
if (!real_mode() && CPL!=0) {
BX_ERROR(("INVD: priveledge check failed, generate #GP(0)"));
exception(BX_GP_EXCEPTION, 0, 0);
}
invalidate_prefetch_q();
BX_DEBUG(("INVD: Flush internal caches !"));
BX_INSTR_CACHE_CNTRL(BX_CPU_ID, BX_INSTR_INVD);
#if BX_SUPPORT_ICACHE
flushICaches();
#endif
@ -157,14 +159,16 @@ void BX_CPU_C::INVD(bxInstruction_c *i)
void BX_CPU_C::WBINVD(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 4
invalidate_prefetch_q();
if (!real_mode() && CPL!=0) {
BX_ERROR(("WBINVD: priveledge check failed, generate #GP(0)"));
exception(BX_GP_EXCEPTION, 0, 0);
}
invalidate_prefetch_q();
BX_DEBUG(("WBINVD: Flush internal caches !"));
BX_INSTR_CACHE_CNTRL(BX_CPU_ID, BX_INSTR_WBINVD);
#if BX_SUPPORT_ICACHE
flushICaches();
#endif
@ -178,8 +182,11 @@ void BX_CPU_C::WBINVD(bxInstruction_c *i)
void BX_CPU_C::CLFLUSH(bxInstruction_c *i)
{
#if BX_SUPPORT_CLFLUSH
bx_segment_reg_t *seg = &BX_CPU_THIS_PTR sregs[i->seg()];
// check if we could access the memory
execute_virtual_checks(&BX_CPU_THIS_PTR sregs[i->seg()], RMAddr(i), 1);
if ((seg->cache.valid & SegAccessROK4G) != SegAccessROK4G) {
execute_virtual_checks(seg, RMAddr(i), 1);
}
#else
BX_INFO(("CLFLUSH: not supported, enable with SSE2"));
UndefinedOpcode(i);
@ -587,9 +594,8 @@ void BX_CPU_C::MOV_CdRd(bxInstruction_c *i)
case 0: // CR0 (MSW)
SetCR0(val_32);
break;
case 1: /* CR1 */
BX_PANIC(("MOV_CdRd: CR1 not implemented yet"));
BX_PANIC(("MOV_CdRd:CR1 not implemented yet"));
break;
case 2: /* CR2 */
BX_DEBUG(("MOV_CdRd:CR2 = %08x", (unsigned) val_32));
@ -819,13 +825,13 @@ void BX_CPU_C::LMSW_Ew(bxInstruction_c *i)
Bit16u msw;
Bit32u cr0;
invalidate_prefetch_q();
if (!real_mode() && CPL!=0) {
BX_ERROR(("LMSW: CPL!=0 not in real mode"));
exception(BX_GP_EXCEPTION, 0, 0);
}
invalidate_prefetch_q();
if (i->modC0()) {
msw = BX_READ_16BIT_REG(i->rm());
}