Check in FETCHDECODE Caching, with changes.

Specific changes from the patch:

1.) renamed fdcache_eip to fdcache_ip, as it is using
the RIP instead of the EIP.

2.) added a Boolean array fdcache_is32 which uses is32
to determine icache hits.  Otherwise we could run 32-bit
code as 16-bit or vice versa.


 Modified Files:
 	config.h.in cpu/cpu.cc cpu/cpu.h memory/memory.cc
This commit is contained in:
Gregory Alexander 2002-06-03 22:39:11 +00:00
parent 75247ef0a4
commit fda1b874e9
4 changed files with 117 additions and 29 deletions

View File

@ -546,6 +546,15 @@ typedef unsigned int Boolean;
#define BX_DYNAMIC_CPU_I386 0
#define BX_DYNAMIC_CPU_SPARC 0
// caching of fetchdecode() calls
#define BX_FETCHDECODE_CACHE 0
#if BX_FETCHDECODE_CACHE
// The number of entries. MUST be a power of 2
#define BX_FDCACHE_SIZE 0x0800
#define BX_FDCACHE_MASK (BX_FDCACHE_SIZE-1)
#endif // BX_FETCHDECODE_CACHE
#define BX_SUPPORT_FPU 0
#define BX_HAVE_GETENV 0

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: cpu.cc,v 1.28 2002-04-18 00:22:19 bdenney Exp $
// $Id: cpu.cc,v 1.29 2002-06-03 22:39:10 yakovlev Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -37,7 +37,12 @@
//unsigned counter[2] = { 0, 0 };
#if BX_FETCHDECODE_CACHE
static unsigned long bx_fdcache_sel;
static unsigned long bx_fdcache_ip;
static Bit32u new_phy_addr;
#endif // BX_FETCHDECODE_CACHE
#if BX_SIM_ID == 0 // only need to define once
// This array defines a look-up table for the even parity-ness
@ -106,11 +111,16 @@ extern void REGISTER_IADDR(Bit32u addr);
BX_CPU_C::cpu_loop(Bit32s max_instr_count)
{
unsigned ret;
BxInstruction_t i;
BxInstruction_t *i;
unsigned maxisize;
Bit8u *fetch_ptr;
Boolean is_32;
#if !BX_FETCHDECODE_CACHE
BxInstruction_t bxinstruction_dummy;
i = &bxinstruction_dummy;
#endif // #if BX_FETCHDECODE_CACHE
#if BX_DEBUGGER
BX_CPU_THIS_PTR break_point = 0;
#ifdef MAGIC_BREAKPOINT
@ -214,18 +224,49 @@ async_events_processed:
}
fetch_ptr = BX_CPU_THIS_PTR fetch_ptr;
#if BX_FETCHDECODE_CACHE
bx_fdcache_ip = new_phy_addr;
bx_fdcache_sel = bx_fdcache_ip & BX_FDCACHE_MASK;
i = &(BX_CPU_THIS_PTR fdcache_i[bx_fdcache_sel]);
if ((BX_CPU_THIS_PTR fdcache_ip[bx_fdcache_sel] == bx_fdcache_ip) &&
(BX_CPU_THIS_PTR fdcache_is32[bx_fdcache_sel] == is_32)) {
// HIT! ;^)
ret = 1; // success!
new_phy_addr += i->ilen;
} else {
// MISS :'(
#endif // #if BX_FETCHDECODE_CACHE
maxisize = 16;
if (BX_CPU_THIS_PTR bytesleft < 16)
if (BX_CPU_THIS_PTR bytesleft < 16) {
maxisize = BX_CPU_THIS_PTR bytesleft;
ret = FetchDecode(fetch_ptr, &i, maxisize, is_32);
}
ret = FetchDecode(fetch_ptr, i, maxisize, is_32);
#if BX_FETCHDECODE_CACHE
// The instruction straddles a page boundary.
// Not storing such instructions in the cache is probably the
// easiest way to handle them
if (ret) {
BX_CPU_THIS_PTR fdcache_ip[bx_fdcache_sel] = bx_fdcache_ip;
BX_CPU_THIS_PTR fdcache_is32[bx_fdcache_sel] = is_32;
new_phy_addr += i->ilen;
} else {
// Invalidate cache!
BX_CPU_THIS_PTR fdcache_ip[bx_fdcache_sel] = 0xFFFFFFFF;
}
}
#endif // #if BX_FETCHDECODE_CACHE
if (ret) {
if (i.ResolveModrm) {
if (i->ResolveModrm) {
// call method on BX_CPU_C object
BX_CPU_CALL_METHOD(i.ResolveModrm, (&i));
BX_CPU_CALL_METHOD(i->ResolveModrm, (i));
}
BX_CPU_THIS_PTR fetch_ptr += i.ilen;
BX_CPU_THIS_PTR bytesleft -= i.ilen;
BX_CPU_THIS_PTR fetch_ptr += i->ilen;
BX_CPU_THIS_PTR bytesleft -= i->ilen;
fetch_decode_OK:
#if BX_DEBUGGER
@ -239,34 +280,34 @@ fetch_decode_OK:
}
#endif
if (i.rep_used && (i.attr & BxRepeatable)) {
if (i->rep_used && (i->attr & BxRepeatable)) {
repeat_loop:
if (i.attr & BxRepeatableZF) {
if (i.as_32) {
if (i->attr & BxRepeatableZF) {
if (i->as_32) {
if (ECX != 0) {
BX_CPU_CALL_METHOD(i.execute, (&i));
BX_CPU_CALL_METHOD(i->execute, (i));
ECX -= 1;
}
if ((i.rep_used==0xf3) && (get_ZF()==0)) goto repeat_done;
if ((i.rep_used==0xf2) && (get_ZF()!=0)) goto repeat_done;
if ((i->rep_used==0xf3) && (get_ZF()==0)) goto repeat_done;
if ((i->rep_used==0xf2) && (get_ZF()!=0)) goto repeat_done;
if (ECX == 0) goto repeat_done;
goto repeat_not_done;
}
else {
if (CX != 0) {
BX_CPU_CALL_METHOD(i.execute, (&i));
BX_CPU_CALL_METHOD(i->execute, (i));
CX -= 1;
}
if ((i.rep_used==0xf3) && (get_ZF()==0)) goto repeat_done;
if ((i.rep_used==0xf2) && (get_ZF()!=0)) goto repeat_done;
if ((i->rep_used==0xf3) && (get_ZF()==0)) goto repeat_done;
if ((i->rep_used==0xf2) && (get_ZF()!=0)) goto repeat_done;
if (CX == 0) goto repeat_done;
goto repeat_not_done;
}
}
else { // normal repeat, no concern for ZF
if (i.as_32) {
if (i->as_32) {
if (ECX != 0) {
BX_CPU_CALL_METHOD(i.execute, (&i));
BX_CPU_CALL_METHOD(i->execute, (i));
ECX -= 1;
}
if (ECX == 0) goto repeat_done;
@ -274,7 +315,7 @@ repeat_loop:
}
else { // 16bit addrsize
if (CX != 0) {
BX_CPU_CALL_METHOD(i.execute, (&i));
BX_CPU_CALL_METHOD(i->execute, (i));
CX -= 1;
}
if (CX == 0) goto repeat_done;
@ -302,12 +343,12 @@ repeat_not_done:
repeat_done:
BX_CPU_THIS_PTR eip += i.ilen;
BX_CPU_THIS_PTR eip += i->ilen;
}
else {
// non repeating instruction
BX_CPU_THIS_PTR eip += i.ilen;
BX_CPU_CALL_METHOD(i.execute, (&i));
BX_CPU_THIS_PTR eip += i->ilen;
BX_CPU_CALL_METHOD(i->execute, (i));
}
BX_CPU_THIS_PTR prev_eip = EIP; // commit new EIP
@ -410,17 +451,22 @@ static Bit8u FetchBuffer[16];
for (; j<16; j++) {
FetchBuffer[j] = *temp_ptr++;
}
ret = FetchDecode(FetchBuffer, &i, 16, is_32);
ret = FetchDecode(FetchBuffer, i, 16, is_32);
if (ret==0)
BX_PANIC(("fetchdecode: cross boundary: ret==0"));
if (i.ResolveModrm) {
BX_CPU_CALL_METHOD(i.ResolveModrm, (&i));
if (i->ResolveModrm) {
BX_CPU_CALL_METHOD(i->ResolveModrm, (i));
}
remain = i.ilen - remain;
remain = i->ilen - remain;
// note: eip has already been advanced to beginning of page
BX_CPU_THIS_PTR fetch_ptr = fetch_ptr + remain;
BX_CPU_THIS_PTR bytesleft -= remain;
#if BX_FETCHDECODE_CACHE
new_phy_addr += remain;
#endif // BX_FETCHDECODE_CACHE
//BX_CPU_THIS_PTR eip += remain;
BX_CPU_THIS_PTR eip = BX_CPU_THIS_PTR prev_eip;
goto fetch_decode_OK;
@ -603,7 +649,9 @@ BX_CPU_C::prefetch(void)
// cs:eIP
// prefetch QSIZE byte quantity aligned on corresponding boundary
Bit32u new_linear_addr;
#if !BX_FETCHDECODE_CACHE
Bit32u new_phy_addr;
#endif // !BX_FETCHDECODE_CACHE
Bit32u temp_eip, temp_limit;
temp_eip = BX_CPU_THIS_PTR eip;
@ -664,7 +712,9 @@ BX_CPU_C::prefetch(void)
BX_CPU_C::revalidate_prefetch_q(void)
{
Bit32u new_linear_addr, new_linear_page, new_linear_offset;
#if !BX_FETCHDECODE_CACHE
Bit32u new_phy_addr;
#endif // !BX_FETCHDECODE_CACHE
new_linear_addr = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base + BX_CPU_THIS_PTR eip;

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: cpu.h,v 1.19 2002-04-18 00:22:19 bdenney Exp $
// $Id: cpu.h,v 1.20 2002-06-03 22:39:10 yakovlev Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -1582,6 +1582,14 @@ public: // for now...
bx_local_apic_c local_apic;
Boolean int_from_local_apic;
#endif
#if BX_FETCHDECODE_CACHE
Bit32u fdcache_ip[BX_FDCACHE_SIZE]; // will store operation's IP
// NOTE: This struct should really be aligned!
BxInstruction_t fdcache_i[BX_FDCACHE_SIZE]; // stores decoded instruction
Boolean fdcache_is32[BX_FDCACHE_SIZE];
#endif // #if BX_FETCHDECODE_CACHE
};

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: memory.cc,v 1.11 2002-04-03 16:48:15 japj Exp $
// $Id: memory.cc,v 1.12 2002-06-03 22:39:11 yakovlev Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -49,6 +49,27 @@ BX_MEM_C::write_physical(BX_CPU_C *cpu, Bit32u addr, unsigned len, void *data)
a20addr = A20ADDR(addr);
BX_INSTR_PHY_WRITE(a20addr, len);
#if BX_FETCHDECODE_CACHE
// NOTE: This piece should be put, if possible, where a write to the memory
// takes place.
// Here it trashes cache even for writes that would end up to ROM
// Invalidate instruction cache for written addresses
// Instructions can be up to 16 bytes long, so I have to trash up to 15 bytes
// before write address (costly!)
// I think it would NOT be safe to invalidate up to the last instruction
// before the write because there COULD be programs which use
// jump-in-the-middle-of-an-instruction schemes (esp. copyprotection
// schemes)
unsigned long bx_fdcache_idx = addr - 15;
for (int count = 15+len; count > 0; --count) {
if (cpu->fdcache_ip[bx_fdcache_idx & BX_FDCACHE_MASK] == bx_fdcache_idx) {
cpu->fdcache_ip[bx_fdcache_idx & BX_FDCACHE_MASK] = 0xFFFFFFFF;
}
++bx_fdcache_idx;
}
#endif // #if BX_FETCHDECODE_CACHE
#if BX_DEBUGGER
// (mch) Check for physical write break points, TODO
// (bbd) Each breakpoint should have an associated CPU#, TODO