Files
retrobsd/tools/virtualmips/x86_trans.c
2014-04-09 14:27:18 +01:00

3026 lines
88 KiB
C

/*
* Copyright (C) yajin 2008 <yajinzhou@gmail.com >
*
* This file is part of the virtualmips distribution.
* See LICENSE file for terms of the license.
*
*/
#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 <signal.h>
#include <fcntl.h>
#include <assert.h>
#include "cpu.h"
#include "vm.h"
#include "mips_exec.h"
#include "mips_memory.h"
#include "mips.h"
#include "mips_cp0.h"
#include "debug.h"
#include "vp_timer.h"
#include "x86_trans.h"
#ifdef _USE_JIT_
struct mips_jit_desc mips_jit[];
static struct mips_jit_desc mips_spec_jit[];
static struct mips_jit_desc mips_bcond_jit[];
static struct mips_jit_desc mips_cop0_jit[];
static struct mips_jit_desc mips_mad_jit[];
static struct mips_jit_desc mips_tlb_jit[];
void fastcall mips_exec_single_step (cpu_mips_t * cpu,
mips_insn_t instruction);
#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)]))
/* Set the Pointer Counter (PC) register */
void mips_set_pc (mips_jit_tcb_t * b, m_va_t new_pc)
{
x86_mov_membase_imm (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, pc),
new_pc & 0xFFFFFFFF, 4);
}
/* Set the Return Address (RA) register */
void mips_set_ra (mips_jit_tcb_t * b, m_va_t ret_pc)
{
x86_mov_membase_imm (b->jit_ptr, X86_EDI, REG_OFFSET (MIPS_GPR_RA),
ret_pc & 0xFFFFFFFF, 4);
}
/*
* Try to branch directly to the specified JIT block without returning to
* main loop.
*/
static void mips_try_direct_far_jump (cpu_mips_t * cpu,
mips_jit_tcb_t * b, m_va_t new_pc)
{
m_va_t new_page;
m_uint32_t pc_hash, pc_offset;
u_char *test1, *test2, *test3, *test4, *test5, *test6;
new_page = new_pc & MIPS_MIN_PAGE_MASK;
pc_offset = (new_pc & MIPS_MIN_PAGE_IMASK) >> 2;
pc_hash = mips_jit_get_pc_hash (cpu, new_pc);
/* Get JIT block info in %edx */
x86_mov_reg_membase (b->jit_ptr, X86_EBX,
X86_EDI, OFFSET (cpu_mips_t, exec_blk_map), 4);
x86_mov_reg_membase (b->jit_ptr, X86_EDX, X86_EBX,
pc_hash * sizeof (void *), 4);
/* no JIT block found ? */
x86_test_reg_reg (b->jit_ptr, X86_EDX, X86_EDX);
test1 = b->jit_ptr;
x86_branch8 (b->jit_ptr, X86_CC_Z, 0, 1);
/* Check block PC */
x86_mov_reg_imm (b->jit_ptr, X86_EAX, (m_uint32_t) new_page);
x86_alu_reg_membase (b->jit_ptr, X86_CMP, X86_EAX, X86_EDX,
OFFSET (mips_jit_tcb_t, start_pc));
test2 = b->jit_ptr;
x86_branch8 (b->jit_ptr, X86_CC_NE, 0, 1);
/*whether newpc is mapped */
x86_shift_reg_imm (b->jit_ptr, X86_SHR, X86_EAX, 29);
x86_alu_reg_imm (b->jit_ptr, X86_AND, X86_EAX, 0x7);
x86_alu_reg_imm (b->jit_ptr, X86_CMP, X86_EAX, 0x4);
test4 = b->jit_ptr;
x86_branch8 (b->jit_ptr, X86_CC_E, 0, 1);
x86_alu_reg_imm (b->jit_ptr, X86_CMP, X86_EAX, 0x5);
test5 = b->jit_ptr;
x86_branch8 (b->jit_ptr, X86_CC_E, 0, 1);
/*check ASID */
x86_lea_membase (b->jit_ptr, X86_ESI, X86_EDI, OFFSET (cpu_mips_t, cp0));
//x86_mov_reg_membase(b->jit_ptr,X86_ESI,
// X86_EDI,OFFSET(cpu_mips_t,cp0),4);
x86_mov_reg_membase (b->jit_ptr, X86_EBX,
X86_ESI, OFFSET (mips_cp0_t, reg[MIPS_CP0_TLB_HI]), 4);
x86_alu_reg_imm (b->jit_ptr, X86_AND, X86_EBX, MIPS_TLB_ASID_MASK);
x86_alu_reg_membase (b->jit_ptr, X86_CMP, X86_EBX, X86_EDX,
OFFSET (mips_jit_tcb_t, asid));
test6 = b->jit_ptr;
x86_branch8 (b->jit_ptr, X86_CC_NE, 0, 1);
x86_patch (test4, b->jit_ptr);
x86_patch (test5, b->jit_ptr);
/* Jump to the code */
x86_mov_reg_membase (b->jit_ptr, X86_ESI,
X86_EDX, OFFSET (mips_jit_tcb_t, jit_insn_ptr), 4);
x86_mov_reg_membase (b->jit_ptr, X86_EBX,
X86_ESI, pc_offset * sizeof (void *), 4);
x86_test_reg_reg (b->jit_ptr, X86_EBX, X86_EBX);
test3 = b->jit_ptr;
x86_branch8 (b->jit_ptr, X86_CC_Z, 0, 1);
x86_jump_reg (b->jit_ptr, X86_EBX);
/* Returns to caller... */
x86_patch (test1, b->jit_ptr);
x86_patch (test2, b->jit_ptr);
x86_patch (test3, b->jit_ptr);
x86_patch (test6, b->jit_ptr);
mips_set_pc (b, new_pc);
mips_jit_tcb_push_epilog (b);
}
/* Set Jump */
static void mips_set_jump (cpu_mips_t * cpu, mips_jit_tcb_t * b,
m_va_t new_pc, int local_jump)
{
int return_to_caller = FALSE;
u_char *jump_ptr;
if (!local_jump)
return_to_caller = TRUE;
if (!return_to_caller && mips_jit_tcb_local_addr (b, new_pc, &jump_ptr)) {
if (jump_ptr) {
x86_jump_code (b->jit_ptr, jump_ptr);
} else {
/* Never jump directly to code in a delay slot. */
/*Hi yajin, why a delay slot can have entry point or why have to jmp
* to delay slot?
* The following is the code from celinux 2.4.
*
* 802a19d4: 1500004a bnez t0,802a1b00 <src_unaligned_dst_aligned>
*
* 802a19d8 <both_aligned>:
* 802a19d8: 00064142 srl t0,a2,0x5
*
* if call function both_aligned(0x802a19d8), it is in delay slot of 0x802a19d4 but it is
* the entry of function both_aligned.
* Just set pc to 0x802a19d8 and return main loop.
*/
if (mips_jit_is_delay_slot (b, new_pc)) {
mips_set_pc (b, new_pc);
mips_jit_tcb_push_epilog (b);
return;
}
mips_jit_tcb_record_patch (b, b->jit_ptr, new_pc);
x86_jump32 (b->jit_ptr, 0);
}
} else {
mips_try_direct_far_jump (cpu, b, new_pc);
#if 0
if (cpu->exec_blk_direct_jump) {
/* Block lookup optimization */
mips_try_direct_far_jump (cpu, b, new_pc);
} else {
mips_set_pc (b, new_pc);
mips_jit_tcb_push_epilog (b);
}
#endif
}
}
/* Basic C call */
void mips_emit_basic_c_call (mips_jit_tcb_t * b, void *f)
{
x86_mov_reg_imm (b->jit_ptr, X86_EBX, f);
x86_call_reg (b->jit_ptr, X86_EBX);
}
/* Emit a simple call to a C function without any parameter */
static void mips_emit_c_call (mips_jit_tcb_t * b, void *f)
{
mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2));
mips_emit_basic_c_call (b, f);
}
/* Single-step operation */
void mips_emit_single_step (mips_jit_tcb_t * b, mips_insn_t insn)
{
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
x86_mov_reg_imm (b->jit_ptr, X86_EDX, insn);
mips_emit_basic_c_call (b, mips_exec_single_step);
}
/* Memory operation */
/*we use EAX EDX ECX to transfer parameter. yajin.
Makesure memory operation DONOT have more than 3 parameters*/
static void mips_emit_memop (mips_jit_tcb_t * b, int op, int base,
int offset, int target, int keep_ll_bit)
{
m_va_t val = sign_extend (offset, 16);
m_uint8_t *test1;
/* Save PC for exception handling */
mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2));
if (!keep_ll_bit) {
x86_clear_reg (b->jit_ptr, X86_EAX);
x86_mov_membase_reg (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, ll_bit),
X86_EAX, 4);
}
x86_mov_reg_imm (b->jit_ptr, X86_EDX, val);
/* EDX = GPR[base] + sign-extended offset */
x86_alu_reg_membase (b->jit_ptr, X86_ADD, X86_EDX, X86_EDI,
REG_OFFSET (base));
/* ECX = target register */
x86_mov_reg_imm (b->jit_ptr, X86_ECX, target);
/* EAX = CPU instance pointer */
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
x86_mov_reg_membase (b->jit_ptr, X86_EBX, X86_EDI, MEMOP_OFFSET (op), 4);
x86_call_reg (b->jit_ptr, X86_EBX);
/*check the return value */
x86_alu_reg_imm (b->jit_ptr, X86_CMP, X86_EAX, 0);
/*IF return value==0.NO exception. */
test1 = b->jit_ptr;
x86_branch8 (b->jit_ptr, X86_CC_E, 0, 1);
mips_jit_tcb_push_epilog (b);
x86_patch (test1, b->jit_ptr);
}
/* Unknown opcode handler */
static asmlinkage void mips_unknown_opcode (cpu_mips_t * cpu,
m_uint32_t opcode)
{
printf ("MIPS64: unhandled opcode 0x%8.8x at 0x%" LL "x (ra=0x%" LL
"x)\n", opcode, cpu->pc, cpu->gpr[MIPS_GPR_RA]);
//mips_dump_regs(cpu);
}
/* Emit unhandled instruction code */
static int mips_emit_unknown (cpu_mips_t * cpu, mips_jit_tcb_t * b,
mips_insn_t opcode)
{
x86_mov_reg_imm (b->jit_ptr, X86_EAX, opcode);
x86_alu_reg_imm (b->jit_ptr, X86_SUB, X86_ESP, 4);
x86_push_reg (b->jit_ptr, X86_EAX);
x86_push_reg (b->jit_ptr, X86_EDI);
mips_emit_c_call (b, mips_unknown_opcode);
x86_alu_reg_imm (b->jit_ptr, X86_ADD, X86_ESP, 12);
return (0);
}
/* Invalid delay slot handler */
static fastcall void mips_invalid_delay_slot (cpu_mips_t * cpu)
{
printf ("MIPS64: invalid instruction in delay slot at 0x%" LL "x (ra=0x%"
LL "x)\n", cpu->pc, cpu->gpr[MIPS_GPR_RA]);
//mips_dump_regs(cpu);
/* Halt the virtual CPU */
cpu->pc = 0;
}
/* Emit unhandled instruction code */
int mips_emit_invalid_delay_slot (mips_jit_tcb_t * b)
{
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
mips_emit_c_call (b, mips_invalid_delay_slot);
x86_alu_reg_imm (b->jit_ptr, X86_ADD, X86_ESP, 12);
mips_jit_tcb_push_epilog (b);
return (0);
}
void mips_check_cpu_pausing (mips_jit_tcb_t * b)
{
u_char *test1;
/* Check pause_request */
x86_mov_reg_membase (b->jit_ptr, X86_EAX,
X86_EDI, OFFSET (cpu_mips_t, pause_request), 4);
x86_alu_reg_imm (b->jit_ptr, X86_AND, X86_EAX, CPU_INTERRUPT_EXIT);
x86_alu_reg_imm (b->jit_ptr, X86_CMP, X86_EAX, CPU_INTERRUPT_EXIT);
test1 = b->jit_ptr;
x86_branch32 (b->jit_ptr, X86_CC_NE, 0, 1);
/*if (cpu->pause_request)&CPU_INTERRUPT_EXIT==CPU_INTERRUPT_EXIT,
* set cpu->state and return to main loop */
mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2));
x86_mov_membase_imm (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, state),
CPU_STATE_PAUSING, 4);
mips_jit_tcb_push_epilog (b);
/*else do noting */
x86_patch (test1, b->jit_ptr);
}
/* Check if there are pending IRQ */
void mips_check_pending_irq (mips_jit_tcb_t * b)
{
u_char *test1;
/* Check the pending IRQ flag */
x86_mov_reg_membase (b->jit_ptr, X86_EAX,
X86_EDI, OFFSET (cpu_mips_t, irq_pending), 4);
x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX);
test1 = b->jit_ptr;
x86_branch32 (b->jit_ptr, X86_CC_Z, 0, 1);
/* Save PC */
mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2));
/* Trigger the IRQ */
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
mips_emit_basic_c_call (b, mips_trigger_irq);
mips_jit_tcb_push_epilog (b);
x86_patch (test1, b->jit_ptr);
}
/* ADD */
static int mips_emit_add (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int rd = bits (insn, 11, 15);
//printf("rs %d rt %d rd %d \n",rs,rt,rd);
/* TODO: Exception handling */
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_alu_reg_membase (b->jit_ptr, X86_ADD, X86_EAX, X86_EDI,
REG_OFFSET (rt));
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4);
return (0);
}
/* ADDI */
static int mips_emit_addi (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int imm = bits (insn, 0, 15);
m_uint32_t val = sign_extend (imm, 16);
// printf("rs %d rt %d val %d \n",rs,rt,val);
/* TODO: Exception handling */
x86_mov_reg_imm (b->jit_ptr, X86_EAX, val);
x86_alu_reg_membase (b->jit_ptr, X86_ADD, X86_EAX, X86_EDI,
REG_OFFSET (rs));
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rt), X86_EAX, 4);
return (0);
}
/* ADDI */
static int mips_emit_addiu (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int imm = bits (insn, 0, 15);
m_uint32_t val = sign_extend (imm, 16);
// printf("rs %d rt %d val %d \n",rs,rt,val);
/* TODO: Exception handling */
x86_mov_reg_imm (b->jit_ptr, X86_EAX, val);
x86_alu_reg_membase (b->jit_ptr, X86_ADD, X86_EAX, X86_EDI,
REG_OFFSET (rs));
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rt), X86_EAX, 4);
return (0);
}
/* ADDu */
static int mips_emit_addu (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int rd = bits (insn, 11, 15);
// printf("rs %d rt %d rd %d \n",rs,rt,rd);
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_alu_reg_membase (b->jit_ptr, X86_ADD, X86_EAX, X86_EDI,
REG_OFFSET (rt));
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4);
return (0);
}
/* AND */
static int mips_emit_and (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int rd = bits (insn, 11, 15);
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_alu_reg_membase (b->jit_ptr, X86_AND, X86_EAX, X86_EDI,
REG_OFFSET (rt));
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4);
return (0);
}
/* ANDI */
static int mips_emit_andi (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int imm = bits (insn, 0, 15);
x86_mov_reg_imm (b->jit_ptr, X86_EAX, imm);
x86_alu_reg_membase (b->jit_ptr, X86_AND, X86_EAX, X86_EDI,
REG_OFFSET (rs));
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rt), X86_EAX, 4);
return (0);
}
static int mips_emit_bcond (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
uint16_t special_func = bits (insn, 16, 20);
return mips_bcond_jit[special_func].emit_func (cpu, b, insn);
}
/*
Hi yajin, why we need call mips_jit_fetch_and_emit twice?
Why do we translate beq like this:
mips_jit_fetch_and_emit(cpu,b,1);
x86_mov_reg_membase(b->jit_ptr,X86_EAX,X86_EDI,REG_OFFSET(rs),4);
x86_alu_reg_membase(b->jit_ptr,X86_CMP,X86_EAX,X86_EDI,REG_OFFSET(rt));
test1 = b->jit_ptr;
x86_branch32(b->jit_ptr, X86_CC_NE, 0, 1);
mips_set_jump(cpu,b,new_pc,1);
x86_patch(test1,b->jit_ptr);
That is fetching the delay slot code first and then jumping to new pc according to
the comparing result of register rs and register rt.
This seems right but it is wrong and not easy to catch this bug!!!
The instruction in delay slot may change the content of register rs and rt and the
comparing result can not be trusted anymore.
We MUST compare register rs and rt and then run the code in delay slot.
*/
/* BEQ (Branch On Equal) */
static int mips_emit_beq (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int offset = bits (insn, 0, 15);
u_char *test1;
m_va_t new_pc;
/* compute the new pc */
new_pc = b->start_pc + (b->mips_trans_pos << 2);
new_pc += sign_extend (offset << 2, 18);
/*
* compare gpr[rs] and gpr[rt].
* compare the low 32 bits first (higher probability).
*/
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_alu_reg_membase (b->jit_ptr, X86_CMP, X86_EAX, X86_EDI,
REG_OFFSET (rt));
test1 = b->jit_ptr;
x86_branch32 (b->jit_ptr, X86_CC_NE, 0, 1);
/* insert the instruction in the delay slot */
mips_jit_fetch_and_emit (cpu, b, 2);
/* set the new pc in cpu structure */
mips_set_jump (cpu, b, new_pc, 1);
x86_patch (test1, b->jit_ptr);
/* if the branch is not taken, we have to execute the delay slot too */
mips_jit_fetch_and_emit (cpu, b, 1);
return (0);
}
/* BEQL (Branch On Equal Likely) */
static int mips_emit_beql (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int offset = bits (insn, 0, 15);
u_char *test1;
m_va_t new_pc;
/* compute the new pc */
new_pc = b->start_pc + (b->mips_trans_pos << 2);
new_pc += sign_extend (offset << 2, 18);
/*
* compare gpr[rs] and gpr[rt].
* compare the low 32 bits first (higher probability).
*/
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_alu_reg_membase (b->jit_ptr, X86_CMP, X86_EAX, X86_EDI,
REG_OFFSET (rt));
test1 = b->jit_ptr;
x86_branch32 (b->jit_ptr, X86_CC_NE, 0, 1);
/* insert the instruction in the delay slot */
mips_jit_fetch_and_emit (cpu, b, 1);
/* set the new pc in cpu structure */
mips_set_jump (cpu, b, new_pc, 1);
x86_patch (test1, b->jit_ptr);
return (0);
}
/* BGEZ (Branch On Greater or Equal Than Zero) */
static int mips_emit_bgez (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int offset = bits (insn, 0, 15);
u_char *test1;
m_va_t new_pc;
/* compute the new pc */
new_pc = b->start_pc + (b->mips_trans_pos << 2);
new_pc += sign_extend (offset << 2, 18);
/* If sign bit is set, don't take the branch */
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX);
test1 = b->jit_ptr;
x86_branch32 (b->jit_ptr, X86_CC_S, 0, 1);
/* insert the instruction in the delay slot */
mips_jit_fetch_and_emit (cpu, b, 2);
/* set the new pc in cpu structure */
mips_set_jump (cpu, b, new_pc, 1);
x86_patch (test1, b->jit_ptr);
/* if the branch is not taken, we have to execute the delay slot too */
mips_jit_fetch_and_emit (cpu, b, 1);
return (0);
}
/* BGEZAL (Branch On Greater or Equal Than Zero And Link) */
static int mips_emit_bgezal (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int offset = bits (insn, 0, 15);
u_char *test1;
m_va_t new_pc;
/* compute the new pc */
new_pc = b->start_pc + (b->mips_trans_pos << 2);
new_pc += sign_extend (offset << 2, 18);
/* set the return address (instruction after the delay slot) */
mips_set_ra (b, b->start_pc + ((b->mips_trans_pos + 1) << 2));
/* If sign bit is set, don't take the branch */
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX);
test1 = b->jit_ptr;
x86_branch32 (b->jit_ptr, X86_CC_S, 0, 1);
/* insert the instruction in the delay slot */
mips_jit_fetch_and_emit (cpu, b, 2);
/* set the new pc in cpu structure */
mips_set_jump (cpu, b, new_pc, 1);
x86_patch (test1, b->jit_ptr);
/* if the branch is not taken, we have to execute the delay slot too */
mips_jit_fetch_and_emit (cpu, b, 1);
return (0);
}
/* BGEZALL (Branch On Greater or Equal Than Zero and Link Likely) */
static int mips_emit_bgezall (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int offset = bits (insn, 0, 15);
u_char *test1;
m_va_t new_pc;
/* compute the new pc */
new_pc = b->start_pc + (b->mips_trans_pos << 2);
new_pc += sign_extend (offset << 2, 18);
/* set the return address (instruction after the delay slot) */
mips_set_ra (b, b->start_pc + ((b->mips_trans_pos + 1) << 2));
/* if sign bit is set, don't take the branch */
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX);
test1 = b->jit_ptr;
x86_branch32 (b->jit_ptr, X86_CC_S, 0, 1);
/* insert the instruction in the delay slot */
mips_jit_fetch_and_emit (cpu, b, 1);
/* set the new pc in cpu structure */
mips_set_jump (cpu, b, new_pc, 1);
x86_patch (test1, b->jit_ptr);
return (0);
}
/* BGEZL (Branch On Greater or Equal Than Zero Likely) */
static int mips_emit_bgezl (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int offset = bits (insn, 0, 15);
u_char *test1;
m_va_t new_pc;
/* compute the new pc */
new_pc = b->start_pc + (b->mips_trans_pos << 2);
new_pc += sign_extend (offset << 2, 18);
/* if sign bit is set, don't take the branch */
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX);
test1 = b->jit_ptr;
x86_branch32 (b->jit_ptr, X86_CC_S, 0, 1);
/* insert the instruction in the delay slot */
mips_jit_fetch_and_emit (cpu, b, 1);
/* set the new pc in cpu structure */
mips_set_jump (cpu, b, new_pc, 1);
x86_patch (test1, b->jit_ptr);
return (0);
}
/* BGTZ (Branch On Greater Than Zero) */
static int mips_emit_bgtz (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int offset = bits (insn, 0, 15);
u_char *test1, *test2;
m_va_t new_pc;
/* compute the new pc */
new_pc = b->start_pc + (b->mips_trans_pos << 2);
new_pc += sign_extend (offset << 2, 18);
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX);
/*goto end if <0 */
test1 = b->jit_ptr;
x86_branch32 (b->jit_ptr, X86_CC_S, 0, 1);
/*goto end if =0 */
test2 = b->jit_ptr;
x86_branch32 (b->jit_ptr, X86_CC_Z, 0, 1);
/* here, we take the branch */
//x86_patch(test2,b->jit_ptr);
/* insert the instruction in the delay slot */
mips_jit_fetch_and_emit (cpu, b, 2);
/* set the new pc in cpu structure */
mips_set_jump (cpu, b, new_pc, 1);
x86_patch (test1, b->jit_ptr);
x86_patch (test2, b->jit_ptr);
/* if the branch is not taken, we have to execute the delay slot too */
mips_jit_fetch_and_emit (cpu, b, 1);
return (0);
}
/* BGTZL (Branch On Greater Than Zero Likely) */
static int mips_emit_bgtzl (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int offset = bits (insn, 0, 15);
u_char *test1, *test2;
m_va_t new_pc;
/* compute the new pc */
new_pc = b->start_pc + (b->mips_trans_pos << 2);
new_pc += sign_extend (offset << 2, 18);
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX);
/*goto end if <0 */
test1 = b->jit_ptr;
x86_branch32 (b->jit_ptr, X86_CC_S, 0, 1);
/*goto end if =0 */
test2 = b->jit_ptr;
x86_branch32 (b->jit_ptr, X86_CC_Z, 0, 1);
/* here, we take the branch */
// x86_patch(test2,b->jit_ptr);
/* insert the instruction in the delay slot */
mips_jit_fetch_and_emit (cpu, b, 1);
/* set the new pc in cpu structure */
mips_set_jump (cpu, b, new_pc, 1);
x86_patch (test1, b->jit_ptr);
x86_patch (test2, b->jit_ptr);
return (0);
}
/* BLEZ (Branch On Less or Equal Than Zero) */
static int mips_emit_blez (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int offset = bits (insn, 0, 15);
u_char *test1, *test2;
m_va_t new_pc;
/* compute the new pc */
new_pc = b->start_pc + (b->mips_trans_pos << 2);
new_pc += sign_extend (offset << 2, 18);
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX);
/*if <0, take the branch */
test1 = b->jit_ptr;
x86_branch32 (b->jit_ptr, X86_CC_S, 0, 1);
/*else if !=0, do not take the branch */
test2 = b->jit_ptr;
x86_branch32 (b->jit_ptr, X86_CC_NZ, 0, 1);
/* here, we take the branch */
x86_patch (test1, b->jit_ptr);
/* insert the instruction in the delay slot */
mips_jit_fetch_and_emit (cpu, b, 2);
/* set the new pc in cpu structure */
mips_set_jump (cpu, b, new_pc, 1);
x86_patch (test2, b->jit_ptr);
/* if the branch is not taken, we have to execute the delay slot too */
mips_jit_fetch_and_emit (cpu, b, 1);
return (0);
}
/* BLEZL (Branch On Less or Equal Than Zero Likely) */
static int mips_emit_blezl (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int offset = bits (insn, 0, 15);
u_char *test1, *test2;
m_va_t new_pc;
/* compute the new pc */
new_pc = b->start_pc + (b->mips_trans_pos << 2);
new_pc += sign_extend (offset << 2, 18);
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX);
/*if <0, take the branch */
test1 = b->jit_ptr;
x86_branch32 (b->jit_ptr, X86_CC_S, 0, 1);
/*else if !=0, do not take the branch */
test2 = b->jit_ptr;
x86_branch32 (b->jit_ptr, X86_CC_NZ, 0, 1);
/* here, we take the branch */
x86_patch (test1, b->jit_ptr);
/* insert the instruction in the delay slot */
mips_jit_fetch_and_emit (cpu, b, 1);
/* set the new pc in cpu structure */
mips_set_jump (cpu, b, new_pc, 1);
x86_patch (test2, b->jit_ptr);
return (0);
}
/* BLTZ (Branch On Less Than Zero) */
static int mips_emit_bltz (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int offset = bits (insn, 0, 15);
u_char *test1;
m_va_t new_pc;
/* compute the new pc */
new_pc = b->start_pc + (b->mips_trans_pos << 2);
new_pc += sign_extend (offset << 2, 18);
/*
* test the sign bit of gpr[rs], if set, take the branch.
*/
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX);
test1 = b->jit_ptr;
x86_branch32 (b->jit_ptr, X86_CC_NS, 0, 1);
/* insert the instruction in the delay slot */
mips_jit_fetch_and_emit (cpu, b, 2);
/* set the new pc in cpu structure */
mips_set_jump (cpu, b, new_pc, 1);
x86_patch (test1, b->jit_ptr);
/* if the branch is not taken, we have to execute the delay slot too */
mips_jit_fetch_and_emit (cpu, b, 1);
return (0);
}
/* BLTZAL (Branch On Less Than Zero And Link) */
static int mips_emit_bltzal (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int offset = bits (insn, 0, 15);
u_char *test1;
m_va_t new_pc;
/* compute the new pc */
new_pc = b->start_pc + (b->mips_trans_pos << 2);
new_pc += sign_extend (offset << 2, 18);
/* set the return address (instruction after the delay slot) */
mips_set_ra (b, b->start_pc + ((b->mips_trans_pos + 1) << 2));
/*
* test the sign bit of gpr[rs], if set, take the branch.
*/
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX);
test1 = b->jit_ptr;
x86_branch32 (b->jit_ptr, X86_CC_NS, 0, 1);
/* insert the instruction in the delay slot */
mips_jit_fetch_and_emit (cpu, b, 2);
/* set the new pc in cpu structure */
mips_set_jump (cpu, b, new_pc, 1);
x86_patch (test1, b->jit_ptr);
/* if the branch is not taken, we have to execute the delay slot too */
mips_jit_fetch_and_emit (cpu, b, 1);
return (0);
}
/* BLTZALL (Branch On Less Than Zero And Link Likely) */
static int mips_emit_bltzall (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int offset = bits (insn, 0, 15);
u_char *test1;
m_va_t new_pc;
/* compute the new pc */
new_pc = b->start_pc + (b->mips_trans_pos << 2);
new_pc += sign_extend (offset << 2, 18);
/* set the return address (instruction after the delay slot) */
mips_set_ra (b, b->start_pc + ((b->mips_trans_pos + 1) << 2));
/*
* test the sign bit of gpr[rs], if set, take the branch.
*/
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX);
test1 = b->jit_ptr;
x86_branch32 (b->jit_ptr, X86_CC_NS, 0, 1);
/* insert the instruction in the delay slot */
mips_jit_fetch_and_emit (cpu, b, 1);
/* set the new pc in cpu structure */
mips_set_jump (cpu, b, new_pc, 1);
x86_patch (test1, b->jit_ptr);
return (0);
}
/* BLTZL (Branch On Less Than Zero Likely) */
static int mips_emit_bltzl (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int offset = bits (insn, 0, 15);
u_char *test1;
m_va_t new_pc;
/* compute the new pc */
new_pc = b->start_pc + (b->mips_trans_pos << 2);
new_pc += sign_extend (offset << 2, 18);
/*
* test the sign bit of gpr[rs], if set, take the branch.
*/
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX);
test1 = b->jit_ptr;
x86_branch32 (b->jit_ptr, X86_CC_NS, 0, 1);
/* insert the instruction in the delay slot */
mips_jit_fetch_and_emit (cpu, b, 1);
/* set the new pc in cpu structure */
mips_set_jump (cpu, b, new_pc, 1);
x86_patch (test1, b->jit_ptr);
return (0);
}
/* BNE (Branch On Not Equal) */
static int mips_emit_bne (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int offset = bits (insn, 0, 15);
u_char *test2;
m_va_t new_pc;
/* compute the new pc */
new_pc = b->start_pc + (b->mips_trans_pos << 2);
new_pc += sign_extend (offset << 2, 18);
/*
* compare gpr[rs] and gpr[rt].
* compare the low 32 bits first (higher probability).
*/
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_alu_reg_membase (b->jit_ptr, X86_CMP, X86_EAX, X86_EDI,
REG_OFFSET (rt));
test2 = b->jit_ptr;
x86_branch32 (b->jit_ptr, X86_CC_E, 0, 1);
/* insert the instruction in the delay slot */
mips_jit_fetch_and_emit (cpu, b, 2);
/* set the new pc in cpu structure */
mips_set_jump (cpu, b, new_pc, 1);
x86_patch (test2, b->jit_ptr);
/* if the branch is not taken, we have to execute the delay slot too */
mips_jit_fetch_and_emit (cpu, b, 1);
return (0);
}
/* BNEL (Branch On Not Equal Likely) */
static int mips_emit_bnel (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int offset = bits (insn, 0, 15);
u_char *test2;
m_va_t new_pc;
/* compute the new pc */
new_pc = b->start_pc + (b->mips_trans_pos << 2);
new_pc += sign_extend (offset << 2, 18);
/*
* compare gpr[rs] and gpr[rt].
* compare the low 32 bits first (higher probability).
*/
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_alu_reg_membase (b->jit_ptr, X86_CMP, X86_EAX, X86_EDI,
REG_OFFSET (rt));
test2 = b->jit_ptr;
x86_branch32 (b->jit_ptr, X86_CC_E, 0, 1);
/* insert the instruction in the delay slot */
mips_jit_fetch_and_emit (cpu, b, 1);
/* set the new pc in cpu structure */
mips_set_jump (cpu, b, new_pc, 1);
x86_patch (test2, b->jit_ptr);
return (0);
}
/* BREAK */
static int mips_emit_break (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
u_int code = bits (insn, 6, 25);
//x86_alu_reg_imm(b->jit_ptr,X86_SUB,X86_ESP,12);
x86_mov_reg_imm (b->jit_ptr, X86_EDX, code);
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
mips_emit_basic_c_call (b, mips_exec_break);
x86_alu_reg_imm (b->jit_ptr, X86_ADD, X86_ESP, 12);
mips_jit_tcb_push_epilog (b);
return (0);
}
/* CACHE */
static int mips_emit_cache (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int base = bits (insn, 21, 25);
int op = bits (insn, 16, 20);
int offset = bits (insn, 0, 15);
mips_emit_memop (b, MIPS_MEMOP_CACHE, base, offset, op, FALSE);
return (0);
}
static int mips_emit_cfc0 (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int fastcall clz_emu (cpu_mips_t * cpu, mips_insn_t insn)
{
int rs = bits (insn, 21, 25);
int rd = bits (insn, 11, 15);
int i;
m_uint32_t val;
val = 32;
for (i = 31; i >= 0; i--) {
if (cpu->gpr[rs] & (1 << i)) {
val = 31 - i;
break;
}
}
cpu->gpr[rd] = val;
return (0);
}
static int mips_emit_clz (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
//x86_alu_reg_imm(b->jit_ptr,X86_SUB,X86_ESP,12);
x86_mov_reg_imm (b->jit_ptr, X86_EDX, insn);
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
mips_emit_basic_c_call (b, clz_emu);
return (0);
}
static int mips_emit_cop0 (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
uint16_t special_func = bits (insn, 21, 25);
return mips_cop0_jit[special_func].emit_func (cpu, b, insn);
}
static int mips_emit_cop1 (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
#if SOFT_FPU
/* Save PC for exception handling */
mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2));
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
mips_emit_basic_c_call (b, mips_exec_soft_fpu);
mips_jit_tcb_push_epilog (b);
return (0);
#else
mips_emit_unknown (cpu, b, insn);
return (0);
#endif
}
static int mips_emit_cop1x (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
#if SOFT_FPU
/* Save PC for exception handling */
mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2));
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
mips_emit_basic_c_call (b, mips_exec_soft_fpu);
mips_jit_tcb_push_epilog (b);
return (0);
#else
mips_emit_unknown (cpu, b, insn);
return (0);
#endif
}
static int mips_emit_cop2 (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_dadd (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_daddi (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_daddiu (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_daddu (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_ddiv (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_ddivu (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_div (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
/* eax = gpr[rs] */
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_cdq (b->jit_ptr);
/* ebx = gpr[rt] */
x86_mov_reg_membase (b->jit_ptr, X86_EBX, X86_EDI, REG_OFFSET (rt), 4);
/* eax = quotient (LO), edx = remainder (HI) */
x86_div_reg (b->jit_ptr, X86_EBX, 1);
/* store LO */
x86_mov_membase_reg (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, lo),
X86_EAX, 4);
/* store HI */
x86_mov_membase_reg (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, hi),
X86_EDX, 4);
return (0);
}
static int mips_emit_divu (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
/* eax = gpr[rs] */
x86_clear_reg (b->jit_ptr, X86_EDX);
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
/* ebx = gpr[rt] */
x86_mov_reg_membase (b->jit_ptr, X86_EBX, X86_EDI, REG_OFFSET (rt), 4);
/* eax = quotient (LO), edx = remainder (HI) */
x86_div_reg (b->jit_ptr, X86_EBX, 0);
/* store LO */
x86_mov_membase_reg (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, lo),
X86_EAX, 4);
/* store HI */
x86_mov_membase_reg (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, hi),
X86_EDX, 4);
return (0);
}
static int mips_emit_dmfc0 (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_dmtc0 (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_dmult (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_dmultu (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_dsll (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_dsllv (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_dsrlv (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_dsrav (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_dsub (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_dsubu (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_dsrl (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_dsra (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_dsll32 (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_dsrl32 (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_dsra32 (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_eret (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2));
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
mips_emit_basic_c_call (b, mips_exec_eret);
mips_jit_tcb_push_epilog (b);
return (0);
}
/* J (Jump) */
static int mips_emit_j (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
u_int instr_index = bits (insn, 0, 25);
m_va_t new_pc;
/* compute the new pc */
new_pc = b->start_pc + (b->mips_trans_pos << 2);
new_pc &= ~((1 << 28) - 1);
new_pc |= instr_index << 2;
/* insert the instruction in the delay slot */
mips_jit_fetch_and_emit (cpu, b, 1);
/* set the new pc in cpu structure */
mips_set_jump (cpu, b, new_pc, 1);
return (0);
}
static int mips_emit_jal (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
u_int instr_index = bits (insn, 0, 25);
m_va_t new_pc, ret_pc;
/* compute the new pc */
new_pc = b->start_pc + (b->mips_trans_pos << 2);
new_pc &= ~((1 << 28) - 1);
new_pc |= instr_index << 2;
/* set the return address (instruction after the delay slot) */
ret_pc = b->start_pc + ((b->mips_trans_pos + 1) << 2);
mips_set_ra (b, ret_pc);
/* insert the instruction in the delay slot */
mips_jit_fetch_and_emit (cpu, b, 1);
/* set the new pc in cpu structure */
mips_set_jump (cpu, b, new_pc, 0);
return (0);
}
static int mips_emit_jalr (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rd = bits (insn, 11, 15);
m_va_t ret_pc;
/* set the return pc (instruction after the delay slot) in GPR[rd] */
ret_pc = b->start_pc + ((b->mips_trans_pos + 1) << 2);
x86_mov_membase_imm (b->jit_ptr, X86_EDI, REG_OFFSET (rd), ret_pc, 4);
/* get the new pc */
x86_mov_reg_membase (b->jit_ptr, X86_ECX, X86_EDI, REG_OFFSET (rs), 4);
x86_mov_membase_reg (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, ret_pc),
X86_ECX, 4);
/* insert the instruction in the delay slot */
mips_jit_fetch_and_emit (cpu, b, 1);
/* set the new pc */
x86_mov_reg_membase (b->jit_ptr, X86_ECX,
X86_EDI, OFFSET (cpu_mips_t, ret_pc), 4);
x86_mov_membase_reg (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, pc),
X86_ECX, 4);
/* returns to the caller which will determine the next path */
mips_jit_tcb_push_epilog (b);
return (0);
}
static int mips_emit_jr (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
/* get the new pc */
x86_mov_reg_membase (b->jit_ptr, X86_ECX, X86_EDI, REG_OFFSET (rs), 4);
x86_mov_membase_reg (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, ret_pc),
X86_ECX, 4);
/* insert the instruction in the delay slot */
mips_jit_fetch_and_emit (cpu, b, 1);
/* set the new pc */
x86_mov_reg_membase (b->jit_ptr, X86_ECX,
X86_EDI, OFFSET (cpu_mips_t, ret_pc), 4);
x86_mov_membase_reg (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, pc),
X86_ECX, 4);
/* returns to the caller which will determine the next path */
mips_jit_tcb_push_epilog (b);
return (0);
}
static int mips_emit_lb (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int base = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int offset = bits (insn, 0, 15);
mips_emit_memop (b, MIPS_MEMOP_LB, base, offset, rt, TRUE);
return (0);
}
static int mips_emit_lbu (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int base = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int offset = bits (insn, 0, 15);
mips_emit_memop (b, MIPS_MEMOP_LBU, base, offset, rt, TRUE);
return (0);
}
static int mips_emit_ld (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_ldc1 (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_ldc2 (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_ldl (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_ldr (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_lh (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int base = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int offset = bits (insn, 0, 15);
mips_emit_memop (b, MIPS_MEMOP_LH, base, offset, rt, TRUE);
return (0);
}
static int mips_emit_lhu (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int base = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int offset = bits (insn, 0, 15);
mips_emit_memop (b, MIPS_MEMOP_LHU, base, offset, rt, TRUE);
return (0);
}
static int mips_emit_ll (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int base = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int offset = bits (insn, 0, 15);
mips_emit_memop (b, MIPS_MEMOP_LL, base, offset, rt, TRUE);
return (0);
}
static int mips_emit_lld (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_lui (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rt = bits (insn, 16, 20);
int imm = bits (insn, 0, 15);
m_reg_t val = sign_extend (imm, 16) << 16;
x86_mov_membase_imm (b->jit_ptr, X86_EDI, REG_OFFSET (rt), val, 4);
return (0);
}
static int mips_emit_lw (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int base = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int offset = bits (insn, 0, 15);
mips_emit_memop (b, MIPS_MEMOP_LW, base, offset, rt, TRUE);
return (0);
}
static int mips_emit_lwc1 (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
#if SOFT_FPU
/* Save PC for exception handling */
mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2));
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
mips_emit_basic_c_call (b, mips_exec_soft_fpu);
mips_jit_tcb_push_epilog (b);
return (0);
#else
mips_emit_unknown (cpu, b, insn);
return (0);
#endif
}
static int mips_emit_lwc2 (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_lwl (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int base = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int offset = bits (insn, 0, 15);
mips_emit_memop (b, MIPS_MEMOP_LWL, base, offset, rt, TRUE);
return (0);
}
static int mips_emit_lwr (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int base = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int offset = bits (insn, 0, 15);
mips_emit_memop (b, MIPS_MEMOP_LWR, base, offset, rt, TRUE);
return (0);
}
static int mips_emit_lwu (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int base = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int offset = bits (insn, 0, 15);
mips_emit_memop (b, MIPS_MEMOP_LWU, base, offset, rt, TRUE);
return (0);
}
static int mips_emit_mad (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int index = bits (insn, 0, 5);
return mips_mad_jit[index].emit_func (cpu, b, insn);
}
static int fastcall madd_emu (cpu_mips_t * cpu, mips_insn_t insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
m_int64_t val, temp;
val = (m_int32_t) (m_int32_t) cpu->gpr[rs];
val *= (m_int32_t) (m_int32_t) cpu->gpr[rt];
temp = cpu->hi;
temp = temp << 32;
temp += cpu->lo;
val += temp;
cpu->lo = sign_extend (val, 32);
cpu->hi = sign_extend (val >> 32, 32);
return (0);
}
static int mips_emit_madd (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
//x86_alu_reg_imm(b->jit_ptr,X86_SUB,X86_ESP,12);
x86_mov_reg_imm (b->jit_ptr, X86_EDX, insn);
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
mips_emit_basic_c_call (b, madd_emu);
return (0);
}
static int fastcall maddu_emu (cpu_mips_t * cpu, mips_insn_t insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
m_int64_t val, temp;
val = (m_uint32_t) (m_uint32_t) cpu->gpr[rs];
val *= (m_uint32_t) (m_uint32_t) cpu->gpr[rt];
temp = cpu->hi;
temp = temp << 32;
temp += cpu->lo;
val += temp;
cpu->lo = sign_extend (val, 32);
cpu->hi = sign_extend (val >> 32, 32);
return (0);
}
static int mips_emit_maddu (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
//x86_alu_reg_imm(b->jit_ptr,X86_SUB,X86_ESP,12);
x86_mov_reg_imm (b->jit_ptr, X86_EDX, insn);
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
mips_emit_basic_c_call (b, maddu_emu);
return (0);
}
static int mips_emit_mfc0 (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
x86_mov_reg_imm (b->jit_ptr, X86_EDX, insn);
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
mips_emit_basic_c_call (b, mips_cp0_exec_mfc0_fastcall);
return (0);
}
static int mips_emit_mfhi (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rd = bits (insn, 11, 15);
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, OFFSET (cpu_mips_t,
hi), 4);
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4);
return (0);
}
static int mips_emit_mflo (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rd = bits (insn, 11, 15);
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, OFFSET (cpu_mips_t,
lo), 4);
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4);
return (0);
}
static int mips_emit_movc (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_movz (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rd = bits (insn, 11, 15);
int rt = bits (insn, 16, 20);
u_char *test1;
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rt), 4);
x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX);
/*goto end if !=0 */
test1 = b->jit_ptr;
x86_branch32 (b->jit_ptr, X86_CC_NZ, 0, 1);
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4);
x86_patch (test1, b->jit_ptr);
return (0);
}
static int mips_emit_movn (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rd = bits (insn, 11, 15);
int rt = bits (insn, 16, 20);
u_char *test1;
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rt), 4);
x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX);
/*goto end if ==0 */
test1 = b->jit_ptr;
x86_branch32 (b->jit_ptr, X86_CC_Z, 0, 1);
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4);
x86_patch (test1, b->jit_ptr);
return (0);
}
static int fastcall msub_emu (cpu_mips_t * cpu, mips_insn_t insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
m_int64_t val, temp;
val = (m_int32_t) (m_int32_t) cpu->gpr[rs];
val *= (m_int32_t) (m_int32_t) cpu->gpr[rt];
temp = cpu->hi;
temp = temp << 32;
temp += cpu->lo;
temp -= val;
//val += temp;
cpu->lo = sign_extend (temp, 32);
cpu->hi = sign_extend (temp >> 32, 32);
return (0);
}
static int mips_emit_msub (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
//x86_alu_reg_imm(b->jit_ptr,X86_SUB,X86_ESP,12);
x86_mov_reg_imm (b->jit_ptr, X86_EDX, insn);
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
mips_emit_basic_c_call (b, msub_emu);
return (0);
}
static int fastcall msubu_emu (cpu_mips_t * cpu, mips_insn_t insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
m_int64_t val, temp;
val = (m_uint32_t) (m_uint32_t) cpu->gpr[rs];
val *= (m_uint32_t) (m_uint32_t) cpu->gpr[rt];
temp = cpu->hi;
temp = temp << 32;
temp += cpu->lo;
temp -= val;
cpu->lo = sign_extend (temp, 32);
cpu->hi = sign_extend (temp >> 32, 32);
return (0);
}
static int mips_emit_msubu (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
//x86_alu_reg_imm(b->jit_ptr,X86_SUB,X86_ESP,12);
x86_mov_reg_imm (b->jit_ptr, X86_EDX, insn);
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
mips_emit_basic_c_call (b, msubu_emu);
return (0);
}
static int mips_emit_mtc0 (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
x86_mov_reg_imm (b->jit_ptr, X86_EDX, insn);
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
mips_emit_basic_c_call (b, mips_cp0_exec_mtc0_fastcall);
return (0);
}
static fastcall int mthi_emu (cpu_mips_t * cpu, mips_insn_t insn)
{
int rs = bits (insn, 21, 25);
cpu->hi = cpu->gpr[rs];
return (0);
}
static fastcall int mtlo_emu (cpu_mips_t * cpu, mips_insn_t insn)
{
int rs = bits (insn, 21, 25);
cpu->lo = cpu->gpr[rs];
return (0);
}
static int mips_emit_mthi (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
//x86_alu_reg_imm(b->jit_ptr,X86_SUB,X86_ESP,12);
x86_mov_reg_imm (b->jit_ptr, X86_EDX, insn);
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
mips_emit_basic_c_call (b, mthi_emu);
return (0);
}
static int mips_emit_mtlo (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
//x86_alu_reg_imm(b->jit_ptr,X86_SUB,X86_ESP,12);
x86_mov_reg_imm (b->jit_ptr, X86_EDX, insn);
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
mips_emit_basic_c_call (b, mtlo_emu);
return (0);
}
/* MUL */
static int mips_emit_mul (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int rd = bits (insn, 11, 15);
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_mov_reg_membase (b->jit_ptr, X86_EBX, X86_EDI, REG_OFFSET (rt), 4);
x86_mul_reg (b->jit_ptr, X86_EBX, 1);
/* store result in gpr[rd] */
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4);
return (0);
}
static int mips_emit_mult (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_mov_reg_membase (b->jit_ptr, X86_EBX, X86_EDI, REG_OFFSET (rt), 4);
x86_mul_reg (b->jit_ptr, X86_EBX, 1);
/* store LO */
x86_mov_membase_reg (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, lo),
X86_EAX, 4);
/* store HI */
x86_mov_membase_reg (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, hi),
X86_EDX, 4);
return (0);
}
static int mips_emit_multu (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_mov_reg_membase (b->jit_ptr, X86_EBX, X86_EDI, REG_OFFSET (rt), 4);
x86_mul_reg (b->jit_ptr, X86_EBX, 0);
/* store LO */
x86_mov_membase_reg (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, lo),
X86_EAX, 4);
/* store HI */
x86_mov_membase_reg (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, hi),
X86_EDX, 4);
return (0);
}
static int mips_emit_nor (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int rd = bits (insn, 11, 15);
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_alu_reg_membase (b->jit_ptr, X86_OR, X86_EAX, X86_EDI,
REG_OFFSET (rt));
x86_not_reg (b->jit_ptr, X86_EAX);
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4);
return (0);
}
static int mips_emit_or (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int rd = bits (insn, 11, 15);
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_alu_reg_membase (b->jit_ptr, X86_OR, X86_EAX, X86_EDI,
REG_OFFSET (rt));
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4);
return (0);
}
static int mips_emit_ori (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int imm = bits (insn, 0, 15);
x86_mov_reg_imm (b->jit_ptr, X86_EAX, imm & 0xffff);
x86_alu_reg_membase (b->jit_ptr, X86_OR, X86_EAX, X86_EDI,
REG_OFFSET (rs));
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rt), X86_EAX, 4);
return (0);
}
static int mips_emit_pref (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
return (0);
}
static int mips_emit_sb (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int base = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int offset = bits (insn, 0, 15);
mips_emit_memop (b, MIPS_MEMOP_SB, base, offset, rt, TRUE);
return (0);
}
static int mips_emit_sc (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int base = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int offset = bits (insn, 0, 15);
mips_emit_memop (b, MIPS_MEMOP_SC, base, offset, rt, TRUE);
return (0);
}
static int mips_emit_scd (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_sd (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_sdc1 (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
#if SOFT_FPU
/* Save PC for exception handling */
mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2));
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
mips_emit_basic_c_call (b, mips_exec_soft_fpu);
mips_jit_tcb_push_epilog (b);
return (0);
#else
mips_emit_unknown (cpu, b, insn);
return (0);
#endif
}
static int mips_emit_sdc2 (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_sdl (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_sdr (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_sh (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int base = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int offset = bits (insn, 0, 15);
mips_emit_memop (b, MIPS_MEMOP_SH, base, offset, rt, TRUE);
return (0);
}
static int mips_emit_sll (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rt = bits (insn, 16, 20);
int rd = bits (insn, 11, 15);
int sa = bits (insn, 6, 10);
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rt), 4);
x86_shift_reg_imm (b->jit_ptr, X86_SHL, X86_EAX, sa);
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4);
return (0);
}
static int mips_emit_sllv (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int rd = bits (insn, 11, 15);
x86_mov_reg_membase (b->jit_ptr, X86_ECX, X86_EDI, REG_OFFSET (rs), 4);
x86_alu_reg_imm (b->jit_ptr, X86_AND, X86_ECX, 0x1f);
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rt), 4);
x86_shift_reg (b->jit_ptr, X86_SHL, X86_EAX);
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4);
return (0);
}
static int mips_emit_slt (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int rd = bits (insn, 11, 15);
u_char *test1;
/* eax = gpr[rt] */
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rt), 4);
/* ecx = gpr[rs] */
x86_mov_reg_membase (b->jit_ptr, X86_ECX, X86_EDI, REG_OFFSET (rs), 4);
/* we set rd to 1 when gpr[rs] < gpr[rt] */
x86_clear_reg (b->jit_ptr, X86_ESI);
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_ESI, 4);
x86_alu_reg_reg (b->jit_ptr, X86_CMP, X86_ECX, X86_EAX);
/* rs >= rt => end */
test1 = b->jit_ptr;
x86_branch8 (b->jit_ptr, X86_CC_GE, 0, 1);
x86_inc_membase (b->jit_ptr, X86_EDI, REG_OFFSET (rd));
/* end */
x86_patch (test1, b->jit_ptr);
return (0);
}
static int mips_emit_slti (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int imm = bits (insn, 0, 15);
m_ireg_t val = sign_extend (imm, 16);
u_char *test1;
/* eax =val */
x86_mov_reg_imm (b->jit_ptr, X86_EAX, val);
/* ecx = gpr[rs] */
x86_mov_reg_membase (b->jit_ptr, X86_ECX, X86_EDI, REG_OFFSET (rs), 4);
/* we set rt to 1 when gpr[rs] < val */
x86_clear_reg (b->jit_ptr, X86_ESI);
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rt), X86_ESI, 4);
x86_alu_reg_reg (b->jit_ptr, X86_CMP, X86_ECX, X86_EAX);
/* rs >= val => end */
test1 = b->jit_ptr;
x86_branch8 (b->jit_ptr, X86_CC_GE, 0, 1);
x86_inc_membase (b->jit_ptr, X86_EDI, REG_OFFSET (rt));
/* end */
x86_patch (test1, b->jit_ptr);
return (0);
}
static int mips_emit_sltiu (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int imm = bits (insn, 0, 15);
m_reg_t val = sign_extend (imm, 16);
u_char *test1;
/* eax =val */
x86_mov_reg_imm (b->jit_ptr, X86_EAX, val);
/* ecx = gpr[rs] */
x86_mov_reg_membase (b->jit_ptr, X86_ECX, X86_EDI, REG_OFFSET (rs), 4);
/* we set rt to 1 when gpr[rs] < val */
x86_clear_reg (b->jit_ptr, X86_ESI);
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rt), X86_ESI, 4);
x86_alu_reg_reg (b->jit_ptr, X86_CMP, X86_ECX, X86_EAX);
/* rs() >= val => end */
test1 = b->jit_ptr;
x86_branch8 (b->jit_ptr, X86_CC_GE, 0, 0);
x86_inc_membase (b->jit_ptr, X86_EDI, REG_OFFSET (rt));
/* end */
x86_patch (test1, b->jit_ptr);
return (0);
}
static int mips_emit_sltu (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int rd = bits (insn, 11, 15);
u_char *test1;
/* eax = gpr[rt] */
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rt), 4);
/* ecx = gpr[rs] */
x86_mov_reg_membase (b->jit_ptr, X86_ECX, X86_EDI, REG_OFFSET (rs), 4);
/* we set rd to 1 when gpr[rs] < gpr[rt] */
x86_clear_reg (b->jit_ptr, X86_ESI);
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_ESI, 4);
x86_alu_reg_reg (b->jit_ptr, X86_CMP, X86_ECX, X86_EAX);
/* rs() >= rt(high) => end */
test1 = b->jit_ptr;
x86_branch8 (b->jit_ptr, X86_CC_GE, 0, 0);
x86_inc_membase (b->jit_ptr, X86_EDI, REG_OFFSET (rd));
/* end */
x86_patch (test1, b->jit_ptr);
return (0);
}
static int mips_emit_spec (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
uint16_t special_func = bits (insn, 0, 5);
return mips_spec_jit[special_func].emit_func (cpu, b, insn);
}
static int mips_emit_sra (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rt = bits (insn, 16, 20);
int rd = bits (insn, 11, 15);
int sa = bits (insn, 6, 10);
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rt), 4);
x86_shift_reg_imm (b->jit_ptr, X86_SAR, X86_EAX, sa);
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4);
return (0);
}
static int mips_emit_srav (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int rd = bits (insn, 11, 15);
x86_mov_reg_membase (b->jit_ptr, X86_ECX, X86_EDI, REG_OFFSET (rs), 4);
x86_alu_reg_imm (b->jit_ptr, X86_AND, X86_ECX, 0x1f);
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rt), 4);
x86_shift_reg (b->jit_ptr, X86_SAR, X86_EAX);
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4);
return (0);
}
static int mips_emit_srl (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rt = bits (insn, 16, 20);
int rd = bits (insn, 11, 15);
int sa = bits (insn, 6, 10);
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rt), 4);
x86_shift_reg_imm (b->jit_ptr, X86_SHR, X86_EAX, sa);
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4);
return (0);
}
static int mips_emit_srlv (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int rd = bits (insn, 11, 15);
x86_mov_reg_membase (b->jit_ptr, X86_ECX, X86_EDI, REG_OFFSET (rs), 4);
x86_alu_reg_imm (b->jit_ptr, X86_AND, X86_ECX, 0x1f);
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rt), 4);
x86_shift_reg (b->jit_ptr, X86_SHR, X86_EAX);
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4);
return (0);
}
static int mips_emit_sub (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int rd = bits (insn, 11, 15);
/* TODO: Exception handling */
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_alu_reg_membase (b->jit_ptr, X86_SUB, X86_EAX, X86_EDI,
REG_OFFSET (rt));
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4);
return (0);
}
static int mips_emit_subu (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int rd = bits (insn, 11, 15);
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_alu_reg_membase (b->jit_ptr, X86_SUB, X86_EAX, X86_EDI,
REG_OFFSET (rt));
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4);
return (0);
}
static int mips_emit_sw (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int base = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int offset = bits (insn, 0, 15);
mips_emit_memop (b, MIPS_MEMOP_SW, base, offset, rt, TRUE);
return (0);
}
static int mips_emit_swc1 (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
#if SOFT_FPU
/* Save PC for exception handling */
mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2));
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
mips_emit_basic_c_call (b, mips_exec_soft_fpu);
mips_jit_tcb_push_epilog (b);
return (0);
#else
mips_emit_unknown (cpu, b, insn);
return (0);
#endif
}
static int mips_emit_swc2 (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_swl (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int base = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int offset = bits (insn, 0, 15);
mips_emit_memop (b, MIPS_MEMOP_SWL, base, offset, rt, TRUE);
return (0);
}
static int mips_emit_swr (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int base = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int offset = bits (insn, 0, 15);
mips_emit_memop (b, MIPS_MEMOP_SWR, base, offset, rt, TRUE);
return (0);
}
static int mips_emit_sync (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
return (0);
}
static int mips_emit_syscall (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2));
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
mips_emit_basic_c_call (b, mips_exec_syscall);
mips_jit_tcb_push_epilog (b);
return (0);
}
static int mips_emit_teq (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
u_char *test1;
/* Compare low part */
x86_mov_reg_membase (b->jit_ptr, X86_ECX, X86_EDI, REG_OFFSET (rs), 4);
x86_alu_reg_membase (b->jit_ptr, X86_CMP, X86_ECX, X86_EDI,
REG_OFFSET (rt));
test1 = b->jit_ptr;
x86_branch32 (b->jit_ptr, X86_CC_NE, 0, 1);
/* Generate trap exception */
x86_alu_reg_imm (b->jit_ptr, X86_SUB, X86_ESP, 12);
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
mips_emit_c_call (b, mips_trigger_trap_exception);
x86_alu_reg_imm (b->jit_ptr, X86_ADD, X86_ESP, 12);
mips_jit_tcb_push_epilog (b);
/* end */
x86_patch (test1, b->jit_ptr);
return (0);
}
static int mips_emit_teqi (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int imm = bits (insn, 0, 15);
m_reg_t val = sign_extend (imm, 16);
u_char *test1;
/* edx:eax = val */
x86_mov_reg_imm (b->jit_ptr, X86_EAX, val);
/* Compare low part */
x86_mov_reg_membase (b->jit_ptr, X86_ECX, X86_EDI, REG_OFFSET (rs), 4);
x86_alu_reg_reg (b->jit_ptr, X86_CMP, X86_ECX, X86_EAX);
test1 = b->jit_ptr;
x86_branch32 (b->jit_ptr, X86_CC_NE, 0, 1);
/* Generate trap exception */
x86_alu_reg_imm (b->jit_ptr, X86_SUB, X86_ESP, 12);
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
mips_emit_c_call (b, mips_trigger_trap_exception);
x86_alu_reg_imm (b->jit_ptr, X86_ADD, X86_ESP, 12);
mips_jit_tcb_push_epilog (b);
/* end */
x86_patch (test1, b->jit_ptr);
return (0);
}
static int mips_emit_tlb (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
uint16_t func = bits (insn, 0, 5);
return mips_tlb_jit[func].emit_func (cpu, b, insn);
}
static int mips_emit_tlbp (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2));
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
mips_emit_basic_c_call (b, mips_cp0_exec_tlbp);
return (0);
}
static int mips_emit_tlbr (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2));
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
mips_emit_basic_c_call (b, mips_cp0_exec_tlbr);
return (0);
}
static int mips_emit_tlbwi (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2));
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
mips_emit_basic_c_call (b, mips_cp0_exec_tlbwi);
return (0);
}
static int mips_emit_tlbwr (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2));
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
mips_emit_basic_c_call (b, mips_cp0_exec_tlbwr);
return (0);
}
static int mips_emit_tge (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_tgei (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_tgeu (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_tgeiu (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_tlt (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_tlti (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_tltiu (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_tltu (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int fastcall tne_emu (cpu_mips_t * cpu, mips_insn_t insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
if ((m_ireg_t) cpu->gpr[rs] != (m_ireg_t) cpu->gpr[rt]) {
/*take a trap */
mips_trigger_trap_exception (cpu);
return (1);
} else
return (0);
}
static int mips_emit_tne (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
x86_mov_reg_imm (b->jit_ptr, X86_EDX, insn);
x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4);
mips_emit_basic_c_call (b, tne_emu);
return (0);
}
static int mips_emit_tnei (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_wait (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
return (0);
}
static int mips_emit_xor (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int rd = bits (insn, 11, 15);
x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4);
x86_alu_reg_membase (b->jit_ptr, X86_XOR, X86_EAX, X86_EDI,
REG_OFFSET (rt));
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4);
return (0);
}
static int mips_emit_xori (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
int rs = bits (insn, 21, 25);
int rt = bits (insn, 16, 20);
int imm = bits (insn, 0, 15);
x86_mov_reg_imm (b->jit_ptr, X86_EAX, imm);
x86_alu_reg_membase (b->jit_ptr, X86_XOR, X86_EAX, X86_EDI,
REG_OFFSET (rs));
x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rt), X86_EAX, 4);
return (0);
}
static int mips_emit_undef (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_unknownBcond (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_unknowncop0 (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_unknownmad (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_unknownSpec (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
static int mips_emit_unknowntlb (cpu_mips_t * cpu, mips_jit_tcb_t * b,
unsigned int insn)
{
mips_emit_unknown (cpu, b, insn);
return (0);
}
/*instruction table*/
struct mips_jit_desc mips_jit[] = {
{"spec", mips_emit_spec, 0x00, 0x99},
{"bcond", mips_emit_bcond, 0x01, 0x99},
{"j", mips_emit_j, 0x02, 0x0},
{"jal", mips_emit_jal, 0x03, 0x0},
{"beq", mips_emit_beq, 0x04, 0x0},
{"bne", mips_emit_bne, 0x05, 0x0},
{"blez", mips_emit_blez, 0x06, 0x0},
{"bgtz", mips_emit_bgtz, 0x07, 0x0},
{"addi", mips_emit_addi, 0x08, 0x1},
{"addiu", mips_emit_addiu, 0x09, 0x1},
{"slti", mips_emit_slti, 0x0A, 0x1},
{"sltiu", mips_emit_sltiu, 0x0B, 0x1},
{"andi", mips_emit_andi, 0x0C, 0x1},
{"ori", mips_emit_ori, 0x0D, 0x1},
{"xori", mips_emit_xori, 0x0E, 0x1},
{"lui", mips_emit_lui, 0x0F, 0x1},
{"cop0", mips_emit_cop0, 0x10, 0x99},
{"cop1", mips_emit_cop1, 0x11, 0x1},
{"cop2", mips_emit_cop2, 0x12, 0x1},
{"cop1x", mips_emit_cop1x, 0x13, 0x1},
{"beql", mips_emit_beql, 0x14, 0x0},
{"bnel", mips_emit_bnel, 0x15, 0x0},
{"blezl", mips_emit_blezl, 0x16, 0x0},
{"bgtzl", mips_emit_bgtzl, 0x17, 0x0},
{"daddi", mips_emit_daddi, 0x18, 0x1},
{"daddiu", mips_emit_daddiu, 0x19, 0x1},
{"ldl", mips_emit_ldl, 0x1A, 0x1},
{"ldr", mips_emit_ldr, 0x1B, 0x1},
{"undef", mips_emit_mad, 0x1C, 0x99},
{"undef", mips_emit_undef, 0x1D, 0x1},
{"undef", mips_emit_undef, 0x1E, 0x1},
{"undef", mips_emit_undef, 0x1F, 0x1},
{"lb", mips_emit_lb, 0x20, 0x1},
{"lh", mips_emit_lh, 0x21, 0x1},
{"lwl", mips_emit_lwl, 0x22, 0x1},
{"lw", mips_emit_lw, 0x23, 0x1},
{"lbu", mips_emit_lbu, 0x24, 0x1},
{"lhu", mips_emit_lhu, 0x25, 0x1},
{"lwr", mips_emit_lwr, 0x26, 0x1},
{"lwu", mips_emit_lwu, 0x27, 0x1},
{"sb", mips_emit_sb, 0x28, 0x1},
{"sh", mips_emit_sh, 0x29, 0x1},
{"swl", mips_emit_swl, 0x2A, 0x1},
{"sw", mips_emit_sw, 0x2B, 0x1},
{"sdl", mips_emit_sdl, 0x2C, 0x1},
{"sdr", mips_emit_sdr, 0x2D, 0x1},
{"swr", mips_emit_swr, 0x2E, 0x1},
{"cache", mips_emit_cache, 0x2F, 0x1},
{"ll", mips_emit_ll, 0x30, 0x1},
{"lwc1", mips_emit_lwc1, 0x31, 0x1},
{"lwc2", mips_emit_lwc2, 0x32, 0x1},
{"pref", mips_emit_pref, 0x33, 0x1},
{"lld", mips_emit_lld, 0x34, 0x1},
{"ldc1", mips_emit_ldc1, 0x35, 0x1},
{"ldc2", mips_emit_ldc2, 0x36, 0x1},
{"ld", mips_emit_ld, 0x37, 0x1},
{"sc", mips_emit_sc, 0x38, 0x1},
{"swc1", mips_emit_swc1, 0x39, 0x1},
{"swc2", mips_emit_swc2, 0x3A, 0x1},
{"undef", mips_emit_undef, 0x3B, 0x1},
{"scd", mips_emit_scd, 0x3C, 0x1},
{"sdc1", mips_emit_sdc1, 0x3D, 0x1},
{"sdc2", mips_emit_sdc2, 0x3E, 0x1},
{"sd", mips_emit_sd, 0x3F, 0x1},
};
/* Based on the func field of spec opcode */
static struct mips_jit_desc mips_spec_jit[] = {
{"sll", mips_emit_sll, 0x00, 0x1},
{"movc", mips_emit_movc, 0x01, 0x1},
{"srl", mips_emit_srl, 0x02, 0x1},
{"sra", mips_emit_sra, 0x03, 0x1},
{"sllv", mips_emit_sllv, 0x04, 0x1},
{"unknownSpec", mips_emit_unknownSpec, 0x05, 0x1},
{"srlv", mips_emit_srlv, 0x06, 0x1},
{"srav", mips_emit_srav, 0x07, 0x1},
{"jr", mips_emit_jr, 0x08, 0x0},
{"jalr", mips_emit_jalr, 0x09, 0x0},
{"movz", mips_emit_movz, 0x0A, 0x1},
{"movn", mips_emit_movn, 0x0B, 0x1},
{"syscall", mips_emit_syscall, 0x0C, 0x1},
{"break", mips_emit_break, 0x0D, 0x1},
{"spim", mips_emit_unknownSpec, 0x0E, 0x1},
{"sync", mips_emit_sync, 0x0F, 0x1},
{"mfhi", mips_emit_mfhi, 0x10, 0x1},
{"mthi", mips_emit_mthi, 0x11, 0x1},
{"mflo", mips_emit_mflo, 0x12, 0x1},
{"mtlo", mips_emit_mtlo, 0x13, 0x1},
{"dsllv", mips_emit_dsllv, 0x14, 0x1},
{"unknownSpec", mips_emit_unknownSpec, 0x15, 0x1},
{"dsrlv", mips_emit_dsrlv, 0x16, 0x1},
{"dsrav", mips_emit_dsrav, 0x17, 0x1},
{"mult", mips_emit_mult, 0x18, 0x1},
{"multu", mips_emit_multu, 0x19, 0x1},
{"div", mips_emit_div, 0x1A, 0x1},
{"divu", mips_emit_divu, 0x1B, 0x1},
{"dmult", mips_emit_dmult, 0x1C, 0x1},
{"dmultu", mips_emit_dmultu, 0x1D, 0x1},
{"ddiv", mips_emit_ddiv, 0x1E, 0x1},
{"ddivu", mips_emit_ddivu, 0x1F, 0x1},
{"add", mips_emit_add, 0x20, 0x1},
{"addu", mips_emit_addu, 0x21, 0x1},
{"sub", mips_emit_sub, 0x22, 0x1},
{"subu", mips_emit_subu, 0x23, 0x1},
{"and", mips_emit_and, 0x24, 0x1},
{"or", mips_emit_or, 0x25, 0x1},
{"xor", mips_emit_xor, 0x26, 0x1},
{"nor", mips_emit_nor, 0x27, 0x1},
{"unknownSpec", mips_emit_unknownSpec, 0x28, 0x1},
{"unknownSpec", mips_emit_unknownSpec, 0x29, 0x1},
{"slt", mips_emit_slt, 0x2A, 0x1},
{"sltu", mips_emit_sltu, 0x2B, 0x1},
{"dadd", mips_emit_dadd, 0x2C, 0x1},
{"daddu", mips_emit_daddu, 0x2D, 0x1},
{"dsub", mips_emit_dsub, 0x2E, 0x1},
{"dsubu", mips_emit_dsubu, 0x2F, 0x1},
{"tge", mips_emit_tge, 0x30, 0x1},
{"tgeu", mips_emit_tgeu, 0x31, 0x1},
{"tlt", mips_emit_tlt, 0x32, 0x1},
{"tltu", mips_emit_tltu, 0x33, 0x1},
{"teq", mips_emit_teq, 0x34, 0x1},
{"unknownSpec", mips_emit_unknownSpec, 0x35, 0x1},
{"tne", mips_emit_tne, 0x36, 0x1},
{"unknownSpec", mips_emit_unknownSpec, 0x37, 0x1},
{"dsll", mips_emit_dsll, 0x38, 0x1},
{"unknownSpec", mips_emit_unknownSpec, 0x39, 0x1},
{"dsrl", mips_emit_dsrl, 0x3A, 0x1},
{"dsra", mips_emit_dsra, 0x3B, 0x1},
{"dsll32", mips_emit_dsll32, 0x3C, 0x1},
{"unknownSpec", mips_emit_unknownSpec, 0x3D, 0x1},
{"dsrl32", mips_emit_dsrl32, 0x3E, 0x1},
{"dsra32", mips_emit_dsra32, 0x3F, 0x1}
};
/* Based on the rt field of bcond opcodes */
static struct mips_jit_desc mips_bcond_jit[] = {
{"bltz", mips_emit_bltz, 0x00, 0x0},
{"bgez", mips_emit_bgez, 0x01, 0x0},
{"bltzl", mips_emit_bltzl, 0x02, 0x0},
{"bgezl", mips_emit_bgezl, 0x03, 0x0},
{"spimi", mips_emit_unknownBcond, 0x04, 0x0},
{"unknownBcond", mips_emit_unknownBcond, 0x05, 0x1},
{"unknownBcond", mips_emit_unknownBcond, 0x06, 0x1},
{"unknownBcond", mips_emit_unknownBcond, 0x07, 0x1},
{"tgei", mips_emit_tgei, 0x08, 0x1},
{"tgeiu", mips_emit_tgeiu, 0x09, 0x1},
{"tlti", mips_emit_tlti, 0x0A, 0x1},
{"tltiu", mips_emit_tltiu, 0x0B, 0x1},
{"teqi", mips_emit_teqi, 0x0C, 0x1},
{"unknownBcond", mips_emit_unknownBcond, 0x0D, 0x1},
{"tnei", mips_emit_tnei, 0x0E, 0x1},
{"unknownBcond", mips_emit_unknownBcond, 0x0F, 0x1},
{"bltzal", mips_emit_bltzal, 0x10, 0x0},
{"bgezal", mips_emit_bgezal, 0x11, 0x0},
{"bltzall", mips_emit_bltzall, 0x12, 0x0},
{"bgezall", mips_emit_bgezall, 0x13, 0x0},
{"unknownBcond", mips_emit_unknownBcond, 0x14, 0x1},
{"unknownBcond", mips_emit_unknownBcond, 0x15, 0x1},
{"unknownBcond", mips_emit_unknownBcond, 0x16, 0x1},
{"unknownBcond", mips_emit_unknownBcond, 0x17, 0x1},
{"unknownBcond", mips_emit_unknownBcond, 0x18, 0x1},
{"unknownBcond", mips_emit_unknownBcond, 0x19, 0x1},
{"unknownBcond", mips_emit_unknownBcond, 0x1A, 0x1},
{"unknownBcond", mips_emit_unknownBcond, 0x1B, 0x1},
{"unknownBcond", mips_emit_unknownBcond, 0x1C, 0x1},
{"unknownBcond", mips_emit_unknownBcond, 0x1D, 0x1},
{"unknownBcond", mips_emit_unknownBcond, 0x1E, 0x1},
{"unknownBcond", mips_emit_unknownBcond, 0x1F, 0x1}
};
static struct mips_jit_desc mips_cop0_jit[] = {
{"mfc0", mips_emit_mfc0, 0x0, 0x1},
{"dmfc0", mips_emit_dmfc0, 0x1, 0x1},
{"cfc0", mips_emit_cfc0, 0x2, 0x1},
{"unknowncop0", mips_emit_unknowncop0, 0x3, 0x1},
{"mtc0", mips_emit_mtc0, 0x4, 0x1},
{"dmtc0", mips_emit_dmtc0, 0x5, 0x1},
{"unknowncop0", mips_emit_unknowncop0, 0x6, 0x1},
{"unknowncop0", mips_emit_unknowncop0, 0x7, 0x1},
{"unknowncop0", mips_emit_unknowncop0, 0x8, 0x1},
{"unknowncop0", mips_emit_unknowncop0, 0x9, 0x1},
{"unknowncop0", mips_emit_unknowncop0, 0xa, 0x1},
{"unknowncop0", mips_emit_unknowncop0, 0xb, 0x1},
{"unknowncop0", mips_emit_unknowncop0, 0xc, 0x1},
{"unknowncop0", mips_emit_unknowncop0, 0xd, 0x1},
{"unknowncop0", mips_emit_unknowncop0, 0xe, 0x1},
{"unknowncop0", mips_emit_unknowncop0, 0xf, 0x1},
{"tlb", mips_emit_tlb, 0x10, 0x1},
{"unknowncop0", mips_emit_unknowncop0, 0x11, 0x1},
{"unknowncop0", mips_emit_unknowncop0, 0x12, 0x1},
{"unknowncop0", mips_emit_unknowncop0, 0x13, 0x1},
{"unknowncop0", mips_emit_unknowncop0, 0x14, 0x1},
{"unknowncop0", mips_emit_unknowncop0, 0x15, 0x1},
{"unknowncop0", mips_emit_unknowncop0, 0x16, 0x1},
{"unknowncop0", mips_emit_unknowncop0, 0x17, 0x1},
{"unknowncop0", mips_emit_unknowncop0, 0x18, 0x1},
{"unknowncop0", mips_emit_unknowncop0, 0x19, 0x1},
{"unknowncop0", mips_emit_unknowncop0, 0x1a, 0x1},
{"unknowncop0", mips_emit_unknowncop0, 0x1b, 0x1},
{"unknowncop0", mips_emit_unknowncop0, 0x1c, 0x1},
{"unknowncop0", mips_emit_unknowncop0, 0x1d, 0x1},
{"unknowncop0", mips_emit_unknowncop0, 0x1e, 0x1},
{"unknowncop0", mips_emit_unknowncop0, 0x1f, 0x1},
};
static struct mips_jit_desc mips_mad_jit[] = {
{"mad", mips_emit_madd, 0x0, 0x1},
{"maddu", mips_emit_maddu, 0x1, 0x1},
{"mul", mips_emit_mul, 0x2, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x3, 0x1},
{"msub", mips_emit_msub, 0x4, 0x1},
{"msubu", mips_emit_msubu, 0x5, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x6, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x7, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x8, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x9, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0xa, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0xb, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0xc, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0xd, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0xe, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0xf, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x10, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x11, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x12, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x13, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x14, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x15, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x16, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x17, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x18, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x19, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x1a, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x1b, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x1c, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x1d, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x1e, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x1f, 0x1},
{"clz", mips_emit_clz, 0x20, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x21, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x22, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x23, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x24, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x25, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x26, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x27, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x28, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x29, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x2a, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x2b, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x2c, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x2d, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x2e, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x2f, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x30, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x31, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x32, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x33, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x34, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x35, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x36, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x37, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x38, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x39, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x3a, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x3b, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x3c, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x3d, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x3e, 0x1},
{"unknownmad_op", mips_emit_unknownmad, 0x3f, 0x1},
};
static struct mips_jit_desc mips_tlb_jit[] = {
{"unknowntlb_op", mips_emit_unknowntlb, 0x0, 0x1},
{"tlbr", mips_emit_tlbr, 0x1, 0x1},
{"tlbwi", mips_emit_tlbwi, 0x2, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x3, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x4, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x5, 0x1},
{"tlbwi", mips_emit_tlbwr, 0x6, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x7, 0x1},
{"tlbp", mips_emit_tlbp, 0x8, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x9, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0xa, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0xb, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0xc, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0xd, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0xe, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0xf, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x10, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x11, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x12, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x13, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x14, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x15, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x16, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x17, 0x1},
{"eret", mips_emit_eret, 0x18, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x19, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x1a, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x1b, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x1c, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x1d, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x1e, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x1f, 0x1},
{"wait", mips_emit_wait, 0x20, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x21, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x22, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x23, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x24, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x25, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x26, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x27, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x28, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x29, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x2a, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x2b, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x2c, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x2d, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x2e, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x2f, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x30, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x31, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x32, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x33, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x34, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x35, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x36, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x37, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x38, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x39, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x3a, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x3b, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x3c, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x3d, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x3e, 0x1},
{"unknowntlb_op", mips_emit_unknowntlb, 0x3f, 0x1},
};
#endif