1 /////////////////////////////////////////////////////////////////////////
2 // $Id: icache.cc,v 1.20 2008/11/13 22:58:54 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
5 // Copyright (c) 2007 Stanislav Shwartsman
6 // Written by Stanislav Shwartsman [sshwarts at sourceforge net]
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Lesser General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 /////////////////////////////////////////////////////////////////////////
24 #define NEED_CPU_REG_SHORTCUTS 1
27 #define LOG_THIS BX_CPU_THIS_PTR
29 bx_bool
BX_CPU_C::fetchInstruction(bxInstruction_c
*iStorage
, Bit32u eipBiased
)
31 unsigned remainingInPage
= BX_CPU_THIS_PTR eipPageWindowSize
- eipBiased
;
32 const Bit8u
*fetchPtr
= BX_CPU_THIS_PTR eipFetchPtr
+ eipBiased
;
36 if (BX_CPU_THIS_PTR cpu_mode
== BX_MODE_LONG_64
)
37 ret
= fetchDecode64(fetchPtr
, iStorage
, remainingInPage
);
40 ret
= fetchDecode32(fetchPtr
, iStorage
, remainingInPage
);
43 // handle instrumentation callback inside boundaryFetch
44 boundaryFetch(fetchPtr
, remainingInPage
, iStorage
);
48 #if BX_INSTRUMENTATION
49 BX_INSTR_OPCODE(BX_CPU_ID
, fetchPtr
, iStorage
->ilen(),
50 BX_CPU_THIS_PTR sregs
[BX_SEG_REG_CS
].cache
.u
.segment
.d_b
, Is64BitMode());
58 bxPageWriteStampTable pageWriteStampTable
;
60 void flushICaches(void)
62 for (unsigned i
=0; i
<BX_SMP_PROCESSORS
; i
++) {
63 BX_CPU(i
)->iCache
.flushICacheEntries();
64 BX_CPU(i
)->invalidate_prefetch_q();
65 BX_CPU(i
)->async_event
|= BX_ASYNC_EVENT_STOP_TRACE
;
68 pageWriteStampTable
.resetWriteStamps();
71 void purgeICaches(void)
76 #if BX_SUPPORT_TRACE_CACHE
80 for (unsigned i
=0; i
<BX_SMP_PROCESSORS
; i
++)
81 BX_CPU(i
)->async_event
|= BX_ASYNC_EVENT_STOP_TRACE
;
84 void BX_CPU_C::serveICacheMiss(bxICacheEntry_c
*cache_entry
, Bit32u eipBiased
, bx_phy_address pAddr
)
86 BX_CPU_THIS_PTR iCache
.alloc_trace(cache_entry
);
88 // Cache miss. We weren't so lucky, but let's be optimistic - try to build
89 // trace from incoming instruction bytes stream !
90 cache_entry
->pAddr
= pAddr
;
91 cache_entry
->writeStamp
= *(BX_CPU_THIS_PTR currPageWriteStampPtr
);
93 unsigned remainingInPage
= BX_CPU_THIS_PTR eipPageWindowSize
- eipBiased
;
94 const Bit8u
*fetchPtr
= BX_CPU_THIS_PTR eipFetchPtr
+ eipBiased
;
97 bxInstruction_c
*i
= cache_entry
->i
;
99 for (unsigned n
=0;n
<BX_MAX_TRACE_LENGTH
;n
++)
101 #if BX_SUPPORT_X86_64
102 if (BX_CPU_THIS_PTR cpu_mode
== BX_MODE_LONG_64
)
103 ret
= fetchDecode64(fetchPtr
, i
, remainingInPage
);
106 ret
= fetchDecode32(fetchPtr
, i
, remainingInPage
);
109 // Fetching instruction on segment/page boundary
111 // The trace is already valid, it has several instructions inside,
112 // in this case just drop the boundary instruction and stop
116 // First instruction is boundary fetch, leave the trace cache entry
117 // invalid and do not cache the instruction.
118 cache_entry
->writeStamp
= ICacheWriteStampInvalid
;
119 cache_entry
->ilen
= 1;
120 boundaryFetch(fetchPtr
, remainingInPage
, i
);
124 // add instruction to the trace
125 unsigned iLen
= i
->ilen();
128 // continue to the next instruction
129 remainingInPage
-= iLen
;
130 if (i
->getStopTraceAttr() || remainingInPage
== 0) break;
135 // try to find a trace starting from current pAddr and merge
136 if (mergeTraces(cache_entry
, i
, pAddr
)) break;
139 BX_CPU_THIS_PTR iCache
.commit_trace(cache_entry
->ilen
);
142 bx_bool
BX_CPU_C::mergeTraces(bxICacheEntry_c
*entry
, bxInstruction_c
*i
, bx_phy_address pAddr
)
144 bxICacheEntry_c
*e
= BX_CPU_THIS_PTR iCache
.get_entry(pAddr
);
146 if ((e
->pAddr
== pAddr
) && (e
->writeStamp
== entry
->writeStamp
))
148 // determine max amount of instruction to take from another entry
149 unsigned max_length
= e
->ilen
;
150 if (max_length
+ entry
->ilen
> BX_MAX_TRACE_LENGTH
)
151 max_length
= BX_MAX_TRACE_LENGTH
- entry
->ilen
;
152 if(max_length
== 0) return 0;
154 memcpy(i
, e
->i
, sizeof(bxInstruction_c
)*max_length
);
155 entry
->ilen
+= max_length
;
156 BX_ASSERT(entry
->ilen
<= BX_MAX_TRACE_LENGTH
);
164 #else // BX_SUPPORT_TRACE_CACHE == 0
166 void BX_CPU_C::serveICacheMiss(bxICacheEntry_c
*cache_entry
, Bit32u eipBiased
, bx_phy_address pAddr
)
168 // The entry will be marked valid if fetchdecode will succeed
169 cache_entry
->writeStamp
= ICacheWriteStampInvalid
;
171 if (fetchInstruction(cache_entry
->i
, eipBiased
)) {
172 cache_entry
->pAddr
= pAddr
;
173 cache_entry
->writeStamp
= *(BX_CPU_THIS_PTR currPageWriteStampPtr
);
179 #endif // BX_SUPPORT_ICACHE