1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Mupen64plus - regcache.c *
3 * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
4 * Copyright (C) 2007 Richard Goedeken (Richard42) *
5 * Copyright (C) 2002 Hacktarux *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the *
19 * Free Software Foundation, Inc., *
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
21 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
27 #include "api/m64p_types.h"
28 #include "api/callbacks.h"
29 #include "r4300/recomp.h"
30 #include "r4300/r4300.h"
31 #include "r4300/recomph.h"
33 static unsigned long long * reg_content[8];
34 static precomp_instr* last_access[8];
35 static precomp_instr* free_since[8];
37 static int is64bits[8];
38 static unsigned long long *r0;
40 void init_cache(precomp_instr* start)
45 reg_content[i] = NULL;
46 last_access[i] = NULL;
47 free_since[i] = start;
51 r0 = (unsigned long long *) reg;
54 void free_all_registers(void)
56 #if defined(PROFILE_R4300)
57 int freestart = code_length;
64 #if defined(PROFILE_R4300)
65 if (last_access[i] && dirty[i]) flushed = 1;
73 while (free_since[i] <= dst)
75 free_since[i]->reg_cache_infos.needed_registers[i] = NULL;
81 #if defined(PROFILE_R4300)
84 long long x86addr = (long long) ((*inst_pointer) + freestart);
86 if (fwrite(&mipsop, 1, 4, pfProfile) != 4 || /* -5 = regcache flushing */
87 fwrite(&x86addr, 1, sizeof(char *), pfProfile) != sizeof(char *)) // write pointer to start of register cache flushing instructions
88 DebugMessage(M64MSG_ERROR, "Error writing R4300 instruction address profiling data");
89 x86addr = (long long) ((*inst_pointer) + code_length);
90 if (fwrite(&src, 1, 4, pfProfile) != 4 || // write 4-byte MIPS opcode for current instruction
91 fwrite(&x86addr, 1, sizeof(char *), pfProfile) != sizeof(char *)) // write pointer to dynamically generated x86 code for this MIPS instruction
92 DebugMessage(M64MSG_ERROR, "Error writing R4300 instruction address profiling data");
97 static void simplify_access(void)
100 dst->local_addr = code_length;
101 for(i=0; i<8; i++) dst->reg_cache_infos.needed_registers[i] = NULL;
104 void free_registers_move_start(void)
106 /* flush all dirty registers and clear needed_registers table */
107 free_all_registers();
109 /* now move the start of the new instruction down past the flushing instructions */
114 // this function frees a specific X86 GPR
115 void free_register(int reg)
119 if (last_access[reg] != NULL)
120 last = last_access[reg]+1;
122 last = free_since[reg];
126 if (last_access[reg] != NULL && dirty[reg])
127 last->reg_cache_infos.needed_registers[reg] = reg_content[reg];
129 last->reg_cache_infos.needed_registers[reg] = NULL;
132 if (last_access[reg] == NULL)
134 free_since[reg] = dst+1;
142 mov_m64rel_xreg64((unsigned long long *) reg_content[reg], reg);
146 movsxd_reg64_reg32(reg, reg);
147 mov_m64rel_xreg64((unsigned long long *) reg_content[reg], reg);
151 last_access[reg] = NULL;
152 free_since[reg] = dst+1;
155 int lru_register(void)
157 unsigned long long oldest_access = 0xFFFFFFFFFFFFFFFFULL;
161 if (i != ESP && (unsigned long long) last_access[i] < oldest_access)
163 oldest_access = (unsigned long long) last_access[i];
170 int lru_base_register(void) /* EBP cannot be used as a base register for SIB addressing byte */
172 unsigned long long oldest_access = 0xFFFFFFFFFFFFFFFFULL;
176 if (i != ESP && i != EBP && (unsigned long long) last_access[i] < oldest_access)
178 oldest_access = (unsigned long long) last_access[i];
185 void set_register_state(int reg, unsigned int *addr, int _dirty, int _is64bits)
188 last_access[reg] = NULL;
190 last_access[reg] = dst;
191 reg_content[reg] = (unsigned long long *) addr;
192 is64bits[reg] = _is64bits;
196 int lock_register(int reg)
199 last_access[reg] = (precomp_instr *) 0xFFFFFFFFFFFFFFFFULL;
200 reg_content[reg] = NULL;
204 void unlock_register(int reg)
206 last_access[reg] = NULL;
209 // this function finds a register to put the data contained in addr,
210 // if there was another value before it's cleanly removed of the
211 // register cache. After that, the register number is returned.
212 // If data are already cached, the function only returns the register number
213 int allocate_register_32(unsigned int *addr)
217 // is it already cached ?
220 for (i = 0; i < 8; i++)
222 if (last_access[i] != NULL && (unsigned int *) reg_content[i] == addr)
224 precomp_instr *last = last_access[i]+1;
228 last->reg_cache_infos.needed_registers[i] = reg_content[i];
231 last_access[i] = dst;
238 // it's not cached, so take the least recently used register
239 reg = lru_register();
241 if (last_access[reg])
245 while (free_since[reg] <= dst)
247 free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL;
252 last_access[reg] = dst;
253 reg_content[reg] = (unsigned long long *) addr;
259 if (addr == (unsigned int *) r0)
260 xor_reg32_reg32(reg, reg);
262 mov_xreg32_m32rel(reg, addr);
268 // this function is similar to allocate_register except it loads
269 // a 64 bits value, and return the register number of the LSB part
270 int allocate_register_64(unsigned long long *addr)
274 // is it already cached?
277 for (i = 0; i < 8; i++)
279 if (last_access[i] != NULL && reg_content[i] == addr)
281 precomp_instr *last = last_access[i]+1;
285 last->reg_cache_infos.needed_registers[i] = reg_content[i];
288 last_access[i] = dst;
289 if (is64bits[i] == 0)
291 movsxd_reg64_reg32(i, i);
299 // it's not cached, so take the least recently used register
300 reg = lru_register();
302 if (last_access[reg])
306 while (free_since[reg] <= dst)
308 free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL;
313 last_access[reg] = dst;
314 reg_content[reg] = addr;
321 xor_reg64_reg64(reg, reg);
323 mov_xreg64_m64rel(reg, addr);
329 // this function checks if the data located at addr are cached in a register
330 // and then, it returns 1 if it's a 64 bit value
331 // 0 if it's a 32 bit value
332 // -1 if it's not cached
333 int is64(unsigned int *addr)
336 for (i = 0; i < 8; i++)
338 if (last_access[i] != NULL && reg_content[i] == (unsigned long long *) addr)
346 int allocate_register_32_w(unsigned int *addr)
350 // is it already cached ?
351 for (i = 0; i < 8; i++)
353 if (last_access[i] != NULL && reg_content[i] == (unsigned long long *) addr)
355 precomp_instr *last = last_access[i] + 1;
359 last->reg_cache_infos.needed_registers[i] = NULL;
362 last_access[i] = dst;
369 // it's not cached, so take the least recently used register
370 reg = lru_register();
372 if (last_access[reg])
376 while (free_since[reg] <= dst)
378 free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL;
383 last_access[reg] = dst;
384 reg_content[reg] = (unsigned long long *) addr;
391 int allocate_register_64_w(unsigned long long *addr)
395 // is it already cached?
396 for (i = 0; i < 8; i++)
398 if (last_access[i] != NULL && reg_content[i] == addr)
400 precomp_instr *last = last_access[i] + 1;
404 last->reg_cache_infos.needed_registers[i] = NULL;
407 last_access[i] = dst;
414 // it's not cached, so take the least recently used register
415 reg = lru_register();
417 if (last_access[reg])
421 while (free_since[reg] <= dst)
423 free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL;
428 last_access[reg] = dst;
429 reg_content[reg] = addr;
436 void allocate_register_32_manually(int reg, unsigned int *addr)
440 /* check if we just happen to already have this r4300 reg cached in the requested x86 reg */
441 if (last_access[reg] != NULL && reg_content[reg] == (unsigned long long *) addr)
443 precomp_instr *last = last_access[reg] + 1;
446 last->reg_cache_infos.needed_registers[reg] = reg_content[reg];
449 last_access[reg] = dst;
450 /* we won't touch is64bits or dirty; the register returned is "read-only" */
454 /* otherwise free up the requested x86 register */
455 if (last_access[reg])
459 while (free_since[reg] <= dst)
461 free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL;
466 /* if the r4300 register is already cached in a different x86 register, then copy it to the requested x86 register */
469 if (last_access[i] != NULL && reg_content[i] == (unsigned long long *) addr)
471 precomp_instr *last = last_access[i]+1;
474 last->reg_cache_infos.needed_registers[i] = reg_content[i];
477 last_access[i] = dst;
479 mov_reg64_reg64(reg, i);
481 mov_reg32_reg32(reg, i);
482 last_access[reg] = dst;
483 is64bits[reg] = is64bits[i];
484 dirty[reg] = dirty[i];
485 reg_content[reg] = reg_content[i];
486 /* free the previous x86 register used to cache this r4300 register */
487 free_since[i] = dst + 1;
488 last_access[i] = NULL;
493 /* otherwise just load the 32-bit value into the requested register */
494 last_access[reg] = dst;
495 reg_content[reg] = (unsigned long long *) addr;
499 if ((unsigned long long *) addr == r0)
500 xor_reg32_reg32(reg, reg);
502 mov_xreg32_m32rel(reg, addr);
505 void allocate_register_32_manually_w(int reg, unsigned int *addr)
509 /* check if we just happen to already have this r4300 reg cached in the requested x86 reg */
510 if (last_access[reg] != NULL && reg_content[reg] == (unsigned long long *) addr)
512 precomp_instr *last = last_access[reg]+1;
515 last->reg_cache_infos.needed_registers[reg] = NULL;
518 last_access[reg] = dst;
524 /* otherwise free up the requested x86 register */
525 if (last_access[reg])
529 while (free_since[reg] <= dst)
531 free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL;
536 /* if the r4300 register is already cached in a different x86 register, then free it and bind to the requested x86 register */
537 for (i = 0; i < 8; i++)
539 if (last_access[i] != NULL && reg_content[i] == (unsigned long long *) addr)
541 precomp_instr *last = last_access[i] + 1;
544 last->reg_cache_infos.needed_registers[i] = NULL;
547 last_access[reg] = dst;
548 reg_content[reg] = reg_content[i];
551 /* free the previous x86 register used to cache this r4300 register */
552 free_since[i] = dst+1;
553 last_access[i] = NULL;
558 /* otherwise just set up the requested register as 32-bit */
559 last_access[reg] = dst;
560 reg_content[reg] = (unsigned long long *) addr;
566 // 0x48 0x83 0xEC 0x8 sub rsp, byte 8
567 // 0x48 0xA1 0xXXXXXXXXXXXXXXXX mov rax, qword (&code start)
568 // 0x48 0x05 0xXXXXXXXX add rax, dword (local_addr)
569 // 0x48 0x89 0x04 0x24 mov [rsp], rax
570 // 0x48 0xB8 0xXXXXXXXXXXXXXXXX mov rax, ®[0]
571 // 0x48 0x8B (reg<<3)|0x80 0xXXXXXXXX mov rdi, [rax + XXXXXXXX]
572 // 0x48 0x8B (reg<<3)|0x80 0xXXXXXXXX mov rsi, [rax + XXXXXXXX]
573 // 0x48 0x8B (reg<<3)|0x80 0xXXXXXXXX mov rbp, [rax + XXXXXXXX]
574 // 0x48 0x8B (reg<<3)|0x80 0xXXXXXXXX mov rdx, [rax + XXXXXXXX]
575 // 0x48 0x8B (reg<<3)|0x80 0xXXXXXXXX mov rcx, [rax + XXXXXXXX]
576 // 0x48 0x8B (reg<<3)|0x80 0xXXXXXXXX mov rbx, [rax + XXXXXXXX]
577 // 0x48 0x8B (reg<<3)|0x80 0xXXXXXXXX mov rax, [rax + XXXXXXXX]
581 static void build_wrapper(precomp_instr *instr, unsigned char* pCode, precomp_block* block)
585 #if defined(PROFILE_R4300)
586 long long x86addr = (long long) pCode;
588 if (fwrite(&mipsop, 1, 4, pfProfile) != 4 || // write 4-byte MIPS opcode
589 fwrite(&x86addr, 1, sizeof(char *), pfProfile) != sizeof(char *)) // write pointer to dynamically generated x86 code for this MIPS instruction
590 DebugMessage(M64MSG_ERROR, "Error writing R4300 instruction address profiling data");
600 *((unsigned long long *) pCode) = (unsigned long long) (&block->code);
605 *((unsigned int *) pCode) = (unsigned int) instr->local_addr;
615 *((unsigned long long *) pCode) = (unsigned long long) ®[0];
621 if (instr->reg_cache_infos.needed_registers[i] != NULL)
625 *pCode++ = 0x80 | (i << 3);
626 riprel = (long long) ((unsigned char *) instr->reg_cache_infos.needed_registers[i] - (unsigned char *) ®[0]);
627 *((int *) pCode) = (int) riprel;
629 if (riprel >= 0x7fffffffLL || riprel < -0x80000000LL)
631 DebugMessage(M64MSG_ERROR, "build_wrapper error: reg[%i] offset too big for relative address from %p to %p",
632 i, (®[0]), instr->reg_cache_infos.needed_registers[i]);
640 void build_wrappers(precomp_instr *instr, int start, int end, precomp_block* block)
643 for (i=start; i<end; i++)
645 instr[i].reg_cache_infos.need_map = 0;
646 for (reg=0; reg<8; reg++)
648 if (instr[i].reg_cache_infos.needed_registers[reg] != NULL)
650 instr[i].reg_cache_infos.need_map = 1;
651 build_wrapper(&instr[i], instr[i].reg_cache_infos.jump_wrapper, block);