X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=source%2Fmupen64plus-core%2Fsrc%2Fr4300%2Fx86%2Fgspecial.c;fp=source%2Fmupen64plus-core%2Fsrc%2Fr4300%2Fx86%2Fgspecial.c;h=053c7af8760d720ec4987ea8dec37b69b133c272;hb=451ab91e3827a6384981b3300e2a7000d2eaba58;hp=0000000000000000000000000000000000000000;hpb=a2ab25365b5b0dddbee476d695d8a31151407581;p=mupen64plus-pandora.git diff --git a/source/mupen64plus-core/src/r4300/x86/gspecial.c b/source/mupen64plus-core/src/r4300/x86/gspecial.c new file mode 100644 index 0000000..053c7af --- /dev/null +++ b/source/mupen64plus-core/src/r4300/x86/gspecial.c @@ -0,0 +1,1157 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - gspecial.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +#include "assemble.h" +#include "interpret.h" + +#include "r4300/recomph.h" +#include "r4300/recomp.h" +#include "r4300/r4300.h" +#include "r4300/ops.h" +#include "r4300/macros.h" +#include "r4300/exception.h" + +void gensll(void) +{ +#ifdef INTERPRET_SLL + gencallinterp((unsigned int)cached_interpreter_table.SLL, 0); +#else + int rt = allocate_register((unsigned int *)dst->f.r.rt); + int rd = allocate_register_w((unsigned int *)dst->f.r.rd); + + mov_reg32_reg32(rd, rt); + shl_reg32_imm8(rd, dst->f.r.sa); +#endif +} + +void gensrl(void) +{ +#ifdef INTERPRET_SRL + gencallinterp((unsigned int)cached_interpreter_table.SRL, 0); +#else + int rt = allocate_register((unsigned int *)dst->f.r.rt); + int rd = allocate_register_w((unsigned int *)dst->f.r.rd); + + mov_reg32_reg32(rd, rt); + shr_reg32_imm8(rd, dst->f.r.sa); +#endif +} + +void gensra(void) +{ +#ifdef INTERPRET_SRA + gencallinterp((unsigned int)cached_interpreter_table.SRA, 0); +#else + int rt = allocate_register((unsigned int *)dst->f.r.rt); + int rd = allocate_register_w((unsigned int *)dst->f.r.rd); + + mov_reg32_reg32(rd, rt); + sar_reg32_imm8(rd, dst->f.r.sa); +#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 *)dst->f.r.rs); + + rt = allocate_register((unsigned int *)dst->f.r.rt); + rd = allocate_register_w((unsigned int *)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 gensrlv(void) +{ +#ifdef INTERPRET_SRLV + gencallinterp((unsigned int)cached_interpreter_table.SRLV, 0); +#else + int rt, rd; + allocate_register_manually(ECX, (unsigned int *)dst->f.r.rs); + + rt = allocate_register((unsigned int *)dst->f.r.rt); + rd = allocate_register_w((unsigned int *)dst->f.r.rd); + + if (rd != ECX) + { + mov_reg32_reg32(rd, rt); + shr_reg32_cl(rd); + } + else + { + int temp = lru_register(); + free_register(temp); + mov_reg32_reg32(temp, rt); + shr_reg32_cl(temp); + mov_reg32_reg32(rd, temp); + } +#endif +} + +void gensrav(void) +{ +#ifdef INTERPRET_SRAV + gencallinterp((unsigned int)cached_interpreter_table.SRAV, 0); +#else + int rt, rd; + allocate_register_manually(ECX, (unsigned int *)dst->f.r.rs); + + rt = allocate_register((unsigned int *)dst->f.r.rt); + rd = allocate_register_w((unsigned int *)dst->f.r.rd); + + if (rd != ECX) + { + mov_reg32_reg32(rd, rt); + sar_reg32_cl(rd); + } + else + { + int temp = lru_register(); + free_register(temp); + mov_reg32_reg32(temp, rt); + sar_reg32_cl(temp); + mov_reg32_reg32(rd, temp); + } +#endif +} + +void genjr(void) +{ +#ifdef INTERPRET_JR + gencallinterp((unsigned int)cached_interpreter_table.JR, 1); +#else + static unsigned int precomp_instr_size = sizeof(precomp_instr); + unsigned int diff = + (unsigned int)(&dst->local_addr) - (unsigned int)(dst); + unsigned int diff_need = + (unsigned int)(&dst->reg_cache_infos.need_map) - (unsigned int)(dst); + unsigned int diff_wrap = + (unsigned int)(&dst->reg_cache_infos.jump_wrapper) - (unsigned int)(dst); + + if (((dst->addr & 0xFFF) == 0xFFC && + (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) + { + gencallinterp((unsigned int)cached_interpreter_table.JR, 1); + return; + } + + free_all_registers(); + simplify_access(); + mov_eax_memoffs32((unsigned int *)dst->f.i.rs); + mov_memoffs32_eax((unsigned int *)&local_rs); + + gendelayslot(); + + mov_eax_memoffs32((unsigned int *)&local_rs); + mov_memoffs32_eax((unsigned int *)&last_addr); + + gencheck_interupt_reg(); + + mov_eax_memoffs32((unsigned int *)&local_rs); + mov_reg32_reg32(EBX, EAX); + and_eax_imm32(0xFFFFF000); + cmp_eax_imm32(dst_block->start & 0xFFFFF000); + je_near_rj(0); + + jump_start_rel32(); + + mov_m32_reg32(&jump_to_address, EBX); + mov_m32_imm32((unsigned int*)(&PC), (unsigned int)(dst+1)); + mov_reg32_imm32(EAX, (unsigned int)jump_to_func); + call_reg32(EAX); + + jump_end_rel32(); + + mov_reg32_reg32(EAX, EBX); + sub_eax_imm32(dst_block->start); + shr_reg32_imm8(EAX, 2); + mul_m32((unsigned int *)(&precomp_instr_size)); + + mov_reg32_preg32pimm32(EBX, EAX, (unsigned int)(dst_block->block)+diff_need); + cmp_reg32_imm32(EBX, 1); + jne_rj(7); + + add_eax_imm32((unsigned int)(dst_block->block)+diff_wrap); // 5 + jmp_reg32(EAX); // 2 + + mov_reg32_preg32pimm32(EAX, EAX, (unsigned int)(dst_block->block)+diff); + add_reg32_m32(EAX, (unsigned int *)(&dst_block->code)); + + jmp_reg32(EAX); +#endif +} + +void genjalr(void) +{ +#ifdef INTERPRET_JALR + gencallinterp((unsigned int)cached_interpreter_table.JALR, 0); +#else + static unsigned int precomp_instr_size = sizeof(precomp_instr); + unsigned int diff = + (unsigned int)(&dst->local_addr) - (unsigned int)(dst); + unsigned int diff_need = + (unsigned int)(&dst->reg_cache_infos.need_map) - (unsigned int)(dst); + unsigned int diff_wrap = + (unsigned int)(&dst->reg_cache_infos.jump_wrapper) - (unsigned int)(dst); + + if (((dst->addr & 0xFFF) == 0xFFC && + (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) + { + gencallinterp((unsigned int)cached_interpreter_table.JALR, 1); + return; + } + + free_all_registers(); + simplify_access(); + mov_eax_memoffs32((unsigned int *)dst->f.r.rs); + mov_memoffs32_eax((unsigned int *)&local_rs); + + gendelayslot(); + + mov_m32_imm32((unsigned int *)(dst-1)->f.r.rd, dst->addr+4); + if ((dst->addr+4) & 0x80000000) + mov_m32_imm32(((unsigned int *)(dst-1)->f.r.rd)+1, 0xFFFFFFFF); + else + mov_m32_imm32(((unsigned int *)(dst-1)->f.r.rd)+1, 0); + + mov_eax_memoffs32((unsigned int *)&local_rs); + mov_memoffs32_eax((unsigned int *)&last_addr); + + gencheck_interupt_reg(); + + mov_eax_memoffs32((unsigned int *)&local_rs); + mov_reg32_reg32(EBX, EAX); + and_eax_imm32(0xFFFFF000); + cmp_eax_imm32(dst_block->start & 0xFFFFF000); + je_near_rj(0); + + jump_start_rel32(); + + mov_m32_reg32(&jump_to_address, EBX); + mov_m32_imm32((unsigned int*)(&PC), (unsigned int)(dst+1)); + mov_reg32_imm32(EAX, (unsigned int)jump_to_func); + call_reg32(EAX); + + jump_end_rel32(); + + mov_reg32_reg32(EAX, EBX); + sub_eax_imm32(dst_block->start); + shr_reg32_imm8(EAX, 2); + mul_m32((unsigned int *)(&precomp_instr_size)); + + mov_reg32_preg32pimm32(EBX, EAX, (unsigned int)(dst_block->block)+diff_need); + cmp_reg32_imm32(EBX, 1); + jne_rj(7); + + add_eax_imm32((unsigned int)(dst_block->block)+diff_wrap); // 5 + jmp_reg32(EAX); // 2 + + mov_reg32_preg32pimm32(EAX, EAX, (unsigned int)(dst_block->block)+diff); + add_reg32_m32(EAX, (unsigned int *)(&dst_block->code)); + + jmp_reg32(EAX); +#endif +} + +void gensyscall(void) +{ +#ifdef INTERPRET_SYSCALL + gencallinterp((unsigned int)cached_interpreter_table.SYSCALL, 0); +#else + free_all_registers(); + simplify_access(); + mov_m32_imm32(&Cause, 8 << 2); + gencallinterp((unsigned int)exception_general, 0); +#endif +} + +void gensync(void) +{ +} + +void genmfhi(void) +{ +#ifdef INTERPRET_MFHI + gencallinterp((unsigned int)cached_interpreter_table.MFHI, 0); +#else + int rd1 = allocate_64_register1_w((unsigned int*)dst->f.r.rd); + int rd2 = allocate_64_register2_w((unsigned int*)dst->f.r.rd); + int hi1 = allocate_64_register1((unsigned int*)&hi); + int hi2 = allocate_64_register2((unsigned int*)&hi); + + mov_reg32_reg32(rd1, hi1); + mov_reg32_reg32(rd2, hi2); +#endif +} + +void genmthi(void) +{ +#ifdef INTERPRET_MTHI + gencallinterp((unsigned int)cached_interpreter_table.MTHI, 0); +#else + int hi1 = allocate_64_register1_w((unsigned int*)&hi); + int hi2 = allocate_64_register2_w((unsigned int*)&hi); + int rs1 = allocate_64_register1((unsigned int*)dst->f.r.rs); + int rs2 = allocate_64_register2((unsigned int*)dst->f.r.rs); + + mov_reg32_reg32(hi1, rs1); + mov_reg32_reg32(hi2, rs2); +#endif +} + +void genmflo(void) +{ +#ifdef INTERPRET_MFLO + gencallinterp((unsigned int)cached_interpreter_table.MFLO, 0); +#else + int rd1 = allocate_64_register1_w((unsigned int*)dst->f.r.rd); + int rd2 = allocate_64_register2_w((unsigned int*)dst->f.r.rd); + int lo1 = allocate_64_register1((unsigned int*)&lo); + int lo2 = allocate_64_register2((unsigned int*)&lo); + + mov_reg32_reg32(rd1, lo1); + mov_reg32_reg32(rd2, lo2); +#endif +} + +void genmtlo(void) +{ +#ifdef INTERPRET_MTLO + gencallinterp((unsigned int)cached_interpreter_table.MTLO, 0); +#else + int lo1 = allocate_64_register1_w((unsigned int*)&lo); + int lo2 = allocate_64_register2_w((unsigned int*)&lo); + int rs1 = allocate_64_register1((unsigned int*)dst->f.r.rs); + int rs2 = allocate_64_register2((unsigned int*)dst->f.r.rs); + + mov_reg32_reg32(lo1, rs1); + mov_reg32_reg32(lo2, rs2); +#endif +} + +void gendsllv(void) +{ +#ifdef INTERPRET_DSLLV + gencallinterp((unsigned int)cached_interpreter_table.DSLLV, 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); + shld_reg32_reg32_cl(rd2,rd1); + shl_reg32_cl(rd1); + test_reg32_imm32(ECX, 0x20); + je_rj(4); + mov_reg32_reg32(rd2, rd1); // 2 + xor_reg32_reg32(rd1, rd1); // 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); + shld_reg32_reg32_cl(temp2, temp1); + shl_reg32_cl(temp1); + test_reg32_imm32(ECX, 0x20); + je_rj(4); + mov_reg32_reg32(temp2, temp1); // 2 + xor_reg32_reg32(temp1, temp1); // 2 + + mov_reg32_reg32(rd1, temp1); + mov_reg32_reg32(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 gendsrav(void) +{ +#ifdef INTERPRET_DSRAV + gencallinterp((unsigned int)cached_interpreter_table.DSRAV, 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); + 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 genmult(void) +{ +#ifdef INTERPRET_MULT + gencallinterp((unsigned int)cached_interpreter_table.MULT, 0); +#else + int rs, rt; + allocate_register_manually_w(EAX, (unsigned int *)&lo, 0); + allocate_register_manually_w(EDX, (unsigned int *)&hi, 0); + rs = allocate_register((unsigned int*)dst->f.r.rs); + rt = allocate_register((unsigned int*)dst->f.r.rt); + mov_reg32_reg32(EAX, rs); + imul_reg32(rt); +#endif +} + +void genmultu(void) +{ +#ifdef INTERPRET_MULTU + gencallinterp((unsigned int)cached_interpreter_table.MULTU, 0); +#else + int rs, rt; + allocate_register_manually_w(EAX, (unsigned int *)&lo, 0); + allocate_register_manually_w(EDX, (unsigned int *)&hi, 0); + rs = allocate_register((unsigned int*)dst->f.r.rs); + rt = allocate_register((unsigned int*)dst->f.r.rt); + mov_reg32_reg32(EAX, rs); + mul_reg32(rt); +#endif +} + +void gendiv(void) +{ +#ifdef INTERPRET_DIV + gencallinterp((unsigned int)cached_interpreter_table.DIV, 0); +#else + int rs, rt; + allocate_register_manually_w(EAX, (unsigned int *)&lo, 0); + allocate_register_manually_w(EDX, (unsigned int *)&hi, 0); + rs = allocate_register((unsigned int*)dst->f.r.rs); + rt = allocate_register((unsigned int*)dst->f.r.rt); + cmp_reg32_imm32(rt, 0); + je_rj((rs == EAX ? 0 : 2) + 1 + 2); + mov_reg32_reg32(EAX, rs); // 0 or 2 + cdq(); // 1 + idiv_reg32(rt); // 2 +#endif +} + +void gendivu(void) +{ +#ifdef INTERPRET_DIVU + gencallinterp((unsigned int)cached_interpreter_table.DIVU, 0); +#else + int rs, rt; + allocate_register_manually_w(EAX, (unsigned int *)&lo, 0); + allocate_register_manually_w(EDX, (unsigned int *)&hi, 0); + rs = allocate_register((unsigned int*)dst->f.r.rs); + rt = allocate_register((unsigned int*)dst->f.r.rt); + cmp_reg32_imm32(rt, 0); + je_rj((rs == EAX ? 0 : 2) + 2 + 2); + mov_reg32_reg32(EAX, rs); // 0 or 2 + xor_reg32_reg32(EDX, EDX); // 2 + div_reg32(rt); // 2 +#endif +} + +void gendmult(void) +{ + gencallinterp((unsigned int)cached_interpreter_table.DMULT, 0); +} + +void gendmultu(void) +{ +#ifdef INTERPRET_DMULTU + gencallinterp((unsigned int)cached_interpreter_table.DMULTU, 0); +#else + free_all_registers(); + simplify_access(); + + mov_eax_memoffs32((unsigned int *)dst->f.r.rs); + mul_m32((unsigned int *)dst->f.r.rt); // EDX:EAX = temp1 + mov_memoffs32_eax((unsigned int *)(&lo)); + + mov_reg32_reg32(EBX, EDX); // EBX = temp1>>32 + mov_eax_memoffs32((unsigned int *)dst->f.r.rs); + mul_m32((unsigned int *)(dst->f.r.rt)+1); + add_reg32_reg32(EBX, EAX); + adc_reg32_imm32(EDX, 0); + mov_reg32_reg32(ECX, EDX); // ECX:EBX = temp2 + + mov_eax_memoffs32((unsigned int *)(dst->f.r.rs)+1); + mul_m32((unsigned int *)dst->f.r.rt); // EDX:EAX = temp3 + + add_reg32_reg32(EBX, EAX); + adc_reg32_imm32(ECX, 0); // ECX:EBX = result2 + mov_m32_reg32((unsigned int*)(&lo)+1, EBX); + + mov_reg32_reg32(ESI, EDX); // ESI = temp3>>32 + mov_eax_memoffs32((unsigned int *)(dst->f.r.rs)+1); + mul_m32((unsigned int *)(dst->f.r.rt)+1); + add_reg32_reg32(EAX, ESI); + adc_reg32_imm32(EDX, 0); // EDX:EAX = temp4 + + add_reg32_reg32(EAX, ECX); + adc_reg32_imm32(EDX, 0); // EDX:EAX = result3 + mov_memoffs32_eax((unsigned int *)(&hi)); + mov_m32_reg32((unsigned int *)(&hi)+1, EDX); +#endif +} + +void genddiv(void) +{ + gencallinterp((unsigned int)cached_interpreter_table.DDIV, 0); +} + +void genddivu(void) +{ + gencallinterp((unsigned int)cached_interpreter_table.DDIVU, 0); +} + +void genadd(void) +{ +#ifdef INTERPRET_ADD + gencallinterp((unsigned int)cached_interpreter_table.ADD, 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); + 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 genaddu(void) +{ +#ifdef INTERPRET_ADDU + gencallinterp((unsigned int)cached_interpreter_table.ADDU, 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); + 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 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 gensubu(void) +{ +#ifdef INTERPRET_SUBU + gencallinterp((unsigned int)cached_interpreter_table.SUBU, 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 genand(void) +{ +#ifdef INTERPRET_AND + gencallinterp((unsigned int)cached_interpreter_table.AND, 0); +#else + int rs1 = allocate_64_register1((unsigned int *)dst->f.r.rs); + int rs2 = allocate_64_register2((unsigned int *)dst->f.r.rs); + int rt1 = allocate_64_register1((unsigned int *)dst->f.r.rt); + int rt2 = allocate_64_register2((unsigned int *)dst->f.r.rt); + int rd1 = allocate_64_register1_w((unsigned int *)dst->f.r.rd); + int rd2 = allocate_64_register2_w((unsigned int *)dst->f.r.rd); + + if (rt1 != rd1 && rs1 != rd1) + { + mov_reg32_reg32(rd1, rs1); + mov_reg32_reg32(rd2, rs2); + and_reg32_reg32(rd1, rt1); + and_reg32_reg32(rd2, rt2); + } + else + { + int temp = lru_register(); + free_register(temp); + mov_reg32_reg32(temp, rs1); + and_reg32_reg32(temp, rt1); + mov_reg32_reg32(rd1, temp); + mov_reg32_reg32(temp, rs2); + and_reg32_reg32(temp, rt2); + mov_reg32_reg32(rd2, temp); + } +#endif +} + +void genor(void) +{ +#ifdef INTERPRET_OR + gencallinterp((unsigned int)cached_interpreter_table.OR, 0); +#else + int rs1 = allocate_64_register1((unsigned int *)dst->f.r.rs); + int rs2 = allocate_64_register2((unsigned int *)dst->f.r.rs); + int rt1 = allocate_64_register1((unsigned int *)dst->f.r.rt); + int rt2 = allocate_64_register2((unsigned int *)dst->f.r.rt); + int rd1 = allocate_64_register1_w((unsigned int *)dst->f.r.rd); + int rd2 = allocate_64_register2_w((unsigned int *)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); + } + 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); + } +#endif +} + +void genxor(void) +{ +#ifdef INTERPRET_XOR + gencallinterp((unsigned int)cached_interpreter_table.XOR, 0); +#else + int rs1 = allocate_64_register1((unsigned int *)dst->f.r.rs); + int rs2 = allocate_64_register2((unsigned int *)dst->f.r.rs); + int rt1 = allocate_64_register1((unsigned int *)dst->f.r.rt); + int rt2 = allocate_64_register2((unsigned int *)dst->f.r.rt); + int rd1 = allocate_64_register1_w((unsigned int *)dst->f.r.rd); + int rd2 = allocate_64_register2_w((unsigned int *)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 gennor(void) +{ +#ifdef INTERPRET_NOR + gencallinterp((unsigned int)cached_interpreter_table.NOR, 0); +#else + int rs1 = allocate_64_register1((unsigned int *)dst->f.r.rs); + int rs2 = allocate_64_register2((unsigned int *)dst->f.r.rs); + int rt1 = allocate_64_register1((unsigned int *)dst->f.r.rt); + int rt2 = allocate_64_register2((unsigned int *)dst->f.r.rt); + int rd1 = allocate_64_register1_w((unsigned int *)dst->f.r.rd); + int rd2 = allocate_64_register2_w((unsigned int *)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 genslt(void) +{ +#ifdef INTERPRET_SLT + gencallinterp((unsigned int)cached_interpreter_table.SLT, 0); +#else + int rs1 = allocate_64_register1((unsigned int *)dst->f.r.rs); + int rs2 = allocate_64_register2((unsigned int *)dst->f.r.rs); + int rt1 = allocate_64_register1((unsigned int *)dst->f.r.rt); + int rt2 = allocate_64_register2((unsigned int *)dst->f.r.rt); + int rd = allocate_register_w((unsigned int *)dst->f.r.rd); + + cmp_reg32_reg32(rs2, rt2); + jl_rj(13); + jne_rj(4); // 2 + cmp_reg32_reg32(rs1, rt1); // 2 + jl_rj(7); // 2 + mov_reg32_imm32(rd, 0); // 5 + jmp_imm_short(5); // 2 + mov_reg32_imm32(rd, 1); // 5 +#endif +} + +void gensltu(void) +{ +#ifdef INTERPRET_SLTU + gencallinterp((unsigned int)cached_interpreter_table.SLTU, 0); +#else + int rs1 = allocate_64_register1((unsigned int *)dst->f.r.rs); + int rs2 = allocate_64_register2((unsigned int *)dst->f.r.rs); + int rt1 = allocate_64_register1((unsigned int *)dst->f.r.rt); + int rt2 = allocate_64_register2((unsigned int *)dst->f.r.rt); + int rd = allocate_register_w((unsigned int *)dst->f.r.rd); + + cmp_reg32_reg32(rs2, rt2); + jb_rj(13); + jne_rj(4); // 2 + cmp_reg32_reg32(rs1, rt1); // 2 + jb_rj(7); // 2 + mov_reg32_imm32(rd, 0); // 5 + jmp_imm_short(5); // 2 + mov_reg32_imm32(rd, 1); // 5 +#endif +} + +void gendadd(void) +{ +#ifdef INTERPRET_DADD + gencallinterp((unsigned int)cached_interpreter_table.DADD, 0); +#else + int rs1 = allocate_64_register1((unsigned int *)dst->f.r.rs); + int rs2 = allocate_64_register2((unsigned int *)dst->f.r.rs); + int rt1 = allocate_64_register1((unsigned int *)dst->f.r.rt); + int rt2 = allocate_64_register2((unsigned int *)dst->f.r.rt); + int rd1 = allocate_64_register1_w((unsigned int *)dst->f.r.rd); + int rd2 = allocate_64_register2_w((unsigned int *)dst->f.r.rd); + + if (rt1 != rd1 && rs1 != rd1) + { + mov_reg32_reg32(rd1, rs1); + mov_reg32_reg32(rd2, rs2); + add_reg32_reg32(rd1, rt1); + adc_reg32_reg32(rd2, rt2); + } + else + { + int temp = lru_register(); + free_register(temp); + mov_reg32_reg32(temp, rs1); + add_reg32_reg32(temp, rt1); + mov_reg32_reg32(rd1, temp); + mov_reg32_reg32(temp, rs2); + adc_reg32_reg32(temp, rt2); + mov_reg32_reg32(rd2, temp); + } +#endif +} + +void gendaddu(void) +{ +#ifdef INTERPRET_DADDU + gencallinterp((unsigned int)cached_interpreter_table.DADDU, 0); +#else + int rs1 = allocate_64_register1((unsigned int *)dst->f.r.rs); + int rs2 = allocate_64_register2((unsigned int *)dst->f.r.rs); + int rt1 = allocate_64_register1((unsigned int *)dst->f.r.rt); + int rt2 = allocate_64_register2((unsigned int *)dst->f.r.rt); + int rd1 = allocate_64_register1_w((unsigned int *)dst->f.r.rd); + int rd2 = allocate_64_register2_w((unsigned int *)dst->f.r.rd); + + if (rt1 != rd1 && rs1 != rd1) + { + mov_reg32_reg32(rd1, rs1); + mov_reg32_reg32(rd2, rs2); + add_reg32_reg32(rd1, rt1); + adc_reg32_reg32(rd2, rt2); + } + else + { + int temp = lru_register(); + free_register(temp); + mov_reg32_reg32(temp, rs1); + add_reg32_reg32(temp, rt1); + mov_reg32_reg32(rd1, temp); + mov_reg32_reg32(temp, rs2); + adc_reg32_reg32(temp, rt2); + mov_reg32_reg32(rd2, temp); + } +#endif +} + +void gendsub(void) +{ +#ifdef INTERPRET_DSUB + gencallinterp((unsigned int)cached_interpreter_table.DSUB, 0); +#else + int rs1 = allocate_64_register1((unsigned int *)dst->f.r.rs); + int rs2 = allocate_64_register2((unsigned int *)dst->f.r.rs); + int rt1 = allocate_64_register1((unsigned int *)dst->f.r.rt); + int rt2 = allocate_64_register2((unsigned int *)dst->f.r.rt); + int rd1 = allocate_64_register1_w((unsigned int *)dst->f.r.rd); + int rd2 = allocate_64_register2_w((unsigned int *)dst->f.r.rd); + + if (rt1 != rd1 && rs1 != rd1) + { + mov_reg32_reg32(rd1, rs1); + mov_reg32_reg32(rd2, rs2); + sub_reg32_reg32(rd1, rt1); + sbb_reg32_reg32(rd2, rt2); + } + else + { + int temp = lru_register(); + free_register(temp); + mov_reg32_reg32(temp, rs1); + sub_reg32_reg32(temp, rt1); + mov_reg32_reg32(rd1, temp); + mov_reg32_reg32(temp, rs2); + sbb_reg32_reg32(temp, rt2); + mov_reg32_reg32(rd2, temp); + } +#endif +} + +void gendsubu(void) +{ +#ifdef INTERPRET_DSUBU + gencallinterp((unsigned int)cached_interpreter_table.DSUBU, 0); +#else + int rs1 = allocate_64_register1((unsigned int *)dst->f.r.rs); + int rs2 = allocate_64_register2((unsigned int *)dst->f.r.rs); + int rt1 = allocate_64_register1((unsigned int *)dst->f.r.rt); + int rt2 = allocate_64_register2((unsigned int *)dst->f.r.rt); + int rd1 = allocate_64_register1_w((unsigned int *)dst->f.r.rd); + int rd2 = allocate_64_register2_w((unsigned int *)dst->f.r.rd); + + if (rt1 != rd1 && rs1 != rd1) + { + mov_reg32_reg32(rd1, rs1); + mov_reg32_reg32(rd2, rs2); + sub_reg32_reg32(rd1, rt1); + sbb_reg32_reg32(rd2, rt2); + } + else + { + int temp = lru_register(); + free_register(temp); + mov_reg32_reg32(temp, rs1); + sub_reg32_reg32(temp, rt1); + mov_reg32_reg32(rd1, temp); + mov_reg32_reg32(temp, rs2); + sbb_reg32_reg32(temp, rt2); + mov_reg32_reg32(rd2, temp); + } +#endif +} + +void genteq(void) +{ + gencallinterp((unsigned int)cached_interpreter_table.TEQ, 0); +} + +void gendsll(void) +{ +#ifdef INTERPRET_DSLL + gencallinterp((unsigned int)cached_interpreter_table.DSLL, 0); +#else + int rt1 = allocate_64_register1((unsigned int *)dst->f.r.rt); + int rt2 = allocate_64_register2((unsigned int *)dst->f.r.rt); + int rd1 = allocate_64_register1_w((unsigned int *)dst->f.r.rd); + int rd2 = allocate_64_register2_w((unsigned int *)dst->f.r.rd); + + mov_reg32_reg32(rd1, rt1); + mov_reg32_reg32(rd2, rt2); + shld_reg32_reg32_imm8(rd2, rd1, dst->f.r.sa); + shl_reg32_imm8(rd1, dst->f.r.sa); + if (dst->f.r.sa & 0x20) + { + mov_reg32_reg32(rd2, rd1); + xor_reg32_reg32(rd1, rd1); + } +#endif +} + +void gendsrl(void) +{ +#ifdef INTERPRET_DSRL + gencallinterp((unsigned int)cached_interpreter_table.DSRL, 0); +#else + int rt1 = allocate_64_register1((unsigned int *)dst->f.r.rt); + int rt2 = allocate_64_register2((unsigned int *)dst->f.r.rt); + int rd1 = allocate_64_register1_w((unsigned int *)dst->f.r.rd); + int rd2 = allocate_64_register2_w((unsigned int *)dst->f.r.rd); + + mov_reg32_reg32(rd1, rt1); + mov_reg32_reg32(rd2, rt2); + shrd_reg32_reg32_imm8(rd1, rd2, dst->f.r.sa); + shr_reg32_imm8(rd2, dst->f.r.sa); + if (dst->f.r.sa & 0x20) + { + mov_reg32_reg32(rd1, rd2); + xor_reg32_reg32(rd2, rd2); + } +#endif +} + +void gendsra(void) +{ +#ifdef INTERPRET_DSRA + gencallinterp((unsigned int)cached_interpreter_table.DSRA, 0); +#else + int rt1 = allocate_64_register1((unsigned int *)dst->f.r.rt); + int rt2 = allocate_64_register2((unsigned int *)dst->f.r.rt); + int rd1 = allocate_64_register1_w((unsigned int *)dst->f.r.rd); + int rd2 = allocate_64_register2_w((unsigned int *)dst->f.r.rd); + + mov_reg32_reg32(rd1, rt1); + mov_reg32_reg32(rd2, rt2); + shrd_reg32_reg32_imm8(rd1, rd2, dst->f.r.sa); + sar_reg32_imm8(rd2, dst->f.r.sa); + if (dst->f.r.sa & 0x20) + { + mov_reg32_reg32(rd1, rd2); + sar_reg32_imm8(rd2, 31); + } +#endif +} + +void gendsll32(void) +{ +#ifdef INTERPRET_DSLL32 + gencallinterp((unsigned int)cached_interpreter_table.DSLL32, 0); +#else + int rt1 = allocate_64_register1((unsigned int *)dst->f.r.rt); + int rd1 = allocate_64_register1_w((unsigned int *)dst->f.r.rd); + int rd2 = allocate_64_register2_w((unsigned int *)dst->f.r.rd); + + mov_reg32_reg32(rd2, rt1); + shl_reg32_imm8(rd2, dst->f.r.sa); + xor_reg32_reg32(rd1, rd1); +#endif +} + +void gendsrl32(void) +{ +#ifdef INTERPRET_DSRL32 + gencallinterp((unsigned int)cached_interpreter_table.DSRL32, 0); +#else + int rt2 = allocate_64_register2((unsigned int *)dst->f.r.rt); + int rd1 = allocate_64_register1_w((unsigned int *)dst->f.r.rd); + int rd2 = allocate_64_register2_w((unsigned int *)dst->f.r.rd); + + mov_reg32_reg32(rd1, rt2); + shr_reg32_imm8(rd1, dst->f.r.sa); + xor_reg32_reg32(rd2, rd2); +#endif +} + +void gendsra32(void) +{ +#ifdef INTERPRET_DSRA32 + gencallinterp((unsigned int)cached_interpreter_table.DSRA32, 0); +#else + int rt2 = allocate_64_register2((unsigned int *)dst->f.r.rt); + int rd = allocate_register_w((unsigned int *)dst->f.r.rd); + + mov_reg32_reg32(rd, rt2); + sar_reg32_imm8(rd, dst->f.r.sa); +#endif +} +