/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - gspecial.c * * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * * Copyright (C) 2007 Richard Goedeken (Richard42) * * 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 "../recomph.h" #include "../recomp.h" #include "../r4300.h" #include "../ops.h" #include "../macros.h" #include "../exception.h" #if !defined(offsetof) # define offsetof(TYPE,MEMBER) ((unsigned int) &((TYPE*)0)->MEMBER) #endif void gensll(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[55]); #endif #ifdef INTERPRET_SLL gencallinterp((unsigned long long)SLL, 0); #else int rt = allocate_register_32((unsigned int *)dst->f.r.rt); int rd = allocate_register_32_w((unsigned int *)dst->f.r.rd); mov_reg32_reg32(rd, rt); shl_reg32_imm8(rd, dst->f.r.sa); #endif } void gensrl(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[56]); #endif #ifdef INTERPRET_SRL gencallinterp((unsigned long long)SRL, 0); #else int rt = allocate_register_32((unsigned int *)dst->f.r.rt); int rd = allocate_register_32_w((unsigned int *)dst->f.r.rd); mov_reg32_reg32(rd, rt); shr_reg32_imm8(rd, dst->f.r.sa); #endif } void gensra(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[57]); #endif #ifdef INTERPRET_SRA gencallinterp((unsigned long long)SRA, 0); #else int rt = allocate_register_32((unsigned int *)dst->f.r.rt); int rd = allocate_register_32_w((unsigned int *)dst->f.r.rd); mov_reg32_reg32(rd, rt); sar_reg32_imm8(rd, dst->f.r.sa); #endif } void gensllv(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[58]); #endif #ifdef INTERPRET_SLLV gencallinterp((unsigned long long)SLLV, 0); #else int rt, rd; allocate_register_32_manually(ECX, (unsigned int *)dst->f.r.rs); rt = allocate_register_32((unsigned int *)dst->f.r.rt); rd = allocate_register_32_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) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[59]); #endif #ifdef INTERPRET_SRLV gencallinterp((unsigned long long)SRLV, 0); #else int rt, rd; allocate_register_32_manually(ECX, (unsigned int *)dst->f.r.rs); rt = allocate_register_32((unsigned int *)dst->f.r.rt); rd = allocate_register_32_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) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[60]); #endif #ifdef INTERPRET_SRAV gencallinterp((unsigned long long)SRAV, 0); #else int rt, rd; allocate_register_32_manually(ECX, (unsigned int *)dst->f.r.rs); rt = allocate_register_32((unsigned int *)dst->f.r.rt); rd = allocate_register_32_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) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[61]); #endif #ifdef INTERPRET_JR gencallinterp((unsigned long long)JR, 1); #else static unsigned int precomp_instr_size = sizeof(precomp_instr); unsigned int diff = (unsigned int) offsetof(precomp_instr, local_addr); unsigned int diff_need = (unsigned int) offsetof(precomp_instr, reg_cache_infos.need_map); unsigned int diff_wrap = (unsigned int) offsetof(precomp_instr, reg_cache_infos.jump_wrapper); unsigned int temp, temp2; if (((dst->addr & 0xFFF) == 0xFFC && (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) { gencallinterp((unsigned long long)JR, 1); return; } free_registers_move_start(); mov_reg32_m32abs(EAX, (unsigned int *)dst->f.i.rs); mov_m32abs_reg32((unsigned int *)&local_rs, EAX); gendelayslot(); mov_reg32_m32abs(EAX, (unsigned int *)&local_rs); mov_m32abs_reg32((unsigned int *)&last_addr, EAX); gencheck_interupt_reg(); mov_reg32_m32abs(EAX, (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_m32abs_reg32(&jump_to_address, EBX); mov_reg64_imm64(RAX, (unsigned long long) (dst+1)); mov_m64abs_reg64((unsigned long long *)(&PC), RAX); mov_reg64_imm64(RAX, (unsigned long long) jump_to_func); call_reg64(RAX); /* will never return from call */ jump_end_rel32(); mov_reg64_imm64(RSI, (unsigned long long) dst_block->block); mov_reg32_reg32(EAX, EBX); sub_eax_imm32(dst_block->start); shr_reg32_imm8(EAX, 2); mul_m32abs((unsigned int *)(&precomp_instr_size)); mov_reg32_preg64preg64pimm32(EBX, RAX, RSI, diff_need); cmp_reg32_imm32(EBX, 1); jne_rj(11); add_reg32_imm32(EAX, diff_wrap); // 6 add_reg64_reg64(RAX, RSI); // 3 jmp_reg64(RAX); // 2 mov_reg32_preg64preg64pimm32(EBX, RAX, RSI, diff); mov_rax_memoffs64((unsigned long long *) &dst_block->code); add_reg64_reg64(RAX, RBX); jmp_reg64(RAX); #endif } void genjalr(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[62]); #endif #ifdef INTERPRET_JALR gencallinterp((unsigned long long)JALR, 0); #else static unsigned int precomp_instr_size = sizeof(precomp_instr); unsigned int diff = (unsigned int) offsetof(precomp_instr, local_addr); unsigned int diff_need = (unsigned int) offsetof(precomp_instr, reg_cache_infos.need_map); unsigned int diff_wrap = (unsigned int) offsetof(precomp_instr, reg_cache_infos.jump_wrapper); if (((dst->addr & 0xFFF) == 0xFFC && (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) { gencallinterp((unsigned long long)JALR, 1); return; } free_registers_move_start(); mov_reg32_m32abs(EAX, (unsigned int *)dst->f.r.rs); mov_m32abs_reg32((unsigned int *)&local_rs, EAX); gendelayslot(); mov_m32abs_imm32((unsigned int *)(dst-1)->f.r.rd, dst->addr+4); if ((dst->addr+4) & 0x80000000) mov_m32abs_imm32(((unsigned int *)(dst-1)->f.r.rd)+1, 0xFFFFFFFF); else mov_m32abs_imm32(((unsigned int *)(dst-1)->f.r.rd)+1, 0); mov_reg32_m32abs(EAX, (unsigned int *)&local_rs); mov_m32abs_reg32((unsigned int *)&last_addr, EAX); gencheck_interupt_reg(); mov_reg32_m32abs(EAX, (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_m32abs_reg32(&jump_to_address, EBX); mov_reg64_imm64(RAX, (unsigned long long) (dst+1)); mov_m64abs_reg64((unsigned long long *)(&PC), RAX); mov_reg64_imm64(RAX, (unsigned long long) jump_to_func); call_reg64(RAX); /* will never return from call */ jump_end_rel32(); mov_reg64_imm64(RSI, (unsigned long long) dst_block->block); mov_reg32_reg32(EAX, EBX); sub_eax_imm32(dst_block->start); shr_reg32_imm8(EAX, 2); mul_m32abs((unsigned int *)(&precomp_instr_size)); mov_reg32_preg64preg64pimm32(EBX, RAX, RSI, diff_need); cmp_reg32_imm32(EBX, 1); jne_rj(11); add_reg32_imm32(EAX, diff_wrap); // 6 add_reg64_reg64(RAX, RSI); // 3 jmp_reg64(RAX); // 2 mov_reg32_preg64preg64pimm32(EBX, RAX, RSI, diff); mov_rax_memoffs64((unsigned long long *) &dst_block->code); add_reg64_reg64(RAX, RBX); jmp_reg64(RAX); #endif } void gensyscall(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[63]); #endif #ifdef INTERPRET_SYSCALL gencallinterp((unsigned long long)SYSCALL, 0); #else free_registers_move_start(); mov_m32abs_imm32(&Cause, 8 << 2); gencallinterp((unsigned long long)exception_general, 0); #endif } void gensync(void) { } void genmfhi(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[64]); #endif #ifdef INTERPRET_MFHI gencallinterp((unsigned long long)MFHI, 0); #else int rd = allocate_register_64_w((unsigned long long *) dst->f.r.rd); int _hi = allocate_register_64((unsigned long long *) &hi); mov_reg64_reg64(rd, _hi); #endif } void genmthi(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[65]); #endif #ifdef INTERPRET_MTHI gencallinterp((unsigned long long)MTHI, 0); #else int _hi = allocate_register_64_w((unsigned long long *) &hi); int rs = allocate_register_64((unsigned long long *) dst->f.r.rs); mov_reg64_reg64(_hi, rs); #endif } void genmflo(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[66]); #endif #ifdef INTERPRET_MFLO gencallinterp((unsigned long long)MFLO, 0); #else int rd = allocate_register_64_w((unsigned long long *) dst->f.r.rd); int _lo = allocate_register_64((unsigned long long *) &lo); mov_reg64_reg64(rd, _lo); #endif } void genmtlo(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[67]); #endif #ifdef INTERPRET_MTLO gencallinterp((unsigned long long)MTLO, 0); #else int _lo = allocate_register_64_w((unsigned long long *)&lo); int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); mov_reg64_reg64(_lo, rs); #endif } void gendsllv(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[68]); #endif #ifdef INTERPRET_DSLLV gencallinterp((unsigned long long)DSLLV, 0); #else int rt, rd; allocate_register_32_manually(ECX, (unsigned int *)dst->f.r.rs); rt = allocate_register_64((unsigned long long *)dst->f.r.rt); rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); if (rd != ECX) { mov_reg64_reg64(rd, rt); shl_reg64_cl(rd); } else { int temp; temp = lru_register(); free_register(temp); mov_reg64_reg64(temp, rt); shl_reg64_cl(temp); mov_reg64_reg64(rd, temp); } #endif } void gendsrlv(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[69]); #endif #ifdef INTERPRET_DSRLV gencallinterp((unsigned long long)DSRLV, 0); #else int rt, rd; allocate_register_32_manually(ECX, (unsigned int *)dst->f.r.rs); rt = allocate_register_64((unsigned long long *)dst->f.r.rt); rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); if (rd != ECX) { mov_reg64_reg64(rd, rt); shr_reg64_cl(rd); } else { int temp; temp = lru_register(); free_register(temp); mov_reg64_reg64(temp, rt); shr_reg64_cl(temp); mov_reg64_reg64(rd, temp); } #endif } void gendsrav(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[70]); #endif #ifdef INTERPRET_DSRAV gencallinterp((unsigned long long)DSRAV, 0); #else int rt, rd; allocate_register_32_manually(ECX, (unsigned int *)dst->f.r.rs); rt = allocate_register_64((unsigned long long *)dst->f.r.rt); rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); if (rd != ECX) { mov_reg64_reg64(rd, rt); sar_reg64_cl(rd); } else { int temp; temp = lru_register(); free_register(temp); mov_reg64_reg64(temp, rt); sar_reg64_cl(temp); mov_reg64_reg64(rd, temp); } #endif } void genmult(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[71]); #endif #ifdef INTERPRET_MULT gencallinterp((unsigned long long)MULT, 0); #else int rs, rt; allocate_register_32_manually_w(EAX, (unsigned int *)&lo); /* these must be done first so they are not assigned by allocate_register() */ allocate_register_32_manually_w(EDX, (unsigned int *)&hi); rs = allocate_register_32((unsigned int*)dst->f.r.rs); rt = allocate_register_32((unsigned int*)dst->f.r.rt); mov_reg32_reg32(EAX, rs); imul_reg32(rt); #endif } void genmultu(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[72]); #endif #ifdef INTERPRET_MULTU gencallinterp((unsigned long long)MULTU, 0); #else int rs, rt; allocate_register_32_manually_w(EAX, (unsigned int *)&lo); allocate_register_32_manually_w(EDX, (unsigned int *)&hi); rs = allocate_register_32((unsigned int*)dst->f.r.rs); rt = allocate_register_32((unsigned int*)dst->f.r.rt); mov_reg32_reg32(EAX, rs); mul_reg32(rt); #endif } void gendiv(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[73]); #endif #ifdef INTERPRET_DIV gencallinterp((unsigned long long)DIV, 0); #else int rs, rt; allocate_register_32_manually_w(EAX, (unsigned int *)&lo); allocate_register_32_manually_w(EDX, (unsigned int *)&hi); rs = allocate_register_32((unsigned int*)dst->f.r.rs); rt = allocate_register_32((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) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[74]); #endif #ifdef INTERPRET_DIVU gencallinterp((unsigned long long)DIVU, 0); #else int rs, rt; allocate_register_32_manually_w(EAX, (unsigned int *)&lo); allocate_register_32_manually_w(EDX, (unsigned int *)&hi); rs = allocate_register_32((unsigned int*)dst->f.r.rs); rt = allocate_register_32((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) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[75]); #endif gencallinterp((unsigned long long)DMULT, 0); } void gendmultu(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[76]); #endif #ifdef INTERPRET_DMULTU gencallinterp((unsigned long long)DMULTU, 0); #else free_registers_move_start(); mov_reg64_m64abs(RAX, (unsigned long long *) dst->f.r.rs); mov_reg64_m64abs(RDX, (unsigned long long *) dst->f.r.rt); mul_reg64(RDX); mov_m64abs_reg64((unsigned long long *) &lo, RAX); mov_m64abs_reg64((unsigned long long *) &hi, RDX); #endif } void genddiv(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[77]); #endif gencallinterp((unsigned long long)DDIV, 0); } void genddivu(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[78]); #endif gencallinterp((unsigned long long)DDIVU, 0); } void genadd(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[79]); #endif #ifdef INTERPRET_ADD gencallinterp((unsigned long long)ADD, 0); #else int rs = allocate_register_32((unsigned int *)dst->f.r.rs); int rt = allocate_register_32((unsigned int *)dst->f.r.rt); int rd = allocate_register_32_w((unsigned int *)dst->f.r.rd); if (rs == rd) add_reg32_reg32(rd, rt); else if (rt == rd) add_reg32_reg32(rd, rs); else { mov_reg32_reg32(rd, rs); add_reg32_reg32(rd, rt); } #endif } void genaddu(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[80]); #endif #ifdef INTERPRET_ADDU gencallinterp((unsigned long long)ADDU, 0); #else int rs = allocate_register_32((unsigned int *)dst->f.r.rs); int rt = allocate_register_32((unsigned int *)dst->f.r.rt); int rd = allocate_register_32_w((unsigned int *)dst->f.r.rd); if (rs == rd) add_reg32_reg32(rd, rt); else if (rt == rd) add_reg32_reg32(rd, rs); else { mov_reg32_reg32(rd, rs); add_reg32_reg32(rd, rt); } #endif } void gensub(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[81]); #endif #ifdef INTERPRET_SUB gencallinterp((unsigned long long)SUB, 0); #else int rs = allocate_register_32((unsigned int *)dst->f.r.rs); int rt = allocate_register_32((unsigned int *)dst->f.r.rt); int rd = allocate_register_32_w((unsigned int *)dst->f.r.rd); if (rs == rd) sub_reg32_reg32(rd, rt); else if (rt == rd) { neg_reg32(rd); add_reg32_reg32(rd, rs); } else { mov_reg32_reg32(rd, rs); sub_reg32_reg32(rd, rt); } #endif } void gensubu(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[82]); #endif #ifdef INTERPRET_SUBU gencallinterp((unsigned long long)SUBU, 0); #else int rs = allocate_register_32((unsigned int *)dst->f.r.rs); int rt = allocate_register_32((unsigned int *)dst->f.r.rt); int rd = allocate_register_32_w((unsigned int *)dst->f.r.rd); if (rs == rd) sub_reg32_reg32(rd, rt); else if (rt == rd) { neg_reg32(rd); add_reg32_reg32(rd, rs); } else { mov_reg32_reg32(rd, rs); sub_reg32_reg32(rd, rt); } #endif } void genand(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[83]); #endif #ifdef INTERPRET_AND gencallinterp((unsigned long long)AND, 0); #else int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); if (rs == rd) and_reg64_reg64(rd, rt); else if (rt == rd) and_reg64_reg64(rd, rs); else { mov_reg64_reg64(rd, rs); and_reg64_reg64(rd, rt); } #endif } void genor(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[84]); #endif #ifdef INTERPRET_OR gencallinterp((unsigned long long)OR, 0); #else int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); if (rs == rd) or_reg64_reg64(rd, rt); else if (rt == rd) or_reg64_reg64(rd, rs); else { mov_reg64_reg64(rd, rs); or_reg64_reg64(rd, rt); } #endif } void genxor(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[85]); #endif #ifdef INTERPRET_XOR gencallinterp((unsigned long long)XOR, 0); #else int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); if (rs == rd) xor_reg64_reg64(rd, rt); else if (rt == rd) xor_reg64_reg64(rd, rs); else { mov_reg64_reg64(rd, rs); xor_reg64_reg64(rd, rt); } #endif } void gennor(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[86]); #endif #ifdef INTERPRET_NOR gencallinterp((unsigned long long)NOR, 0); #else int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); if (rs == rd) { or_reg64_reg64(rd, rt); not_reg64(rd); } else if (rt == rd) { or_reg64_reg64(rd, rs); not_reg64(rd); } else { mov_reg64_reg64(rd, rs); or_reg64_reg64(rd, rt); not_reg64(rd); } #endif } void genslt(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[87]); #endif #ifdef INTERPRET_SLT gencallinterp((unsigned long long)SLT, 0); #else int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); cmp_reg64_reg64(rs, rt); setl_reg8(rd); and_reg64_imm8(rd, 1); #endif } void gensltu(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[88]); #endif #ifdef INTERPRET_SLTU gencallinterp((unsigned long long)SLTU, 0); #else int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); cmp_reg64_reg64(rs, rt); setb_reg8(rd); and_reg64_imm8(rd, 1); #endif } void gendadd(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[89]); #endif #ifdef INTERPRET_DADD gencallinterp((unsigned long long)DADD, 0); #else int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); if (rs == rd) add_reg64_reg64(rd, rt); else if (rt == rd) add_reg64_reg64(rd, rs); else { mov_reg64_reg64(rd, rs); add_reg64_reg64(rd, rt); } #endif } void gendaddu(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[90]); #endif #ifdef INTERPRET_DADDU gencallinterp((unsigned long long)DADDU, 0); #else int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); if (rs == rd) add_reg64_reg64(rd, rt); else if (rt == rd) add_reg64_reg64(rd, rs); else { mov_reg64_reg64(rd, rs); add_reg64_reg64(rd, rt); } #endif } void gendsub(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[91]); #endif #ifdef INTERPRET_DSUB gencallinterp((unsigned long long)DSUB, 0); #else int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); if (rs == rd) sub_reg64_reg64(rd, rt); else if (rt == rd) { neg_reg64(rd); add_reg64_reg64(rd, rs); } else { mov_reg64_reg64(rd, rs); sub_reg64_reg64(rd, rt); } #endif } void gendsubu(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[92]); #endif #ifdef INTERPRET_DSUBU gencallinterp((unsigned long long)DSUBU, 0); #else int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); if (rs == rd) sub_reg64_reg64(rd, rt); else if (rt == rd) { neg_reg64(rd); add_reg64_reg64(rd, rs); } else { mov_reg64_reg64(rd, rs); sub_reg64_reg64(rd, rt); } #endif } void genteq(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[96]); #endif gencallinterp((unsigned long long)TEQ, 0); } void gendsll(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[93]); #endif #ifdef INTERPRET_DSLL gencallinterp((unsigned long long)DSLL, 0); #else int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); mov_reg64_reg64(rd, rt); shl_reg64_imm8(rd, dst->f.r.sa); #endif } void gendsrl(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[94]); #endif #ifdef INTERPRET_DSRL gencallinterp((unsigned long long)DSRL, 0); #else int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); mov_reg64_reg64(rd, rt); shr_reg64_imm8(rd, dst->f.r.sa); #endif } void gendsra(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[95]); #endif #ifdef INTERPRET_DSRA gencallinterp((unsigned long long)DSRA, 0); #else int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); mov_reg64_reg64(rd, rt); sar_reg64_imm8(rd, dst->f.r.sa); #endif } void gendsll32(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[97]); #endif #ifdef INTERPRET_DSLL32 gencallinterp((unsigned long long)DSLL32, 0); #else int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); mov_reg64_reg64(rd, rt); shl_reg64_imm8(rd, dst->f.r.sa + 32); #endif } void gendsrl32(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[98]); #endif #ifdef INTERPRET_DSRL32 gencallinterp((unsigned long long)DSRL32, 0); #else int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); mov_reg64_reg64(rd, rt); shr_reg64_imm8(rd, dst->f.r.sa + 32); #endif } void gendsra32(void) { #if defined(COUNT_INSTR) inc_m32abs(&instr_count[99]); #endif #ifdef INTERPRET_DSRA32 gencallinterp((unsigned long long)DSRA32, 0); #else int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); mov_reg64_reg64(rd, rt); sar_reg64_imm8(rd, dst->f.r.sa + 32); #endif }