void genxor(void) { #ifdef INTERPRET_XOR gencallinterp((unsigned int)cached_interpreter_table.XOR, 0); #else int rs1 = allocate_64_register1((unsigned int *)g_dev.r4300.recomp.dst->f.r.rs); int rs2 = allocate_64_register2((unsigned int *)g_dev.r4300.recomp.dst->f.r.rs); int rt1 = allocate_64_register1((unsigned int *)g_dev.r4300.recomp.dst->f.r.rt); int rt2 = allocate_64_register2((unsigned int *)g_dev.r4300.recomp.dst->f.r.rt); int rd1 = allocate_64_register1_w((unsigned int *)g_dev.r4300.recomp.dst->f.r.rd); int rd2 = allocate_64_register2_w((unsigned int *)g_dev.r4300.recomp.dst->f.r.rd); if (rt1 != rd1 && rs1 != rd1) { mov_reg32_reg32(rd1, rs1); mov_reg32_reg32(rd2, rs2); xor_reg32_reg32(rd1, rt1); xor_reg32_reg32(rd2, rt2); } else { int temp = lru_register(); free_register(temp); mov_reg32_reg32(temp, rs1); xor_reg32_reg32(temp, rt1); mov_reg32_reg32(rd1, temp); mov_reg32_reg32(temp, rs2); xor_reg32_reg32(temp, rt2); mov_reg32_reg32(rd2, temp); } #endif }
void gensllv(void) { #ifdef INTERPRET_SLLV gencallinterp((unsigned int)cached_interpreter_table.SLLV, 0); #else int rt, rd; allocate_register_manually(ECX, (unsigned int *)g_dev.r4300.recomp.dst->f.r.rs); rt = allocate_register((unsigned int *)g_dev.r4300.recomp.dst->f.r.rt); rd = allocate_register_w((unsigned int *)g_dev.r4300.recomp.dst->f.r.rd); if (rd != ECX) { mov_reg32_reg32(rd, rt); shl_reg32_cl(rd); } else { int temp = lru_register(); free_register(temp); mov_reg32_reg32(temp, rt); shl_reg32_cl(temp); mov_reg32_reg32(rd, temp); } #endif }
void gendsrav() { #ifdef INTERPRET_DSRAV gencallinterp((unsigned long)DSRAV, 0); #else int rt1, rt2, rd1, rd2; allocate_register_manually(ECX, (unsigned long *)dst->f.r.rs); rt1 = allocate_64_register1((unsigned long *)dst->f.r.rt); rt2 = allocate_64_register2((unsigned long *)dst->f.r.rt); rd1 = allocate_64_register1_w((unsigned long *)dst->f.r.rd); rd2 = allocate_64_register2_w((unsigned long *)dst->f.r.rd); if (rd1 != ECX && rd2 != ECX) { mov_reg32_reg32(rd1, rt1); mov_reg32_reg32(rd2, rt2); shrd_reg32_reg32_cl(rd1,rd2); sar_reg32_cl(rd2); test_reg32_imm32(ECX, 0x20); je_rj(5); mov_reg32_reg32(rd1, rd2); // 2 sar_reg32_imm8(rd2, 31); // 3 } else { int temp1, temp2; force_32(ECX); temp1 = lru_register(); temp2 = lru_register_exc1(temp1); free_register(temp1); free_register(temp2); mov_reg32_reg32(temp1, rt1); mov_reg32_reg32(temp2, rt2); shrd_reg32_reg32_cl(temp1, temp2); sar_reg32_cl(temp2); test_reg32_imm32(ECX, 0x20); je_rj(5); mov_reg32_reg32(temp1, temp2); // 2 sar_reg32_imm8(temp2, 31); // 3 mov_reg32_reg32(rd1, temp1); mov_reg32_reg32(rd2, temp2); } #endif }
void gendsrav(usf_state_t * state) { #ifdef INTERPRET_DSRAV gencallinterp(state, (unsigned int)state->current_instruction_table.DSRAV, 0); #else int rt1, rt2, rd1, rd2; allocate_register_manually(state, ECX, (unsigned int *)state->dst->f.r.rs); rt1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rt); rt2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rt); rd1 = allocate_64_register1_w(state, (unsigned int *)state->dst->f.r.rd); rd2 = allocate_64_register2_w(state, (unsigned int *)state->dst->f.r.rd); if (rd1 != ECX && rd2 != ECX) { mov_reg32_reg32(state, rd1, rt1); mov_reg32_reg32(state, rd2, rt2); shrd_reg32_reg32_cl(state, rd1,rd2); sar_reg32_cl(state, rd2); test_reg32_imm32(state, ECX, 0x20); je_rj(state, 5); mov_reg32_reg32(state, rd1, rd2); // 2 sar_reg32_imm8(state, rd2, 31); // 3 } else { int temp1, temp2; force_32(state, ECX); temp1 = lru_register(state); temp2 = lru_register_exc1(state, temp1); free_register(state, temp1); free_register(state, temp2); mov_reg32_reg32(state, temp1, rt1); mov_reg32_reg32(state, temp2, rt2); shrd_reg32_reg32_cl(state, temp1, temp2); sar_reg32_cl(state, temp2); test_reg32_imm32(state, ECX, 0x20); je_rj(state, 5); mov_reg32_reg32(state, temp1, temp2); // 2 sar_reg32_imm8(state, temp2, 31); // 3 mov_reg32_reg32(state, rd1, temp1); mov_reg32_reg32(state, rd2, temp2); } #endif }
void gendsrlv(void) { #ifdef INTERPRET_DSRLV gencallinterp((unsigned int)cached_interpreter_table.DSRLV, 0); #else int rt1, rt2, rd1, rd2; allocate_register_manually(ECX, (unsigned int *)dst->f.r.rs); rt1 = allocate_64_register1((unsigned int *)dst->f.r.rt); rt2 = allocate_64_register2((unsigned int *)dst->f.r.rt); rd1 = allocate_64_register1_w((unsigned int *)dst->f.r.rd); rd2 = allocate_64_register2_w((unsigned int *)dst->f.r.rd); if (rd1 != ECX && rd2 != ECX) { mov_reg32_reg32(rd1, rt1); mov_reg32_reg32(rd2, rt2); shrd_reg32_reg32_cl(rd1,rd2); shr_reg32_cl(rd2); test_reg32_imm32(ECX, 0x20); je_rj(4); mov_reg32_reg32(rd1, rd2); // 2 xor_reg32_reg32(rd2, rd2); // 2 } else { int temp1, temp2; force_32(ECX); temp1 = lru_register(); temp2 = lru_register_exc1(temp1); free_register(temp1); free_register(temp2); mov_reg32_reg32(temp1, rt1); mov_reg32_reg32(temp2, rt2); shrd_reg32_reg32_cl(temp1, temp2); shr_reg32_cl(temp2); test_reg32_imm32(ECX, 0x20); je_rj(4); mov_reg32_reg32(temp1, temp2); // 2 xor_reg32_reg32(temp2, temp2); // 2 mov_reg32_reg32(rd1, temp1); mov_reg32_reg32(rd2, temp2); } #endif }
void allocate_register_32_manually_w(int reg, unsigned int *addr) { int i; /* check if we just happen to already have this r4300 reg cached in the requested x86 reg */ if (last_access[reg] != NULL && reg_content[reg] == (unsigned long long *) addr) { precomp_instr *last = last_access[reg]+1; while (last <= dst) { last->reg_cache_infos.needed_registers[reg] = NULL; last++; } last_access[reg] = dst; is64bits[reg] = 0; dirty[reg] = 1; return; } /* otherwise free up the requested x86 register */ if (last_access[reg]) free_register(reg); else { while (free_since[reg] <= dst) { free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; free_since[reg]++; } } /* if the r4300 register is already cached in a different x86 register, then free it and bind to the requested x86 register */ for (i = 0; i < 8; i++) { if (last_access[i] != NULL && reg_content[i] == (unsigned long long *) addr) { precomp_instr *last = last_access[i] + 1; while (last <= dst) { last->reg_cache_infos.needed_registers[i] = NULL; last++; } last_access[reg] = dst; reg_content[reg] = reg_content[i]; dirty[reg] = 1; is64bits[reg] = 0; /* free the previous x86 register used to cache this r4300 register */ free_since[i] = dst+1; last_access[i] = NULL; return; } } /* otherwise just set up the requested register as 32-bit */ last_access[reg] = dst; reg_content[reg] = (unsigned long long *) addr; dirty[reg] = 1; is64bits[reg] = 0; }
// this function is similar to allocate_register except it loads // a 64 bits value, and return the register number of the LSB part int allocate_register_64(usf_state_t * state, unsigned long long *addr) { int reg, i; // is it already cached? if (addr != NULL) { for (i = 0; i < 8; i++) { if (state->last_access[i] != NULL && state->reg_content[i] == addr) { precomp_instr *last = state->last_access[i]+1; while (last <= state->dst) { last->reg_cache_infos.needed_registers[i] = state->reg_content[i]; last++; } state->last_access[i] = state->dst; if (state->is64bits[i] == 0) { movsxd_reg64_reg32(state, i, i); state->is64bits[i] = 1; } return i; } } } // it's not cached, so take the least recently used register reg = lru_register(state); if (state->last_access[reg]) free_register(state, reg); else { while (state->free_since[reg] <= state->dst) { state->free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; state->free_since[reg]++; } } state->last_access[reg] = state->dst; state->reg_content[reg] = addr; state->dirty[reg] = 0; state->is64bits[reg] = 1; if (addr != NULL) { if (addr == state->r0) xor_reg64_reg64(state, reg, reg); else mov_xreg64_m64rel(state, reg, addr); } return reg; }
// this function is similar to allocate_register except it loads // a 64 bits value, and return the register number of the LSB part int allocate_register_64(unsigned long long *addr) { int reg, i; // is it already cached? if (addr != NULL) { for (i = 0; i < 8; i++) { if (last_access[i] != NULL && reg_content[i] == addr) { precomp_instr *last = last_access[i]+1; while (last <= dst) { last->reg_cache_infos.needed_registers[i] = reg_content[i]; last++; } last_access[i] = dst; if (is64bits[i] == 0) { movsxd_reg64_reg32(i, i); is64bits[i] = 1; } return i; } } } // it's not cached, so take the least recently used register reg = lru_register(); if (last_access[reg]) free_register(reg); else { while (free_since[reg] <= dst) { free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; free_since[reg]++; } } last_access[reg] = dst; reg_content[reg] = addr; dirty[reg] = 0; is64bits[reg] = 1; if (addr != NULL) { if (addr == r0) xor_reg64_reg64(reg, reg); else mov_xreg64_m64rel(reg, addr); } return reg; }
// this function frees a specific X86 GPR void free_register(int reg) { precomp_instr *last; if (last_access[reg] != NULL && r64[reg] != -1 && (int)reg_content[reg] != (int)reg_content[r64[reg]]-4) { free_register(r64[reg]); return; } if (last_access[reg] != NULL) last = last_access[reg]+1; else last = free_since[reg]; while (last <= dst) { if (last_access[reg] != NULL && dirty[reg]) last->reg_cache_infos.needed_registers[reg] = reg_content[reg]; else last->reg_cache_infos.needed_registers[reg] = NULL; if (last_access[reg] != NULL && r64[reg] != -1) { if (dirty[r64[reg]]) last->reg_cache_infos.needed_registers[r64[reg]] = reg_content[r64[reg]]; else last->reg_cache_infos.needed_registers[r64[reg]] = NULL; } last++; } if (last_access[reg] == NULL) { free_since[reg] = dst+1; return; } if (dirty[reg]) { mov_m32_reg32(reg_content[reg], reg); if (r64[reg] == -1) { sar_reg32_imm8(reg, 31); mov_m32_reg32((unsigned int*)reg_content[reg]+1, reg); } else mov_m32_reg32(reg_content[r64[reg]], r64[reg]); } last_access[reg] = NULL; free_since[reg] = dst+1; if (r64[reg] != -1) { last_access[r64[reg]] = NULL; free_since[r64[reg]] = dst+1; } }
// this function frees a specific X86 GPR void free_register(int reg) { struct precomp_instr *last; if (g_dev.r4300.regcache_state.last_access[reg] != NULL && g_dev.r4300.regcache_state.r64[reg] != -1 && (int)g_dev.r4300.regcache_state.reg_content[reg] != (int)g_dev.r4300.regcache_state.reg_content[g_dev.r4300.regcache_state.r64[reg]]-4) { free_register(g_dev.r4300.regcache_state.r64[reg]); return; } if (g_dev.r4300.regcache_state.last_access[reg] != NULL) last = g_dev.r4300.regcache_state.last_access[reg]+1; else last = g_dev.r4300.regcache_state.free_since[reg]; while (last <= g_dev.r4300.recomp.dst) { if (g_dev.r4300.regcache_state.last_access[reg] != NULL && g_dev.r4300.regcache_state.dirty[reg]) last->reg_cache_infos.needed_registers[reg] = g_dev.r4300.regcache_state.reg_content[reg]; else last->reg_cache_infos.needed_registers[reg] = NULL; if (g_dev.r4300.regcache_state.last_access[reg] != NULL && g_dev.r4300.regcache_state.r64[reg] != -1) { if (g_dev.r4300.regcache_state.dirty[g_dev.r4300.regcache_state.r64[reg]]) last->reg_cache_infos.needed_registers[g_dev.r4300.regcache_state.r64[reg]] = g_dev.r4300.regcache_state.reg_content[g_dev.r4300.regcache_state.r64[reg]]; else last->reg_cache_infos.needed_registers[g_dev.r4300.regcache_state.r64[reg]] = NULL; } last++; } if (g_dev.r4300.regcache_state.last_access[reg] == NULL) { g_dev.r4300.regcache_state.free_since[reg] = g_dev.r4300.recomp.dst+1; return; } if (g_dev.r4300.regcache_state.dirty[reg]) { mov_m32_reg32(g_dev.r4300.regcache_state.reg_content[reg], reg); if (g_dev.r4300.regcache_state.r64[reg] == -1) { sar_reg32_imm8(reg, 31); mov_m32_reg32((unsigned int*)g_dev.r4300.regcache_state.reg_content[reg]+1, reg); } else mov_m32_reg32(g_dev.r4300.regcache_state.reg_content[g_dev.r4300.regcache_state.r64[reg]], g_dev.r4300.regcache_state.r64[reg]); } g_dev.r4300.regcache_state.last_access[reg] = NULL; g_dev.r4300.regcache_state.free_since[reg] = g_dev.r4300.recomp.dst+1; if (g_dev.r4300.regcache_state.r64[reg] != -1) { g_dev.r4300.regcache_state.last_access[g_dev.r4300.regcache_state.r64[reg]] = NULL; g_dev.r4300.regcache_state.free_since[g_dev.r4300.regcache_state.r64[reg]] = g_dev.r4300.recomp.dst+1; } }
// this function frees a specific X86 GPR void free_register(usf_state_t * state, int reg) { precomp_instr *last; if (state->last_access[reg] != NULL && state->r64[reg] != -1 && (int)state->reg_content[reg] != (int)state->reg_content[state->r64[reg]]-4) { free_register(state, state->r64[reg]); return; } if (state->last_access[reg] != NULL) last = state->last_access[reg]+1; else last = state->free_since[reg]; while (last <= state->dst) { if (state->last_access[reg] != NULL && state->dirty[reg]) last->reg_cache_infos.needed_registers[reg] = state->reg_content[reg]; else last->reg_cache_infos.needed_registers[reg] = NULL; if (state->last_access[reg] != NULL && state->r64[reg] != -1) { if (state->dirty[state->r64[reg]]) last->reg_cache_infos.needed_registers[state->r64[reg]] = state->reg_content[state->r64[reg]]; else last->reg_cache_infos.needed_registers[state->r64[reg]] = NULL; } last++; } if (state->last_access[reg] == NULL) { state->free_since[reg] = state->dst+1; return; } if (state->dirty[reg]) { mov_m32_reg32(state, state->reg_content[reg], reg); if (state->r64[reg] == -1) { sar_reg32_imm8(state, reg, 31); mov_m32_reg32(state, (unsigned int*)state->reg_content[reg]+1, reg); } else mov_m32_reg32(state, state->reg_content[state->r64[reg]], state->r64[reg]); } state->last_access[reg] = NULL; state->free_since[reg] = state->dst+1; if (state->r64[reg] != -1) { state->last_access[state->r64[reg]] = NULL; state->free_since[state->r64[reg]] = state->dst+1; } }
int generate_code(mdk_context_t *ctx) { int i, r1, r2; char *inst; if (ctx == NULL) return EINVAL; for (i = 0; ctx->tkn[i].token; i++) { if (ctx->tkn[i].type != MDK_TOKEN_VALUE) { switch (ctx->tkn[i].type) { case MDK_TOKEN_ADD: inst = "ADD"; break; case MDK_TOKEN_SUB: inst = "SUB"; break; case MDK_TOKEN_MUL: inst = "MUL"; break; case MDK_TOKEN_DIV: inst = "DIV"; break; default: /* error */ break; } r1 = capt_register(ctx); r2 = capt_register(ctx); printf("POP QB%d\n", r1); printf("POP QB%d\n", r2); printf("%s QB%d,QB%d\n", inst, r1, r2); printf("PUSH QB%d\n", r1); free_register(ctx, r1); free_register(ctx, r2); } else printf("PUSH %s\n", ctx->tkn[i].token); printf(";\n"); } r1 = capt_register(ctx); printf("POP QB%d\n", r1); free_register(ctx, r1); return 0; }
void free_all_registers(usf_state_t * state) { int i; for (i=0; i<8; i++) { if (state->last_access[i]) free_register(state, i); else { while (state->free_since[i] <= state->dst) { state->free_since[i]->reg_cache_infos.needed_registers[i] = NULL; state->free_since[i]++; } } } }
int allocate_register_64_w(usf_state_t *state, unsigned long long *addr) { int reg, i; // is it already cached? for (i = 0; i < 8; i++) { if (state->last_access[i] != NULL && state->reg_content[i] == addr) { precomp_instr *last = state->last_access[i] + 1; while (last <= state->dst) { last->reg_cache_infos.needed_registers[i] = NULL; last++; } state->last_access[i] = state->dst; state->is64bits[i] = 1; state->dirty[i] = 1; return i; } } // it's not cached, so take the least recently used register reg = lru_register(state); if (state->last_access[reg]) free_register(state, reg); else { while (state->free_since[reg] <= state->dst) { state->free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; state->free_since[reg]++; } } state->last_access[reg] = state->dst; state->reg_content[reg] = addr; state->dirty[reg] = 1; state->is64bits[reg] = 1; return reg; }
int allocate_register_64_w(unsigned long long *addr) { int reg, i; // is it already cached? for (i = 0; i < 8; i++) { if (last_access[i] != NULL && reg_content[i] == addr) { precomp_instr *last = last_access[i] + 1; while (last <= dst) { last->reg_cache_infos.needed_registers[i] = NULL; last++; } last_access[i] = dst; is64bits[i] = 1; dirty[i] = 1; return i; } } // it's not cached, so take the least recently used register reg = lru_register(); if (last_access[reg]) free_register(reg); else { while (free_since[reg] <= dst) { free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; free_since[reg]++; } } last_access[reg] = dst; reg_content[reg] = addr; dirty[reg] = 1; is64bits[reg] = 1; return reg; }
void free_all_registers(void) { #if defined(PROFILE_R4300) int freestart = code_length; int flushed = 0; #endif int i; for (i=0; i<8; i++) { #if defined(PROFILE_R4300) if (last_access[i] && dirty[i]) flushed = 1; #endif if (last_access[i]) { free_register(i); } else { while (free_since[i] <= dst) { free_since[i]->reg_cache_infos.needed_registers[i] = NULL; free_since[i]++; } } } #if defined(PROFILE_R4300) if (flushed == 1) { long long x86addr = (long long) ((*inst_pointer) + freestart); int mipsop = -5; if (fwrite(&mipsop, 1, 4, pfProfile) != 4 || /* -5 = regcache flushing */ fwrite(&x86addr, 1, sizeof(char *), pfProfile) != sizeof(char *)) // write pointer to start of register cache flushing instructions DebugMessage(M64MSG_ERROR, "Error writing R4300 instruction address profiling data"); x86addr = (long long) ((*inst_pointer) + code_length); if (fwrite(&src, 1, 4, pfProfile) != 4 || // write 4-byte MIPS opcode for current instruction fwrite(&x86addr, 1, sizeof(char *), pfProfile) != sizeof(char *)) // write pointer to dynamically generated x86 code for this MIPS instruction DebugMessage(M64MSG_ERROR, "Error writing R4300 instruction address profiling data"); } #endif }
void free_all_registers(void) { #if defined(PROFILE_R4300) int freestart = g_dev.r4300.recomp.code_length; int flushed = 0; #endif int i; for (i=0; i<8; i++) { #if defined(PROFILE_R4300) if (g_dev.r4300.regcache_state.last_access[i] && g_dev.r4300.regcache_state.dirty[i]) flushed = 1; #endif if (g_dev.r4300.regcache_state.last_access[i]) free_register(i); else { while (g_dev.r4300.regcache_state.free_since[i] <= g_dev.r4300.recomp.dst) { g_dev.r4300.regcache_state.free_since[i]->reg_cache_infos.needed_registers[i] = NULL; g_dev.r4300.regcache_state.free_since[i]++; } } } #if defined(PROFILE_R4300) if (flushed == 1) { long x86addr = (long) ((*g_dev.r4300.recomp.inst_pointer) + freestart); int mipsop = -5; fwrite(&mipsop, 1, 4, g_dev.r4300.recomp.pfProfile); /* -5 = regcache flushing */ fwrite(&x86addr, 1, sizeof(char *), g_dev.r4300.recomp.pfProfile); // write pointer to start of register cache flushing instructions x86addr = (long) ((*g_dev.r4300.recomp.inst_pointer) + g_dev.r4300.recomp.code_length); fwrite(&g_dev.r4300.recomp.src, 1, 4, g_dev.r4300.recomp.pfProfile); // write 4-byte MIPS opcode for current instruction fwrite(&x86addr, 1, sizeof(char *), g_dev.r4300.recomp.pfProfile); // write pointer to dynamically generated x86 code for this MIPS instruction } #endif }
void genaddu(void) { #ifdef INTERPRET_ADDU gencallinterp((unsigned int)cached_interpreter_table.ADDU, 0); #else int rs = allocate_register((unsigned int *)g_dev.r4300.recomp.dst->f.r.rs); int rt = allocate_register((unsigned int *)g_dev.r4300.recomp.dst->f.r.rt); int rd = allocate_register_w((unsigned int *)g_dev.r4300.recomp.dst->f.r.rd); if (rt != rd && rs != rd) { mov_reg32_reg32(rd, rs); add_reg32_reg32(rd, rt); } else { int temp = lru_register(); free_register(temp); mov_reg32_reg32(temp, rs); add_reg32_reg32(temp, rt); mov_reg32_reg32(rd, temp); } #endif }
void gennor() { #ifdef INTERPRET_NOR gencallinterp((unsigned long)NOR, 0); #else int rs1 = allocate_64_register1((unsigned long *)dst->f.r.rs); int rs2 = allocate_64_register2((unsigned long *)dst->f.r.rs); int rt1 = allocate_64_register1((unsigned long *)dst->f.r.rt); int rt2 = allocate_64_register2((unsigned long *)dst->f.r.rt); int rd1 = allocate_64_register1_w((unsigned long *)dst->f.r.rd); int rd2 = allocate_64_register2_w((unsigned long *)dst->f.r.rd); if (rt1 != rd1 && rs1 != rd1) { mov_reg32_reg32(rd1, rs1); mov_reg32_reg32(rd2, rs2); or_reg32_reg32(rd1, rt1); or_reg32_reg32(rd2, rt2); not_reg32(rd1); not_reg32(rd2); } else { int temp = lru_register(); free_register(temp); mov_reg32_reg32(temp, rs1); or_reg32_reg32(temp, rt1); mov_reg32_reg32(rd1, temp); mov_reg32_reg32(temp, rs2); or_reg32_reg32(temp, rt2); mov_reg32_reg32(rd2, temp); not_reg32(rd1); not_reg32(rd2); } #endif }
void gensubu(usf_state_t * state) { #ifdef INTERPRET_SUBU gencallinterp(state, (unsigned int)state->current_instruction_table.SUBU, 0); #else int rs = allocate_register(state, (unsigned int *)state->dst->f.r.rs); int rt = allocate_register(state, (unsigned int *)state->dst->f.r.rt); int rd = allocate_register_w(state, (unsigned int *)state->dst->f.r.rd); if (rt != rd && rs != rd) { mov_reg32_reg32(state, rd, rs); sub_reg32_reg32(state, rd, rt); } else { int temp = lru_register(state); free_register(state, temp); mov_reg32_reg32(state, temp, rs); sub_reg32_reg32(state, temp, rt); mov_reg32_reg32(state, rd, temp); } #endif }
void gensubu() { #ifdef INTERPRET_SUBU gencallinterp((unsigned long)SUBU, 0); #else int rs = allocate_register((unsigned long *)dst->f.r.rs); int rt = allocate_register((unsigned long *)dst->f.r.rt); int rd = allocate_register_w((unsigned long *)dst->f.r.rd); if (rt != rd && rs != rd) { mov_reg32_reg32(rd, rs); sub_reg32_reg32(rd, rt); } else { int temp = lru_register(); free_register(temp); mov_reg32_reg32(temp, rs); sub_reg32_reg32(temp, rt); mov_reg32_reg32(rd, temp); } #endif }
void gennor(usf_state_t * state) { #ifdef INTERPRET_NOR gencallinterp(state, (unsigned int)state->current_instruction_table.NOR, 0); #else int rs1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rs); int rs2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rs); int rt1 = allocate_64_register1(state, (unsigned int *)state->dst->f.r.rt); int rt2 = allocate_64_register2(state, (unsigned int *)state->dst->f.r.rt); int rd1 = allocate_64_register1_w(state, (unsigned int *)state->dst->f.r.rd); int rd2 = allocate_64_register2_w(state, (unsigned int *)state->dst->f.r.rd); if (rt1 != rd1 && rs1 != rd1) { mov_reg32_reg32(state, rd1, rs1); mov_reg32_reg32(state, rd2, rs2); or_reg32_reg32(state, rd1, rt1); or_reg32_reg32(state, rd2, rt2); not_reg32(state, rd1); not_reg32(state, rd2); } else { int temp = lru_register(state); free_register(state, temp); mov_reg32_reg32(state, temp, rs1); or_reg32_reg32(state, temp, rt1); mov_reg32_reg32(state, rd1, temp); mov_reg32_reg32(state, temp, rs2); or_reg32_reg32(state, temp, rt2); mov_reg32_reg32(state, rd2, temp); not_reg32(state, rd1); not_reg32(state, rd2); } #endif }
void gensub(void) { #ifdef INTERPRET_SUB gencallinterp((unsigned int)cached_interpreter_table.SUB, 0); #else int rs = allocate_register((unsigned int *)dst->f.r.rs); int rt = allocate_register((unsigned int *)dst->f.r.rt); int rd = allocate_register_w((unsigned int *)dst->f.r.rd); if (rt != rd && rs != rd) { mov_reg32_reg32(rd, rs); sub_reg32_reg32(rd, rt); } else { int temp = lru_register(); free_register(temp); mov_reg32_reg32(temp, rs); sub_reg32_reg32(temp, rt); mov_reg32_reg32(rd, temp); } #endif }
void allocate_register_32_manually(int reg, unsigned int *addr) { int i; /* check if we just happen to already have this r4300 reg cached in the requested x86 reg */ if (last_access[reg] != NULL && reg_content[reg] == (unsigned long long *) addr) { precomp_instr *last = last_access[reg] + 1; while (last <= dst) { last->reg_cache_infos.needed_registers[reg] = reg_content[reg]; last++; } last_access[reg] = dst; /* we won't touch is64bits or dirty; the register returned is "read-only" */ return; } /* otherwise free up the requested x86 register */ if (last_access[reg]) free_register(reg); else { while (free_since[reg] <= dst) { free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; free_since[reg]++; } } /* if the r4300 register is already cached in a different x86 register, then copy it to the requested x86 register */ for (i=0; i<8; i++) { if (last_access[i] != NULL && reg_content[i] == (unsigned long long *) addr) { precomp_instr *last = last_access[i]+1; while (last <= dst) { last->reg_cache_infos.needed_registers[i] = reg_content[i]; last++; } last_access[i] = dst; if (is64bits[i]) mov_reg64_reg64(reg, i); else mov_reg32_reg32(reg, i); last_access[reg] = dst; is64bits[reg] = is64bits[i]; dirty[reg] = dirty[i]; reg_content[reg] = reg_content[i]; /* free the previous x86 register used to cache this r4300 register */ free_since[i] = dst + 1; last_access[i] = NULL; return; } } /* otherwise just load the 32-bit value into the requested register */ last_access[reg] = dst; reg_content[reg] = (unsigned long long *) addr; dirty[reg] = 0; is64bits[reg] = 0; if ((unsigned long long *) addr == r0) xor_reg32_reg32(reg, reg); else mov_xreg32_m32rel(reg, addr); }
int allocate_64_register2_w(unsigned int *addr) { int reg1, reg2, i; // is it already cached as a 32 bits value ? for (i=0; i<8; i++) { if (g_dev.r4300.regcache_state.last_access[i] != NULL && g_dev.r4300.regcache_state.reg_content[i] == addr) { if (g_dev.r4300.regcache_state.r64[i] == -1) { allocate_register_w(addr); reg2 = lru_register(); if (g_dev.r4300.regcache_state.last_access[reg2]) free_register(reg2); else { while (g_dev.r4300.regcache_state.free_since[reg2] <= g_dev.r4300.recomp.dst) { g_dev.r4300.regcache_state.free_since[reg2]->reg_cache_infos.needed_registers[reg2] = NULL; g_dev.r4300.regcache_state.free_since[reg2]++; } } g_dev.r4300.regcache_state.r64[i] = reg2; g_dev.r4300.regcache_state.r64[reg2] = i; g_dev.r4300.regcache_state.last_access[reg2] = g_dev.r4300.recomp.dst; g_dev.r4300.regcache_state.reg_content[reg2] = addr+1; g_dev.r4300.regcache_state.dirty[reg2] = 1; mov_reg32_reg32(reg2, i); sar_reg32_imm8(reg2, 31); return reg2; } else { g_dev.r4300.regcache_state.last_access[i] = g_dev.r4300.recomp.dst; g_dev.r4300.regcache_state.last_access[g_dev.r4300.regcache_state.r64[i]] = g_dev.r4300.recomp.dst; g_dev.r4300.regcache_state.dirty[i] = g_dev.r4300.regcache_state.dirty[g_dev.r4300.regcache_state.r64[i]] = 1; return g_dev.r4300.regcache_state.r64[i]; } } } reg1 = allocate_register_w(addr); reg2 = lru_register(); if (g_dev.r4300.regcache_state.last_access[reg2]) free_register(reg2); else { while (g_dev.r4300.regcache_state.free_since[reg2] <= g_dev.r4300.recomp.dst) { g_dev.r4300.regcache_state.free_since[reg2]->reg_cache_infos.needed_registers[reg2] = NULL; g_dev.r4300.regcache_state.free_since[reg2]++; } } g_dev.r4300.regcache_state.r64[reg1] = reg2; g_dev.r4300.regcache_state.r64[reg2] = reg1; g_dev.r4300.regcache_state.last_access[reg2] = g_dev.r4300.recomp.dst; g_dev.r4300.regcache_state.reg_content[reg2] = addr+1; g_dev.r4300.regcache_state.dirty[reg2] = 1; return reg2; }
void allocate_register_manually_w(int reg, unsigned int *addr, int load) { int i; if (g_dev.r4300.regcache_state.last_access[reg] != NULL && g_dev.r4300.regcache_state.reg_content[reg] == addr) { struct precomp_instr *last = g_dev.r4300.regcache_state.last_access[reg]+1; while (last <= g_dev.r4300.recomp.dst) { last->reg_cache_infos.needed_registers[reg] = g_dev.r4300.regcache_state.reg_content[reg]; last++; } g_dev.r4300.regcache_state.last_access[reg] = g_dev.r4300.recomp.dst; if (g_dev.r4300.regcache_state.r64[reg] != -1) { last = g_dev.r4300.regcache_state.last_access[g_dev.r4300.regcache_state.r64[reg]]+1; while (last <= g_dev.r4300.recomp.dst) { last->reg_cache_infos.needed_registers[g_dev.r4300.regcache_state.r64[reg]] = g_dev.r4300.regcache_state.reg_content[g_dev.r4300.regcache_state.r64[reg]]; last++; } g_dev.r4300.regcache_state.last_access[g_dev.r4300.regcache_state.r64[reg]] = NULL; g_dev.r4300.regcache_state.free_since[g_dev.r4300.regcache_state.r64[reg]] = g_dev.r4300.recomp.dst+1; g_dev.r4300.regcache_state.r64[reg] = -1; } g_dev.r4300.regcache_state.dirty[reg] = 1; return; } if (g_dev.r4300.regcache_state.last_access[reg]) free_register(reg); else { while (g_dev.r4300.regcache_state.free_since[reg] <= g_dev.r4300.recomp.dst) { g_dev.r4300.regcache_state.free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; g_dev.r4300.regcache_state.free_since[reg]++; } } // is it already cached ? for (i=0; i<8; i++) { if (g_dev.r4300.regcache_state.last_access[i] != NULL && g_dev.r4300.regcache_state.reg_content[i] == addr) { struct precomp_instr *last = g_dev.r4300.regcache_state.last_access[i]+1; while (last <= g_dev.r4300.recomp.dst) { last->reg_cache_infos.needed_registers[i] = g_dev.r4300.regcache_state.reg_content[i]; last++; } g_dev.r4300.regcache_state.last_access[i] = g_dev.r4300.recomp.dst; if (g_dev.r4300.regcache_state.r64[i] != -1) { last = g_dev.r4300.regcache_state.last_access[g_dev.r4300.regcache_state.r64[i]]+1; while (last <= g_dev.r4300.recomp.dst) { last->reg_cache_infos.needed_registers[g_dev.r4300.regcache_state.r64[i]] = NULL; last++; } g_dev.r4300.regcache_state.free_since[g_dev.r4300.regcache_state.r64[i]] = g_dev.r4300.recomp.dst+1; g_dev.r4300.regcache_state.last_access[g_dev.r4300.regcache_state.r64[i]] = NULL; g_dev.r4300.regcache_state.r64[i] = -1; } if (load) mov_reg32_reg32(reg, i); g_dev.r4300.regcache_state.last_access[reg] = g_dev.r4300.recomp.dst; g_dev.r4300.regcache_state.dirty[reg] = 1; g_dev.r4300.regcache_state.r64[reg] = -1; g_dev.r4300.regcache_state.reg_content[reg] = g_dev.r4300.regcache_state.reg_content[i]; g_dev.r4300.regcache_state.free_since[i] = g_dev.r4300.recomp.dst+1; g_dev.r4300.regcache_state.last_access[i] = NULL; return; } } g_dev.r4300.regcache_state.last_access[reg] = g_dev.r4300.recomp.dst; g_dev.r4300.regcache_state.reg_content[reg] = addr; g_dev.r4300.regcache_state.dirty[reg] = 1; g_dev.r4300.regcache_state.r64[reg] = -1; if (addr != NULL && load) { if (addr == g_dev.r4300.regcache_state.r0 || addr == g_dev.r4300.regcache_state.r0+1) xor_reg32_reg32(reg, reg); else mov_reg32_m32(reg, addr); } }
void allocate_register_manually_w(int reg, unsigned int *addr, int load) { int i; if (last_access[reg] != NULL && reg_content[reg] == addr) { precomp_instr *last = last_access[reg]+1; while (last <= dst) { last->reg_cache_infos.needed_registers[reg] = reg_content[reg]; last++; } last_access[reg] = dst; if (r64[reg] != -1) { last = last_access[r64[reg]]+1; while (last <= dst) { last->reg_cache_infos.needed_registers[r64[reg]] = reg_content[r64[reg]]; last++; } last_access[r64[reg]] = NULL; free_since[r64[reg]] = dst+1; r64[reg] = -1; } dirty[reg] = 1; return; } if (last_access[reg]) free_register(reg); else { while (free_since[reg] <= dst) { free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; free_since[reg]++; } } // is it already cached ? for (i=0; i<8; i++) { if (last_access[i] != NULL && reg_content[i] == addr) { precomp_instr *last = last_access[i]+1; while (last <= dst) { last->reg_cache_infos.needed_registers[i] = reg_content[i]; last++; } last_access[i] = dst; if (r64[i] != -1) { last = last_access[r64[i]]+1; while (last <= dst) { last->reg_cache_infos.needed_registers[r64[i]] = NULL; last++; } free_since[r64[i]] = dst+1; last_access[r64[i]] = NULL; r64[i] = -1; } if (load) mov_reg32_reg32(reg, i); last_access[reg] = dst; dirty[reg] = 1; r64[reg] = -1; reg_content[reg] = reg_content[i]; free_since[i] = dst+1; last_access[i] = NULL; return; } } last_access[reg] = dst; reg_content[reg] = addr; dirty[reg] = 1; r64[reg] = -1; if (addr != NULL && load) { if (addr == r0 || addr == r0+1) xor_reg32_reg32(reg, reg); else mov_reg32_m32(reg, addr); } }
void lock_register(int reg) { free_register(reg); last_access[reg] = (precomp_instr *)0xFFFFFFFF; reg_content[reg] = NULL; }
int allocate_64_register2_w(unsigned int *addr) { int reg1, reg2, i; // is it already cached as a 32 bits value ? for (i=0; i<8; i++) { if (last_access[i] != NULL && reg_content[i] == addr) { if (r64[i] == -1) { allocate_register_w(addr); reg2 = lru_register(); if (last_access[reg2]) free_register(reg2); else { while (free_since[reg2] <= dst) { free_since[reg2]->reg_cache_infos.needed_registers[reg2] = NULL; free_since[reg2]++; } } r64[i] = reg2; r64[reg2] = i; last_access[reg2] = dst; reg_content[reg2] = addr+1; dirty[reg2] = 1; mov_reg32_reg32(reg2, i); sar_reg32_imm8(reg2, 31); return reg2; } else { last_access[i] = dst; last_access[r64[i]] = dst; dirty[i] = dirty[r64[i]] = 1; return r64[i]; } } } reg1 = allocate_register_w(addr); reg2 = lru_register(); if (last_access[reg2]) free_register(reg2); else { while (free_since[reg2] <= dst) { free_since[reg2]->reg_cache_infos.needed_registers[reg2] = NULL; free_since[reg2]++; } } r64[reg1] = reg2; r64[reg2] = reg1; last_access[reg2] = dst; reg_content[reg2] = addr+1; dirty[reg2] = 1; return reg2; }
int allocate_register_w(unsigned int *addr) { unsigned int oldest_access = 0xFFFFFFFF; int reg = 0, i; // is it already cached ? for (i=0; i<8; i++) { if (last_access[i] != NULL && reg_content[i] == addr) { precomp_instr *last = last_access[i]+1; while (last <= dst) { last->reg_cache_infos.needed_registers[i] = NULL; last++; } last_access[i] = dst; dirty[i] = 1; if (r64[i] != -1) { last = last_access[r64[i]]+1; while (last <= dst) { last->reg_cache_infos.needed_registers[r64[i]] = NULL; last++; } free_since[r64[i]] = dst+1; last_access[r64[i]] = NULL; r64[i] = -1; } return i; } } // if it's not cached, we take the least recently used register for (i=0; i<8; i++) { if (i != ESP && (unsigned int)last_access[i] < oldest_access) { oldest_access = (int)last_access[i]; reg = i; } } if (last_access[reg]) free_register(reg); else { while (free_since[reg] <= dst) { free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; free_since[reg]++; } } last_access[reg] = dst; reg_content[reg] = addr; dirty[reg] = 1; r64[reg] = -1; return reg; }