mupen64plus-oldsvn/r4300/x86_64/gr4300.c

2285 lines
61 KiB
C

/**
* Mupen64 - r4300/x86_64/gr4300.c
* Copyright (C) 2007 Richard Goedeken, Hacktarux
* Based on code written by Hacktarux, Copyright (C) 2002
*
* Mupen64 homepage: http://mupen64.emulation64.com
* Forum homepage: http://www.emutalk.net/forumdisplay.php?f=50
*
* This program is free software; you can redistribute it and/
* or modify it under the terms of the GNU General Public Li-
* cence as published by the Free Software Foundation; either
* version 2 of the Licence, or any later version.
*
* This program is distributed in the hope that it will be use-
* ful, but WITHOUT ANY WARRANTY; without even the implied war-
* ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public Licence for more details.
*
* You should have received a copy of the GNU General Public
* Licence along with this program; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
* USA.
*
**/
#include "assemble.h"
#include "../r4300.h"
#include "../macros.h"
#include "../../memory/memory.h"
#include "../interupt.h"
#include "../ops.h"
#include "../recomph.h"
#include "regcache.h"
#include "../exception.h"
#include "interpret.h"
#if !defined(offsetof)
# define offsetof(TYPE,MEMBER) ((unsigned int) &((TYPE*)0)->MEMBER)
#endif
#if defined(COUNT_INSTR)
unsigned int instr_count[132];
char instr_name[][10] =
{
"reserved", "NI", "J", "JAL", "BEQ", "BNE", "BLEZ", "BGTZ",
"ADDI", "ADDIU", "SLTI", "SLTIU", "ANDI", "ORI", "XORI", "LUI",
"BEQL", "BNEL", "BLEZL", "BGTZL", "DADDI", "DADDIU", "LDL", "LDR",
"LB", "LH", "LW", "LWL", "LBU", "LHU", "LWU", "LWR",
"SB", "SH", "SW", "SWL", "SWR", "SDL", "SDR", "LWC1",
"LDC1", "LD", "LL", "SWC1", "SDC1", "SD", "SC", "BLTZ",
"BGEZ", "BLTZL", "BGEZL", "BLTZAL", "BGEZAL", "BLTZALL", "BGEZALL", "SLL",
"SRL", "SRA", "SLLV", "SRLV", "SRAV", "JR", "JALR", "SYSCALL",
"MFHI", "MTHI", "MFLO", "MTLO", "DSLLV", "DSRLV", "DSRAV", "MULT",
"MULTU", "DIV", "DIVU", "DMULT", "DMULTU", "DDIV", "DDIVU", "ADD",
"ADDU", "SUB", "SUBU", "AND", "OR", "XOR", "NOR", "SLT",
"SLTU", "DADD", "DADDU", "DSUB", "DSUBU", "DSLL", "DSRL", "DSRA",
"TEQ", "DSLL32", "DSRL32", "DSRA32", "BC1F", "BC1T", "BC1FL", "BC1TL",
"TLBWI", "TLBP", "TLBR", "TLBWR", "ERET", "MFC0", "MTC0", "MFC1",
"DMFC1", "CFC1", "MTC1", "DMTC1", "CTC1", "f.CVT", "f.CMP", "f.ADD",
"f.SUB", "f.MUL", "f.DIV", "f.SQRT", "f.ABS", "f.MOV", "f.NEG", "f.ROUND",
"f.TRUNC", "f.CEIL", "f.FLOOR"
};
unsigned int instr_type[131] = { 9, 10, 6, 6, 7, 7, 7, 7, 3, 3, 4, 4, 3, 4, 4, 0,
7, 7, 7, 7, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 7,
7, 7, 7, 7, 7, 7, 7, 3, 3, 3, 3, 3, 3, 6, 6, 10,
2, 2, 2, 2, 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 3,
3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
8, 4, 4, 4, 7, 7, 7, 7, 10, 10, 10, 10, 8, 2, 2, 2,
2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 2, 5, 5,
5, 5, 5 };
char instr_typename[][20] = { "Load", "Store", "Data move/convert", "32-bit math", "64-bit math", "Float Math",
"Jump", "Branch", "Exceptions", "Reserved", "Other" };
#endif
extern unsigned int op;
precomp_instr fake_instr;
static long long debug_reg_storage[8];
int branch_taken = 0;
void gennotcompiled()
{
free_registers_move_start();
if (dst->addr == 0xa4000040)
{
sub_reg64_imm32(RSP, 0x18); // fixme why is this here, how does stack get re-adjusted?
mov_reg64_reg64(RAX, RSP);
sub_reg64_imm32(RAX, 8);
mov_memoffs64_rax((unsigned long long *)(&return_address));
}
mov_reg64_imm64(RAX, (unsigned long long) dst);
mov_memoffs64_rax((unsigned long long *) &PC); /* RIP-relative will not work here */
mov_reg64_imm64(RAX, (unsigned long long) NOTCOMPILED);
call_reg64(RAX);
}
void genlink_subblock()
{
free_all_registers();
jmp(dst->addr+4);
}
void gendebug()
{
free_all_registers();
mov_memoffs64_rax((unsigned long long *) &debug_reg_storage);
mov_reg64_imm64(RAX, (unsigned long long) &debug_reg_storage);
mov_preg64pimm8_reg64(RAX, 8, RBX);
mov_preg64pimm8_reg64(RAX, 16, RCX);
mov_preg64pimm8_reg64(RAX, 24, RDX);
mov_preg64pimm8_reg64(RAX, 32, RSP);
mov_preg64pimm8_reg64(RAX, 40, RBP);
mov_preg64pimm8_reg64(RAX, 48, RSI);
mov_preg64pimm8_reg64(RAX, 56, RDI);
mov_reg64_imm64(RAX, (unsigned long long) dst);
mov_memoffs64_rax((unsigned long long *) &PC);
mov_reg32_imm32(EAX, (unsigned int) src);
mov_memoffs32_eax((unsigned int *) &op);
mov_reg64_imm64(RAX, (unsigned long long) debug);
call_reg64(RAX);
mov_reg64_imm64(RAX, (unsigned long long) &debug_reg_storage);
mov_reg64_preg64pimm8(RDI, RAX, 56);
mov_reg64_preg64pimm8(RSI, RAX, 48);
mov_reg64_preg64pimm8(RBP, RAX, 40);
mov_reg64_preg64pimm8(RSP, RAX, 32);
mov_reg64_preg64pimm8(RDX, RAX, 24);
mov_reg64_preg64pimm8(RCX, RAX, 16);
mov_reg64_preg64pimm8(RBX, RAX, 8);
mov_reg64_preg64(RAX, RAX);
}
void gencallinterp(unsigned long addr, int jump)
{
free_registers_move_start();
if (jump)
mov_m32abs_imm32((unsigned int*)(&dyna_interp), 1);
mov_reg64_imm64(RAX, (unsigned long long) dst);
mov_m64abs_reg64((unsigned long long *)(&PC), RAX);
mov_reg64_imm64(RAX, addr);
call_reg64(RAX);
if (jump)
{
mov_m32abs_imm32((unsigned int*)(&dyna_interp), 0);
mov_reg64_imm64(RAX, (unsigned long long)dyna_jump);
call_reg64(RAX);
}
}
void genupdate_count(unsigned int addr)
{
#if !defined(COMPARE_CORE) && !defined(DBG)
mov_reg32_imm32(EAX, addr);
sub_reg32_m32abs(EAX, (unsigned int*)(&last_addr));
shr_reg32_imm8(EAX, 1);
add_m32abs_reg32((unsigned int*)(&Count), EAX);
#else
mov_reg64_imm64(RAX, (unsigned long long) (dst+1));
mov_m64abs_reg64((unsigned long long *)(&PC), RAX);
mov_reg64_imm64(RAX, (unsigned long long)update_count);
call_reg64(RAX);
#endif
}
void gendelayslot()
{
mov_m32abs_imm32((void*)(&delay_slot), 1);
recompile_opcode();
free_all_registers();
genupdate_count(dst->addr+4);
mov_m32abs_imm32((void*)(&delay_slot), 0);
}
void genni()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[1]);
#endif
#ifdef EMU64_DEBUG
gencallinterp((unsigned long long)NI, 0);
#endif
}
void genreserved()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[0]);
#endif
#ifdef EMU64_DEBUG
gencallinterp((unsigned long long)RESERVED, 0);
#endif
}
void genfin_block()
{
gencallinterp((unsigned long long)FIN_BLOCK, 0);
}
void gencheck_interupt(unsigned long long instr_structure)
{
mov_reg32_m32abs(EAX, (void*)(&next_interupt));
cmp_reg32_m32abs(EAX, (void*)&Count);
ja_rj(0);
jump_start_rel8();
mov_reg64_imm64(RAX, (unsigned long long) instr_structure);
mov_m64abs_reg64((unsigned long long *)(&PC), RAX);
mov_reg64_imm64(RAX, (unsigned long long) gen_interupt);
call_reg64(RAX);
jump_end_rel8();
}
void gencheck_interupt_out(unsigned int addr)
{
mov_reg32_m32abs(EAX, (void*)(&next_interupt));
cmp_reg32_m32abs(EAX, (void*)&Count);
ja_rj(0);
jump_start_rel8();
mov_m32abs_imm32((unsigned int*)(&fake_instr.addr), addr);
mov_reg64_imm64(RAX, (unsigned long long) (&fake_instr));
mov_m64abs_reg64((unsigned long long *)(&PC), RAX);
mov_reg64_imm64(RAX, (unsigned long long) gen_interupt);
call_reg64(RAX);
jump_end_rel8();
}
void gencheck_interupt_reg() // addr is in EAX
{
mov_reg32_m32abs(EBX, (void*)&next_interupt);
cmp_reg32_m32abs(EBX, (void*)&Count);
ja_rj(0);
jump_start_rel8();
mov_m32abs_reg32((unsigned int*)(&fake_instr.addr), EAX);
mov_reg64_imm64(RAX, (unsigned long long) (&fake_instr));
mov_m64abs_reg64((unsigned long long *)(&PC), RAX);
mov_reg64_imm64(RAX, (unsigned long long) gen_interupt);
call_reg64(RAX);
jump_end_rel8();
}
void gennop()
{
}
void genj()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[2]);
#endif
#ifdef INTERPRET_J
gencallinterp((unsigned long long)J, 1);
#else
unsigned int naddr;
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)J, 1);
return;
}
gendelayslot();
naddr = ((dst-1)->f.j.inst_index<<2) | (dst->addr & 0xF0000000);
mov_m32abs_imm32((void*)(&last_addr), naddr);
gencheck_interupt((unsigned long long) &actual->block[(naddr-actual->start)/4]);
jmp(naddr);
#endif
}
void genj_out()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[2]);
#endif
#ifdef INTERPRET_J_OUT
gencallinterp((unsigned long long)J_OUT, 1);
#else
unsigned int naddr;
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)J_OUT, 1);
return;
}
gendelayslot();
naddr = ((dst-1)->f.j.inst_index<<2) | (dst->addr & 0xF0000000);
mov_m32abs_imm32((void*)(&last_addr), naddr);
gencheck_interupt_out(naddr);
mov_m32abs_imm32(&jump_to_address, naddr);
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);
#endif
}
void genj_idle()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[2]);
#endif
#ifdef INTERPRET_J_IDLE
gencallinterp((unsigned long long)J_IDLE, 1);
#else
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)J_IDLE, 1);
return;
}
mov_reg32_m32abs(EAX, (unsigned int *)(&next_interupt));
sub_reg32_m32abs(EAX, (unsigned int *)(&Count));
cmp_reg32_imm8(EAX, 3);
jbe_rj(11);
and_eax_imm32(0xFFFFFFFC);
add_m32abs_reg32((unsigned int *)(&Count), EAX);
genj();
#endif
}
void genjal()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[3]);
#endif
#ifdef INTERPRET_JAL
gencallinterp((unsigned long long)JAL, 1);
#else
unsigned int naddr;
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)JAL, 1);
return;
}
gendelayslot();
mov_m32abs_imm32((unsigned int *)(reg + 31), dst->addr + 4);
if (((dst->addr + 4) & 0x80000000))
mov_m32abs_imm32((unsigned int *)(&reg[31])+1, 0xFFFFFFFF);
else
mov_m32abs_imm32((unsigned int *)(&reg[31])+1, 0);
naddr = ((dst-1)->f.j.inst_index<<2) | (dst->addr & 0xF0000000);
mov_m32abs_imm32((void*)(&last_addr), naddr);
gencheck_interupt((unsigned long long) &actual->block[(naddr-actual->start)/4]);
jmp(naddr);
#endif
}
void genjal_out()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[3]);
#endif
#ifdef INTERPRET_JAL_OUT
gencallinterp((unsigned long long)JAL_OUT, 1);
#else
unsigned int naddr;
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)JAL_OUT, 1);
return;
}
gendelayslot();
mov_m32abs_imm32((unsigned int *)(reg + 31), dst->addr + 4);
if (((dst->addr + 4) & 0x80000000))
mov_m32abs_imm32((unsigned int *)(&reg[31])+1, 0xFFFFFFFF);
else
mov_m32abs_imm32((unsigned int *)(&reg[31])+1, 0);
naddr = ((dst-1)->f.j.inst_index<<2) | (dst->addr & 0xF0000000);
mov_m32abs_imm32((void*)(&last_addr), naddr);
gencheck_interupt_out(naddr);
mov_m32abs_imm32(&jump_to_address, naddr);
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);
#endif
}
void genjal_idle()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[3]);
#endif
#ifdef INTERPRET_JAL_IDLE
gencallinterp((unsigned long long)JAL_IDLE, 1);
#else
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)JAL_IDLE, 1);
return;
}
mov_reg32_m32abs(EAX, (unsigned int *)(&next_interupt));
sub_reg32_m32abs(EAX, (unsigned int *)(&Count));
cmp_reg32_imm8(EAX, 3);
jbe_rj(11);
and_eax_imm32(0xFFFFFFFC);
add_m32abs_reg32((unsigned int *)(&Count), EAX);
genjal();
#endif
}
void genbeq_test()
{
int rs_64bit = is64((unsigned int *)dst->f.i.rs);
int rt_64bit = is64((unsigned int *)dst->f.i.rt);
if (rs_64bit == 0 && rt_64bit == 0)
{
int rs = allocate_register_32((unsigned int *)dst->f.i.rs);
int rt = allocate_register_32((unsigned int *)dst->f.i.rt);
cmp_reg32_reg32(rs, rt);
sete_m8abs((unsigned char *) &branch_taken);
}
else if (rs_64bit == -1)
{
int rt = allocate_register_64((unsigned long long *)dst->f.i.rt);
cmp_reg64_m64abs(rt, (unsigned long long *) dst->f.i.rs);
sete_m8abs((unsigned char *) &branch_taken);
}
else if (rt_64bit == -1)
{
int rs = allocate_register_64((unsigned long long *)dst->f.i.rs);
cmp_reg64_m64abs(rs, (unsigned long long *)dst->f.i.rt);
sete_m8abs((unsigned char *) &branch_taken);
}
else
{
int rs = allocate_register_64((unsigned long long *)dst->f.i.rs);
int rt = allocate_register_64((unsigned long long *)dst->f.i.rt);
cmp_reg64_reg64(rs, rt);
sete_m8abs((unsigned char *) &branch_taken);
}
}
void gentest()
{
cmp_m32abs_imm32((unsigned int *)(&branch_taken), 0);
je_near_rj(0);
jump_start_rel32();
mov_m32abs_imm32((void*)(&last_addr), dst->addr + (dst-1)->f.i.immediate*4);
gencheck_interupt((unsigned long long) (dst + (dst-1)->f.i.immediate));
jmp(dst->addr + (dst-1)->f.i.immediate*4);
jump_end_rel32();
mov_m32abs_imm32((void*)(&last_addr), dst->addr + 4);
gencheck_interupt((unsigned long long)(dst + 1));
jmp(dst->addr + 4);
}
void genbeq()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[4]);
#endif
#ifdef INTERPRET_BEQ
gencallinterp((unsigned long long)BEQ, 1);
#else
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)BEQ, 1);
return;
}
genbeq_test();
gendelayslot();
gentest();
#endif
}
void gentest_out()
{
cmp_m32abs_imm32((unsigned int *)(&branch_taken), 0);
je_near_rj(0);
jump_start_rel32();
mov_m32abs_imm32((void*)(&last_addr), dst->addr + (dst-1)->f.i.immediate*4);
gencheck_interupt_out(dst->addr + (dst-1)->f.i.immediate*4);
mov_m32abs_imm32(&jump_to_address, dst->addr + (dst-1)->f.i.immediate*4);
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);
jump_end_rel32();
mov_m32abs_imm32((void*)(&last_addr), dst->addr + 4);
gencheck_interupt((unsigned long long) (dst + 1));
jmp(dst->addr + 4);
}
void genbeq_out()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[4]);
#endif
#ifdef INTERPRET_BEQ_OUT
gencallinterp((unsigned long long)BEQ_OUT, 1);
#else
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)BEQ_OUT, 1);
return;
}
genbeq_test();
gendelayslot();
gentest_out();
#endif
}
void gentest_idle()
{
int reg;
reg = lru_register();
free_register(reg);
cmp_m32abs_imm32((unsigned int *)(&branch_taken), 0);
je_near_rj(0);
jump_start_rel32();
mov_reg32_m32abs(reg, (unsigned int *)(&next_interupt));
sub_reg32_m32abs(reg, (unsigned int *)(&Count));
cmp_reg32_imm8(reg, 3);
jbe_rj(0);
jump_start_rel8();
and_reg32_imm32(reg, 0xFFFFFFFC);
add_m32abs_reg32((unsigned int *)(&Count), reg);
jump_end_rel8();
jump_end_rel32();
}
void genbeq_idle()
{
#ifdef INTERPRET_BEQ_IDLE
gencallinterp((unsigned long long)BEQ_IDLE, 1);
#else
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)BEQ_IDLE, 1);
return;
}
genbeq_test();
gentest_idle();
genbeq();
#endif
}
void genbne_test()
{
int rs_64bit = is64((unsigned int *)dst->f.i.rs);
int rt_64bit = is64((unsigned int *)dst->f.i.rt);
if (rs_64bit == 0 && rt_64bit == 0)
{
int rs = allocate_register_32((unsigned int *)dst->f.i.rs);
int rt = allocate_register_32((unsigned int *)dst->f.i.rt);
cmp_reg32_reg32(rs, rt);
setne_m8abs((unsigned char *) &branch_taken);
}
else if (rs_64bit == -1)
{
int rt = allocate_register_64((unsigned long long *) dst->f.i.rt);
cmp_reg64_m64abs(rt, (unsigned long long *)dst->f.i.rs);
setne_m8abs((unsigned char *) &branch_taken);
}
else if (rt_64bit == -1)
{
int rs = allocate_register_64((unsigned long long *) dst->f.i.rs);
cmp_reg64_m64abs(rs, (unsigned long long *)dst->f.i.rt);
setne_m8abs((unsigned char *) &branch_taken);
}
else
{
int rs = allocate_register_64((unsigned long long *)dst->f.i.rs);
int rt = allocate_register_64((unsigned long long *)dst->f.i.rt);
cmp_reg64_reg64(rs, rt);
setne_m8abs((unsigned char *) &branch_taken);
}
}
void genbne()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[5]);
#endif
#ifdef INTERPRET_BNE
gencallinterp((unsigned long long)BNE, 1);
#else
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)BNE, 1);
return;
}
genbne_test();
gendelayslot();
gentest();
#endif
}
void genbne_out()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[5]);
#endif
#ifdef INTERPRET_BNE_OUT
gencallinterp((unsigned long long)BNE_OUT, 1);
#else
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)BNE_OUT, 1);
return;
}
genbne_test();
gendelayslot();
gentest_out();
#endif
}
void genbne_idle()
{
#ifdef INTERPRET_BNE_IDLE
gencallinterp((unsigned long long)BNE_IDLE, 1);
#else
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)BNE_IDLE, 1);
return;
}
genbne_test();
gentest_idle();
genbne();
#endif
}
void genblez_test()
{
int rs_64bit = is64((unsigned int *)dst->f.i.rs);
if (rs_64bit == 0)
{
int rs = allocate_register_32((unsigned int *)dst->f.i.rs);
cmp_reg32_imm32(rs, 0);
setle_m8abs((unsigned char *) &branch_taken);
}
else
{
int rs = allocate_register_64((unsigned long long *)dst->f.i.rs);
cmp_reg64_imm8(rs, 0);
setle_m8abs((unsigned char *) &branch_taken);
}
}
void genblez()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[6]);
#endif
#ifdef INTERPRET_BLEZ
gencallinterp((unsigned long long)BLEZ, 1);
#else
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)BLEZ, 1);
return;
}
genblez_test();
gendelayslot();
gentest();
#endif
}
void genblez_out()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[6]);
#endif
#ifdef INTERPRET_BLEZ_OUT
gencallinterp((unsigned long long)BLEZ_OUT, 1);
#else
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)BLEZ_OUT, 1);
return;
}
genblez_test();
gendelayslot();
gentest_out();
#endif
}
void genblez_idle()
{
#ifdef INTERPRET_BLEZ_IDLE
gencallinterp((unsigned long long)BLEZ_IDLE, 1);
#else
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)BLEZ_IDLE, 1);
return;
}
genblez_test();
gentest_idle();
genblez();
#endif
}
void genbgtz_test()
{
int rs_64bit = is64((unsigned int *)dst->f.i.rs);
if (rs_64bit == 0)
{
int rs = allocate_register_32((unsigned int *)dst->f.i.rs);
cmp_reg32_imm32(rs, 0);
setg_m8abs((unsigned char *) &branch_taken);
}
else
{
int rs = allocate_register_64((unsigned long long *)dst->f.i.rs);
cmp_reg64_imm8(rs, 0);
setg_m8abs((unsigned char *) &branch_taken);
}
}
void genbgtz()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[7]);
#endif
#ifdef INTERPRET_BGTZ
gencallinterp((unsigned long long)BGTZ, 1);
#else
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)BGTZ, 1);
return;
}
genbgtz_test();
gendelayslot();
gentest();
#endif
}
void genbgtz_out()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[7]);
#endif
#ifdef INTERPRET_BGTZ_OUT
gencallinterp((unsigned long long)BGTZ_OUT, 1);
#else
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)BGTZ_OUT, 1);
return;
}
genbgtz_test();
gendelayslot();
gentest_out();
#endif
}
void genbgtz_idle()
{
#ifdef INTERPRET_BGTZ_IDLE
gencallinterp((unsigned long long)BGTZ_IDLE, 1);
#else
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)BGTZ_IDLE, 1);
return;
}
genbgtz_test();
gentest_idle();
genbgtz();
#endif
}
void genaddi()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[8]);
#endif
#ifdef INTERPRET_ADDI
gencallinterp((unsigned long long)ADDI, 0);
#else
int rs = allocate_register_32((unsigned int *)dst->f.i.rs);
int rt = allocate_register_32_w((unsigned int *)dst->f.i.rt);
mov_reg32_reg32(rt, rs);
add_reg32_imm32(rt,(int)dst->f.i.immediate);
#endif
}
void genaddiu()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[9]);
#endif
#ifdef INTERPRET_ADDIU
gencallinterp((unsigned long long)ADDIU, 0);
#else
int rs = allocate_register_32((unsigned int *)dst->f.i.rs);
int rt = allocate_register_32_w((unsigned int *)dst->f.i.rt);
mov_reg32_reg32(rt, rs);
add_reg32_imm32(rt,(int)dst->f.i.immediate);
#endif
}
void genslti()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[10]);
#endif
#ifdef INTERPRET_SLTI
gencallinterp((unsigned long long)SLTI, 0);
#else
int rs = allocate_register_64((unsigned long long *) dst->f.i.rs);
int rt = allocate_register_64_w((unsigned long long *) dst->f.i.rt);
int imm = (int) dst->f.i.immediate;
cmp_reg64_imm32(rs, imm);
setl_reg8(rt);
and_reg64_imm8(rt, 1);
#endif
}
void gensltiu()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[11]);
#endif
#ifdef INTERPRET_SLTIU
gencallinterp((unsigned long long)SLTIU, 0);
#else
int rs = allocate_register_64((unsigned long long *)dst->f.i.rs);
int rt = allocate_register_64_w((unsigned long long *)dst->f.i.rt);
int imm = (int) dst->f.i.immediate;
cmp_reg64_imm32(rs, imm);
setb_reg8(rt);
and_reg64_imm8(rt, 1);
#endif
}
void genandi()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[12]);
#endif
#ifdef INTERPRET_ANDI
gencallinterp((unsigned long long)ANDI, 0);
#else
int rs = allocate_register_64((unsigned long long *)dst->f.i.rs);
int rt = allocate_register_64_w((unsigned long long *)dst->f.i.rt);
mov_reg64_reg64(rt, rs);
and_reg64_imm32(rt, (unsigned short)dst->f.i.immediate);
#endif
}
void genori()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[13]);
#endif
#ifdef INTERPRET_ORI
gencallinterp((unsigned long long)ORI, 0);
#else
int rs = allocate_register_64((unsigned long long *) dst->f.i.rs);
int rt = allocate_register_64_w((unsigned long long *) dst->f.i.rt);
mov_reg64_reg64(rt, rs);
or_reg64_imm32(rt, (unsigned short)dst->f.i.immediate);
#endif
}
void genxori()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[14]);
#endif
#ifdef INTERPRET_XORI
gencallinterp((unsigned long long)XORI, 0);
#else
int rs = allocate_register_64((unsigned long long *)dst->f.i.rs);
int rt = allocate_register_64_w((unsigned long long *)dst->f.i.rt);
mov_reg64_reg64(rt, rs);
xor_reg64_imm32(rt, (unsigned short)dst->f.i.immediate);
#endif
}
void genlui()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[15]);
#endif
#ifdef INTERPRET_LUI
gencallinterp((unsigned long long)LUI, 0);
#else
int rt = allocate_register_32_w((unsigned int *)dst->f.i.rt);
mov_reg32_imm32(rt, (unsigned int)dst->f.i.immediate << 16);
#endif
}
void gentestl()
{
cmp_m32abs_imm32((unsigned int *)(&branch_taken), 0);
je_near_rj(0);
jump_start_rel32();
gendelayslot();
mov_m32abs_imm32((void*)(&last_addr), dst->addr + (dst-1)->f.i.immediate*4);
gencheck_interupt((unsigned long long) (dst + (dst-1)->f.i.immediate));
jmp(dst->addr + (dst-1)->f.i.immediate*4);
jump_end_rel32();
genupdate_count(dst->addr-4);
mov_m32abs_imm32((void*)(&last_addr), dst->addr + 4);
gencheck_interupt((unsigned long long) (dst + 1));
jmp(dst->addr + 4);
}
void genbeql()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[16]);
#endif
#ifdef INTERPRET_BEQL
gencallinterp((unsigned long long)BEQL, 1);
#else
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)BEQL, 1);
return;
}
genbeq_test();
free_all_registers();
gentestl();
#endif
}
void gentestl_out()
{
cmp_m32abs_imm32((unsigned int *)(&branch_taken), 0);
je_near_rj(0);
jump_start_rel32();
gendelayslot();
mov_m32abs_imm32((void*)(&last_addr), dst->addr + (dst-1)->f.i.immediate*4);
gencheck_interupt_out(dst->addr + (dst-1)->f.i.immediate*4);
mov_m32abs_imm32(&jump_to_address, dst->addr + (dst-1)->f.i.immediate*4);
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);
jump_end_rel32();
genupdate_count(dst->addr-4);
mov_m32abs_imm32((void*)(&last_addr), dst->addr + 4);
gencheck_interupt((unsigned long long) (dst + 1));
jmp(dst->addr + 4);
}
void genbeql_out()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[16]);
#endif
#ifdef INTERPRET_BEQL_OUT
gencallinterp((unsigned long long)BEQL_OUT, 1);
#else
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)BEQL_OUT, 1);
return;
}
genbeq_test();
free_all_registers();
gentestl_out();
#endif
}
void genbeql_idle()
{
#ifdef INTERPRET_BEQL_IDLE
gencallinterp((unsigned long long)BEQL_IDLE, 1);
#else
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)BEQL_IDLE, 1);
return;
}
genbeq_test();
gentest_idle();
genbeql();
#endif
}
void genbnel()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[17]);
#endif
#ifdef INTERPRET_BNEL
gencallinterp((unsigned long long)BNEL, 1);
#else
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)BNEL, 1);
return;
}
genbne_test();
free_all_registers();
gentestl();
#endif
}
void genbnel_out()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[17]);
#endif
#ifdef INTERPRET_BNEL_OUT
gencallinterp((unsigned long long)BNEL_OUT, 1);
#else
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)BNEL_OUT, 1);
return;
}
genbne_test();
free_all_registers();
gentestl_out();
#endif
}
void genbnel_idle()
{
#ifdef INTERPRET_BNEL_IDLE
gencallinterp((unsigned long long)BNEL_IDLE, 1);
#else
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)BNEL_IDLE, 1);
return;
}
genbne_test();
gentest_idle();
genbnel();
#endif
}
void genblezl()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[18]);
#endif
#ifdef INTERPRET_BLEZL
gencallinterp((unsigned long long)BLEZL, 1);
#else
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)BLEZL, 1);
return;
}
genblez_test();
free_all_registers();
gentestl();
#endif
}
void genblezl_out()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[18]);
#endif
#ifdef INTERPRET_BLEZL_OUT
gencallinterp((unsigned long long)BLEZL_OUT, 1);
#else
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)BLEZL_OUT, 1);
return;
}
genblez_test();
free_all_registers();
gentestl_out();
#endif
}
void genblezl_idle()
{
#ifdef INTERPRET_BLEZL_IDLE
gencallinterp((unsigned long long)BLEZL_IDLE, 1);
#else
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)BLEZL_IDLE, 1);
return;
}
genblez_test();
gentest_idle();
genblezl();
#endif
}
void genbgtzl()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[19]);
#endif
#ifdef INTERPRET_BGTZL
gencallinterp((unsigned long long)BGTZL, 1);
#else
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)BGTZL, 1);
return;
}
genbgtz_test();
free_all_registers();
gentestl();
#endif
}
void genbgtzl_out()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[19]);
#endif
#ifdef INTERPRET_BGTZL_OUT
gencallinterp((unsigned long long)BGTZL_OUT, 1);
#else
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)BGTZL_OUT, 1);
return;
}
genbgtz_test();
free_all_registers();
gentestl_out();
#endif
}
void genbgtzl_idle()
{
#ifdef INTERPRET_BGTZL_IDLE
gencallinterp((unsigned long long)BGTZL_IDLE, 1);
#else
if (((dst->addr & 0xFFF) == 0xFFC &&
(dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump)
{
gencallinterp((unsigned long long)BGTZL_IDLE, 1);
return;
}
genbgtz_test();
gentest_idle();
genbgtzl();
#endif
}
void gendaddi()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[20]);
#endif
#ifdef INTERPRET_DADDI
gencallinterp((unsigned long long)DADDI, 0);
#else
int rs = allocate_register_64((unsigned long long *)dst->f.i.rs);
int rt = allocate_register_64_w((unsigned long long *)dst->f.i.rt);
mov_reg64_reg64(rt, rs);
add_reg64_imm32(rt, (int) dst->f.i.immediate);
#endif
}
void gendaddiu()
{
#ifdef INTERPRET_DADDIU
gencallinterp((unsigned long long)DADDIU, 0);
#else
int rs = allocate_register_64((unsigned long long *)dst->f.i.rs);
int rt = allocate_register_64_w((unsigned long long *)dst->f.i.rt);
mov_reg64_reg64(rt, rs);
add_reg64_imm32(rt, (int) dst->f.i.immediate);
#endif
}
void ld_register_alloc(int *pGpr1, int *pGpr2, int *pBase1, int *pBase2)
{
int gpr1, gpr2, base1, base2 = 0;
#ifdef COMPARE_CORE
free_registers_move_start(); // to maintain parity with 32-bit core
#endif
if (dst->f.i.rs == dst->f.i.rt)
{
allocate_register_32((unsigned int*)dst->f.r.rs); // tell regcache we need to read RS register here
gpr1 = allocate_register_32_w((unsigned int*)dst->f.r.rt); // tell regcache we will modify RT register during this instruction
gpr2 = lock_register(lru_register()); // free and lock least recently used register for usage here
add_reg32_imm32(gpr1, (int)dst->f.i.immediate);
mov_reg32_reg32(gpr2, gpr1);
}
else
{
gpr2 = allocate_register_32((unsigned int*)dst->f.r.rs); // tell regcache we need to read RS register here
gpr1 = allocate_register_32_w((unsigned int*)dst->f.r.rt); // tell regcache we will modify RT register during this instruction
free_register(gpr2); // write out gpr2 if dirty because I'm going to trash it right now
add_reg32_imm32(gpr2, (int)dst->f.i.immediate);
mov_reg32_reg32(gpr1, gpr2);
lock_register(gpr2); // lock the freed gpr2 it so it doesn't get returned in the lru query
}
base1 = lock_register(lru_base_register()); // get another lru register
if (!fast_memory)
{
base2 = lock_register(lru_base_register()); // and another one if necessary
unlock_register(base2);
}
unlock_register(base1); // unlock the locked registers (they are
unlock_register(gpr2);
set_register_state(gpr1, NULL, 0, 0); // clear gpr1 state because it hasn't been written yet -
// we don't want it to be pushed/popped around read_rdramX call
*pGpr1 = gpr1;
*pGpr2 = gpr2;
*pBase1 = base1;
*pBase2 = base2;
}
void genldl()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[22]);
#endif
gencallinterp((unsigned long long)LDL, 0);
}
void genldr()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[23]);
#endif
gencallinterp((unsigned long long)LDR, 0);
}
void genlb()
{
int gpr1, gpr2, base1, base2 = 0;
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[24]);
#endif
#ifdef INTERPRET_LB
gencallinterp((unsigned long long)LB, 0);
#else
ld_register_alloc(&gpr1, &gpr2, &base1, &base2);
mov_reg64_imm64(base1, (unsigned long long) readmemb);
if(fast_memory)
{
and_reg32_imm32(gpr1, 0xDF800000);
cmp_reg32_imm32(gpr1, 0x80000000);
}
else
{
mov_reg64_imm64(base2, (unsigned long long) read_rdramb);
shr_reg32_imm8(gpr1, 16);
mov_reg64_preg64x8preg64(gpr1, gpr1, base1);
cmp_reg64_reg64(gpr1, base2);
}
je_rj(0);
jump_start_rel8();
mov_reg64_imm64(gpr1, (unsigned long long) (dst+1));
mov_m64abs_reg64((unsigned long long *)(&PC), gpr1);
mov_m32abs_reg32((unsigned int *)(&address), gpr2);
mov_reg64_imm64(gpr1, (unsigned long long) dst->f.i.rt);
mov_m64abs_reg64((unsigned long long *)(&rdword), gpr1);
shr_reg32_imm8(gpr2, 16);
mov_reg64_preg64x8preg64(gpr2, gpr2, base1);
stack_save_registers();
call_reg64(gpr2);
stack_load_registers();
movsx_reg32_m8abs(gpr1, (unsigned char *)dst->f.i.rt);
jmp_imm_short(24);
jump_end_rel8();
mov_reg64_imm64(base1, (unsigned long long) rdram); // 10
and_reg32_imm32(gpr2, 0x7FFFFF); // 6
xor_reg8_imm8(gpr2, 3); // 4
movsx_reg32_8preg64preg64(gpr1, gpr2, base1); // 4
set_register_state(gpr1, (unsigned int*)dst->f.i.rt, 1, 0);
#endif
}
void genlh()
{
int gpr1, gpr2, base1, base2 = 0;
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[25]);
#endif
#ifdef INTERPRET_LH
gencallinterp((unsigned long long)LH, 0);
#else
ld_register_alloc(&gpr1, &gpr2, &base1, &base2);
mov_reg64_imm64(base1, (unsigned long long) readmemh);
if(fast_memory)
{
and_reg32_imm32(gpr1, 0xDF800000);
cmp_reg32_imm32(gpr1, 0x80000000);
}
else
{
mov_reg64_imm64(base2, (unsigned long long) read_rdramh);
shr_reg32_imm8(gpr1, 16);
mov_reg64_preg64x8preg64(gpr1, gpr1, base1);
cmp_reg64_reg64(gpr1, base2);
}
je_rj(0);
jump_start_rel8();
mov_reg64_imm64(gpr1, (unsigned long long) (dst+1));
mov_m64abs_reg64((unsigned long long *)(&PC), gpr1);
mov_m32abs_reg32((unsigned int *)(&address), gpr2);
mov_reg64_imm64(gpr1, (unsigned long long) dst->f.i.rt);
mov_m64abs_reg64((unsigned long long *)(&rdword), gpr1);
shr_reg32_imm8(gpr2, 16);
mov_reg64_preg64x8preg64(gpr2, gpr2, base1);
stack_save_registers();
call_reg64(gpr2);
stack_load_registers();
movsx_reg32_m16abs(gpr1, (unsigned short *)dst->f.i.rt);
jmp_imm_short(24);
jump_end_rel8();
mov_reg64_imm64(base1, (unsigned long long) rdram); // 10
and_reg32_imm32(gpr2, 0x7FFFFF); // 6
xor_reg8_imm8(gpr2, 2); // 4
movsx_reg32_16preg64preg64(gpr1, gpr2, base1); // 4
set_register_state(gpr1, (unsigned int*)dst->f.i.rt, 1, 0);
#endif
}
void genlwl()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[27]);
#endif
gencallinterp((unsigned long long)LWL, 0);
}
void genlw()
{
int gpr1, gpr2, base1, base2 = 0;
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[26]);
#endif
#ifdef INTERPRET_LW
gencallinterp((unsigned long long)LW, 0);
#else
ld_register_alloc(&gpr1, &gpr2, &base1, &base2);
mov_reg64_imm64(base1, (unsigned long long) readmem);
if(fast_memory)
{
and_reg32_imm32(gpr1, 0xDF800000);
cmp_reg32_imm32(gpr1, 0x80000000);
}
else
{
mov_reg64_imm64(base2, (unsigned long long) read_rdram);
shr_reg32_imm8(gpr1, 16);
mov_reg64_preg64x8preg64(gpr1, gpr1, base1);
cmp_reg64_reg64(gpr1, base2);
}
jne_rj(21);
mov_reg64_imm64(base1, (unsigned long long) rdram); // 10
and_reg32_imm32(gpr2, 0x7FFFFF); // 6
mov_reg32_preg64preg64(gpr1, gpr2, base1); // 3
jmp_imm_short(0); // 2
jump_start_rel8();
mov_reg64_imm64(gpr1, (unsigned long long) (dst+1));
mov_m64abs_reg64((unsigned long long *)(&PC), gpr1);
mov_m32abs_reg32((unsigned int *)(&address), gpr2);
mov_reg64_imm64(gpr1, (unsigned long long) dst->f.i.rt);
mov_m64abs_reg64((unsigned long long *)(&rdword), gpr1);
shr_reg32_imm8(gpr2, 16);
mov_reg64_preg64x8preg64(gpr1, gpr2, base1);
stack_save_registers();
call_reg64(gpr1);
stack_load_registers();
mov_reg32_m32abs(gpr1, (unsigned int *)(dst->f.i.rt));
jump_end_rel8();
set_register_state(gpr1, (unsigned int*)dst->f.i.rt, 1, 0); // set gpr1 state as dirty, and bound to r4300 reg RT
#endif
}
void genlbu()
{
int gpr1, gpr2, base1, base2 = 0;
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[28]);
#endif
#ifdef INTERPRET_LBU
gencallinterp((unsigned long long)LBU, 0);
#else
ld_register_alloc(&gpr1, &gpr2, &base1, &base2);
mov_reg64_imm64(base1, (unsigned long long) readmemb);
if(fast_memory)
{
and_reg32_imm32(gpr1, 0xDF800000);
cmp_reg32_imm32(gpr1, 0x80000000);
}
else
{
mov_reg64_imm64(base2, (unsigned long long) read_rdramb);
shr_reg32_imm8(gpr1, 16);
mov_reg64_preg64x8preg64(gpr1, gpr1, base1);
cmp_reg64_reg64(gpr1, base2);
}
je_rj(0);
jump_start_rel8();
mov_reg64_imm64(gpr1, (unsigned long long) (dst+1));
mov_m64abs_reg64((unsigned long long *)(&PC), gpr1);
mov_m32abs_reg32((unsigned int *)(&address), gpr2);
mov_reg64_imm64(gpr1, (unsigned long long) dst->f.i.rt);
mov_m64abs_reg64((unsigned long long *)(&rdword), gpr1);
shr_reg32_imm8(gpr2, 16);
mov_reg64_preg64x8preg64(gpr2, gpr2, base1);
stack_save_registers();
call_reg64(gpr2);
stack_load_registers();
mov_reg32_m32abs(gpr1, (unsigned int *)dst->f.i.rt);
jmp_imm_short(23);
jump_end_rel8();
mov_reg64_imm64(base1, (unsigned long long) rdram); // 10
and_reg32_imm32(gpr2, 0x7FFFFF); // 6
xor_reg8_imm8(gpr2, 3); // 4
mov_reg32_preg64preg64(gpr1, gpr2, base1); // 3
and_reg32_imm32(gpr1, 0xFF);
set_register_state(gpr1, (unsigned int*)dst->f.i.rt, 1, 0);
#endif
}
void genlhu()
{
int gpr1, gpr2, base1, base2 = 0;
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[29]);
#endif
#ifdef INTERPRET_LHU
gencallinterp((unsigned long long)LHU, 0);
#else
ld_register_alloc(&gpr1, &gpr2, &base1, &base2);
mov_reg64_imm64(base1, (unsigned long long) readmemh);
if(fast_memory)
{
and_reg32_imm32(gpr1, 0xDF800000);
cmp_reg32_imm32(gpr1, 0x80000000);
}
else
{
mov_reg64_imm64(base2, (unsigned long long) read_rdramh);
shr_reg32_imm8(gpr1, 16);
mov_reg64_preg64x8preg64(gpr1, gpr1, base1);
cmp_reg64_reg64(gpr1, base2);
}
je_rj(0);
jump_start_rel8();
mov_reg64_imm64(gpr1, (unsigned long long) (dst+1));
mov_m64abs_reg64((unsigned long long *)(&PC), gpr1);
mov_m32abs_reg32((unsigned int *)(&address), gpr2);
mov_reg64_imm64(gpr1, (unsigned long long) dst->f.i.rt);
mov_m64abs_reg64((unsigned long long *)(&rdword), gpr1);
shr_reg32_imm8(gpr2, 16);
mov_reg64_preg64x8preg64(gpr2, gpr2, base1);
stack_save_registers();
call_reg64(gpr2);
stack_load_registers();
mov_reg32_m32abs(gpr1, (unsigned int *)dst->f.i.rt);
jmp_imm_short(23);
jump_end_rel8();
mov_reg64_imm64(base1, (unsigned long long) rdram); // 10
and_reg32_imm32(gpr2, 0x7FFFFF); // 6
xor_reg8_imm8(gpr2, 2); // 4
mov_reg32_preg64preg64(gpr1, gpr2, base1); // 3
and_reg32_imm32(gpr1, 0xFFFF);
set_register_state(gpr1, (unsigned int*)dst->f.i.rt, 1, 0);
#endif
}
void genlwr()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[31]);
#endif
gencallinterp((unsigned long long)LWR, 0);
}
void genlwu()
{
int gpr1, gpr2, base1, base2 = 0;
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[30]);
#endif
#ifdef INTERPRET_LWU
gencallinterp((unsigned long long)LWU, 0);
#else
ld_register_alloc(&gpr1, &gpr2, &base1, &base2);
mov_reg64_imm64(base1, (unsigned long long) readmem);
if(fast_memory)
{
and_reg32_imm32(gpr1, 0xDF800000);
cmp_reg32_imm32(gpr1, 0x80000000);
}
else
{
mov_reg64_imm64(base2, (unsigned long long) read_rdram);
shr_reg32_imm8(gpr1, 16);
mov_reg64_preg64x8preg64(gpr1, gpr1, base1);
cmp_reg64_reg64(gpr1, base2);
}
je_rj(0);
jump_start_rel8();
mov_reg64_imm64(gpr1, (unsigned long long) (dst+1));
mov_m64abs_reg64((unsigned long long *)(&PC), gpr1);
mov_m32abs_reg32((unsigned int *)(&address), gpr2);
mov_reg64_imm64(gpr1, (unsigned long long) dst->f.i.rt);
mov_m64abs_reg64((unsigned long long *)(&rdword), gpr1);
shr_reg32_imm8(gpr2, 16);
mov_reg64_preg64x8preg64(gpr2, gpr2, base1);
stack_save_registers();
call_reg64(gpr2);
stack_load_registers();
mov_reg32_m32abs(gpr1, (unsigned int *)dst->f.i.rt);
jmp_imm_short(19);
jump_end_rel8();
mov_reg64_imm64(base1, (unsigned long long) rdram); // 10
and_reg32_imm32(gpr2, 0x7FFFFF); // 6
mov_reg32_preg64preg64(gpr1, gpr2, base1); // 3
set_register_state(gpr1, (unsigned int*)dst->f.i.rt, 1, 1);
#endif
}
void gensb()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[32]);
#endif
#ifdef INTERPRET_SB
gencallinterp((unsigned long long)SB, 0);
#else
free_registers_move_start();
mov_reg8_m8abs(CL, (unsigned char *)dst->f.i.rt);
mov_reg32_m32abs(EAX, (unsigned int *)dst->f.i.rs);
add_eax_imm32((int)dst->f.i.immediate);
mov_reg32_reg32(EBX, EAX);
mov_reg64_imm64(RSI, (unsigned long long) writememb);
if(fast_memory)
{
and_eax_imm32(0xDF800000);
cmp_eax_imm32(0x80000000);
}
else
{
mov_reg64_imm64(RDI, (unsigned long long) write_rdramb);
shr_reg32_imm8(EAX, 16);
mov_reg64_preg64x8preg64(RAX, RAX, RSI);
cmp_reg64_reg64(RAX, RDI);
}
je_rj(50);
mov_reg64_imm64(RAX, (unsigned long long) (dst+1)); // 10
mov_m64abs_reg64((unsigned long long *)(&PC), RAX); // 8
mov_m32abs_reg32((unsigned int *)(&address), EBX); // 7
mov_m8abs_reg8((unsigned char *)(&byte), CL); // 7
shr_reg32_imm8(EBX, 16); // 3
mov_reg64_preg64x8preg64(RBX, RBX, RSI); // 4
call_reg64(RBX); // 2
mov_reg32_m32abs(EAX, (unsigned int *)(&address)); // 7
jmp_imm_short(25); // 2
mov_reg64_imm64(RSI, (unsigned long long) rdram); // 10
mov_reg32_reg32(EAX, EBX); // 2
and_reg32_imm32(EBX, 0x7FFFFF); // 6
xor_reg8_imm8(BL, 3); // 4
mov_preg64preg64_reg8(RBX, RSI, CL); // 3
mov_reg64_imm64(RSI, (unsigned long long) invalid_code);
mov_reg32_reg32(EBX, EAX);
shr_reg32_imm8(EBX, 12);
cmp_preg64preg64_imm8(RBX, RSI, 0);
jne_rj(65);
mov_reg64_imm64(RDI, (unsigned long long) blocks); // 10
mov_reg32_reg32(ECX, EBX); // 2
mov_reg64_preg64x8preg64(RBX, RBX, RDI); // 4
mov_reg64_preg64pimm32(RBX, RBX, (int) offsetof(precomp_block, block)); // 7
mov_reg64_imm64(RDI, (unsigned long long) NOTCOMPILED); // 10
and_eax_imm32(0xFFF); // 5
shr_reg32_imm8(EAX, 2); // 3
mov_reg32_imm32(EDX, sizeof(precomp_instr)); // 5
mul_reg32(EDX); // 2
mov_reg64_preg64preg64pimm32(RAX, RAX, RBX, (int) offsetof(precomp_instr, ops)); // 8
cmp_reg64_reg64(RAX, RDI); // 3
je_rj(4); // 2
mov_preg64preg64_imm8(RCX, RSI, 1); // 4
#endif
}
void gensh()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[33]);
#endif
#ifdef INTERPRET_SH
gencallinterp((unsigned long long)SH, 0);
#else
free_registers_move_start();
mov_reg16_m16abs(CX, (unsigned short *)dst->f.i.rt);
mov_reg32_m32abs(EAX, (unsigned int *)dst->f.i.rs);
add_eax_imm32((int)dst->f.i.immediate);
mov_reg32_reg32(EBX, EAX);
mov_reg64_imm64(RSI, (unsigned long long) writememh);
if(fast_memory)
{
and_eax_imm32(0xDF800000);
cmp_eax_imm32(0x80000000);
}
else
{
mov_reg64_imm64(RDI, (unsigned long long) write_rdramh);
shr_reg32_imm8(EAX, 16);
mov_reg64_preg64x8preg64(RAX, RAX, RSI);
cmp_reg64_reg64(RAX, RDI);
}
je_rj(51);
mov_reg64_imm64(RAX, (unsigned long long) (dst+1)); // 10
mov_m64abs_reg64((unsigned long long *)(&PC), RAX); // 8
mov_m32abs_reg32((unsigned int *)(&address), EBX); // 7
mov_m16abs_reg16((unsigned short *)(&hword), CX); // 8
shr_reg32_imm8(EBX, 16); // 3
mov_reg64_preg64x8preg64(RBX, RBX, RSI); // 4
call_reg64(RBX); // 2
mov_reg32_m32abs(EAX, (unsigned int *)(&address)); // 7
jmp_imm_short(26); // 2
mov_reg64_imm64(RSI, (unsigned long long) rdram); // 10
mov_reg32_reg32(EAX, EBX); // 2
and_reg32_imm32(EBX, 0x7FFFFF); // 6
xor_reg8_imm8(BL, 2); // 4
mov_preg64preg64_reg16(RBX, RSI, CX); // 4
mov_reg64_imm64(RSI, (unsigned long long) invalid_code);
mov_reg32_reg32(EBX, EAX);
shr_reg32_imm8(EBX, 12);
cmp_preg64preg64_imm8(RBX, RSI, 0);
jne_rj(65);
mov_reg64_imm64(RDI, (unsigned long long) blocks); // 10
mov_reg32_reg32(ECX, EBX); // 2
mov_reg64_preg64x8preg64(RBX, RBX, RDI); // 4
mov_reg64_preg64pimm32(RBX, RBX, (int) offsetof(precomp_block, block)); // 7
mov_reg64_imm64(RDI, (unsigned long long) NOTCOMPILED); // 10
and_eax_imm32(0xFFF); // 5
shr_reg32_imm8(EAX, 2); // 3
mov_reg32_imm32(EDX, sizeof(precomp_instr)); // 5
mul_reg32(EDX); // 2
mov_reg64_preg64preg64pimm32(RAX, RAX, RBX, (int) offsetof(precomp_instr, ops)); // 8
cmp_reg64_reg64(RAX, RDI); // 3
je_rj(4); // 2
mov_preg64preg64_imm8(RCX, RSI, 1); // 4
#endif
}
void genswl()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[35]);
#endif
gencallinterp((unsigned long long)SWL, 0);
}
void gensw()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[34]);
#endif
#ifdef INTERPRET_SW
gencallinterp((unsigned long long)SW, 0);
#else
free_registers_move_start();
mov_reg32_m32abs(ECX, (unsigned int *)dst->f.i.rt);
mov_reg32_m32abs(EAX, (unsigned int *)dst->f.i.rs);
add_eax_imm32((int)dst->f.i.immediate);
mov_reg32_reg32(EBX, EAX);
mov_reg64_imm64(RSI, (unsigned long long) writemem);
if(fast_memory)
{
and_eax_imm32(0xDF800000);
cmp_eax_imm32(0x80000000);
}
else
{
mov_reg64_imm64(RDI, (unsigned long long) write_rdram);
shr_reg32_imm8(EAX, 16);
mov_reg64_preg64x8preg64(RAX, RAX, RSI);
cmp_reg64_reg64(RAX, RDI);
}
je_rj(50);
mov_reg64_imm64(RAX, (unsigned long long) (dst+1)); // 10
mov_m64abs_reg64((unsigned long long *)(&PC), RAX); // 8
mov_m32abs_reg32((unsigned int *)(&address), EBX); // 7
mov_m32abs_reg32((unsigned int *)(&word), ECX); // 7
shr_reg32_imm8(EBX, 16); // 3
mov_reg64_preg64x8preg64(RBX, RBX, RSI); // 4
call_reg64(RBX); // 2
mov_reg32_m32abs(EAX, (unsigned int *)(&address)); // 7
jmp_imm_short(21); // 2
mov_reg64_imm64(RSI, (unsigned long long) rdram); // 10
mov_reg32_reg32(EAX, EBX); // 2
and_reg32_imm32(EBX, 0x7FFFFF); // 6
mov_preg64preg64_reg32(RBX, RSI, ECX); // 3
mov_reg64_imm64(RSI, (unsigned long long) invalid_code);
mov_reg32_reg32(EBX, EAX);
shr_reg32_imm8(EBX, 12);
cmp_preg64preg64_imm8(RBX, RSI, 0);
jne_rj(65);
mov_reg64_imm64(RDI, (unsigned long long) blocks); // 10
mov_reg32_reg32(ECX, EBX); // 2
mov_reg64_preg64x8preg64(RBX, RBX, RDI); // 4
mov_reg64_preg64pimm32(RBX, RBX, (int) offsetof(precomp_block, block)); // 7
mov_reg64_imm64(RDI, (unsigned long long) NOTCOMPILED); // 10
and_eax_imm32(0xFFF); // 5
shr_reg32_imm8(EAX, 2); // 3
mov_reg32_imm32(EDX, sizeof(precomp_instr)); // 5
mul_reg32(EDX); // 2
mov_reg64_preg64preg64pimm32(RAX, RAX, RBX, (int) offsetof(precomp_instr, ops)); // 8
cmp_reg64_reg64(RAX, RDI); // 3
je_rj(4); // 2
mov_preg64preg64_imm8(RCX, RSI, 1); // 4
#endif
}
void gensdl()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[37]);
#endif
gencallinterp((unsigned long long)SDL, 0);
}
void gensdr()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[38]);
#endif
gencallinterp((unsigned long long)SDR, 0);
}
void genswr()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[36]);
#endif
gencallinterp((unsigned long long)SWR, 0);
}
void gencheck_cop1_unusable()
{
free_registers_move_start();
test_m32abs_imm32((unsigned int*)&Status, 0x20000000);
jne_rj(0);
jump_start_rel8();
gencallinterp((unsigned long long)check_cop1_unusable, 0);
jump_end_rel8();
}
void genlwc1()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[39]);
#endif
#ifdef INTERPRET_LWC1
gencallinterp((unsigned long long)LWC1, 0);
#else
gencheck_cop1_unusable();
mov_reg32_m32abs(EAX, (unsigned int *)(&reg[dst->f.lf.base]));
add_eax_imm32((int)dst->f.lf.offset);
mov_reg32_reg32(EBX, EAX);
mov_reg64_imm64(RSI, (unsigned long long) readmem);
if(fast_memory)
{
and_eax_imm32(0xDF800000);
cmp_eax_imm32(0x80000000);
}
else
{
mov_reg64_imm64(RDI, (unsigned long long) read_rdram);
shr_reg32_imm8(EAX, 16);
mov_reg64_preg64x8preg64(RAX, RAX, RSI);
cmp_reg64_reg64(RAX, RDI);
}
je_rj(52);
mov_reg64_imm64(RAX, (unsigned long long) (dst+1)); // 10
mov_m64abs_reg64((unsigned long long *)(&PC), RAX); // 8
mov_m32abs_reg32((unsigned int *)(&address), EBX); // 7
mov_reg64_m64abs(RDX, (unsigned long long *)(&reg_cop1_simple[dst->f.lf.ft])); // 8
mov_m64abs_reg64((unsigned long long *)(&rdword), RDX); // 8
shr_reg32_imm8(EBX, 16); // 3
mov_reg64_preg64x8preg64(RBX, RBX, RSI); // 4
call_reg64(RBX); // 2
jmp_imm_short(29); // 2
mov_reg64_imm64(RSI, (unsigned long long) rdram); // 10
and_reg32_imm32(EBX, 0x7FFFFF); // 6
mov_reg32_preg64preg64(EAX, RBX, RSI); // 3
mov_reg64_m64abs(RBX, (unsigned long long *)(&reg_cop1_simple[dst->f.lf.ft])); // 8
mov_preg64_reg32(RBX, EAX); // 2
#endif
}
void genldc1()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[40]);
#endif
#ifdef INTERPRET_LDC1
gencallinterp((unsigned long long)LDC1, 0);
#else
gencheck_cop1_unusable();
mov_reg32_m32abs(EAX, (unsigned int *)(&reg[dst->f.lf.base]));
add_eax_imm32((int)dst->f.lf.offset);
mov_reg32_reg32(EBX, EAX);
mov_reg64_imm64(RSI, (unsigned long long) readmemd);
if(fast_memory)
{
and_eax_imm32(0xDF800000);
cmp_eax_imm32(0x80000000);
}
else
{
mov_reg64_imm64(RDI, (unsigned long long) read_rdramd);
shr_reg32_imm8(EAX, 16);
mov_reg64_preg64x8preg64(RAX, RAX, RSI);
cmp_reg64_reg64(RAX, RDI);
}
je_rj(52);
mov_reg64_imm64(RAX, (unsigned long long) (dst+1)); // 10
mov_m64abs_reg64((unsigned long long *)(&PC), RAX); // 8
mov_m32abs_reg32((unsigned int *)(&address), EBX); // 7
mov_reg64_m64abs(RDX, (unsigned long long *)(&reg_cop1_double[dst->f.lf.ft])); // 8
mov_m64abs_reg64((unsigned long long *)(&rdword), RDX); // 8
shr_reg32_imm8(EBX, 16); // 3
mov_reg64_preg64x8preg64(RBX, RBX, RSI); // 4
call_reg64(RBX); // 2
jmp_imm_short(40); // 2
mov_reg64_imm64(RSI, (unsigned long long) rdram); // 10
and_reg32_imm32(EBX, 0x7FFFFF); // 6
mov_reg64_preg64preg64(RAX, RBX, RSI); // 4
mov_reg64_m64abs(RBX, (unsigned long long *)(&reg_cop1_double[dst->f.lf.ft])); // 8
mov_preg64pimm32_reg32(RBX, 4, EAX); // 6
shr_reg64_imm8(RAX, 32); // 4
mov_preg64_reg32(RBX, EAX); // 2
#endif
}
void gencache()
{
}
void genld()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[41]);
#endif
#ifdef INTERPRET_LD
gencallinterp((unsigned long long)LD, 0);
#else
free_registers_move_start();
mov_reg32_m32abs(EAX, (unsigned int *)dst->f.i.rs);
add_eax_imm32((int)dst->f.i.immediate);
mov_reg32_reg32(EBX, EAX);
mov_reg64_imm64(RSI, (unsigned long long) readmemd);
if(fast_memory)
{
and_eax_imm32(0xDF800000);
cmp_eax_imm32(0x80000000);
}
else
{
mov_reg64_imm64(RDI, (unsigned long long) read_rdramd);
shr_reg32_imm8(EAX, 16);
mov_reg64_preg64x8preg64(RAX, RAX, RSI);
cmp_reg64_reg64(RAX, RDI);
}
je_rj(62);
mov_reg64_imm64(RAX, (unsigned long long) (dst+1)); // 10
mov_m64abs_reg64((unsigned long long *)(&PC), RAX); // 8
mov_m32abs_reg32((unsigned int *)(&address), EBX); // 7
mov_reg64_imm64(RAX, (unsigned long long) dst->f.i.rt); // 10
mov_m64abs_reg64((unsigned long long *)(&rdword), RAX); // 8
shr_reg32_imm8(EBX, 16); // 3
mov_reg64_preg64x8preg64(RBX, RBX, RSI); // 4
call_reg64(RBX); // 2
mov_reg64_m64abs(RAX, (unsigned long long *)(dst->f.i.rt)); // 8
jmp_imm_short(33); // 2
mov_reg64_imm64(RSI, (unsigned long long) rdram); // 10
and_reg32_imm32(EBX, 0x7FFFFF); // 6
mov_reg32_preg64preg64(EAX, RBX, RSI); // 3
mov_reg32_preg64preg64pimm32(EBX, RBX, RSI, 4); // 7
shl_reg64_imm8(RAX, 32); // 4
or_reg64_reg64(RAX, RBX); // 3
set_register_state(RAX, (unsigned int*)dst->f.i.rt, 1, 1);
#endif
}
void genswc1()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[43]);
#endif
#ifdef INTERPRET_SWC1
gencallinterp((unsigned long long)SWC1, 0);
#else
gencheck_cop1_unusable();
mov_reg64_m64abs(RDX, (unsigned long long *)(&reg_cop1_simple[dst->f.lf.ft]));
mov_reg32_preg64(ECX, RDX);
mov_reg32_m32abs(EAX, (unsigned int *)(&reg[dst->f.lf.base]));
add_eax_imm32((int)dst->f.lf.offset);
mov_reg32_reg32(EBX, EAX);
mov_reg64_imm64(RSI, (unsigned long long) writemem);
if(fast_memory)
{
and_eax_imm32(0xDF800000);
cmp_eax_imm32(0x80000000);
}
else
{
mov_reg64_imm64(RDI, (unsigned long long) write_rdram);
shr_reg32_imm8(EAX, 16);
mov_reg64_preg64x8preg64(RAX, RAX, RSI);
cmp_reg64_reg64(RAX, RDI);
}
je_rj(50);
mov_reg64_imm64(RAX, (unsigned long long) (dst+1)); // 10
mov_m64abs_reg64((unsigned long long *)(&PC), RAX); // 8
mov_m32abs_reg32((unsigned int *)(&address), EBX); // 7
mov_m32abs_reg32((unsigned int *)(&word), ECX); // 7
shr_reg32_imm8(EBX, 16); // 3
mov_reg64_preg64x8preg64(RBX, RBX, RSI); // 4
call_reg64(RBX); // 2
mov_reg32_m32abs(EAX, (unsigned int *)(&address)); // 7
jmp_imm_short(21); // 2
mov_reg64_imm64(RSI, (unsigned long long) rdram); // 10
mov_reg32_reg32(EAX, EBX); // 2
and_reg32_imm32(EBX, 0x7FFFFF); // 6
mov_preg64preg64_reg32(RBX, RSI, ECX); // 3
mov_reg64_imm64(RSI, (unsigned long long) invalid_code);
mov_reg32_reg32(EBX, EAX);
shr_reg32_imm8(EBX, 12);
cmp_preg64preg64_imm8(RBX, RSI, 0);
jne_rj(65);
mov_reg64_imm64(RDI, (unsigned long long) blocks); // 10
mov_reg32_reg32(ECX, EBX); // 2
mov_reg64_preg64x8preg64(RBX, RBX, RDI); // 4
mov_reg64_preg64pimm32(RBX, RBX, (int) offsetof(precomp_block, block)); // 7
mov_reg64_imm64(RDI, (unsigned long long) NOTCOMPILED); // 10
and_eax_imm32(0xFFF); // 5
shr_reg32_imm8(EAX, 2); // 3
mov_reg32_imm32(EDX, sizeof(precomp_instr)); // 5
mul_reg32(EDX); // 2
mov_reg64_preg64preg64pimm32(RAX, RAX, RBX, (int) offsetof(precomp_instr, ops)); // 8
cmp_reg64_reg64(RAX, RDI); // 3
je_rj(4); // 2
mov_preg64preg64_imm8(RCX, RSI, 1); // 4
#endif
}
void gensdc1()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[44]);
#endif
#ifdef INTERPRET_SDC1
gencallinterp((unsigned long long)SDC1, 0);
#else
gencheck_cop1_unusable();
mov_reg64_m64abs(RSI, (unsigned long long *)(&reg_cop1_double[dst->f.lf.ft]));
mov_reg32_preg64(ECX, RSI);
mov_reg32_preg64pimm32(EDX, RSI, 4);
mov_reg32_m32abs(EAX, (unsigned int *)(&reg[dst->f.lf.base]));
add_eax_imm32((int)dst->f.lf.offset);
mov_reg32_reg32(EBX, EAX);
mov_reg64_imm64(RSI, (unsigned long long) writememd);
if(fast_memory)
{
and_eax_imm32(0xDF800000);
cmp_eax_imm32(0x80000000);
}
else
{
mov_reg64_imm64(RDI, (unsigned long long) write_rdramd);
shr_reg32_imm8(EAX, 16);
mov_reg64_preg64x8preg64(RAX, RAX, RSI);
cmp_reg64_reg64(RAX, RDI);
}
je_rj(57);
mov_reg64_imm64(RAX, (unsigned long long) (dst+1)); // 10
mov_m64abs_reg64((unsigned long long *)(&PC), RAX); // 8
mov_m32abs_reg32((unsigned int *)(&address), EBX); // 7
mov_m32abs_reg32((unsigned int *)(&dword), ECX); // 7
mov_m32abs_reg32((unsigned int *)(&dword)+1, EDX); // 7
shr_reg32_imm8(EBX, 16); // 3
mov_reg64_preg64x8preg64(RBX, RBX, RSI); // 4
call_reg64(RBX); // 2
mov_reg32_m32abs(EAX, (unsigned int *)(&address)); // 7
jmp_imm_short(28); // 2
mov_reg64_imm64(RSI, (unsigned long long) rdram); // 10
mov_reg32_reg32(EAX, EBX); // 2
and_reg32_imm32(EBX, 0x7FFFFF); // 6
mov_preg64preg64pimm32_reg32(RBX, RSI, 4, ECX); // 7
mov_preg64preg64_reg32(RBX, RSI, EDX); // 3
mov_reg64_imm64(RSI, (unsigned long long) invalid_code);
mov_reg32_reg32(EBX, EAX);
shr_reg32_imm8(EBX, 12);
cmp_preg64preg64_imm8(RBX, RSI, 0);
jne_rj(65);
mov_reg64_imm64(RDI, (unsigned long long) blocks); // 10
mov_reg32_reg32(ECX, EBX); // 2
mov_reg64_preg64x8preg64(RBX, RBX, RDI); // 4
mov_reg64_preg64pimm32(RBX, RBX, (int) offsetof(precomp_block, block)); // 7
mov_reg64_imm64(RDI, (unsigned long long) NOTCOMPILED); // 10
and_eax_imm32(0xFFF); // 5
shr_reg32_imm8(EAX, 2); // 3
mov_reg32_imm32(EDX, sizeof(precomp_instr)); // 5
mul_reg32(EDX); // 2
mov_reg64_preg64preg64pimm32(RAX, RAX, RBX, (int) offsetof(precomp_instr, ops)); // 8
cmp_reg64_reg64(RAX, RDI); // 3
je_rj(4); // 2
mov_preg64preg64_imm8(RCX, RSI, 1); // 4
#endif
}
void gensd()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[45]);
#endif
#ifdef INTERPRET_SD
gencallinterp((unsigned long long)SD, 0);
#else
free_registers_move_start();
mov_reg32_m32abs(ECX, (unsigned int *)dst->f.i.rt);
mov_reg32_m32abs(EDX, ((unsigned int *)dst->f.i.rt)+1);
mov_reg32_m32abs(EAX, (unsigned int *)dst->f.i.rs);
add_eax_imm32((int)dst->f.i.immediate);
mov_reg32_reg32(EBX, EAX);
mov_reg64_imm64(RSI, (unsigned long long) writememd);
if(fast_memory)
{
and_eax_imm32(0xDF800000);
cmp_eax_imm32(0x80000000);
}
else
{
mov_reg64_imm64(RDI, (unsigned long long) write_rdramd);
shr_reg32_imm8(EAX, 16);
mov_reg64_preg64x8preg64(RAX, RAX, RSI);
cmp_reg64_reg64(RAX, RDI);
}
je_rj(57);
mov_reg64_imm64(RAX, (unsigned long long) (dst+1)); // 10
mov_m64abs_reg64((unsigned long long *)(&PC), RAX); // 8
mov_m32abs_reg32((unsigned int *)(&address), EBX); // 7
mov_m32abs_reg32((unsigned int *)(&dword), ECX); // 7
mov_m32abs_reg32((unsigned int *)(&dword)+1, EDX); // 7
shr_reg32_imm8(EBX, 16); // 3
mov_reg64_preg64x8preg64(RBX, RBX, RSI); // 4
call_reg64(RBX); // 2
mov_reg32_m32abs(EAX, (unsigned int *)(&address)); // 7
jmp_imm_short(28); // 2
mov_reg64_imm64(RSI, (unsigned long long) rdram); // 10
mov_reg32_reg32(EAX, EBX); // 2
and_reg32_imm32(EBX, 0x7FFFFF); // 6
mov_preg64preg64pimm32_reg32(RBX, RSI, 4, ECX); // 7
mov_preg64preg64_reg32(RBX, RSI, EDX); // 3
mov_reg64_imm64(RSI, (unsigned long long) invalid_code);
mov_reg32_reg32(EBX, EAX);
shr_reg32_imm8(EBX, 12);
cmp_preg64preg64_imm8(RBX, RSI, 0);
jne_rj(65);
mov_reg64_imm64(RDI, (unsigned long long) blocks); // 10
mov_reg32_reg32(ECX, EBX); // 2
mov_reg64_preg64x8preg64(RBX, RBX, RDI); // 4
mov_reg64_preg64pimm32(RBX, RBX, (int) offsetof(precomp_block, block)); // 7
mov_reg64_imm64(RDI, (unsigned long long) NOTCOMPILED); // 10
and_eax_imm32(0xFFF); // 5
shr_reg32_imm8(EAX, 2); // 3
mov_reg32_imm32(EDX, sizeof(precomp_instr)); // 5
mul_reg32(EDX); // 2
mov_reg64_preg64preg64pimm32(RAX, RAX, RBX, (int) offsetof(precomp_instr, ops)); // 8
cmp_reg64_reg64(RAX, RDI); // 3
je_rj(4); // 2
mov_preg64preg64_imm8(RCX, RSI, 1); // 4
#endif
}
void genll()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[42]);
#endif
gencallinterp((unsigned long long)LL, 0);
}
void gensc()
{
#if defined(COUNT_INSTR)
inc_m32abs(&instr_count[46]);
#endif
gencallinterp((unsigned long long)SC, 0);
}