Source to ./mips64_amd64_trans.c
/*
* Cisco router simulation platform.
* Copyright (c) 2005,2006 Christophe Fillot ([email protected])
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include "cpu.h"
#include "vm.h"
#include "tcb.h"
#include "mips64_jit.h"
#include "mips64_amd64_trans.h"
#include "mips64_cp0.h"
#include "memory.h"
/* Macros for CPU structure access */
#define REG_OFFSET(reg) (OFFSET(cpu_mips_t,gpr[(reg)]))
#define CP0_REG_OFFSET(c0reg) (OFFSET(cpu_mips_t,cp0.reg[(c0reg)]))
#define MEMOP_OFFSET(op) (OFFSET(cpu_mips_t,mem_op_fn[(op)]))
#define DECLARE_INSN(name) \
static int mips64_emit_##name(cpu_mips_t *cpu,cpu_tc_t *b,\
mips_insn_t insn)
/* Set an IRQ */
void mips64_set_irq(cpu_mips_t *cpu,m_uint8_t irq)
{
m_uint32_t m;
m = (1 << (irq + MIPS_CP0_CAUSE_ISHIFT)) & MIPS_CP0_CAUSE_IMASK;
atomic_or(&cpu->irq_cause,m);
}
/* Clear an IRQ */
void mips64_clear_irq(cpu_mips_t *cpu,m_uint8_t irq)
{
m_uint32_t m;
m = (1 << (irq + MIPS_CP0_CAUSE_ISHIFT)) & MIPS_CP0_CAUSE_IMASK;
atomic_and(&cpu->irq_cause,~m);
if (!cpu->irq_cause)
cpu->irq_pending = 0;
}
/* Load a 64 bit immediate value */
static inline void mips64_load_imm(cpu_tc_t *b,u_int reg,m_uint64_t value)
{
if (value > 0xffffffffULL)
amd64_mov_reg_imm_size(b->jit_ptr,reg,value,8);
else
amd64_mov_reg_imm(b->jit_ptr,reg,value);
}
/* Set the Pointer Counter (PC) register */
void mips64_set_pc(cpu_tc_t *b,m_uint64_t new_pc)
{
mips64_load_imm(b,AMD64_RAX,new_pc);
amd64_mov_membase_reg(b->jit_ptr,
AMD64_R15,OFFSET(cpu_mips_t,pc),
AMD64_RAX,8);
}
/* Set the Return Address (RA) register */
void mips64_set_ra(cpu_tc_t *b,m_uint64_t ret_pc)
{
mips64_load_imm(b,AMD64_RAX,ret_pc);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,
REG_OFFSET(MIPS_GPR_RA),
AMD64_RAX,8);
}
/*
* Try to branch directly to the specified JIT block without returning to
* the main loop.
*/
static void mips64_try_direct_far_jump(cpu_mips_t *cpu,cpu_tc_t *b,
m_uint64_t new_pc)
{
m_uint64_t new_page;
m_uint32_t pc_hash,pc_offset;
u_char *test1,*test2,*test3,*test4;
new_page = new_pc & MIPS_MIN_PAGE_MASK;
pc_offset = (new_pc & MIPS_MIN_PAGE_IMASK) >> 2;
pc_hash = mips64_jit_get_virt_hash(new_pc);
/* Get generic CPU pointer */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RSI,
AMD64_R15,OFFSET(cpu_mips_t,gen),8);
/* Get JIT block info in %rdx */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RBX,
AMD64_RSI,OFFSET(cpu_gen_t,tb_virt_hash),8);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RDX,
AMD64_RBX,pc_hash*sizeof(void *),8);
/* no JIT block found ? */
amd64_test_reg_reg(b->jit_ptr,AMD64_RDX,AMD64_RDX);
test1 = b->jit_ptr;
amd64_branch8(b->jit_ptr, X86_CC_Z, 0, 1);
/* Check block virtual address */
mips64_load_imm(b,AMD64_RAX,new_page);
amd64_alu_reg_membase_size(b->jit_ptr,X86_CMP,AMD64_RAX,AMD64_RDX,
OFFSET(cpu_tb_t,vaddr),8);
test2 = b->jit_ptr;
amd64_branch8(b->jit_ptr, X86_CC_NE, 0, 1);
/* Get pointer to the Translated Code block */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RBX,
AMD64_RDX,OFFSET(cpu_tb_t,tc),8);
amd64_test_reg_reg(b->jit_ptr,AMD64_RBX,AMD64_RBX);
test3 = b->jit_ptr;
amd64_branch8(b->jit_ptr, X86_CC_Z, 0, 1);
/* Jump to the code */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RSI,
AMD64_RBX,OFFSET(cpu_tc_t,jit_insn_ptr),8);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,
AMD64_RSI,pc_offset * sizeof(void *),8);
amd64_test_reg_reg(b->jit_ptr,AMD64_RAX,AMD64_RAX);
test4 = b->jit_ptr;
amd64_branch8(b->jit_ptr, X86_CC_Z, 0, 1);
amd64_jump_reg(b->jit_ptr,AMD64_RAX);
/* Returns to caller... */
amd64_patch(test1,b->jit_ptr);
amd64_patch(test2,b->jit_ptr);
amd64_patch(test3,b->jit_ptr);
amd64_patch(test4,b->jit_ptr);
mips64_set_pc(b,new_pc);
mips64_jit_tcb_push_epilog(b);
}
/* Set Jump */
static void mips64_set_jump(cpu_mips_t *cpu,cpu_tc_t *b,
m_uint64_t new_pc,int local_jump)
{
int return_to_caller = FALSE;
u_char *jump_ptr;
if (cpu->sym_trace && !local_jump)
return_to_caller = TRUE;
if (!return_to_caller && mips64_jit_tcb_local_addr(b,new_pc,&jump_ptr)) {
if (jump_ptr) {
amd64_jump_code(b->jit_ptr,jump_ptr);
} else {
/* Never jump directly to code in a delay slot */
if (mips64_jit_is_delay_slot(b,new_pc)) {
mips64_set_pc(b,new_pc);
mips64_jit_tcb_push_epilog(b);
return;
}
mips64_jit_tcb_record_patch(cpu,b,b->jit_ptr,new_pc);
amd64_jump32(b->jit_ptr,0);
}
} else {
if (1 /*cpu->exec_blk_direct_jump*/) { /* zzz */
/* Block lookup optimization */
mips64_try_direct_far_jump(cpu,b,new_pc);
} else {
mips64_set_pc(b,new_pc);
mips64_jit_tcb_push_epilog(b);
}
}
}
/* Basic C call */
static forced_inline void mips64_emit_basic_c_call(cpu_tc_t *b,void *f)
{
amd64_mov_reg_imm(b->jit_ptr,AMD64_RCX,f);
amd64_call_reg(b->jit_ptr,AMD64_RCX);
}
/* Emit a simple call to a C function without any parameter */
static void mips64_emit_c_call(cpu_tc_t *b,void *f)
{
mips64_set_pc(b,b->vaddr+((b->trans_pos-1)<<2));
amd64_mov_reg_imm(b->jit_ptr,AMD64_RCX,f);
amd64_call_reg(b->jit_ptr,AMD64_RCX);
}
/* Single-step operation */
void mips64_emit_single_step(cpu_tc_t *b,mips_insn_t insn)
{
amd64_mov_reg_reg(b->jit_ptr,AMD64_RDI,AMD64_R15,8);
amd64_mov_reg_imm(b->jit_ptr,AMD64_RSI,insn);
mips64_emit_basic_c_call(b,mips64_exec_single_step);
}
/* Fast memory operation prototype */
typedef void (*memop_fast_access)(cpu_tc_t *b,int target);
/* Fast LW */
static void mips64_memop_fast_lw(cpu_tc_t *b,int target)
{
amd64_mov_reg_memindex(b->jit_ptr,AMD64_RAX,AMD64_RBX,0,AMD64_RSI,0,4);
amd64_bswap32(b->jit_ptr,X86_EAX);
amd64_movsxd_reg_reg(b->jit_ptr,AMD64_RDX,X86_EAX);
/* Save value in register */
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(target),AMD64_RDX,8);
}
/* Fast SW */
static void mips64_memop_fast_sw(cpu_tc_t *b,int target)
{
/* Load value from register */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(target),4);
amd64_bswap32(b->jit_ptr,X86_EAX);
amd64_mov_memindex_reg(b->jit_ptr,AMD64_RBX,0,AMD64_RSI,0,AMD64_RAX,4);
}
/* Fast memory operation (64-bit) */
static void mips64_emit_memop_fast64(cpu_tc_t *b,int write_op,
int opcode,int base,int offset,
int target,int keep_ll_bit,
memop_fast_access op_handler)
{
m_uint64_t val = sign_extend(offset,16);
u_char *test1,*test2,*p_exit;
test2 = NULL;
/* XXX */
amd64_inc_membase(b->jit_ptr,AMD64_R15,OFFSET(cpu_mips_t,mts_lookups));
/* RSI = GPR[base] + sign-extended offset */
mips64_load_imm(b,AMD64_RSI,val);
amd64_alu_reg_membase(b->jit_ptr,X86_ADD,
AMD64_RSI,AMD64_R15,REG_OFFSET(base));
/* RBX = mts64_entry index */
amd64_mov_reg_reg_size(b->jit_ptr,X86_EBX,X86_ESI,4);
amd64_mov_reg_reg_size(b->jit_ptr,X86_EAX,X86_ESI,4);
amd64_shift_reg_imm_size(b->jit_ptr,X86_SHR,X86_EBX,MTS64_HASH_SHIFT1,4);
amd64_shift_reg_imm_size(b->jit_ptr,X86_SHR,X86_EAX,MTS64_HASH_SHIFT2,4);
amd64_alu_reg_reg(b->jit_ptr,X86_XOR,AMD64_RBX,AMD64_RAX);
amd64_alu_reg_imm_size(b->jit_ptr,X86_AND,X86_EBX,MTS64_HASH_MASK,8);
/* RCX = mts64 entry */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RCX,
AMD64_R15,
OFFSET(cpu_mips_t,mts_u.mts64_cache),8);
amd64_shift_reg_imm(b->jit_ptr,X86_SHL,AMD64_RBX,5); /* TO FIX */
amd64_alu_reg_reg(b->jit_ptr,X86_ADD,AMD64_RCX,AMD64_RBX);
/* Compare virtual page address (EAX = vpage) */
amd64_mov_reg_reg(b->jit_ptr,AMD64_RAX,AMD64_RSI,8);
amd64_alu_reg_imm(b->jit_ptr,X86_AND,AMD64_RAX,MIPS_MIN_PAGE_MASK);
amd64_alu_reg_membase_size(b->jit_ptr,X86_CMP,AMD64_RAX,AMD64_RCX,
OFFSET(mts64_entry_t,gvpa),8);
test1 = b->jit_ptr;
x86_branch8(b->jit_ptr, X86_CC_NZ, 0, 1);
/* Test if we are writing to a COW page */
if (write_op) {
amd64_test_membase_imm_size(b->jit_ptr,
AMD64_RCX,OFFSET(mts64_entry_t,flags),
MTS_FLAG_WRCATCH,4);
test2 = b->jit_ptr;
amd64_branch8(b->jit_ptr, X86_CC_NZ, 0, 1);
}
/* ESI = offset in page, RBX = Host Page Address */
amd64_alu_reg_imm(b->jit_ptr,X86_AND,X86_ESI,MIPS_MIN_PAGE_IMASK);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RBX,
AMD64_RCX,OFFSET(mts64_entry_t,hpa),8);
/* Memory access */
op_handler(b,target);
p_exit = b->jit_ptr;
amd64_jump8(b->jit_ptr,0);
if (test2)
amd64_patch(test2,b->jit_ptr);
/* === Slow lookup === */
amd64_patch(test1,b->jit_ptr);
/* Save PC for exception handling */
mips64_set_pc(b,b->vaddr+((b->trans_pos-1)<<2));
/* Sign-extend virtual address */
//amd64_movsxd_reg_reg(b->jit_ptr,AMD64_RSI,X86_ESI);
/* RDX = target register */
amd64_mov_reg_imm(b->jit_ptr,AMD64_RDX,target);
/* RDI = CPU instance */
amd64_mov_reg_reg(b->jit_ptr,AMD64_RDI,AMD64_R15,8);
/* Call memory access function */
amd64_alu_reg_imm(b->jit_ptr,X86_SUB,AMD64_RSP,8);
amd64_call_membase(b->jit_ptr,AMD64_R15,MEMOP_OFFSET(opcode));
amd64_alu_reg_imm(b->jit_ptr,X86_ADD,AMD64_RSP,8);
amd64_patch(p_exit,b->jit_ptr);
}
/* Fast memory operation (32-bit) */
static void mips64_emit_memop_fast32(cpu_tc_t *b,int write_op,
int opcode,int base,int offset,
int target,int keep_ll_bit,
memop_fast_access op_handler)
{
m_uint32_t val = sign_extend(offset,16);
u_char *test1,*test2,*p_exit;
test2 = NULL;
/* XXX */
amd64_inc_membase(b->jit_ptr,AMD64_R15,OFFSET(cpu_mips_t,mts_lookups));
/* ESI = GPR[base] + sign-extended offset */
amd64_mov_reg_imm(b->jit_ptr,X86_ESI,val);
amd64_alu_reg_membase_size(b->jit_ptr,X86_ADD,
X86_ESI,AMD64_R15,REG_OFFSET(base),4);
/* RBX = mts32_entry index */
amd64_mov_reg_reg_size(b->jit_ptr,X86_EBX,X86_ESI,4);
amd64_mov_reg_reg_size(b->jit_ptr,X86_EAX,X86_ESI,4);
amd64_shift_reg_imm_size(b->jit_ptr,X86_SHR,X86_EBX,MTS32_HASH_SHIFT1,4);
amd64_shift_reg_imm_size(b->jit_ptr,X86_SHR,X86_EAX,MTS32_HASH_SHIFT2,4);
amd64_alu_reg_reg(b->jit_ptr,X86_XOR,AMD64_RBX,AMD64_RAX);
amd64_alu_reg_imm_size(b->jit_ptr,X86_AND,X86_EBX,MTS32_HASH_MASK,4);
/* RCX = mts32 entry */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RCX,
AMD64_R15,
OFFSET(cpu_mips_t,mts_u.mts32_cache),8);
amd64_shift_reg_imm(b->jit_ptr,X86_SHL,AMD64_RBX,5); /* TO FIX */
amd64_alu_reg_reg(b->jit_ptr,X86_ADD,AMD64_RCX,AMD64_RBX);
/* Compare virtual page address (EAX = vpage) */
amd64_mov_reg_reg(b->jit_ptr,X86_EAX,X86_ESI,4);
amd64_alu_reg_imm(b->jit_ptr,X86_AND,X86_EAX,MIPS_MIN_PAGE_MASK);
amd64_alu_reg_membase_size(b->jit_ptr,X86_CMP,X86_EAX,AMD64_RCX,
OFFSET(mts32_entry_t,gvpa),4);
test1 = b->jit_ptr;
x86_branch8(b->jit_ptr, X86_CC_NZ, 0, 1);
/* Test if we are writing to a COW page */
if (write_op) {
amd64_test_membase_imm_size(b->jit_ptr,
AMD64_RCX,OFFSET(mts32_entry_t,flags),
MTS_FLAG_WRCATCH,4);
test2 = b->jit_ptr;
amd64_branch8(b->jit_ptr, X86_CC_NZ, 0, 1);
}
/* ESI = offset in page, RBX = Host Page Address */
amd64_alu_reg_imm(b->jit_ptr,X86_AND,X86_ESI,MIPS_MIN_PAGE_IMASK);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RBX,
AMD64_RCX,OFFSET(mts32_entry_t,hpa),8);
/* Memory access */
op_handler(b,target);
p_exit = b->jit_ptr;
amd64_jump8(b->jit_ptr,0);
/* === Slow lookup === */
amd64_patch(test1,b->jit_ptr);
if (test2)
amd64_patch(test2,b->jit_ptr);
/* Save PC for exception handling */
mips64_set_pc(b,b->vaddr+((b->trans_pos-1)<<2));
/* Sign-extend virtual address */
amd64_movsxd_reg_reg(b->jit_ptr,AMD64_RSI,X86_ESI);
/* RDX = target register */
amd64_mov_reg_imm(b->jit_ptr,AMD64_RDX,target);
/* RDI = CPU instance */
amd64_mov_reg_reg(b->jit_ptr,AMD64_RDI,AMD64_R15,8);
/* Call memory access function */
amd64_alu_reg_imm(b->jit_ptr,X86_SUB,AMD64_RSP,8);
amd64_call_membase(b->jit_ptr,AMD64_R15,MEMOP_OFFSET(opcode));
amd64_alu_reg_imm(b->jit_ptr,X86_ADD,AMD64_RSP,8);
amd64_patch(p_exit,b->jit_ptr);
}
/* Fast memory operation */
static void mips64_emit_memop_fast(cpu_mips_t *cpu,cpu_tc_t *b,
int write_op,int opcode,
int base,int offset,
int target,int keep_ll_bit,
memop_fast_access op_handler)
{
switch(cpu->addr_mode) {
case 32:
mips64_emit_memop_fast32(b,write_op,opcode,base,offset,target,
keep_ll_bit,op_handler);
break;
case 64:
mips64_emit_memop_fast64(b,write_op,opcode,base,offset,target,
keep_ll_bit,op_handler);
break;
}
}
/* Memory operation */
static void mips64_emit_memop(cpu_tc_t *b,int op,int base,int offset,
int target,int keep_ll_bit)
{
m_uint64_t val = sign_extend(offset,16);
/* Save PC for exception handling */
mips64_set_pc(b,b->vaddr+((b->trans_pos-1)<<2));
/* RDI = CPU instance */
amd64_mov_reg_reg(b->jit_ptr,AMD64_RDI,AMD64_R15,8);
if (!keep_ll_bit) {
amd64_clear_reg(b->jit_ptr,AMD64_RCX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_RDI,OFFSET(cpu_mips_t,ll_bit),
X86_ECX,4);
}
/* RSI = GPR[base] + sign-extended offset */
mips64_load_imm(b,AMD64_RSI,val);
amd64_alu_reg_membase(b->jit_ptr,X86_ADD,
AMD64_RSI,AMD64_RDI,REG_OFFSET(base));
/* RDX = target register */
amd64_mov_reg_imm(b->jit_ptr,AMD64_RDX,target);
/* Call memory access function */
amd64_alu_reg_imm(b->jit_ptr,X86_SUB,AMD64_RSP,8);
amd64_call_membase(b->jit_ptr,AMD64_RDI,MEMOP_OFFSET(op));
amd64_alu_reg_imm(b->jit_ptr,X86_ADD,AMD64_RSP,8);
}
/* Coprocessor Register transfert operation */
static void mips64_emit_cp_xfr_op(cpu_tc_t *b,int rt,int rd,void *f)
{
/* update pc */
mips64_set_pc(b,b->vaddr+((b->trans_pos-1)<<2));
/* cp0 register */
amd64_mov_reg_imm(b->jit_ptr,AMD64_RDX,rd);
/* gpr */
amd64_mov_reg_imm(b->jit_ptr,AMD64_RSI,rt);
/* cpu instance */
amd64_mov_reg_reg(b->jit_ptr,AMD64_RDI,AMD64_R15,8);
amd64_alu_reg_imm(b->jit_ptr,X86_SUB,AMD64_RSP,8);
mips64_emit_basic_c_call(b,f);
amd64_alu_reg_imm(b->jit_ptr,X86_ADD,AMD64_RSP,8);
}
/* Virtual Breakpoint */
void mips64_emit_breakpoint(cpu_tc_t *b)
{
amd64_mov_reg_reg(b->jit_ptr,AMD64_RDI,AMD64_R15,8);
amd64_alu_reg_imm(b->jit_ptr,X86_SUB,AMD64_RSP,8);
mips64_emit_c_call(b,mips64_run_breakpoint);
amd64_alu_reg_imm(b->jit_ptr,X86_ADD,AMD64_RSP,8);
}
/* Unknown opcode handler */
static fastcall void mips64_unknown_opcode(cpu_mips_t *cpu,m_uint32_t opcode)
{
printf("CPU = %p\n",cpu);
printf("MIPS64: unhandled opcode 0x%8.8x at 0x%llx (ra=0x%llx)\n",
opcode,cpu->pc,cpu->gpr[MIPS_GPR_RA]);
mips64_dump_regs(cpu->gen);
}
/* Emit unhandled instruction code */
static int mips64_emit_unknown(cpu_mips_t *cpu,cpu_tc_t *b,
mips_insn_t opcode)
{
amd64_mov_reg_imm(b->jit_ptr,AMD64_RSI,opcode);
amd64_mov_reg_reg(b->jit_ptr,AMD64_RDI,AMD64_R15,8);
amd64_alu_reg_imm(b->jit_ptr,X86_SUB,AMD64_RSP,8);
mips64_emit_c_call(b,mips64_unknown_opcode);
amd64_alu_reg_imm(b->jit_ptr,X86_ADD,AMD64_RSP,8);
return(0);
}
/* Invalid delay slot handler */
static fastcall void mips64_invalid_delay_slot(cpu_mips_t *cpu)
{
printf("MIPS64: invalid instruction in delay slot at 0x%llx (ra=0x%llx)\n",
cpu->pc,cpu->gpr[MIPS_GPR_RA]);
mips64_dump_regs(cpu->gen);
/* Halt the virtual CPU */
cpu->pc = 0;
}
/* Emit unhandled instruction code */
int mips64_emit_invalid_delay_slot(cpu_tc_t *b)
{
amd64_mov_reg_reg(b->jit_ptr,AMD64_RDI,AMD64_R15,8);
amd64_alu_reg_imm(b->jit_ptr,X86_SUB,AMD64_RSP,8);
mips64_emit_c_call(b,mips64_invalid_delay_slot);
amd64_alu_reg_imm(b->jit_ptr,X86_ADD,AMD64_RSP,8);
return(0);
}
/*
* Increment count register and trigger the timer IRQ if value in compare
* register is the same.
*/
void mips64_inc_cp0_count_reg(cpu_tc_t *b)
{
amd64_inc_membase_size(b->jit_ptr,
AMD64_R15,OFFSET(cpu_mips_t,cp0_virt_cnt_reg),4);
#if 0 /* TIMER_IRQ */
u_char *test1;
/* increment the virtual count register */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,
AMD64_R15,OFFSET(cpu_mips_t,cp0_virt_cnt_reg),4);
amd64_inc_reg_size(b->jit_ptr,AMD64_RAX,4);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,
OFFSET(cpu_mips_t,cp0_virt_cnt_reg),
AMD64_RAX,4);
/* check with the virtual compare register */
amd64_alu_reg_membase_size(b->jit_ptr,X86_CMP,AMD64_RAX,
AMD64_R15,OFFSET(cpu_mips_t,cp0_virt_cmp_reg),4);
test1 = b->jit_ptr;
amd64_branch8(b->jit_ptr, X86_CC_NE, 0, 1);
/* we have to trigger the timer irq */
amd64_mov_reg_reg(b->jit_ptr,AMD64_RDI,AMD64_R15,8);
mips64_emit_basic_c_call(b,mips64_trigger_timer_irq);
amd64_patch(test1,b->jit_ptr);
#endif
}
/* Check if there are pending IRQ */
void mips64_check_pending_irq(cpu_tc_t *b)
{
u_char *test1;
/* Check the pending IRQ flag */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,
AMD64_R15,OFFSET(cpu_mips_t,irq_pending),4);
amd64_test_reg_reg_size(b->jit_ptr,AMD64_RAX,AMD64_RAX,4);
test1 = b->jit_ptr;
amd64_branch8(b->jit_ptr, X86_CC_Z, 0, 1);
/* Update PC */
mips64_set_pc(b,b->vaddr+((b->trans_pos-1)<<2));
/* Trigger the IRQ */
amd64_mov_reg_reg(b->jit_ptr,AMD64_RDI,AMD64_R15,8);
amd64_alu_reg_imm(b->jit_ptr,X86_SUB,AMD64_RSP,8);
mips64_emit_basic_c_call(b,mips64_trigger_irq);
amd64_alu_reg_imm(b->jit_ptr,X86_ADD,AMD64_RSP,8);
mips64_jit_tcb_push_epilog(b);
amd64_patch(test1,b->jit_ptr);
}
/* Increment the number of executed instructions (performance debugging) */
void mips64_inc_perf_counter(cpu_tc_t *b)
{
amd64_inc_membase_size(b->jit_ptr,
AMD64_R15,OFFSET(cpu_mips_t,perf_counter),4);
}
/* ADD */
DECLARE_INSN(ADD)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_alu_reg_membase(b->jit_ptr,X86_ADD,AMD64_RAX,AMD64_R15,
REG_OFFSET(rt));
amd64_movsxd_reg_reg(b->jit_ptr,AMD64_RAX,X86_EAX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RAX,8);
return(0);
}
/* ADDI */
DECLARE_INSN(ADDI)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int imm = bits(insn,0,15);
m_uint64_t val = sign_extend(imm,16);
/* TODO: Exception handling */
mips64_load_imm(b,AMD64_RAX,val);
amd64_alu_reg_membase(b->jit_ptr,X86_ADD,AMD64_RAX,
AMD64_R15,REG_OFFSET(rs));
amd64_movsxd_reg_reg(b->jit_ptr,AMD64_RAX,X86_EAX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rt),AMD64_RAX,8);
return(0);
}
/* ADDIU */
DECLARE_INSN(ADDIU)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int imm = bits(insn,0,15);
m_uint64_t val = sign_extend(imm,16);
mips64_load_imm(b,AMD64_RAX,val);
if (rs != 0) {
amd64_alu_reg_membase(b->jit_ptr,X86_ADD,AMD64_RAX,
AMD64_R15,REG_OFFSET(rs));
}
amd64_movsxd_reg_reg(b->jit_ptr,AMD64_RDX,X86_EAX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rt),AMD64_RDX,8);
return(0);
}
/* ADDU */
DECLARE_INSN(ADDU)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_alu_reg_membase(b->jit_ptr,X86_ADD,AMD64_RAX,AMD64_R15,
REG_OFFSET(rt));
amd64_movsxd_reg_reg(b->jit_ptr,AMD64_RAX,X86_EAX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RAX,8);
return(0);
}
/* AND */
DECLARE_INSN(AND)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_alu_reg_membase(b->jit_ptr,X86_AND,AMD64_RAX,AMD64_R15,
REG_OFFSET(rt));
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RAX,8);
return(0);
}
/* ANDI */
DECLARE_INSN(ANDI)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int imm = bits(insn,0,15);
mips64_load_imm(b,AMD64_RAX,imm);
amd64_alu_reg_membase(b->jit_ptr,X86_AND,AMD64_RAX,
AMD64_R15,REG_OFFSET(rs));
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rt),AMD64_RAX,8);
return(0);
}
/* B (Branch, virtual instruction) */
DECLARE_INSN(B)
{
int offset = bits(insn,0,15);
m_uint64_t new_pc;
/* compute the new pc */
new_pc = b->vaddr + (b->trans_pos << 2);
new_pc += sign_extend(offset << 2,18);
/* insert the instruction in the delay slot */
mips64_jit_fetch_and_emit(cpu,b,1);
/* set the new pc in cpu structure */
mips64_set_jump(cpu,b,new_pc,1);
return(0);
}
/* BAL (Branch and Link, virtual instruction) */
DECLARE_INSN(BAL)
{
int offset = bits(insn,0,15);
m_uint64_t new_pc;
/* compute the new pc */
new_pc = b->vaddr + (b->trans_pos << 2);
new_pc += sign_extend(offset << 2,18);
/* set the return address (instruction after the delay slot) */
mips64_set_ra(b,b->vaddr + ((b->trans_pos + 1) << 2));
/* insert the instruction in the delay slot */
mips64_jit_fetch_and_emit(cpu,b,1);
/* set the new pc in cpu structure */
mips64_set_jump(cpu,b,new_pc,0);
return(0);
}
/* BEQ (Branch On Equal) */
DECLARE_INSN(BEQ)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int offset = bits(insn,0,15);
u_char *test1;
m_uint64_t new_pc;
/* compute the new pc */
new_pc = b->vaddr + (b->trans_pos << 2);
new_pc += sign_extend(offset << 2,18);
/*
* compare gpr[rs] and gpr[rt].
*/
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_alu_reg_membase(b->jit_ptr,X86_CMP,AMD64_RAX,
AMD64_R15,REG_OFFSET(rt));
test1 = b->jit_ptr;
amd64_branch32(b->jit_ptr, X86_CC_NE, 0, 1);
/* insert the instruction in the delay slot */
mips64_jit_fetch_and_emit(cpu,b,2);
/* set the new pc in cpu structure */
mips64_set_jump(cpu,b,new_pc,1);
amd64_patch(test1,b->jit_ptr);
/* if the branch is not taken, we have to execute the delay slot too */
mips64_jit_fetch_and_emit(cpu,b,1);
return(0);
}
/* BEQL (Branch On Equal Likely) */
DECLARE_INSN(BEQL)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int offset = bits(insn,0,15);
u_char *test1;
m_uint64_t new_pc;
/* compute the new pc */
new_pc = b->vaddr + (b->trans_pos << 2);
new_pc += sign_extend(offset << 2,18);
/*
* compare gpr[rs] and gpr[rt].
*/
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_alu_reg_membase(b->jit_ptr,X86_CMP,AMD64_RAX,
AMD64_R15,REG_OFFSET(rt));
test1 = b->jit_ptr;
amd64_branch32(b->jit_ptr, X86_CC_NE, 0, 1);
/* insert the instruction in the delay slot */
mips64_jit_fetch_and_emit(cpu,b,1);
/* set the new pc in cpu structure */
mips64_set_jump(cpu,b,new_pc,1);
amd64_patch(test1,b->jit_ptr);
return(0);
}
/* BEQZ (Branch On Equal Zero) */
DECLARE_INSN(BEQZ)
{
int rs = bits(insn,21,25);
int offset = bits(insn,0,15);
u_char *test1;
m_uint64_t new_pc;
/* compute the new pc */
new_pc = b->vaddr + (b->trans_pos << 2);
new_pc += sign_extend(offset << 2,18);
/*
* compare gpr[rs] with 0.
*/
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_test_reg_reg(b->jit_ptr,AMD64_RAX,AMD64_RAX);
test1 = b->jit_ptr;
amd64_branch32(b->jit_ptr, X86_CC_NZ, 0, 1);
/* insert the instruction in the delay slot */
mips64_jit_fetch_and_emit(cpu,b,2);
/* set the new pc in cpu structure */
mips64_set_jump(cpu,b,new_pc,1);
amd64_patch(test1,b->jit_ptr);
/* if the branch is not taken, we have to execute the delay slot too */
mips64_jit_fetch_and_emit(cpu,b,1);
return(0);
}
/* BNEZ (Branch On Not Equal Zero) */
DECLARE_INSN(BNEZ)
{
int rs = bits(insn,21,25);
int offset = bits(insn,0,15);
u_char *test1;
m_uint64_t new_pc;
/* compute the new pc */
new_pc = b->vaddr + (b->trans_pos << 2);
new_pc += sign_extend(offset << 2,18);
/*
* compare gpr[rs] with 0.
*/
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_test_reg_reg(b->jit_ptr,AMD64_RAX,AMD64_RAX);
test1 = b->jit_ptr;
amd64_branch32(b->jit_ptr, X86_CC_Z, 0, 1);
/* insert the instruction in the delay slot */
mips64_jit_fetch_and_emit(cpu,b,2);
/* set the new pc in cpu structure */
mips64_set_jump(cpu,b,new_pc,1);
amd64_patch(test1,b->jit_ptr);
/* if the branch is not taken, we have to execute the delay slot too */
mips64_jit_fetch_and_emit(cpu,b,1);
return(0);
}
/* BGEZ (Branch On Greater or Equal Than Zero) */
DECLARE_INSN(BGEZ)
{
int rs = bits(insn,21,25);
int offset = bits(insn,0,15);
u_char *test1;
m_uint64_t new_pc;
/* compute the new pc */
new_pc = b->vaddr + (b->trans_pos << 2);
new_pc += sign_extend(offset << 2,18);
/* If sign bit is set, don't take the branch */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_test_reg_reg(b->jit_ptr,AMD64_RAX,AMD64_RAX);
test1 = b->jit_ptr;
amd64_branch32(b->jit_ptr, X86_CC_S, 0, 1);
/* insert the instruction in the delay slot */
mips64_jit_fetch_and_emit(cpu,b,2);
/* set the new pc in cpu structure */
mips64_set_jump(cpu,b,new_pc,1);
amd64_patch(test1,b->jit_ptr);
/* if the branch is not taken, we have to execute the delay slot too */
mips64_jit_fetch_and_emit(cpu,b,1);
return(0);
}
/* BGEZAL (Branch On Greater or Equal Than Zero And Link) */
DECLARE_INSN(BGEZAL)
{
int rs = bits(insn,21,25);
int offset = bits(insn,0,15);
u_char *test1;
m_uint64_t new_pc;
/* compute the new pc */
new_pc = b->vaddr + (b->trans_pos << 2);
new_pc += sign_extend(offset << 2,18);
/* set the return address (instruction after the delay slot) */
mips64_set_ra(b,b->vaddr + ((b->trans_pos + 1) << 2));
/* If sign bit is set, don't take the branch */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_test_reg_reg(b->jit_ptr,AMD64_RAX,AMD64_RAX);
test1 = b->jit_ptr;
amd64_branch32(b->jit_ptr, X86_CC_S, 0, 1);
/* insert the instruction in the delay slot */
mips64_jit_fetch_and_emit(cpu,b,2);
/* set the new pc in cpu structure */
mips64_set_jump(cpu,b,new_pc,1);
amd64_patch(test1,b->jit_ptr);
/* if the branch is not taken, we have to execute the delay slot too */
mips64_jit_fetch_and_emit(cpu,b,1);
return(0);
}
/* BGEZALL (Branch On Greater or Equal Than Zero And Link Likely) */
DECLARE_INSN(BGEZALL)
{
int rs = bits(insn,21,25);
int offset = bits(insn,0,15);
u_char *test1;
m_uint64_t new_pc;
/* compute the new pc */
new_pc = b->vaddr + (b->trans_pos << 2);
new_pc += sign_extend(offset << 2,18);
/* set the return address (instruction after the delay slot) */
mips64_set_ra(b,b->vaddr + ((b->trans_pos + 1) << 2));
/* If sign bit is set, don't take the branch */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_test_reg_reg(b->jit_ptr,AMD64_RAX,AMD64_RAX);
test1 = b->jit_ptr;
amd64_branch32(b->jit_ptr, X86_CC_S, 0, 1);
/* insert the instruction in the delay slot */
mips64_jit_fetch_and_emit(cpu,b,1);
/* set the new pc in cpu structure */
mips64_set_jump(cpu,b,new_pc,1);
amd64_patch(test1,b->jit_ptr);
return(0);
}
/* BGEZL (Branch On Greater or Equal Than Zero Likely) */
DECLARE_INSN(BGEZL)
{
int rs = bits(insn,21,25);
int offset = bits(insn,0,15);
u_char *test1;
m_uint64_t new_pc;
/* compute the new pc */
new_pc = b->vaddr + (b->trans_pos << 2);
new_pc += sign_extend(offset << 2,18);
/* If sign bit is set, don't take the branch */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_test_reg_reg(b->jit_ptr,AMD64_RAX,AMD64_RAX);
test1 = b->jit_ptr;
amd64_branch32(b->jit_ptr, X86_CC_S, 0, 1);
/* insert the instruction in the delay slot */
mips64_jit_fetch_and_emit(cpu,b,1);
/* set the new pc in cpu structure */
mips64_set_jump(cpu,b,new_pc,1);
amd64_patch(test1,b->jit_ptr);
return(0);
}
/* BGTZ (Branch On Greater Than Zero) */
DECLARE_INSN(BGTZ)
{
int rs = bits(insn,21,25);
int offset = bits(insn,0,15);
u_char *test1;
m_uint64_t new_pc;
/* compute the new pc */
new_pc = b->vaddr + (b->trans_pos << 2);
new_pc += sign_extend(offset << 2,18);
/* compare reg to zero */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_clear_reg(b->jit_ptr,AMD64_RCX);
amd64_alu_reg_reg(b->jit_ptr,X86_CMP,AMD64_RAX,AMD64_RCX);
test1 = b->jit_ptr;
amd64_branch32(b->jit_ptr, X86_CC_LE, 0, 1);
/* insert the instruction in the delay slot */
mips64_jit_fetch_and_emit(cpu,b,2);
/* set the new pc in cpu structure */
mips64_set_jump(cpu,b,new_pc,1);
amd64_patch(test1,b->jit_ptr);
/* if the branch is not taken, we have to execute the delay slot too */
mips64_jit_fetch_and_emit(cpu,b,1);
return(0);
}
/* BGTZL (Branch On Greater Than Zero Likely) */
DECLARE_INSN(BGTZL)
{
int rs = bits(insn,21,25);
int offset = bits(insn,0,15);
u_char *test1;
m_uint64_t new_pc;
/* compute the new pc */
new_pc = b->vaddr + (b->trans_pos << 2);
new_pc += sign_extend(offset << 2,18);
/* compare reg to zero */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_clear_reg(b->jit_ptr,AMD64_RCX);
amd64_alu_reg_reg(b->jit_ptr,X86_CMP,AMD64_RAX,AMD64_RCX);
test1 = b->jit_ptr;
amd64_branch32(b->jit_ptr, X86_CC_LE, 0, 1);
/* insert the instruction in the delay slot */
mips64_jit_fetch_and_emit(cpu,b,1);
/* set the new pc in cpu structure */
mips64_set_jump(cpu,b,new_pc,1);
amd64_patch(test1,b->jit_ptr);
return(0);
}
/* BLEZ (Branch On Less or Equal Than Zero) */
DECLARE_INSN(BLEZ)
{
int rs = bits(insn,21,25);
int offset = bits(insn,0,15);
u_char *test1;
m_uint64_t new_pc;
/* compute the new pc */
new_pc = b->vaddr + (b->trans_pos << 2);
new_pc += sign_extend(offset << 2,18);
/* compare reg to zero */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_clear_reg(b->jit_ptr,AMD64_RCX);
amd64_alu_reg_reg(b->jit_ptr,X86_CMP,AMD64_RAX,AMD64_RCX);
test1 = b->jit_ptr;
amd64_branch32(b->jit_ptr, X86_CC_GT, 0, 1);
/* insert the instruction in the delay slot */
mips64_jit_fetch_and_emit(cpu,b,2);
/* set the new pc in cpu structure */
mips64_set_jump(cpu,b,new_pc,1);
amd64_patch(test1,b->jit_ptr);
/* if the branch is not taken, we have to execute the delay slot too */
mips64_jit_fetch_and_emit(cpu,b,1);
return(0);
}
/* BLEZL (Branch On Less or Equal Than Zero Likely) */
DECLARE_INSN(BLEZL)
{
int rs = bits(insn,21,25);
int offset = bits(insn,0,15);
u_char *test1;
m_uint64_t new_pc;
/* compute the new pc */
new_pc = b->vaddr + (b->trans_pos << 2);
new_pc += sign_extend(offset << 2,18);
/* compare reg to zero */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_clear_reg(b->jit_ptr,AMD64_RCX);
amd64_alu_reg_reg(b->jit_ptr,X86_CMP,AMD64_RAX,AMD64_RCX);
test1 = b->jit_ptr;
amd64_branch32(b->jit_ptr, X86_CC_GT, 0, 1);
/* insert the instruction in the delay slot */
mips64_jit_fetch_and_emit(cpu,b,1);
/* set the new pc in cpu structure */
mips64_set_jump(cpu,b,new_pc,1);
amd64_patch(test1,b->jit_ptr);
return(0);
}
/* BLTZ (Branch On Less Than Zero) */
DECLARE_INSN(BLTZ)
{
int rs = bits(insn,21,25);
int offset = bits(insn,0,15);
u_char *test1;
m_uint64_t new_pc;
/* compute the new pc */
new_pc = b->vaddr + (b->trans_pos << 2);
new_pc += sign_extend(offset << 2,18);
/* If sign bit isn't set, don't take the branch */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_test_reg_reg(b->jit_ptr,AMD64_RAX,AMD64_RAX);
test1 = b->jit_ptr;
amd64_branch32(b->jit_ptr, X86_CC_NS, 0, 1);
/* insert the instruction in the delay slot */
mips64_jit_fetch_and_emit(cpu,b,2);
/* set the new pc in cpu structure */
mips64_set_jump(cpu,b,new_pc,1);
amd64_patch(test1,b->jit_ptr);
/* if the branch is not taken, we have to execute the delay slot too */
mips64_jit_fetch_and_emit(cpu,b,1);
return(0);
}
/* BLTZAL (Branch On Less Than Zero And Link) */
DECLARE_INSN(BLTZAL)
{
int rs = bits(insn,21,25);
int offset = bits(insn,0,15);
u_char *test1;
m_uint64_t new_pc;
/* compute the new pc */
new_pc = b->vaddr + (b->trans_pos << 2);
new_pc += sign_extend(offset << 2,18);
/* set the return address (instruction after the delay slot) */
mips64_set_ra(b,b->vaddr + ((b->trans_pos + 1) << 2));
/* If sign bit isn't set, don't take the branch */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_test_reg_reg(b->jit_ptr,AMD64_RAX,AMD64_RAX);
test1 = b->jit_ptr;
amd64_branch32(b->jit_ptr, X86_CC_NS, 0, 1);
/* insert the instruction in the delay slot */
mips64_jit_fetch_and_emit(cpu,b,2);
/* set the new pc in cpu structure */
mips64_set_jump(cpu,b,new_pc,1);
amd64_patch(test1,b->jit_ptr);
/* if the branch is not taken, we have to execute the delay slot too */
mips64_jit_fetch_and_emit(cpu,b,1);
return(0);
}
/* BLTZALL (Branch On Less Than Zero And Link Likely) */
DECLARE_INSN(BLTZALL)
{
int rs = bits(insn,21,25);
int offset = bits(insn,0,15);
u_char *test1;
m_uint64_t new_pc;
/* compute the new pc */
new_pc = b->vaddr + (b->trans_pos << 2);
new_pc += sign_extend(offset << 2,18);
/* set the return address (instruction after the delay slot) */
mips64_set_ra(b,b->vaddr + ((b->trans_pos + 1) << 2));
/* If sign bit isn't set, don't take the branch */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_test_reg_reg(b->jit_ptr,AMD64_RAX,AMD64_RAX);
test1 = b->jit_ptr;
amd64_branch32(b->jit_ptr, X86_CC_NS, 0, 1);
/* insert the instruction in the delay slot */
mips64_jit_fetch_and_emit(cpu,b,1);
/* set the new pc in cpu structure */
mips64_set_jump(cpu,b,new_pc,1);
amd64_patch(test1,b->jit_ptr);
return(0);
}
/* BLTZL (Branch On Less Than Zero Likely) */
DECLARE_INSN(BLTZL)
{
int rs = bits(insn,21,25);
int offset = bits(insn,0,15);
u_char *test1;
m_uint64_t new_pc;
/* compute the new pc */
new_pc = b->vaddr + (b->trans_pos << 2);
new_pc += sign_extend(offset << 2,18);
/* If sign bit isn't set, don't take the branch */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_test_reg_reg(b->jit_ptr,AMD64_RAX,AMD64_RAX);
test1 = b->jit_ptr;
amd64_branch32(b->jit_ptr, X86_CC_NS, 0, 1);
/* insert the instruction in the delay slot */
mips64_jit_fetch_and_emit(cpu,b,1);
/* set the new pc in cpu structure */
mips64_set_jump(cpu,b,new_pc,1);
amd64_patch(test1,b->jit_ptr);
return(0);
}
/* BNE (Branch On Not Equal) */
DECLARE_INSN(BNE)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int offset = bits(insn,0,15);
u_char *test1;
m_uint64_t new_pc;
/* compute the new pc */
new_pc = b->vaddr + (b->trans_pos << 2);
new_pc += sign_extend(offset << 2,18);
/*
* compare gpr[rs] and gpr[rt].
*/
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_alu_reg_membase(b->jit_ptr,X86_CMP,AMD64_RAX,
AMD64_R15,REG_OFFSET(rt));
test1 = b->jit_ptr;
amd64_branch32(b->jit_ptr, X86_CC_E, 0, 1);
/* insert the instruction in the delay slot */
mips64_jit_fetch_and_emit(cpu,b,2);
/* set the new pc in cpu structure */
mips64_set_jump(cpu,b,new_pc,1);
amd64_patch(test1,b->jit_ptr);
/* if the branch is not taken, we have to execute the delay slot too */
mips64_jit_fetch_and_emit(cpu,b,1);
return(0);
}
/* BNEL (Branch On Not Equal Likely) */
DECLARE_INSN(BNEL)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int offset = bits(insn,0,15);
u_char *test1;
m_uint64_t new_pc;
/* compute the new pc */
new_pc = b->vaddr + (b->trans_pos << 2);
new_pc += sign_extend(offset << 2,18);
/*
* compare gpr[rs] and gpr[rt].
*/
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_alu_reg_membase(b->jit_ptr,X86_CMP,AMD64_RAX,
AMD64_R15,REG_OFFSET(rt));
test1 = b->jit_ptr;
amd64_branch32(b->jit_ptr, X86_CC_E, 0, 1);
/* insert the instruction in the delay slot */
mips64_jit_fetch_and_emit(cpu,b,1);
/* set the new pc in cpu structure */
mips64_set_jump(cpu,b,new_pc,1);
amd64_patch(test1,b->jit_ptr);
return(0);
}
/* BREAK */
DECLARE_INSN(BREAK)
{
u_int code = bits(insn,6,25);
amd64_mov_reg_imm(b->jit_ptr,AMD64_RSI,code);
amd64_mov_reg_reg(b->jit_ptr,AMD64_RDI,AMD64_R15,8);
amd64_alu_reg_imm(b->jit_ptr,X86_SUB,AMD64_RSP,8);
mips64_emit_basic_c_call(b,mips64_exec_break);
amd64_alu_reg_imm(b->jit_ptr,X86_ADD,AMD64_RSP,8);
mips64_jit_tcb_push_epilog(b);
return(0);
}
/* CACHE */
DECLARE_INSN(CACHE)
{
int base = bits(insn,21,25);
int op = bits(insn,16,20);
int offset = bits(insn,0,15);
mips64_emit_memop(b,MIPS_MEMOP_CACHE,base,offset,op,0);
return(0);
}
/* CFC0 */
DECLARE_INSN(CFC0)
{
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
mips64_emit_cp_xfr_op(b,rt,rd,mips64_cp0_exec_cfc0);
return(0);
}
/* CTC0 */
DECLARE_INSN(CTC0)
{
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
mips64_emit_cp_xfr_op(b,rt,rd,mips64_cp0_exec_ctc0);
return(0);
}
/* DADDIU */
DECLARE_INSN(DADDIU)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int imm = bits(insn,0,15);
m_uint64_t val = sign_extend(imm,16);
mips64_load_imm(b,AMD64_RCX,val);
amd64_alu_reg_membase(b->jit_ptr,X86_ADD,AMD64_RCX,
AMD64_R15,REG_OFFSET(rs));
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rt),AMD64_RCX,8);
return(0);
}
/* DADDU: rd = rs + rt */
DECLARE_INSN(DADDU)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RCX,AMD64_R15,REG_OFFSET(rs),8);
amd64_alu_reg_membase(b->jit_ptr,X86_ADD,AMD64_RCX,
AMD64_R15,REG_OFFSET(rt));
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RCX,8);
return(0);
}
/* DIV */
DECLARE_INSN(DIV)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
/* eax = gpr[rs] */
amd64_clear_reg(b->jit_ptr,AMD64_RDX);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),4);
/* ecx = gpr[rt] */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RCX,AMD64_R15,REG_OFFSET(rt),4);
/* eax = quotient (LO), edx = remainder (HI) */
amd64_div_reg_size(b->jit_ptr,AMD64_RCX,1,4);
/* store LO */
amd64_movsxd_reg_reg(b->jit_ptr,AMD64_RAX,X86_EAX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,OFFSET(cpu_mips_t,lo),
AMD64_RAX,8);
/* store HI */
amd64_movsxd_reg_reg(b->jit_ptr,AMD64_RDX,X86_EDX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,OFFSET(cpu_mips_t,hi),
AMD64_RDX,8);
return(0);
}
/* DIVU */
DECLARE_INSN(DIVU)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
/* eax = gpr[rs] */
amd64_clear_reg(b->jit_ptr,AMD64_RDX);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),4);
/* ecx = gpr[rt] */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RCX,AMD64_R15,REG_OFFSET(rt),4);
/* eax = quotient (LO), edx = remainder (HI) */
amd64_div_reg_size(b->jit_ptr,AMD64_RCX,0,4);
/* store LO */
amd64_movsxd_reg_reg(b->jit_ptr,AMD64_RAX,X86_EAX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,OFFSET(cpu_mips_t,lo),
AMD64_RAX,8);
/* store HI */
amd64_movsxd_reg_reg(b->jit_ptr,AMD64_RDX,X86_EDX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,OFFSET(cpu_mips_t,hi),
AMD64_RDX,8);
return(0);
}
/* DMFC0 */
DECLARE_INSN(DMFC0)
{
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
mips64_emit_cp_xfr_op(b,rt,rd,mips64_cp0_exec_dmfc0);
return(0);
}
/* DMFC1 */
DECLARE_INSN(DMFC1)
{
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
mips64_emit_cp_xfr_op(b,rt,rd,mips64_exec_dmfc1);
return(0);
}
/* DMTC0 */
DECLARE_INSN(DMTC0)
{
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
mips64_emit_cp_xfr_op(b,rt,rd,mips64_cp0_exec_dmtc0);
return(0);
}
/* DMTC1 */
DECLARE_INSN(DMTC1)
{
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
mips64_emit_cp_xfr_op(b,rt,rd,mips64_exec_dmtc1);
return(0);
}
/* DSLL */
DECLARE_INSN(DSLL)
{
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
int sa = bits(insn,6,10);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rt),8);
amd64_shift_reg_imm(b->jit_ptr,X86_SHL,AMD64_RAX,sa);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RAX,8);
return(0);
}
/* DSLL32 */
DECLARE_INSN(DSLL32)
{
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
int sa = bits(insn,6,10);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rt),8);
amd64_shift_reg_imm(b->jit_ptr,X86_SHL,AMD64_RAX,sa+32);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RAX,8);
return(0);
}
/* DSLLV */
DECLARE_INSN(DSLLV)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RCX,AMD64_R15,REG_OFFSET(rs),4);
amd64_alu_reg_imm(b->jit_ptr,X86_AND,AMD64_RCX,0x3f);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rt),8);
amd64_shift_reg(b->jit_ptr,X86_SHL,AMD64_RAX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RAX,8);
return(0);
}
/* DSRA */
DECLARE_INSN(DSRA)
{
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
int sa = bits(insn,6,10);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rt),8);
amd64_shift_reg_imm(b->jit_ptr,X86_SAR,AMD64_RAX,sa);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RAX,8);
return(0);
}
/* DSRA32 */
DECLARE_INSN(DSRA32)
{
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
int sa = bits(insn,6,10);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rt),8);
amd64_shift_reg_imm(b->jit_ptr,X86_SAR,AMD64_RAX,sa+32);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RAX,8);
return(0);
}
/* DSRAV */
DECLARE_INSN(DSRAV)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RCX,AMD64_R15,REG_OFFSET(rs),4);
amd64_alu_reg_imm(b->jit_ptr,X86_AND,AMD64_RCX,0x3f);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rt),8);
amd64_shift_reg(b->jit_ptr,X86_SAR,AMD64_RAX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RAX,8);
return(0);
}
/* DSRL */
DECLARE_INSN(DSRL)
{
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
int sa = bits(insn,6,10);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rt),8);
amd64_shift_reg_imm(b->jit_ptr,X86_SHR,AMD64_RAX,sa);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RAX,8);
return(0);
}
/* DSRL32 */
DECLARE_INSN(DSRL32)
{
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
int sa = bits(insn,6,10);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rt),8);
amd64_shift_reg_imm(b->jit_ptr,X86_SHR,AMD64_RAX,sa+32);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RAX,8);
return(0);
}
/* DSRLV */
DECLARE_INSN(DSRLV)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RCX,AMD64_R15,REG_OFFSET(rs),4);
amd64_alu_reg_imm(b->jit_ptr,X86_AND,AMD64_RCX,0x3f);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rt),8);
amd64_shift_reg(b->jit_ptr,X86_SHR,AMD64_RAX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RAX,8);
return(0);
}
/* DSUBU: rd = rs - rt */
DECLARE_INSN(DSUBU)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_alu_reg_membase(b->jit_ptr,X86_SUB,AMD64_RAX,
AMD64_R15,REG_OFFSET(rt));
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RAX,8);
return(0);
}
/* ERET */
DECLARE_INSN(ERET)
{
mips64_set_pc(b,b->vaddr+((b->trans_pos-1)<<2));
amd64_mov_reg_reg(b->jit_ptr,AMD64_RDI,AMD64_R15,8);
amd64_alu_reg_imm(b->jit_ptr,X86_SUB,AMD64_RSP,8);
mips64_emit_basic_c_call(b,mips64_exec_eret);
amd64_alu_reg_imm(b->jit_ptr,X86_ADD,AMD64_RSP,8);
mips64_jit_tcb_push_epilog(b);
return(0);
}
/* J (Jump) */
DECLARE_INSN(J)
{
u_int instr_index = bits(insn,0,25);
m_uint64_t new_pc;
/* compute the new pc */
new_pc = b->vaddr + (b->trans_pos << 2);
new_pc &= ~((1 << 28) - 1);
new_pc |= instr_index << 2;
/* insert the instruction in the delay slot */
mips64_jit_fetch_and_emit(cpu,b,1);
/* set the new pc in cpu structure */
mips64_set_jump(cpu,b,new_pc,1);
return(0);
}
/* JAL (Jump And Link) */
DECLARE_INSN(JAL)
{
u_int instr_index = bits(insn,0,25);
m_uint64_t new_pc;
/* compute the new pc */
new_pc = b->vaddr + (b->trans_pos << 2);
new_pc &= ~((1 << 28) - 1);
new_pc |= instr_index << 2;
/* set the return address (instruction after the delay slot) */
mips64_set_ra(b,b->vaddr + ((b->trans_pos + 1) << 2));
/* insert the instruction in the delay slot */
mips64_jit_fetch_and_emit(cpu,b,1);
/* set the new pc in cpu structure */
mips64_set_jump(cpu,b,new_pc,0);
return(0);
}
/* JALR (Jump and Link Register) */
DECLARE_INSN(JALR)
{
int rs = bits(insn,21,25);
int rd = bits(insn,11,15);
m_uint64_t ret_pc;
/* set the return pc (instruction after the delay slot) in GPR[rd] */
ret_pc = b->vaddr + ((b->trans_pos + 1) << 2);
mips64_load_imm(b,AMD64_RAX,ret_pc);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RAX,8);
/* get the new pc */
amd64_mov_reg_membase(b->jit_ptr,AMD64_R14,AMD64_R15,REG_OFFSET(rs),8);
#if DEBUG_JR0
{
u_char *test1;
amd64_test_reg_reg(b->jit_ptr,AMD64_R14,AMD64_R14);
test1 = b->jit_ptr;
amd64_branch8(b->jit_ptr, X86_CC_NZ, 0, 1);
amd64_mov_reg_reg(b->jit_ptr,AMD64_RDI,AMD64_R15,8);
amd64_alu_reg_imm(b->jit_ptr,X86_SUB,AMD64_RSP,8);
mips64_emit_c_call(b,mips64_debug_jr0);
amd64_alu_reg_imm(b->jit_ptr,X86_ADD,AMD64_RSP,8);
amd64_patch(test1,b->jit_ptr);
}
#endif
/* insert the instruction in the delay slot */
mips64_jit_fetch_and_emit(cpu,b,1);
/* set the new pc */
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,OFFSET(cpu_mips_t,pc),
AMD64_R14,8);
/* returns to the caller which will determine the next path */
mips64_jit_tcb_push_epilog(b);
return(0);
}
/* JR (Jump Register) */
DECLARE_INSN(JR)
{
int rs = bits(insn,21,25);
/* get the new pc */
amd64_mov_reg_membase(b->jit_ptr,AMD64_R14,AMD64_R15,REG_OFFSET(rs),8);
#if DEBUG_JR0
{
u_char *test1;
amd64_test_reg_reg(b->jit_ptr,AMD64_RCX,AMD64_RCX);
test1 = b->jit_ptr;
amd64_branch8(b->jit_ptr, X86_CC_NZ, 0, 1);
amd64_mov_reg_reg(b->jit_ptr,AMD64_RDI,AMD64_R15,8);
amd64_alu_reg_imm(b->jit_ptr,X86_SUB,AMD64_RSP,8);
mips64_emit_c_call(b,mips64_debug_jr0);
amd64_alu_reg_imm(b->jit_ptr,X86_ADD,AMD64_RSP,8);
amd64_patch(test1,b->jit_ptr);
}
#endif
/* insert the instruction in the delay slot */
mips64_jit_fetch_and_emit(cpu,b,1);
/* set the new pc */
amd64_mov_membase_reg(b->jit_ptr,
AMD64_R15,OFFSET(cpu_mips_t,pc),
AMD64_R14,8);
/* returns to the caller which will determine the next path */
mips64_jit_tcb_push_epilog(b);
return(0);
}
/* LB (Load Byte) */
DECLARE_INSN(LB)
{
int base = bits(insn,21,25);
int rt = bits(insn,16,20);
int offset = bits(insn,0,15);
mips64_emit_memop(b,MIPS_MEMOP_LB,base,offset,rt,TRUE);
return(0);
}
/* LBU (Load Byte Unsigned) */
DECLARE_INSN(LBU)
{
int base = bits(insn,21,25);
int rt = bits(insn,16,20);
int offset = bits(insn,0,15);
mips64_emit_memop(b,MIPS_MEMOP_LBU,base,offset,rt,TRUE);
return(0);
}
/* LD (Load Double-Word) */
DECLARE_INSN(LD)
{
int base = bits(insn,21,25);
int rt = bits(insn,16,20);
int offset = bits(insn,0,15);
mips64_emit_memop(b,MIPS_MEMOP_LD,base,offset,rt,TRUE);
return(0);
}
/* LDC1 (Load Double-Word to Coprocessor 1) */
DECLARE_INSN(LDC1)
{
int base = bits(insn,21,25);
int ft = bits(insn,16,20);
int offset = bits(insn,0,15);
mips64_emit_memop(b,MIPS_MEMOP_LDC1,base,offset,ft,TRUE);
return(0);
}
/* LDL (Load Double-Word Left) */
DECLARE_INSN(LDL)
{
int base = bits(insn,21,25);
int rt = bits(insn,16,20);
int offset = bits(insn,0,15);
mips64_emit_memop(b,MIPS_MEMOP_LDL,base,offset,rt,TRUE);
return(0);
}
/* LDR (Load Double-Word Right) */
DECLARE_INSN(LDR)
{
int base = bits(insn,21,25);
int rt = bits(insn,16,20);
int offset = bits(insn,0,15);
mips64_emit_memop(b,MIPS_MEMOP_LDR,base,offset,rt,TRUE);
return(0);
}
/* LH (Load Half-Word) */
DECLARE_INSN(LH)
{
int base = bits(insn,21,25);
int rt = bits(insn,16,20);
int offset = bits(insn,0,15);
mips64_emit_memop(b,MIPS_MEMOP_LH,base,offset,rt,TRUE);
return(0);
}
/* LHU (Load Half-Word Unsigned) */
DECLARE_INSN(LHU)
{
int base = bits(insn,21,25);
int rt = bits(insn,16,20);
int offset = bits(insn,0,15);
mips64_emit_memop(b,MIPS_MEMOP_LHU,base,offset,rt,TRUE);
return(0);
}
/* LI (virtual) */
DECLARE_INSN(LI)
{
int rt = bits(insn,16,20);
int imm = bits(insn,0,15);
m_uint64_t val = sign_extend(imm,16);
mips64_load_imm(b,AMD64_RCX,val);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rt),AMD64_RCX,8);
return(0);
}
/* LL (Load Linked) */
DECLARE_INSN(LL)
{
int base = bits(insn,21,25);
int rt = bits(insn,16,20);
int offset = bits(insn,0,15);
mips64_emit_memop(b,MIPS_MEMOP_LL,base,offset,rt,TRUE);
return(0);
}
/* LUI */
DECLARE_INSN(LUI)
{
int rt = bits(insn,16,20);
int imm = bits(insn,0,15);
m_uint64_t val = sign_extend(imm,16) << 16;
#if 1
mips64_load_imm(b,AMD64_RCX,val);
#else
amd64_mov_reg_imm(b->jit_ptr,AMD64_RCX,imm);
amd64_shift_reg_imm(b->jit_ptr,X86_SHL,AMD64_RCX,48);
amd64_shift_reg_imm(b->jit_ptr,X86_SAR,AMD64_RCX,32);
#endif
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rt),AMD64_RCX,8);
return(0);
}
/* LW (Load Word) */
DECLARE_INSN(LW)
{
int base = bits(insn,21,25);
int rt = bits(insn,16,20);
int offset = bits(insn,0,15);
if (cpu->fast_memop) {
mips64_emit_memop_fast(cpu,b,0,MIPS_MEMOP_LW,base,offset,rt,TRUE,
mips64_memop_fast_lw);
} else {
mips64_emit_memop(b,MIPS_MEMOP_LW,base,offset,rt,TRUE);
}
return(0);
}
/* LWL (Load Word Left) */
DECLARE_INSN(LWL)
{
int base = bits(insn,21,25);
int rt = bits(insn,16,20);
int offset = bits(insn,0,15);
mips64_emit_memop(b,MIPS_MEMOP_LWL,base,offset,rt,TRUE);
return(0);
}
/* LWR (Load Word Right) */
DECLARE_INSN(LWR)
{
int base = bits(insn,21,25);
int rt = bits(insn,16,20);
int offset = bits(insn,0,15);
mips64_emit_memop(b,MIPS_MEMOP_LWR,base,offset,rt,TRUE);
return(0);
}
/* LWU (Load Word Unsigned) */
DECLARE_INSN(LWU)
{
int base = bits(insn,21,25);
int rt = bits(insn,16,20);
int offset = bits(insn,0,15);
mips64_emit_memop(b,MIPS_MEMOP_LWU,base,offset,rt,TRUE);
return(0);
}
/* MFC0 */
DECLARE_INSN(MFC0)
{
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
mips64_emit_cp_xfr_op(b,rt,rd,mips64_cp0_exec_mfc0);
return(0);
}
/* MFC1 */
DECLARE_INSN(MFC1)
{
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
mips64_emit_cp_xfr_op(b,rt,rd,mips64_exec_mfc1);
return(0);
}
/* MFHI */
DECLARE_INSN(MFHI)
{
int rd = bits(insn,11,15);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RDX,
AMD64_R15,OFFSET(cpu_mips_t,hi),8);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RDX,8);
return(0);
}
/* MFLO */
DECLARE_INSN(MFLO)
{
int rd = bits(insn,11,15);
if (!rd) return(0);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RDX,
AMD64_R15,OFFSET(cpu_mips_t,lo),8);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RDX,8);
return(0);
}
/* MOVE (virtual instruction, real: ADDU) */
DECLARE_INSN(MOVE)
{
int rs = bits(insn,21,25);
int rd = bits(insn,11,15);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RDX,AMD64_R15,REG_OFFSET(rs),4);
amd64_movsxd_reg_reg(b->jit_ptr,AMD64_RDX,X86_EDX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RDX,8);
return(0);
}
/* MOVZ */
DECLARE_INSN(MOVZ)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
u_char *test1;
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rt),8);
amd64_test_reg_reg(b->jit_ptr,AMD64_RAX,AMD64_RAX);
test1 = b->jit_ptr;
amd64_branch32(b->jit_ptr, X86_CC_NZ, 0, 1);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RDX,AMD64_R15,REG_OFFSET(rs),8);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RDX,8);
amd64_patch(test1,b->jit_ptr);
return(0);
}
/* MTC0 */
DECLARE_INSN(MTC0)
{
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
mips64_emit_cp_xfr_op(b,rt,rd,mips64_cp0_exec_mtc0);
return(0);
}
/* MTC1 */
DECLARE_INSN(MTC1)
{
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
mips64_emit_cp_xfr_op(b,rt,rd,mips64_exec_mtc1);
return(0);
}
/* MTHI */
DECLARE_INSN(MTHI)
{
int rs = bits(insn,21,25);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RDX,AMD64_R15,REG_OFFSET(rs),8);
amd64_mov_membase_reg(b->jit_ptr,
AMD64_R15,OFFSET(cpu_mips_t,hi),AMD64_RDX,8);
return(0);
}
/* MTLO */
DECLARE_INSN(MTLO)
{
int rs = bits(insn,21,25);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RDX,AMD64_R15,REG_OFFSET(rs),8);
amd64_mov_membase_reg(b->jit_ptr,
AMD64_R15,OFFSET(cpu_mips_t,lo),AMD64_RDX,8);
return(0);
}
/* MUL */
DECLARE_INSN(MUL)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
/* eax = gpr[rs] */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),4);
/* ecx = gpr[rt] */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RCX,AMD64_R15,REG_OFFSET(rt),4);
amd64_mul_reg_size(b->jit_ptr,AMD64_RCX,1,4);
/* store result in gpr[rd] */
amd64_movsxd_reg_reg(b->jit_ptr,AMD64_RAX,X86_EAX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RAX,8);
return(0);
}
/* MULT */
DECLARE_INSN(MULT)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
/* eax = gpr[rs] */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),4);
/* ecx = gpr[rt] */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RCX,AMD64_R15,REG_OFFSET(rt),4);
amd64_mul_reg_size(b->jit_ptr,AMD64_RCX,1,4);
/* store LO */
amd64_movsxd_reg_reg(b->jit_ptr,AMD64_RAX,X86_EAX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,OFFSET(cpu_mips_t,lo),
AMD64_RAX,8);
/* store HI */
amd64_movsxd_reg_reg(b->jit_ptr,AMD64_RDX,X86_EDX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,OFFSET(cpu_mips_t,hi),
AMD64_RDX,8);
return(0);
}
/* MULTU */
DECLARE_INSN(MULTU)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
/* eax = gpr[rs] */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),4);
/* ecx = gpr[rt] */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RCX,AMD64_R15,REG_OFFSET(rt),4);
amd64_mul_reg_size(b->jit_ptr,AMD64_RCX,0,4);
/* store LO */
amd64_movsxd_reg_reg(b->jit_ptr,AMD64_RAX,X86_EAX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,OFFSET(cpu_mips_t,lo),
AMD64_RAX,8);
/* store HI */
amd64_movsxd_reg_reg(b->jit_ptr,AMD64_RDX,X86_EDX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,OFFSET(cpu_mips_t,hi),
AMD64_RDX,8);
return(0);
}
/* NOP */
DECLARE_INSN(NOP)
{
return(0);
}
/* NOR */
DECLARE_INSN(NOR)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_alu_reg_membase(b->jit_ptr,X86_OR,AMD64_RAX,AMD64_R15,
REG_OFFSET(rt));
amd64_not_reg(b->jit_ptr,AMD64_RAX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RAX,8);
return(0);
}
/* OR */
DECLARE_INSN(OR)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_alu_reg_membase(b->jit_ptr,X86_OR,AMD64_RAX,AMD64_R15,
REG_OFFSET(rt));
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RAX,8);
return(0);
}
/* ORI */
DECLARE_INSN(ORI)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int imm = bits(insn,0,15);
mips64_load_imm(b,AMD64_RAX,imm);
amd64_alu_reg_membase(b->jit_ptr,X86_OR,AMD64_RAX,
AMD64_R15,REG_OFFSET(rs));
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rt),AMD64_RAX,8);
return(0);
}
/* PREF */
DECLARE_INSN(PREF)
{
amd64_nop(b->jit_ptr);
return(0);
}
/* PREFI */
DECLARE_INSN(PREFI)
{
amd64_nop(b->jit_ptr);
return(0);
}
/* SB (Store Byte) */
DECLARE_INSN(SB)
{
int base = bits(insn,21,25);
int rt = bits(insn,16,20);
int offset = bits(insn,0,15);
mips64_emit_memop(b,MIPS_MEMOP_SB,base,offset,rt,FALSE);
return(0);
}
/* SC (Store Conditional) */
DECLARE_INSN(SC)
{
int base = bits(insn,21,25);
int rt = bits(insn,16,20);
int offset = bits(insn,0,15);
mips64_emit_memop(b,MIPS_MEMOP_SC,base,offset,rt,TRUE);
return(0);
}
/* SD (Store Double-Word) */
DECLARE_INSN(SD)
{
int base = bits(insn,21,25);
int rt = bits(insn,16,20);
int offset = bits(insn,0,15);
mips64_emit_memop(b,MIPS_MEMOP_SD,base,offset,rt,FALSE);
return(0);
}
/* SDL (Store Double-Word Left) */
DECLARE_INSN(SDL)
{
int base = bits(insn,21,25);
int rt = bits(insn,16,20);
int offset = bits(insn,0,15);
mips64_emit_memop(b,MIPS_MEMOP_SDL,base,offset,rt,FALSE);
return(0);
}
/* SDR (Store Double-Word Right) */
DECLARE_INSN(SDR)
{
int base = bits(insn,21,25);
int rt = bits(insn,16,20);
int offset = bits(insn,0,15);
mips64_emit_memop(b,MIPS_MEMOP_SDR,base,offset,rt,FALSE);
return(0);
}
/* SDC1 (Store Double-Word from Coprocessor 1) */
DECLARE_INSN(SDC1)
{
int base = bits(insn,21,25);
int ft = bits(insn,16,20);
int offset = bits(insn,0,15);
mips64_emit_memop(b,MIPS_MEMOP_SDC1,base,offset,ft,FALSE);
return(0);
}
/* SH (Store Half-Word) */
DECLARE_INSN(SH)
{
int base = bits(insn,21,25);
int rt = bits(insn,16,20);
int offset = bits(insn,0,15);
mips64_emit_memop(b,MIPS_MEMOP_SH,base,offset,rt,FALSE);
return(0);
}
/* SLL */
DECLARE_INSN(SLL)
{
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
int sa = bits(insn,6,10);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rt),4);
amd64_shift_reg_imm(b->jit_ptr,X86_SHL,AMD64_RAX,sa);
amd64_movsxd_reg_reg(b->jit_ptr,AMD64_RAX,X86_EAX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RAX,8);
return(0);
}
/* SLLV */
DECLARE_INSN(SLLV)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RCX,AMD64_R15,REG_OFFSET(rs),4);
amd64_alu_reg_imm(b->jit_ptr,X86_AND,AMD64_RCX,0x1f);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rt),4);
amd64_shift_reg(b->jit_ptr,X86_SHL,AMD64_RAX);
amd64_movsxd_reg_reg(b->jit_ptr,AMD64_RAX,X86_EAX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RAX,8);
return(0);
}
/* SLT */
DECLARE_INSN(SLT)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
u_char *test1;
/* RDX = gpr[rs] */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RDX,AMD64_R15,REG_OFFSET(rs),8);
/* RAX = gpr[rt] */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rt),8);
/* we set rd to 1 when gpr[rs] < gpr[rt] */
amd64_clear_reg(b->jit_ptr,AMD64_RCX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RCX,8);
amd64_alu_reg_reg(b->jit_ptr,X86_CMP,AMD64_RDX,AMD64_RAX);
test1 = b->jit_ptr;
amd64_branch8(b->jit_ptr, X86_CC_GE, 0, 1);
amd64_inc_membase(b->jit_ptr,AMD64_R15,REG_OFFSET(rd));
/* end */
amd64_patch(test1,b->jit_ptr);
return(0);
}
/* SLTI */
DECLARE_INSN(SLTI)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int imm = bits(insn,0,15);
m_uint64_t val = sign_extend(imm,16);
u_char *test1;
/* RDX = val */
mips64_load_imm(b,AMD64_RDX,val);
/* RAX = gpr[rs] */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
/* we set rt to 1 when gpr[rs] < val */
amd64_clear_reg(b->jit_ptr,AMD64_RCX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rt),AMD64_RCX,8);
amd64_alu_reg_reg(b->jit_ptr,X86_CMP,AMD64_RAX,AMD64_RDX);
test1 = b->jit_ptr;
amd64_branch8(b->jit_ptr, X86_CC_GE, 0, 1);
amd64_inc_membase(b->jit_ptr,AMD64_R15,REG_OFFSET(rt));
/* end */
amd64_patch(test1,b->jit_ptr);
return(0);
}
/* SLTU */
DECLARE_INSN(SLTU)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
u_char *test1;
/* RDX = gpr[rs] */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RDX,AMD64_R15,REG_OFFSET(rs),8);
/* RAX = gpr[rt] */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rt),8);
/* we set rd to 1 when gpr[rs] < gpr[rt] */
amd64_clear_reg(b->jit_ptr,AMD64_RCX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RCX,8);
amd64_alu_reg_reg(b->jit_ptr,X86_CMP,AMD64_RDX,AMD64_RAX);
test1 = b->jit_ptr;
amd64_branch8(b->jit_ptr, X86_CC_AE, 0, 0);
amd64_inc_membase(b->jit_ptr,AMD64_R15,REG_OFFSET(rd));
/* end */
amd64_patch(test1,b->jit_ptr);
return(0);
}
/* SLTIU */
DECLARE_INSN(SLTIU)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int imm = bits(insn,0,15);
m_uint64_t val = sign_extend(imm,16);
u_char *test1;
/* RDX = val */
mips64_load_imm(b,AMD64_RDX,val);
/* RAX = gpr[rs] */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
/* we set rt to 1 when gpr[rs] < val */
amd64_clear_reg(b->jit_ptr,AMD64_RCX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rt),AMD64_RCX,8);
amd64_alu_reg_reg(b->jit_ptr,X86_CMP,AMD64_RAX,AMD64_RDX);
test1 = b->jit_ptr;
amd64_branch8(b->jit_ptr, X86_CC_AE, 0, 0);
amd64_inc_membase(b->jit_ptr,AMD64_R15,REG_OFFSET(rt));
/* end */
amd64_patch(test1,b->jit_ptr);
return(0);
}
/* SRA */
DECLARE_INSN(SRA)
{
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
int sa = bits(insn,6,10);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rt),4);
amd64_shift_reg_imm_size(b->jit_ptr,X86_SAR,AMD64_RAX,sa,4);
amd64_movsxd_reg_reg(b->jit_ptr,AMD64_RAX,X86_EAX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RAX,8);
return(0);
}
/* SRAV */
DECLARE_INSN(SRAV)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RCX,AMD64_R15,REG_OFFSET(rs),4);
amd64_alu_reg_imm(b->jit_ptr,X86_AND,AMD64_RCX,0x1f);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rt),4);
amd64_shift_reg_size(b->jit_ptr,X86_SAR,AMD64_RAX,4);
amd64_movsxd_reg_reg(b->jit_ptr,AMD64_RAX,X86_EAX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RAX,8);
return(0);
}
/* SRL */
DECLARE_INSN(SRL)
{
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
int sa = bits(insn,6,10);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rt),4);
amd64_shift_reg_imm(b->jit_ptr,X86_SHR,AMD64_RAX,sa);
amd64_movsxd_reg_reg(b->jit_ptr,AMD64_RAX,X86_EAX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RAX,8);
return(0);
}
/* SRLV */
DECLARE_INSN(SRLV)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RCX,AMD64_R15,REG_OFFSET(rs),4);
amd64_alu_reg_imm(b->jit_ptr,X86_AND,AMD64_RCX,0x1f);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rt),4);
amd64_shift_reg(b->jit_ptr,X86_SHR,AMD64_RAX);
amd64_movsxd_reg_reg(b->jit_ptr,AMD64_RAX,X86_EAX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RAX,8);
return(0);
}
/* SUB */
DECLARE_INSN(SUB)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
/* TODO: Exception handling */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_alu_reg_membase(b->jit_ptr,X86_SUB,AMD64_RAX,AMD64_R15,
REG_OFFSET(rt));
amd64_movsxd_reg_reg(b->jit_ptr,AMD64_RAX,X86_EAX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RAX,8);
return(0);
}
/* SUBU */
DECLARE_INSN(SUBU)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_alu_reg_membase(b->jit_ptr,X86_SUB,AMD64_RAX,AMD64_R15,
REG_OFFSET(rt));
amd64_movsxd_reg_reg(b->jit_ptr,AMD64_RAX,X86_EAX);
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RAX,8);
return(0);
}
/* SW (Store Word) */
DECLARE_INSN(SW)
{
int base = bits(insn,21,25);
int rt = bits(insn,16,20);
int offset = bits(insn,0,15);
if (cpu->fast_memop) {
mips64_emit_memop_fast(cpu,b,1,MIPS_MEMOP_SW,base,offset,rt,FALSE,
mips64_memop_fast_sw);
} else {
mips64_emit_memop(b,MIPS_MEMOP_SW,base,offset,rt,FALSE);
}
return(0);
}
/* SWL (Store Word Left) */
DECLARE_INSN(SWL)
{
int base = bits(insn,21,25);
int rt = bits(insn,16,20);
int offset = bits(insn,0,15);
mips64_emit_memop(b,MIPS_MEMOP_SWL,base,offset,rt,FALSE);
return(0);
}
/* SWR (Store Word Right) */
DECLARE_INSN(SWR)
{
int base = bits(insn,21,25);
int rt = bits(insn,16,20);
int offset = bits(insn,0,15);
mips64_emit_memop(b,MIPS_MEMOP_SWR,base,offset,rt,FALSE);
return(0);
}
/* SYNC */
DECLARE_INSN(SYNC)
{
return(0);
}
/* SYSCALL */
DECLARE_INSN(SYSCALL)
{
mips64_set_pc(b,b->vaddr+((b->trans_pos-1)<<2));
amd64_mov_reg_reg(b->jit_ptr,AMD64_RDI,AMD64_R15,8);
amd64_alu_reg_imm(b->jit_ptr,X86_SUB,AMD64_RSP,8);
mips64_emit_basic_c_call(b,mips64_exec_syscall);
amd64_alu_reg_imm(b->jit_ptr,X86_ADD,AMD64_RSP,8);
mips64_jit_tcb_push_epilog(b);
return(0);
}
/* TEQ (Trap If Equal) */
DECLARE_INSN(TEQ)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
u_char *test1;
/*
* compare gpr[rs] and gpr[rt].
*/
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_alu_reg_membase(b->jit_ptr,X86_CMP,AMD64_RAX,
AMD64_R15,REG_OFFSET(rt));
test1 = b->jit_ptr;
amd64_branch8(b->jit_ptr, X86_CC_NE, 0, 1);
/* Generate trap exception */
amd64_mov_reg_reg(b->jit_ptr,AMD64_RDI,AMD64_R15,8);
amd64_alu_reg_imm(b->jit_ptr,X86_SUB,AMD64_RSP,8);
mips64_emit_c_call(b,mips64_trigger_trap_exception);
amd64_alu_reg_imm(b->jit_ptr,X86_ADD,AMD64_RSP,8);
mips64_jit_tcb_push_epilog(b);
/* end */
amd64_patch(test1,b->jit_ptr);
return(0);
}
/* TEQI (Trap If Equal Immediate) */
DECLARE_INSN(TEQI)
{
int rs = bits(insn,21,25);
int imm = bits(insn,0,15);
m_uint64_t val = sign_extend(imm,16);
u_char *test1;
/* RDX = val */
mips64_load_imm(b,AMD64_RDX,val);
/* RAX = gpr[rs] */
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_alu_reg_reg(b->jit_ptr,X86_CMP,AMD64_RAX,AMD64_RDX);
test1 = b->jit_ptr;
amd64_branch8(b->jit_ptr, X86_CC_NE, 0, 1);
/* Generate trap exception */
amd64_mov_reg_reg(b->jit_ptr,AMD64_RDI,AMD64_R15,8);
amd64_alu_reg_imm(b->jit_ptr,X86_SUB,AMD64_RSP,8);
mips64_emit_c_call(b,mips64_trigger_trap_exception);
amd64_alu_reg_imm(b->jit_ptr,X86_ADD,AMD64_RSP,8);
mips64_jit_tcb_push_epilog(b);
/* end */
amd64_patch(test1,b->jit_ptr);
return(0);
}
/* TLBP */
DECLARE_INSN(TLBP)
{
mips64_set_pc(b,b->vaddr+((b->trans_pos-1)<<2));
amd64_mov_reg_reg(b->jit_ptr,AMD64_RDI,AMD64_R15,8);
amd64_alu_reg_imm(b->jit_ptr,X86_SUB,AMD64_RSP,8);
mips64_emit_basic_c_call(b,mips64_cp0_exec_tlbp);
amd64_alu_reg_imm(b->jit_ptr,X86_ADD,AMD64_RSP,8);
return(0);
}
/* TLBR */
DECLARE_INSN(TLBR)
{
mips64_set_pc(b,b->vaddr+((b->trans_pos-1)<<2));
amd64_mov_reg_reg(b->jit_ptr,AMD64_RDI,AMD64_R15,8);
amd64_alu_reg_imm(b->jit_ptr,X86_SUB,AMD64_RSP,8);
mips64_emit_basic_c_call(b,mips64_cp0_exec_tlbr);
amd64_alu_reg_imm(b->jit_ptr,X86_ADD,AMD64_RSP,8);
return(0);
}
/* TLBWI */
DECLARE_INSN(TLBWI)
{
mips64_set_pc(b,b->vaddr+((b->trans_pos-1)<<2));
amd64_mov_reg_reg(b->jit_ptr,AMD64_RDI,AMD64_R15,8);
amd64_alu_reg_imm(b->jit_ptr,X86_SUB,AMD64_RSP,8);
mips64_emit_basic_c_call(b,mips64_cp0_exec_tlbwi);
amd64_alu_reg_imm(b->jit_ptr,X86_ADD,AMD64_RSP,8);
return(0);
}
/* TLBWR */
DECLARE_INSN(TLBWR)
{
mips64_set_pc(b,b->vaddr+((b->trans_pos-1)<<2));
amd64_mov_reg_reg(b->jit_ptr,AMD64_RDI,AMD64_R15,8);
amd64_alu_reg_imm(b->jit_ptr,X86_SUB,AMD64_RSP,8);
mips64_emit_basic_c_call(b,mips64_cp0_exec_tlbwr);
amd64_alu_reg_imm(b->jit_ptr,X86_ADD,AMD64_RSP,8);
return(0);
}
/* XOR */
DECLARE_INSN(XOR)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int rd = bits(insn,11,15);
amd64_mov_reg_membase(b->jit_ptr,AMD64_RAX,AMD64_R15,REG_OFFSET(rs),8);
amd64_alu_reg_membase(b->jit_ptr,X86_XOR,AMD64_RAX,AMD64_R15,
REG_OFFSET(rt));
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rd),AMD64_RAX,8);
return(0);
}
/* XORI */
DECLARE_INSN(XORI)
{
int rs = bits(insn,21,25);
int rt = bits(insn,16,20);
int imm = bits(insn,0,15);
mips64_load_imm(b,AMD64_RAX,imm);
amd64_alu_reg_membase(b->jit_ptr,X86_XOR,AMD64_RAX,
AMD64_R15,REG_OFFSET(rs));
amd64_mov_membase_reg(b->jit_ptr,AMD64_R15,REG_OFFSET(rt),AMD64_RAX,8);
return(0);
}
/* MIPS instruction array */
struct mips64_insn_tag mips64_insn_tags[] = {
{ mips64_emit_LI , 0xffe00000 , 0x24000000, 1 }, /* virtual */
{ mips64_emit_MOVE , 0xfc1f07ff , 0x00000021, 1 }, /* virtual */
{ mips64_emit_B , 0xffff0000 , 0x10000000, 0 }, /* virtual */
{ mips64_emit_BAL , 0xffff0000 , 0x04110000, 0 }, /* virtual */
{ mips64_emit_BEQZ , 0xfc1f0000 , 0x10000000, 0 }, /* virtual */
{ mips64_emit_BNEZ , 0xfc1f0000 , 0x14000000, 0 }, /* virtual */
{ mips64_emit_ADD , 0xfc0007ff , 0x00000020, 1 },
{ mips64_emit_ADDI , 0xfc000000 , 0x20000000, 1 },
{ mips64_emit_ADDIU , 0xfc000000 , 0x24000000, 1 },
{ mips64_emit_ADDU , 0xfc0007ff , 0x00000021, 1 },
{ mips64_emit_AND , 0xfc0007ff , 0x00000024, 1 },
{ mips64_emit_ANDI , 0xfc000000 , 0x30000000, 1 },
{ mips64_emit_BEQ , 0xfc000000 , 0x10000000, 0 },
{ mips64_emit_BEQL , 0xfc000000 , 0x50000000, 0 },
{ mips64_emit_BGEZ , 0xfc1f0000 , 0x04010000, 0 },
{ mips64_emit_BGEZAL , 0xfc1f0000 , 0x04110000, 0 },
{ mips64_emit_BGEZALL , 0xfc1f0000 , 0x04130000, 0 },
{ mips64_emit_BGEZL , 0xfc1f0000 , 0x04030000, 0 },
{ mips64_emit_BGTZ , 0xfc1f0000 , 0x1c000000, 0 },
{ mips64_emit_BGTZL , 0xfc1f0000 , 0x5c000000, 0 },
{ mips64_emit_BLEZ , 0xfc1f0000 , 0x18000000, 0 },
{ mips64_emit_BLEZL , 0xfc1f0000 , 0x58000000, 0 },
{ mips64_emit_BLTZ , 0xfc1f0000 , 0x04000000, 0 },
{ mips64_emit_BLTZAL , 0xfc1f0000 , 0x04100000, 0 },
{ mips64_emit_BLTZALL , 0xfc1f0000 , 0x04120000, 0 },
{ mips64_emit_BLTZL , 0xfc1f0000 , 0x04020000, 0 },
{ mips64_emit_BNE , 0xfc000000 , 0x14000000, 0 },
{ mips64_emit_BNEL , 0xfc000000 , 0x54000000, 0 },
{ mips64_emit_BREAK , 0xfc00003f , 0x0000000d, 1 },
{ mips64_emit_CACHE , 0xfc000000 , 0xbc000000, 1 },
{ mips64_emit_CFC0 , 0xffe007ff , 0x40400000, 1 },
{ mips64_emit_CTC0 , 0xffe007ff , 0x40600000, 1 },
{ mips64_emit_DADDIU , 0xfc000000 , 0x64000000, 1 },
{ mips64_emit_DADDU , 0xfc0007ff , 0x0000002d, 1 },
{ mips64_emit_DIV , 0xfc00ffff , 0x0000001a, 1 },
{ mips64_emit_DIVU , 0xfc00ffff , 0x0000001b, 1 },
{ mips64_emit_DMFC0 , 0xffe007f8 , 0x40200000, 1 },
{ mips64_emit_DMFC1 , 0xffe007ff , 0x44200000, 1 },
{ mips64_emit_DMTC0 , 0xffe007f8 , 0x40a00000, 1 },
{ mips64_emit_DMTC1 , 0xffe007ff , 0x44a00000, 1 },
{ mips64_emit_DSLL , 0xffe0003f , 0x00000038, 1 },
{ mips64_emit_DSLL32 , 0xffe0003f , 0x0000003c, 1 },
{ mips64_emit_DSLLV , 0xfc0007ff , 0x00000014, 1 },
{ mips64_emit_DSRA , 0xffe0003f , 0x0000003b, 1 },
{ mips64_emit_DSRA32 , 0xffe0003f , 0x0000003f, 1 },
{ mips64_emit_DSRAV , 0xfc0007ff , 0x00000017, 1 },
{ mips64_emit_DSRL , 0xffe0003f , 0x0000003a, 1 },
{ mips64_emit_DSRL32 , 0xffe0003f , 0x0000003e, 1 },
{ mips64_emit_DSRLV , 0xfc0007ff , 0x00000016, 1 },
{ mips64_emit_DSUBU , 0xfc0007ff , 0x0000002f, 1 },
{ mips64_emit_ERET , 0xffffffff , 0x42000018, 0 },
{ mips64_emit_J , 0xfc000000 , 0x08000000, 0 },
{ mips64_emit_JAL , 0xfc000000 , 0x0c000000, 0 },
{ mips64_emit_JALR , 0xfc1f003f , 0x00000009, 0 },
{ mips64_emit_JR , 0xfc1ff83f , 0x00000008, 0 },
{ mips64_emit_LB , 0xfc000000 , 0x80000000, 1 },
{ mips64_emit_LBU , 0xfc000000 , 0x90000000, 1 },
{ mips64_emit_LD , 0xfc000000 , 0xdc000000, 1 },
{ mips64_emit_LDC1 , 0xfc000000 , 0xd4000000, 1 },
{ mips64_emit_LDL , 0xfc000000 , 0x68000000, 1 },
{ mips64_emit_LDR , 0xfc000000 , 0x6c000000, 1 },
{ mips64_emit_LH , 0xfc000000 , 0x84000000, 1 },
{ mips64_emit_LHU , 0xfc000000 , 0x94000000, 1 },
{ mips64_emit_LL , 0xfc000000 , 0xc0000000, 1 },
{ mips64_emit_LUI , 0xffe00000 , 0x3c000000, 1 },
{ mips64_emit_LW , 0xfc000000 , 0x8c000000, 1 },
{ mips64_emit_LWL , 0xfc000000 , 0x88000000, 1 },
{ mips64_emit_LWR , 0xfc000000 , 0x98000000, 1 },
{ mips64_emit_LWU , 0xfc000000 , 0x9c000000, 1 },
{ mips64_emit_MFC0 , 0xffe007ff , 0x40000000, 1 },
{ mips64_emit_CFC0 , 0xffe007ff , 0x40000001, 1 }, /* MFC0 / Set 1 */
{ mips64_emit_MFC1 , 0xffe007ff , 0x44000000, 1 },
{ mips64_emit_MFHI , 0xffff07ff , 0x00000010, 1 },
{ mips64_emit_MFLO , 0xffff07ff , 0x00000012, 1 },
{ mips64_emit_MOVZ , 0xfc0007ff , 0x0000000a, 1 },
{ mips64_emit_MTC0 , 0xffe007ff , 0x40800000, 1 },
{ mips64_emit_MTC1 , 0xffe007ff , 0x44800000, 1 },
{ mips64_emit_MTHI , 0xfc1fffff , 0x00000011, 1 },
{ mips64_emit_MTLO , 0xfc1fffff , 0x00000013, 1 },
{ mips64_emit_MUL , 0xfc0007ff , 0x70000002, 1 },
{ mips64_emit_MULT , 0xfc00ffff , 0x00000018, 1 },
{ mips64_emit_MULTU , 0xfc00ffff , 0x00000019, 1 },
{ mips64_emit_NOP , 0xffffffff , 0x00000000, 1 },
{ mips64_emit_NOR , 0xfc0007ff , 0x00000027, 1 },
{ mips64_emit_OR , 0xfc0007ff , 0x00000025, 1 },
{ mips64_emit_ORI , 0xfc000000 , 0x34000000, 1 },
{ mips64_emit_PREF , 0xfc000000 , 0xcc000000, 1 },
{ mips64_emit_PREFI , 0xfc0007ff , 0x4c00000f, 1 },
{ mips64_emit_SB , 0xfc000000 , 0xa0000000, 1 },
{ mips64_emit_SC , 0xfc000000 , 0xe0000000, 1 },
{ mips64_emit_SD , 0xfc000000 , 0xfc000000, 1 },
{ mips64_emit_SDC1 , 0xfc000000 , 0xf4000000, 1 },
{ mips64_emit_SDL , 0xfc000000 , 0xb0000000, 1 },
{ mips64_emit_SDR , 0xfc000000 , 0xb4000000, 1 },
{ mips64_emit_SH , 0xfc000000 , 0xa4000000, 1 },
{ mips64_emit_SLL , 0xffe0003f , 0x00000000, 1 },
{ mips64_emit_SLLV , 0xfc0007ff , 0x00000004, 1 },
{ mips64_emit_SLT , 0xfc0007ff , 0x0000002a, 1 },
{ mips64_emit_SLTI , 0xfc000000 , 0x28000000, 1 },
{ mips64_emit_SLTIU , 0xfc000000 , 0x2c000000, 1 },
{ mips64_emit_SLTU , 0xfc0007ff , 0x0000002b, 1 },
{ mips64_emit_SRA , 0xffe0003f , 0x00000003, 1 },
{ mips64_emit_SRAV , 0xfc0007ff , 0x00000007, 1 },
{ mips64_emit_SRL , 0xffe0003f , 0x00000002, 1 },
{ mips64_emit_SRLV , 0xfc0007ff , 0x00000006, 1 },
{ mips64_emit_SUB , 0xfc0007ff , 0x00000022, 1 },
{ mips64_emit_SUBU , 0xfc0007ff , 0x00000023, 1 },
{ mips64_emit_SW , 0xfc000000 , 0xac000000, 1 },
{ mips64_emit_SWL , 0xfc000000 , 0xa8000000, 1 },
{ mips64_emit_SWR , 0xfc000000 , 0xb8000000, 1 },
{ mips64_emit_SYNC , 0xfffff83f , 0x0000000f, 1 },
{ mips64_emit_SYSCALL , 0xfc00003f , 0x0000000c, 1 },
{ mips64_emit_TEQ , 0xfc00003f , 0x00000034, 1 },
{ mips64_emit_TEQI , 0xfc1f0000 , 0x040c0000, 1 },
{ mips64_emit_TLBP , 0xffffffff , 0x42000008, 1 },
{ mips64_emit_TLBR , 0xffffffff , 0x42000001, 1 },
{ mips64_emit_TLBWI , 0xffffffff , 0x42000002, 1 },
{ mips64_emit_TLBWR , 0xffffffff , 0x42000006, 1 },
{ mips64_emit_XOR , 0xfc0007ff , 0x00000026, 1 },
{ mips64_emit_XORI , 0xfc000000 , 0x38000000, 1 },
{ mips64_emit_unknown , 0x00000000 , 0x00000000, 1 },
{ NULL , 0x00000000 , 0x00000000, 0 },
};