1 |
/* |
2 |
* PearPC |
3 |
* jitc.cc |
4 |
* |
5 |
* Copyright (C) 2004 Sebastian Biallas (sb@biallas.net) |
6 |
* |
7 |
* This program is free software; you can redistribute it and/or modify |
8 |
* it under the terms of the GNU General Public License version 2 as |
9 |
* published by the Free Software Foundation. |
10 |
* |
11 |
* This program is distributed in the hope that it will be useful, |
12 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 |
* GNU General Public License for more details. |
15 |
* |
16 |
* You should have received a copy of the GNU General Public License |
17 |
* along with this program; if not, write to the Free Software |
18 |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
19 |
*/ |
20 |
|
21 |
#include <cstdlib> |
22 |
#include <cstring> |
23 |
|
24 |
#include "system/sys.h" |
25 |
#include "tools/snprintf.h" |
26 |
|
27 |
#include "jitc.h" |
28 |
#include "jitc_debug.h" |
29 |
#include "jitc_asm.h" |
30 |
|
31 |
#include "ppc_dec.h" |
32 |
#include "ppc_mmu.h" |
33 |
#include "ppc_tools.h" |
34 |
|
35 |
JITC gJITC; |
36 |
|
37 |
static TranslationCacheFragment *jitcAllocFragment(); |
38 |
|
39 |
/* |
40 |
* Intern |
41 |
* Called whenever a new fragment is needed |
42 |
* returns true if a new fragment was really necessary |
43 |
*/ |
44 |
static bool FASTCALL jitcEmitNextFragment() |
45 |
{ |
46 |
// save old |
47 |
TranslationCacheFragment *tcf_old = gJITC.currentPage->tcf_current; |
48 |
NativeAddress tcp_old = gJITC.currentPage->tcp; |
49 |
// alloc new |
50 |
gJITC.currentPage->tcf_current = jitcAllocFragment(); |
51 |
gJITC.currentPage->tcf_current->prev = tcf_old; |
52 |
if (((uint)(gJITC.currentPage->tcf_current->base - gJITC.currentPage->tcp)) < 20) { |
53 |
// next Fragment directly follows |
54 |
gJITC.currentPage->bytesLeft += FRAGMENT_SIZE; |
55 |
return false; |
56 |
} else { |
57 |
gJITC.currentPage->tcp = gJITC.currentPage->tcf_current->base; |
58 |
gJITC.currentPage->bytesLeft = FRAGMENT_SIZE; |
59 |
// hardcoded JMP from old to new fragment |
60 |
// FIXME: use 0xeb if possible |
61 |
tcp_old[0] = 0xe9; |
62 |
*((uint32 *)&tcp_old[1]) = gJITC.currentPage->tcp - (tcp_old+5); |
63 |
return true; |
64 |
} |
65 |
} |
66 |
|
67 |
/* |
68 |
* emit one byte of native code |
69 |
*/ |
70 |
void FASTCALL jitcEmit1(byte b) |
71 |
{ |
72 |
jitcDebugLogEmit(&b, 1); |
73 |
/* |
74 |
* We always have to leave at least 5 bytes in the fragment |
75 |
* to issue a final JMP |
76 |
*/ |
77 |
if (gJITC.currentPage->bytesLeft <= 5) { |
78 |
jitcEmitNextFragment(); |
79 |
} |
80 |
*(gJITC.currentPage->tcp++) = b; |
81 |
gJITC.currentPage->bytesLeft--; |
82 |
} |
83 |
|
84 |
/* |
85 |
* emit native code |
86 |
*/ |
87 |
void FASTCALL jitcEmit(byte *instr, int size) |
88 |
{ |
89 |
jitcDebugLogEmit(instr, size); |
90 |
if ((gJITC.currentPage->bytesLeft - size) < 5) { |
91 |
jitcEmitNextFragment(); |
92 |
} |
93 |
memcpy(gJITC.currentPage->tcp, instr, size); |
94 |
gJITC.currentPage->tcp += size; |
95 |
gJITC.currentPage->bytesLeft -= size; |
96 |
} |
97 |
|
98 |
/* |
99 |
* Assures that the next instruction will be |
100 |
* emitted in the current fragment |
101 |
*/ |
102 |
bool FASTCALL jitcEmitAssure(int size) |
103 |
{ |
104 |
if ((gJITC.currentPage->bytesLeft - size) < 5) { |
105 |
jitcEmitNextFragment(); |
106 |
return false; |
107 |
} |
108 |
return true; |
109 |
} |
110 |
|
111 |
void FASTCALL jitcEmitAlign(int align) |
112 |
{ |
113 |
do { |
114 |
int missalign = ((uint)gJITC.currentPage->tcp) % align; |
115 |
if (missalign) { |
116 |
int bytes = align - missalign; |
117 |
if ((gJITC.currentPage->bytesLeft - bytes) < 5) { |
118 |
if (jitcEmitNextFragment()) continue; |
119 |
} |
120 |
gJITC.currentPage->tcp += bytes; |
121 |
gJITC.currentPage->bytesLeft -= bytes; |
122 |
} |
123 |
} while (false); |
124 |
} |
125 |
/* |
126 |
* Intern. |
127 |
* Maps ClientPage to base address |
128 |
*/ |
129 |
static void inline jitcMapClientPage(uint32 baseaddr, ClientPage *cp) |
130 |
{ |
131 |
gJITC.clientPages[baseaddr >> 12] = cp; |
132 |
cp->baseaddress = baseaddr; |
133 |
} |
134 |
|
135 |
/* |
136 |
* Intern. |
137 |
* Unmaps ClientPage at base address |
138 |
*/ |
139 |
static void inline jitcUnmapClientPage(uint32 baseaddr) |
140 |
{ |
141 |
gJITC.clientPages[baseaddr >> 12] = NULL; |
142 |
} |
143 |
|
144 |
/* |
145 |
* Intern. |
146 |
* Unmaps ClientPage |
147 |
*/ |
148 |
static void inline jitcUnmapClientPage(ClientPage *cp) |
149 |
{ |
150 |
jitcUnmapClientPage(cp->baseaddress); |
151 |
} |
152 |
|
153 |
/* |
154 |
* Moves client page to the end of the LRU list |
155 |
* page *must* be in LRU list before |
156 |
*/ |
157 |
extern "C" FASTCALL ClientPage *jitcTouchClientPage(ClientPage *cp) |
158 |
{ |
159 |
if (cp->moreRU) { |
160 |
// there's a page which is used more recently |
161 |
if (cp->lessRU) { |
162 |
// we've got at least 3 pages and |
163 |
// cp is neither LRU nor MRU |
164 |
cp->moreRU->lessRU = cp->lessRU; |
165 |
cp->lessRU->moreRU = cp->moreRU; |
166 |
} else { |
167 |
// page is LRU |
168 |
gJITC.LRUpage = cp->moreRU; |
169 |
gJITC.LRUpage->lessRU = NULL; |
170 |
} |
171 |
cp->moreRU = NULL; |
172 |
cp->lessRU = gJITC.MRUpage; |
173 |
gJITC.MRUpage->moreRU = cp; |
174 |
gJITC.MRUpage = cp; |
175 |
} |
176 |
return cp; |
177 |
} |
178 |
|
179 |
/* |
180 |
* Puts fragments into the freeFragmentsList |
181 |
*/ |
182 |
//#include <valgrind/valgrind.h> |
183 |
void FASTCALL jitcDestroyFragments(TranslationCacheFragment *tcf) |
184 |
{ |
185 |
while (tcf) { |
186 |
// VALGRIND_DISCARD_TRANSLATIONS(tcf->base, FRAGMENT_SIZE); |
187 |
// FIXME: this could be done in O(1) with an additional |
188 |
// variable in ClientPage |
189 |
TranslationCacheFragment *next = tcf->prev; |
190 |
tcf->prev = gJITC.freeFragmentsList; |
191 |
gJITC.freeFragmentsList = tcf; |
192 |
tcf = next; |
193 |
} |
194 |
} |
195 |
|
196 |
/* |
197 |
* Unmaps ClientPage and destroys fragments |
198 |
*/ |
199 |
static void FASTCALL jitcDestroyClientPage(ClientPage *cp) |
200 |
{ |
201 |
// assert(cp->tcf_current) |
202 |
jitcDestroyFragments(cp->tcf_current); |
203 |
memset(cp->entrypoints, 0, sizeof cp->entrypoints); |
204 |
cp->tcf_current = NULL; |
205 |
jitcUnmapClientPage(cp); |
206 |
} |
207 |
|
208 |
/* |
209 |
* Moves client page into the freeClientPages list |
210 |
* (and out of the LRU list) |
211 |
* page *must* be in LRU list before |
212 |
*/ |
213 |
static void FASTCALL jitcFreeClientPage(ClientPage *cp) |
214 |
{ |
215 |
// assert(gJITC.LRUpage) |
216 |
// assert(gJITC.MRUpage) |
217 |
|
218 |
// delete page from LRU list |
219 |
if (!cp->lessRU) { |
220 |
// cp is LRU |
221 |
if (!cp->moreRU) { |
222 |
// cp is also MRU |
223 |
gJITC.LRUpage = gJITC.MRUpage = NULL; |
224 |
} else { |
225 |
// assert(cp->moreRU) |
226 |
gJITC.LRUpage = cp->moreRU; |
227 |
gJITC.LRUpage->lessRU = NULL; |
228 |
} |
229 |
} else { |
230 |
if (!cp->moreRU) { |
231 |
// cp is MRU |
232 |
// assert(cp->LRUprev) |
233 |
gJITC.MRUpage = cp->lessRU; |
234 |
gJITC.MRUpage->moreRU = NULL; |
235 |
} else { |
236 |
cp->moreRU->lessRU = cp->lessRU; |
237 |
cp->lessRU->moreRU = cp->moreRU; |
238 |
} |
239 |
} |
240 |
// and move it into the freeClientPages list |
241 |
cp->moreRU = gJITC.freeClientPages; |
242 |
gJITC.freeClientPages = cp; |
243 |
} |
244 |
|
245 |
/* |
246 |
* Destroys and frees ClientPage |
247 |
*/ |
248 |
extern "C" void FASTCALL jitcDestroyAndFreeClientPage(ClientPage *cp) |
249 |
{ |
250 |
gJITC.destroy_write++; |
251 |
jitcDestroyClientPage(cp); |
252 |
jitcFreeClientPage(cp); |
253 |
} |
254 |
|
255 |
/* |
256 |
* Destroys and touches ClientPage |
257 |
*/ |
258 |
static void FASTCALL jitcDestroyAndTouchClientPage(ClientPage *cp) |
259 |
{ |
260 |
gJITC.destroy_oopages++; |
261 |
jitcDestroyClientPage(cp); |
262 |
jitcTouchClientPage(cp); |
263 |
} |
264 |
|
265 |
/* |
266 |
* Removes and returns fragment from top of freeFragmentsList |
267 |
*/ |
268 |
static TranslationCacheFragment *jitcGetFragment() |
269 |
{ |
270 |
TranslationCacheFragment *tcf = gJITC.freeFragmentsList; |
271 |
gJITC.freeFragmentsList = tcf->prev; |
272 |
tcf->prev = NULL; |
273 |
return tcf; |
274 |
} |
275 |
|
276 |
/* |
277 |
* Returns free fragment |
278 |
* May destroy a page to make new free fragments |
279 |
*/ |
280 |
static TranslationCacheFragment *jitcAllocFragment() |
281 |
{ |
282 |
if (!gJITC.freeFragmentsList) { |
283 |
/* |
284 |
* There are no free fragments |
285 |
* -> must free a ClientPage |
286 |
*/ |
287 |
gJITC.destroy_write--; // destroy and free will increase this |
288 |
gJITC.destroy_ootc++; |
289 |
jitcDestroyAndFreeClientPage(gJITC.LRUpage); |
290 |
} |
291 |
return jitcGetFragment(); |
292 |
} |
293 |
|
294 |
/* |
295 |
* Moves page from freeClientPages at the end of the LRU list if there's |
296 |
* a free page or destroys the LRU page and touches it |
297 |
*/ |
298 |
extern "C" ClientPage FASTCALL *jitcCreateClientPage(uint32 baseaddr) |
299 |
{ |
300 |
ClientPage *cp; |
301 |
if (gJITC.freeClientPages) { |
302 |
// get page |
303 |
cp = gJITC.freeClientPages; |
304 |
gJITC.freeClientPages = gJITC.freeClientPages->moreRU; |
305 |
// and move to the end of LRU list |
306 |
if (gJITC.MRUpage) { |
307 |
gJITC.MRUpage->moreRU = cp; |
308 |
cp->lessRU = gJITC.MRUpage; |
309 |
gJITC.MRUpage = cp; |
310 |
} else { |
311 |
cp->lessRU = NULL; |
312 |
gJITC.LRUpage = gJITC.MRUpage = cp; |
313 |
} |
314 |
cp->moreRU = NULL; |
315 |
} else { |
316 |
cp = gJITC.LRUpage; |
317 |
jitcDestroyAndTouchClientPage(cp); |
318 |
// destroy some more |
319 |
if (gJITC.LRUpage) jitcDestroyAndTouchClientPage(gJITC.LRUpage); |
320 |
if (gJITC.LRUpage) jitcDestroyAndTouchClientPage(gJITC.LRUpage); |
321 |
if (gJITC.LRUpage) jitcDestroyAndTouchClientPage(gJITC.LRUpage); |
322 |
if (gJITC.LRUpage) jitcDestroyAndTouchClientPage(gJITC.LRUpage); |
323 |
} |
324 |
jitcMapClientPage(baseaddr, cp); |
325 |
return cp; |
326 |
} |
327 |
|
328 |
/* |
329 |
* Returns the ClientPage which maps to baseaddr or |
330 |
* creates a new page that maps to baseaddr |
331 |
*/ |
332 |
ClientPage FASTCALL *jitcGetOrCreateClientPage(uint32 baseaddr) |
333 |
{ |
334 |
ClientPage *cp = gJITC.clientPages[baseaddr >> 12]; |
335 |
if (cp) { |
336 |
return cp; |
337 |
} else { |
338 |
return jitcCreateClientPage(baseaddr); |
339 |
} |
340 |
} |
341 |
|
342 |
static inline void jitcCreateEntrypoint(ClientPage *cp, uint32 ofs) |
343 |
{ |
344 |
cp->entrypoints[ofs >> 2] = cp->tcp; |
345 |
} |
346 |
|
347 |
static inline NativeAddress jitcGetEntrypoint(ClientPage *cp, uint32 ofs) |
348 |
{ |
349 |
return cp->entrypoints[ofs >> 2]; |
350 |
} |
351 |
|
352 |
extern uint64 gJITCCompileTicks; |
353 |
extern uint64 gJITCRunTicks; |
354 |
extern uint64 gJITCRunTicksStart; |
355 |
|
356 |
extern "C" NativeAddress FASTCALL jitcNewEntrypoint(ClientPage *cp, uint32 baseaddr, uint32 ofs) |
357 |
{ |
358 |
/* |
359 |
gJITCRunTicks += jitcDebugGetTicks() - gJITCRunTicksStart; |
360 |
uint64 jitcCompileStartTicks = jitcDebugGetTicks(); |
361 |
*/ |
362 |
jitcDebugLogAdd("=== jitcNewEntrypoint: %08x Beginning jitc ===\n", baseaddr+ofs); |
363 |
gJITC.currentPage = cp; |
364 |
|
365 |
jitcEmitAlign(gJITC.hostCPUCaps.loop_align); |
366 |
|
367 |
NativeAddress entry = cp->tcp; |
368 |
jitcCreateEntrypoint(cp, ofs); |
369 |
|
370 |
byte *physpage; |
371 |
ppc_direct_physical_memory_handle(baseaddr, physpage); |
372 |
|
373 |
gJITC.pc = ofs; |
374 |
jitcInvalidateAll(); |
375 |
gJITC.checkedPriviledge = false; |
376 |
gJITC.checkedFloat = false; |
377 |
gJITC.checkedVector = false; |
378 |
|
379 |
// now we've setup gJITC and can start the real compilation |
380 |
|
381 |
while (1) { |
382 |
gJITC.current_opc = ppc_word_from_BE(*(uint32 *)(&physpage[ofs])); |
383 |
jitcDebugLogNewInstruction(); |
384 |
JITCFlow flow = ppc_gen_opc(); |
385 |
if (flow == flowContinue) { |
386 |
/* nothing to do */ |
387 |
} else if (flow == flowEndBlock) { |
388 |
jitcClobberAll(); |
389 |
|
390 |
gJITC.checkedPriviledge = false; |
391 |
gJITC.checkedFloat = false; |
392 |
gJITC.checkedVector = false; |
393 |
if (ofs+4 < 4096) { |
394 |
jitcCreateEntrypoint(cp, ofs+4); |
395 |
} |
396 |
} else { |
397 |
/* flowEndBlockUnreachable */ |
398 |
break; |
399 |
} |
400 |
ofs += 4; |
401 |
if (ofs == 4096) { |
402 |
/* |
403 |
* End of page. |
404 |
* We must use jump to the next page via |
405 |
* ppc_new_pc_asm |
406 |
*/ |
407 |
jitcClobberAll(); |
408 |
asmALURegImm(X86_MOV, EAX, 4096); |
409 |
asmJMP((NativeAddress)ppc_new_pc_rel_asm); |
410 |
break; |
411 |
} |
412 |
gJITC.pc += 4; |
413 |
} |
414 |
/* |
415 |
gJITCRunTicksStart = jitcDebugGetTicks(); |
416 |
gJITCCompileTicks += jitcDebugGetTicks() - jitcCompileStartTicks; |
417 |
*/ |
418 |
return entry; |
419 |
} |
420 |
|
421 |
extern "C" NativeAddress FASTCALL jitcStartTranslation(ClientPage *cp, uint32 baseaddr, uint32 ofs) |
422 |
{ |
423 |
cp->tcf_current = jitcAllocFragment(); |
424 |
cp->tcp = cp->tcf_current->base; |
425 |
cp->bytesLeft = FRAGMENT_SIZE; |
426 |
|
427 |
return jitcNewEntrypoint(cp, baseaddr, ofs); |
428 |
} |
429 |
|
430 |
/* |
431 |
* Called whenever the client PC changes (to a new BB) |
432 |
* Note that entry is a physical address |
433 |
*/ |
434 |
extern "C" NativeAddress FASTCALL jitcNewPC(uint32 entry) |
435 |
{ |
436 |
if (entry > gMemorySize) { |
437 |
ht_printf("entry not physical: %08x\n", entry); |
438 |
exit(-1); |
439 |
} |
440 |
uint32 baseaddr = entry & 0xfffff000; |
441 |
ClientPage *cp = jitcGetOrCreateClientPage(baseaddr); |
442 |
jitcTouchClientPage(cp); |
443 |
if (!cp->tcf_current) { |
444 |
return jitcStartTranslation(cp, baseaddr, entry & 0xfff); |
445 |
} else { |
446 |
NativeAddress ofs = jitcGetEntrypoint(cp, entry & 0xfff); |
447 |
if (ofs) { |
448 |
return ofs; |
449 |
} else { |
450 |
return jitcNewEntrypoint(cp, baseaddr, entry & 0xfff); |
451 |
} |
452 |
} |
453 |
} |
454 |
|
455 |
extern "C" void FASTCALL jitc_error_msr_unsupported_bits(uint32 a) |
456 |
{ |
457 |
ht_printf("JITC msr Error: %08x\n", a); |
458 |
exit(1); |
459 |
} |
460 |
|
461 |
extern "C" void FASTCALL jitc_error(const char *error) |
462 |
{ |
463 |
ht_printf("JITC Error: %s\n", error); |
464 |
exit(1); |
465 |
} |
466 |
|
467 |
extern "C" void FASTCALL jitc_error_program(uint32 a, uint32 b) |
468 |
{ |
469 |
if (a != 0x00020000) { // Filter out trap exceptions, no need to report them |
470 |
ht_printf("JITC Warning: program exception: %08x %08x\n", a, b); |
471 |
} |
472 |
} |
473 |
|
474 |
extern uint8 jitcFlagsMapping[257]; |
475 |
extern uint8 jitcFlagsMapping2[256]; |
476 |
extern uint8 jitcFlagsMappingCMP_U[257]; |
477 |
extern uint8 jitcFlagsMappingCMP_L[257]; |
478 |
|
479 |
bool jitc_init(int maxClientPages, uint32 tcSize) |
480 |
{ |
481 |
memset(&gJITC, 0, sizeof gJITC); |
482 |
|
483 |
x86GetCaps(gJITC.hostCPUCaps); |
484 |
|
485 |
gJITC.translationCache = (byte*)sys_alloc_read_write_execute(tcSize); |
486 |
if (!gJITC.translationCache) return false; |
487 |
int maxPages = gMemorySize / 4096; |
488 |
gJITC.clientPages = (ClientPage **)malloc(maxPages * sizeof (ClientPage *)); |
489 |
memset(gJITC.clientPages, 0, maxPages * sizeof (ClientPage *)); |
490 |
|
491 |
// allocate fragments |
492 |
TranslationCacheFragment *tcf = (TranslationCacheFragment *)malloc(sizeof (TranslationCacheFragment)); |
493 |
gJITC.freeFragmentsList = tcf; |
494 |
tcf->base = gJITC.translationCache; |
495 |
for (uint32 addr=FRAGMENT_SIZE; addr < tcSize; addr += FRAGMENT_SIZE) { |
496 |
tcf->prev = (TranslationCacheFragment *)malloc(sizeof (TranslationCacheFragment)); |
497 |
tcf = tcf->prev; |
498 |
tcf->base = gJITC.translationCache + addr; |
499 |
} |
500 |
tcf->prev = NULL; |
501 |
|
502 |
// allocate client pages |
503 |
ClientPage *cp = (ClientPage *)malloc(sizeof (ClientPage)); |
504 |
memset(cp->entrypoints, 0, sizeof cp->entrypoints); |
505 |
cp->tcf_current = NULL; // not translated yet |
506 |
cp->lessRU = NULL; |
507 |
gJITC.LRUpage = NULL; |
508 |
gJITC.freeClientPages = cp; |
509 |
for (int i=1; i < maxClientPages; i++) { |
510 |
cp->moreRU = (ClientPage *)malloc(sizeof (ClientPage)); |
511 |
cp->moreRU->lessRU = cp; |
512 |
cp = cp->moreRU; |
513 |
|
514 |
memset(cp->entrypoints, 0, sizeof cp->entrypoints); |
515 |
cp->tcf_current = NULL; // not translated yet |
516 |
} |
517 |
cp->moreRU = NULL; |
518 |
gJITC.MRUpage = NULL; |
519 |
|
520 |
// initialize native registers |
521 |
NativeRegType *nr = (NativeRegType *)malloc(sizeof (NativeRegType)); |
522 |
nr->reg = EAX; |
523 |
nr->lessRU = NULL; |
524 |
gJITC.LRUreg = nr; |
525 |
gJITC.nativeRegsList[EAX] = nr; |
526 |
for (NativeReg reg = ECX; reg <= EDI; reg=(NativeReg)(reg+1)) { |
527 |
if (reg != ESP) { |
528 |
nr->moreRU = (NativeRegType *)malloc(sizeof (NativeRegType)); |
529 |
nr->moreRU->lessRU = nr; |
530 |
nr = nr->moreRU; |
531 |
nr->reg = reg; |
532 |
gJITC.nativeRegsList[reg] = nr; |
533 |
} |
534 |
} |
535 |
nr->moreRU = NULL; |
536 |
gJITC.MRUreg = nr; |
537 |
|
538 |
for (int i=1; i<9; i++) { |
539 |
gJITC.floatRegPerm[i] = i; |
540 |
gJITC.floatRegPermInverse[i] = i; |
541 |
} |
542 |
|
543 |
jitcFlagsMapping[0] = 1<<6; // GT |
544 |
jitcFlagsMapping[1] = 1<<7; // LT |
545 |
jitcFlagsMapping[1<<8] = 1<<5; // EQ |
546 |
jitcFlagsMappingCMP_U[0] = 1<<5; // EQ |
547 |
jitcFlagsMappingCMP_U[1] = 1<<6; // GT |
548 |
jitcFlagsMappingCMP_U[1<<8] = 1<<7; // LT |
549 |
jitcFlagsMappingCMP_L[0] = 1<<1; // EQ |
550 |
jitcFlagsMappingCMP_L[1] = 1<<2; // GT |
551 |
jitcFlagsMappingCMP_L[1<<8] = 1<<3; // LT |
552 |
for (int i=0; i<256; i++) { |
553 |
switch (i & 0xc0) { |
554 |
case 0x00: // neither zero nor sign |
555 |
jitcFlagsMapping2[i] = 1<<6; // GT |
556 |
break; |
557 |
case 0x40: // zero flag |
558 |
jitcFlagsMapping2[i] = 1<<5; // EQ |
559 |
break; |
560 |
case 0x80: // sign flag |
561 |
jitcFlagsMapping2[i] = 1<<7; // LT |
562 |
break; |
563 |
case 0xc0: // impossible |
564 |
jitcFlagsMapping2[i] = 0; |
565 |
break; |
566 |
} |
567 |
} |
568 |
|
569 |
for (int i=XMM0; i<=XMM_SENTINEL; i++) { |
570 |
gJITC.LRUvregs[i] = (NativeVectorReg)(i-1); |
571 |
gJITC.MRUvregs[i] = (NativeVectorReg)(i+1); |
572 |
} |
573 |
|
574 |
gJITC.LRUvregs[XMM0] = XMM_SENTINEL; |
575 |
gJITC.MRUvregs[XMM_SENTINEL] = XMM0; |
576 |
|
577 |
gJITC.nativeVectorReg = VECTREG_NO; |
578 |
|
579 |
/* |
580 |
* Note that REG_NO=-1 and PPC_REG_NO=0 so this works |
581 |
* by accident. |
582 |
*/ |
583 |
memset(gJITC.clientReg, REG_NO, sizeof gJITC.clientReg); |
584 |
memset(gJITC.nativeReg, PPC_REG_NO, sizeof gJITC.nativeReg); |
585 |
memset(gJITC.nativeRegState, rsUnused, sizeof gJITC.nativeRegState); |
586 |
|
587 |
memset(gJITC.n2cVectorReg, PPC_REG_NO, sizeof gJITC.n2cVectorReg); |
588 |
memset(gJITC.c2nVectorReg, VECTREG_NO, sizeof gJITC.c2nVectorReg); |
589 |
memset(gJITC.nativeVectorRegState, rsUnused, sizeof gJITC.nativeVectorRegState); |
590 |
|
591 |
/* |
592 |
* This -1 register is to be read-only, and only used when |
593 |
* needed, and must ALWAYS stay this way! |
594 |
* |
595 |
* It's absolutely fundamental to doing NOT's with SSE |
596 |
*/ |
597 |
memset(&gCPU.vr[JITC_VECTOR_NEG1], 0xff, sizeof gCPU.vr[0]); |
598 |
|
599 |
memset(gJITC.tlb_code_eff, 0xff, sizeof gJITC.tlb_code_eff); |
600 |
memset(gJITC.tlb_data_read_eff, 0xff, sizeof gJITC.tlb_data_read_eff); |
601 |
memset(gJITC.tlb_data_write_eff, 0xff, sizeof gJITC.tlb_data_write_eff); |
602 |
gJITC.tlb_code_hits = 0; |
603 |
gJITC.tlb_data_read_hits = 0; |
604 |
gJITC.tlb_data_write_hits = 0; |
605 |
gJITC.tlb_code_misses = 0; |
606 |
gJITC.tlb_data_read_misses = 0; |
607 |
gJITC.tlb_data_write_misses = 0; |
608 |
return true; |
609 |
} |
610 |
|
611 |
void jitc_done() |
612 |
{ |
613 |
if (gJITC.translationCache) sys_free_read_write_execute(gJITC.translationCache); |
614 |
} |