1 #ifndef CPUDYNTRANSCOMPONENT_H
2 #define CPUDYNTRANSCOMPONENT_H
43 #define N_DYNTRANS_IC_ARGS 3
69 #define DYNTRANS_PAGE_NSPECIALENTRIES 2
75 #define DECLARE_DYNTRANS_INSTR(name) static void instr_##name(CPUDyntransComponent* cpubase, DyntransIC* ic);
76 #define DYNTRANS_INSTR(class,name) void class::instr_##name(CPUDyntransComponent* cpubase, DyntransIC* ic)
77 #define DYNTRANS_INSTR_HEAD(class) class* cpu = (class*) cpubase;
79 #define REG32(arg) (*((uint32_t*)((arg).p)))
80 #define REG64(arg) (*((uint64_t*)((arg).p)))
82 #define DYNTRANS_SYNCH_PC cpu->m_nextIC = ic; cpu->DyntransResyncPC()
136 void DyntransClearICPage(
struct DyntransIC* icpage);
181 class DyntransTranslationPage
184 DyntransTranslationPage(
int nICentriesPerpage)
187 , m_nextCacheEntryForAddr(-1)
191 m_ic.resize(nICentriesPerpage);
200 int m_nextCacheEntryForAddr;
210 vector< struct DyntransIC > m_ic;
213 class DyntransTranslationCache
216 DyntransTranslationCache()
217 : m_nICentriesPerpage(0)
226 void Reinit(
size_t approximateSize,
int nICentriesPerpage,
int pageShift)
228 size_t approximateSizePerPage =
sizeof(
struct DyntransIC) * nICentriesPerpage + 64;
229 size_t nrOfPages = approximateSize / approximateSizePerPage;
232 std::cerr <<
"Too small translation cache!\n";
233 throw std::exception();
236 if (nICentriesPerpage == m_nICentriesPerpage &&
237 nrOfPages == m_pageCache.size() &&
238 pageShift == m_pageShift)
241 m_nICentriesPerpage = nICentriesPerpage;
242 m_pageShift = pageShift;
246 m_pageCache.resize(nrOfPages, DyntransTranslationPage(nICentriesPerpage));
250 m_lastFree = nrOfPages - 1;
251 for (
int i=m_firstFree; i<=m_lastFree; i++) {
252 m_pageCache[i].m_prev = i-1;
256 m_pageCache[i].m_next = -1;
258 m_pageCache[i].m_next = i+1;
262 m_firstMRU = m_lastMRU = -1;
268 m_addrToFirstPageIndex.resize(1024 * 1048576 >> m_pageShift);
269 for (
size_t i=0; i<m_addrToFirstPageIndex.size(); ++i)
270 m_addrToFirstPageIndex[i] = -1;
272 ValidateConsistency();
275 void ValidateConsistency()
278 vector<bool> pageIsInMRUList;
279 vector<bool> pageIsInFreeList;
280 vector<bool> pageIsInMRUListReverse;
281 vector<bool> pageIsInFreeListReverse;
283 pageIsInMRUList.resize(m_pageCache.size(),
false);
284 pageIsInFreeList.resize(m_pageCache.size(),
false);
285 pageIsInMRUListReverse.resize(m_pageCache.size(),
false);
286 pageIsInFreeListReverse.resize(m_pageCache.size(),
false);
291 pageIsInFreeList[i] =
true;
292 i = m_pageCache[i].m_next;
298 pageIsInFreeListReverse[i] =
true;
299 i = m_pageCache[i].m_prev;
305 pageIsInMRUList[i] =
true;
306 i = m_pageCache[i].m_next;
312 pageIsInMRUListReverse[i] =
true;
313 i = m_pageCache[i].m_prev;
317 for (
size_t j=0; j<m_pageCache.size(); ++j) {
318 if (pageIsInFreeList[j] != pageIsInFreeListReverse[j]) {
319 std::cerr <<
"Forward and reverse Free-list iteration mismatch, position " << j <<
"!\n";
320 throw std::exception();
323 if (pageIsInMRUList[j] != pageIsInMRUListReverse[j]) {
324 std::cerr <<
"Forward and reverse MRU-list iteration mismatch, position " << j <<
"!\n";
325 throw std::exception();
328 if ((pageIsInMRUList[j] ^ pageIsInFreeList[j]) ==
false) {
329 std::cerr <<
"Each page should be in exactly ONE of the two lists, position " << j <<
"!\n";
330 throw std::exception();
334 vector<bool> pageIsPointedToByQuickLookupTable;
335 vector<bool> pageIsPointedToByQLTChain;
336 pageIsPointedToByQuickLookupTable.resize(m_pageCache.size(),
false);
337 pageIsPointedToByQLTChain.resize(m_pageCache.size(),
false);
339 for (
size_t k=0; k<m_addrToFirstPageIndex.size(); ++k)
340 if (m_addrToFirstPageIndex[k] >= 0)
341 pageIsPointedToByQuickLookupTable[m_addrToFirstPageIndex[k]] =
true;
343 for (
size_t k=0; k<m_pageCache.size(); ++k) {
344 int index = m_pageCache[k].m_nextCacheEntryForAddr;
346 pageIsPointedToByQLTChain[index] =
true;
349 for (
size_t k=0; k<pageIsInFreeList.size(); ++k) {
350 if (!pageIsInFreeList[k])
353 if (m_pageCache[k].m_nextCacheEntryForAddr >= 0) {
354 std::cerr <<
"Pages on the free-list should not have m_nextCacheEntryForAddr set!\n";
355 throw std::exception();
358 if (pageIsPointedToByQuickLookupTable[k]) {
359 std::cerr <<
"Pages on the free-list should not be pointed to by the quick lookup table!\n";
360 throw std::exception();
363 if (pageIsPointedToByQLTChain[k]) {
364 std::cerr <<
"Pages on the free-list should not be in the quick lookup table chain!\n";
365 throw std::exception();
369 for (
size_t k=0; k<pageIsInMRUList.size(); ++k) {
370 if (!pageIsInMRUList[k])
373 uint64_t
addr = m_pageCache[k].m_addr;
374 uint64_t physPageNumber =
addr >> m_pageShift;
375 int quickLookupIndex = physPageNumber & (m_addrToFirstPageIndex.size() - 1);
376 int pageIndex = m_addrToFirstPageIndex[quickLookupIndex];
378 while (pageIndex >= 0) {
379 if (m_pageCache[pageIndex].m_addr ==
addr)
382 pageIndex = m_pageCache[pageIndex].m_nextCacheEntryForAddr;
386 std::cerr <<
"Pages in the MRU list must be reachable from the quick lookup table!\n";
387 throw std::exception();
393 void FreeLeastRecentlyUsedPage()
397 assert(m_firstFree < 0);
399 if (m_firstMRU == m_lastMRU) {
400 std::cerr <<
"Attempt to free a page, but there's only one page in the MRU list. Too small!\n";
401 throw std::exception();
405 int index = m_lastMRU;
406 assert(m_pageCache[index].m_prev >= 0);
407 assert(m_pageCache[index].m_next < 0);
410 m_lastMRU = m_pageCache[index].m_prev;
411 m_pageCache[m_lastMRU].m_next = -1;
414 if (m_firstFree < 0) {
416 m_firstFree = m_lastFree = index;
417 m_pageCache[index].m_prev = -1;
418 m_pageCache[index].m_next = -1;
420 m_pageCache[index].m_prev = -1;
421 m_pageCache[index].m_next = m_firstFree;
422 m_pageCache[m_firstFree].m_prev = index;
427 uint64_t physPageNumber = m_pageCache[index].m_addr >> m_pageShift;
428 int quickLookupIndex = physPageNumber & (m_addrToFirstPageIndex.size() - 1);
429 int pageIndex = m_addrToFirstPageIndex[quickLookupIndex];
430 if (pageIndex == index) {
432 m_addrToFirstPageIndex[quickLookupIndex] = m_pageCache[index].m_nextCacheEntryForAddr;
436 if (m_pageCache[pageIndex].m_nextCacheEntryForAddr == index) {
437 m_pageCache[pageIndex].m_nextCacheEntryForAddr = m_pageCache[index].m_nextCacheEntryForAddr;
441 pageIndex = m_pageCache[pageIndex].m_nextCacheEntryForAddr;
445 m_pageCache[index].m_nextCacheEntryForAddr = -1;
447 ValidateConsistency();
450 struct DyntransIC *AllocateNewPage(uint64_t
addr,
bool showFunctionTraceCall)
452 int index = m_firstFree;
458 if (index == m_lastFree) {
460 m_firstFree = m_lastFree = -1;
463 m_firstFree = m_pageCache[index].m_next;
464 m_pageCache[m_firstFree].m_prev = -1;
471 if (m_firstMRU == -1) {
473 m_firstMRU = m_lastMRU = index;
474 m_pageCache[index].m_next = m_pageCache[index].m_prev = -1;
477 m_pageCache[m_firstMRU].m_prev = index;
478 m_pageCache[index].m_next = m_firstMRU;
480 m_pageCache[index].m_prev = -1;
484 m_pageCache[index].m_addr =
addr;
485 m_pageCache[index].m_showFunctionTraceCall = showFunctionTraceCall;
488 uint64_t physPageNumber =
addr >> m_pageShift;
489 int quickLookupIndex = physPageNumber & (m_addrToFirstPageIndex.size() - 1);
492 if (m_addrToFirstPageIndex[quickLookupIndex] < 0) {
493 m_addrToFirstPageIndex[quickLookupIndex] = index;
494 m_pageCache[index].m_nextCacheEntryForAddr = -1;
497 m_pageCache[index].m_nextCacheEntryForAddr = m_addrToFirstPageIndex[quickLookupIndex];
498 m_addrToFirstPageIndex[quickLookupIndex] = index;
501 ValidateConsistency();
503 return &(m_pageCache[index].m_ic[0]);
506 struct DyntransIC *GetICPage(uint64_t
addr,
bool showFunctionTraceCall,
bool& clear)
511 addr >>= m_pageShift;
512 uint64_t physPageNumber =
addr;
513 addr <<= m_pageShift;
515 int quickLookupIndex = physPageNumber & (m_addrToFirstPageIndex.size() - 1);
516 int pageIndex = m_addrToFirstPageIndex[quickLookupIndex];
521 while (pageIndex >= 0) {
522 if (m_pageCache[pageIndex].m_addr ==
addr)
527 pageIndex = m_pageCache[pageIndex].m_nextCacheEntryForAddr;
531 if (pageIndex >= 0) {
534 if (m_firstMRU != pageIndex) {
536 int prev = m_pageCache[pageIndex].m_prev;
537 int next = m_pageCache[pageIndex].m_next;
539 m_pageCache[prev].m_next = next;
541 m_pageCache[next].m_prev = prev;
544 if (pageIndex == m_lastMRU)
548 m_pageCache[pageIndex].m_prev = -1;
549 m_pageCache[pageIndex].m_next = m_firstMRU;
550 m_pageCache[m_firstMRU].m_prev = pageIndex;
551 m_firstMRU = pageIndex;
564 ValidateConsistency();
568 m_pageCache[pageIndex].m_showFunctionTraceCall = showFunctionTraceCall;
572 return &(m_pageCache[pageIndex].m_ic[0]);
581 FreeLeastRecentlyUsedPage();
585 return AllocateNewPage(
addr, showFunctionTraceCall);
591 int m_nICentriesPerpage;
603 vector<int> m_addrToFirstPageIndex;
606 vector<DyntransTranslationPage> m_pageCache;
633 #endif // CPUDYNTRANSCOMPONENT_H