2002-05-29 13:02:40 +04:00
|
|
|
----------------------------------------------------------------------
|
|
|
|
Patch name: patche-fetchdecode-cache
|
|
|
|
Author: tld
|
|
|
|
Date: May, 29th 2002
|
|
|
|
|
|
|
|
Detailed description:
|
|
|
|
|
|
|
|
I somehow managed to implement the fetchdecode caching system I wrote
|
|
|
|
about last night (and to which I didn't get any answer)
|
|
|
|
I couldn't benchmark it as I wanted (mainly, I lack the tools) so I
|
|
|
|
don't really know what performance change it brought.
|
|
|
|
|
|
|
|
It has issues with code morphing (and some other things I can't
|
|
|
|
recognize in the code), but if the cache is "small enough" it works.
|
|
|
|
For those interested, I left the source code on
|
|
|
|
http://tld.digitalcurse.com/bochs/cpu.cc which is meant to
|
|
|
|
replace the
|
|
|
|
file cpu/cpu.cc in the CVS snapshot 20020527 which you can find at
|
|
|
|
http://tld.digitalcurse.com/bochs/bochs-20020527.tar.bz2 if
|
2002-05-30 01:52:36 +04:00
|
|
|
you don't have CVS access.
|
2002-05-29 13:02:40 +04:00
|
|
|
|
|
|
|
I'd like to hear comments on this.
|
|
|
|
|
|
|
|
PS. Of course, my code does NOT follow bochs' code standard which is not
|
|
|
|
intended to be inserted into the release. This is just intended as a
|
|
|
|
prototype did in 2 hours (of which, 1.5 for understanding the
|
|
|
|
surrounding code...)
|
|
|
|
|
|
|
|
Patch was created with:
|
|
|
|
cvs diff -u
|
|
|
|
Apply patch to what version:
|
|
|
|
cvs checked out on May, 29th 2002
|
|
|
|
Instructions:
|
|
|
|
To patch, go to main bochs directory.
|
|
|
|
Type "patch -p0 < THIS_PATCH_FILE".
|
|
|
|
----------------------------------------------------------------------
|
2002-05-30 01:52:36 +04:00
|
|
|
Index: config.h.in
|
|
|
|
===================================================================
|
|
|
|
RCS file: /cvsroot/bochs/bochs/config.h.in,v
|
|
|
|
retrieving revision 1.48
|
|
|
|
diff -u -r1.48 config.h.in
|
|
|
|
--- config.h.in 18 Apr 2002 01:00:53 -0000 1.48
|
|
|
|
+++ config.h.in 29 May 2002 21:46:52 -0000
|
|
|
|
@@ -189,6 +189,14 @@
|
|
|
|
|
|
|
|
#define BX_SUPPORT_V8086_MODE 1
|
|
|
|
|
|
|
|
+
|
|
|
|
+// Use fetchdecode cache
|
|
|
|
+// 1 = use the cache
|
|
|
|
+// 0 = don't use the cache
|
|
|
|
+
|
|
|
|
+#define BX_FETCHDECODE_CACHE 01
|
|
|
|
+
|
|
|
|
+
|
|
|
|
// Support shadowing of ROM from C0000 to FFFFF.
|
|
|
|
// This allows that region to be written to.
|
|
|
|
#define BX_SHADOW_RAM 0
|
|
|
|
Index: cpu/cpu.cc
|
|
|
|
===================================================================
|
|
|
|
RCS file: /cvsroot/bochs/bochs/cpu/cpu.cc,v
|
|
|
|
retrieving revision 1.28
|
2002-05-29 13:02:40 +04:00
|
|
|
diff -u -r1.28 cpu.cc
|
|
|
|
--- cpu/cpu.cc 18 Apr 2002 00:22:19 -0000 1.28
|
2002-05-30 01:52:36 +04:00
|
|
|
+++ cpu/cpu.cc 29 May 2002 21:46:53 -0000
|
|
|
|
@@ -26,7 +26,6 @@
|
|
|
|
|
|
|
|
#define BX_INSTR_SPY 0
|
|
|
|
|
|
|
|
-
|
|
|
|
#define NEED_CPU_REG_SHORTCUTS 1
|
|
|
|
#include "bochs.h"
|
|
|
|
#define LOG_THIS BX_CPU_THIS_PTR
|
|
|
|
@@ -37,6 +36,35 @@
|
2002-05-29 13:02:40 +04:00
|
|
|
|
|
|
|
//unsigned counter[2] = { 0, 0 };
|
|
|
|
|
2002-05-30 01:52:36 +04:00
|
|
|
+#if BX_FETCHDECODE_CACHE
|
|
|
|
+ // The number of entries. MUST be a power of 2
|
|
|
|
+ #define BX_FDCACHE_SIZE 0x0100
|
|
|
|
+ #define BX_FDCACHE_MASK (BX_FDCACHE_SIZE-1)
|
|
|
|
+
|
|
|
|
+ // To get information about hit ratio every so operations
|
|
|
|
+ #define BX_FDCACHE_STATS 0x100000
|
|
|
|
+
|
|
|
|
+ // The following stuff must be added to the processor's data (or else... poor MP!)
|
|
|
|
+ // note from cb : still to do
|
2002-05-29 13:02:40 +04:00
|
|
|
+
|
2002-05-30 01:52:36 +04:00
|
|
|
+ Bit32u fdcache_eip[BX_FDCACHE_SIZE]; // will store operation's IP
|
2002-05-29 13:02:40 +04:00
|
|
|
+
|
2002-05-30 01:52:36 +04:00
|
|
|
+ // NOTE: This struct should really be aligned!
|
|
|
|
+ BxInstruction_t fdcache_i[BX_FDCACHE_SIZE]; // stores decoded instruction
|
2002-05-29 13:02:40 +04:00
|
|
|
+
|
2002-05-30 01:52:36 +04:00
|
|
|
+ Bit32u fdcache_cs; // the last used CS
|
|
|
|
+ Bit32u fdcache_32; // was the segment 32bit?
|
2002-05-29 13:02:40 +04:00
|
|
|
+
|
2002-05-30 01:52:36 +04:00
|
|
|
+ // End of stuff to insert
|
|
|
|
+
|
|
|
|
+ unsigned long bx_fdcache_sel,
|
|
|
|
+ bx_fdcache_eip;
|
|
|
|
+
|
|
|
|
+ #if BX_FDCACHE_STATS
|
|
|
|
+ int bx_fdcache_hit = 0; // cache hits
|
|
|
|
+ int bx_fdcache_acc = BX_FDCACHE_STATS; // total accesses (countdown)
|
|
|
|
+ #endif // BX_FDCACHE_STATS
|
|
|
|
+#endif // BX_FETCHDECODE_CACHE
|
2002-05-29 13:02:40 +04:00
|
|
|
|
|
|
|
|
|
|
|
#if BX_SIM_ID == 0 // only need to define once
|
2002-05-30 01:52:36 +04:00
|
|
|
@@ -106,11 +134,13 @@
|
2002-05-29 13:02:40 +04:00
|
|
|
BX_CPU_C::cpu_loop(Bit32s max_instr_count)
|
|
|
|
{
|
|
|
|
unsigned ret;
|
|
|
|
- BxInstruction_t i;
|
|
|
|
+ BxInstruction_t bxinstruction_dummy, *i = &bxinstruction_dummy;
|
|
|
|
unsigned maxisize;
|
|
|
|
Bit8u *fetch_ptr;
|
|
|
|
Boolean is_32;
|
2002-05-30 01:52:36 +04:00
|
|
|
|
|
|
|
+printf("sizeof(BxInstruction_t) = %i\n", sizeof(BxInstruction_t));
|
|
|
|
+
|
|
|
|
#if BX_DEBUGGER
|
|
|
|
BX_CPU_THIS_PTR break_point = 0;
|
|
|
|
#ifdef MAGIC_BREAKPOINT
|
|
|
|
@@ -217,15 +247,67 @@
|
2002-05-29 13:02:40 +04:00
|
|
|
maxisize = 16;
|
|
|
|
if (BX_CPU_THIS_PTR bytesleft < 16)
|
|
|
|
maxisize = BX_CPU_THIS_PTR bytesleft;
|
|
|
|
- ret = FetchDecode(fetch_ptr, &i, maxisize, is_32);
|
|
|
|
+
|
2002-05-30 01:52:36 +04:00
|
|
|
+#if BX_FETCHDECODE_CACHE
|
|
|
|
+ bx_fdcache_eip = EIP;
|
|
|
|
+ bx_fdcache_sel = bx_fdcache_eip & BX_FDCACHE_MASK;
|
2002-05-29 13:02:40 +04:00
|
|
|
+
|
2002-05-30 01:52:36 +04:00
|
|
|
+ i = &fdcache_i[bx_fdcache_sel];
|
|
|
|
+
|
|
|
|
+ // NOTE: I'm not sure this is the correct value to check for (I don't know bochs)
|
|
|
|
+ // Maybe I should also check for other things?
|
|
|
|
+ if (fdcache_cs != BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base || fdcache_32 != is_32) {
|
|
|
|
+ // Clear the EIP values
|
|
|
|
+ for (int tmp = BX_FDCACHE_SIZE-1; tmp >= 0; --tmp) {
|
|
|
|
+ fdcache_eip[tmp] = 0xFFFFFFFF; // do NOT fill with 0s!
|
2002-05-29 13:02:40 +04:00
|
|
|
+ }
|
2002-05-30 01:52:36 +04:00
|
|
|
+ fdcache_cs = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base;
|
|
|
|
+ fdcache_32 = is_32;
|
2002-05-29 13:02:40 +04:00
|
|
|
+ }
|
2002-05-30 01:52:36 +04:00
|
|
|
+
|
|
|
|
+ if (fdcache_eip[bx_fdcache_sel] == bx_fdcache_eip) {
|
|
|
|
+ // HIT! :-)
|
|
|
|
+ #if BX_FDCACHE_STATS
|
|
|
|
+ ++bx_fdcache_hit;
|
2002-05-29 13:02:40 +04:00
|
|
|
+ #endif
|
|
|
|
+
|
2002-05-30 01:52:36 +04:00
|
|
|
+ // (debugging stuff)
|
|
|
|
+ // printf("%8.8x:%8.8x !\n", BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base, EIP);
|
|
|
|
+
|
|
|
|
+ ret = 1; // success!
|
2002-05-29 13:02:40 +04:00
|
|
|
+ } else {
|
2002-05-30 01:52:36 +04:00
|
|
|
+ // MISS :'(
|
2002-05-29 13:02:40 +04:00
|
|
|
+ ret = FetchDecode(fetch_ptr, i, maxisize, is_32);
|
|
|
|
+
|
2002-05-30 01:52:36 +04:00
|
|
|
+ // (debugging stuff)
|
|
|
|
+ // printf("%8.8x:%8.8x\n", BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base, EIP);
|
2002-05-29 13:02:40 +04:00
|
|
|
+
|
2002-05-30 01:52:36 +04:00
|
|
|
+ // NOTE: I don't know what ret is for. This way is safer, I guess...
|
2002-05-29 13:02:40 +04:00
|
|
|
+ if (ret) {
|
2002-05-30 01:52:36 +04:00
|
|
|
+ fdcache_eip[bx_fdcache_sel] = bx_fdcache_eip; // store the computed value
|
2002-05-29 13:02:40 +04:00
|
|
|
+ } else {
|
2002-05-30 01:52:36 +04:00
|
|
|
+ fdcache_eip[bx_fdcache_sel] = 0xFFFFFFFF;
|
2002-05-29 13:02:40 +04:00
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
2002-05-30 01:52:36 +04:00
|
|
|
+ #if BX_FDCACHE_STATS
|
|
|
|
+ if (!--bx_fdcache_acc) {
|
|
|
|
+ bx_fdcache_acc = BX_FDCACHE_STATS;
|
|
|
|
+ printf("%6.6x\n", bx_fdcache_hit);
|
|
|
|
+ bx_fdcache_hit = 0;
|
2002-05-29 13:02:40 +04:00
|
|
|
+ }
|
2002-05-30 01:52:36 +04:00
|
|
|
+ #endif // BX_FDCACHE_STATS
|
|
|
|
+#else // #if BX_FETCHDECODE_CACHE
|
2002-05-29 13:02:40 +04:00
|
|
|
+ ret = FetchDecode(fetch_ptr, i, maxisize, is_32);
|
2002-05-30 01:52:36 +04:00
|
|
|
+#endif // BX_FETCHDECODE_CACHE
|
2002-05-29 13:02:40 +04:00
|
|
|
|
|
|
|
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
|
2002-05-30 01:52:36 +04:00
|
|
|
@@ -239,34 +321,34 @@
|
2002-05-29 13:02:40 +04:00
|
|
|
}
|
|
|
|
#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;
|
2002-05-30 01:52:36 +04:00
|
|
|
@@ -274,7 +356,7 @@
|
2002-05-29 13:02:40 +04:00
|
|
|
}
|
|
|
|
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;
|
2002-05-30 01:52:36 +04:00
|
|
|
@@ -302,12 +384,12 @@
|
2002-05-29 13:02:40 +04:00
|
|
|
|
|
|
|
|
|
|
|
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
|
2002-05-30 01:52:36 +04:00
|
|
|
@@ -410,13 +492,13 @@
|
2002-05-29 13:02:40 +04:00
|
|
|
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;
|