not64/r4300/ppc/MIPS-to-PPC.c
2022-11-21 16:20:02 -05:00

7011 lines
174 KiB
C

/**
* Wii64 - MIPS-to-PPC.c
* Copyright (C) 2007, 2008, 2009, 2010 Mike Slegeir
*
* Convert MIPS code into PPC (take 2 1/2)
*
* Wii64 homepage: http://www.emulatemii.com
* email address: tehpola@gmail.com
*
*
* This program is free software; you can redistribute it and/
* or modify it under the terms of the GNU General Public Li-
* cence as published by the Free Software Foundation; either
* version 2 of the Licence, or any later version.
*
* This program is distributed in the hope that it will be use-
* ful, but WITHOUT ANY WARRANTY; without even the implied war-
* ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public Licence for more details.
*
**/
/* TODO: FP conversion to/from longs
Optimize idle branches (generate a call to gen_interrupt)
Optimize instruction scheduling & reduce branch instructions
FIXME: Branch comparisons need to operate on 64-bit values when necessary
*/
#include <string.h>
#include "MIPS-to-PPC.h"
#include "Register-Cache.h"
#include "Interpreter.h"
#include "Wrappers.h"
#include "../Recomp-Cache.h"
#include "../../gc_memory/memory.h"
#include <math.h>
#include <assert.h>
// Prototypes for functions used and defined in this file
static void genCallInterp(MIPS_instr);
#define JUMPTO_REG 0
#define JUMPTO_OFF 1
#define JUMPTO_ADDR 2
#define JUMPTO_REG_SIZE 2
#define JUMPTO_OFF_SIZE 11
#define JUMPTO_ADDR_SIZE 11
static void genJumpTo(unsigned int loc, unsigned int type);
static void genUpdateCount(int checkCount);
static void genCheckFP(void);
static void genCallDynaMem(memType type, int count, int _rs, int _rt, short immed);
void RecompCache_Update(PowerPC_func*);
static int inline mips_is_jump(MIPS_instr);
void jump_to(unsigned int);
void check_interupt();
extern int llbit;
extern long local_rs32, local_rt32;
extern unsigned long FCR0, FCR31;
extern unsigned long next_interupt, last_addr;
extern unsigned long count_per_op;
unsigned long long __udivmoddi4(unsigned long long, unsigned long long, unsigned long long*);
double __ieee754_sqrt(double);
float __ieee754_sqrtf(float);
long long __fixdfdi(double);
long long __fixsfdi(float);
#define CANT_COMPILE_DELAY() \
((get_src_pc()&0xFFF) == 0xFFC && \
(get_src_pc() < 0x80000000 || \
get_src_pc() >= 0xC0000000))
static inline unsigned short extractUpper16(void* address){
unsigned int addr = (unsigned int)address;
return (addr>>16) + ((addr>>15)&1);
}
static inline short extractLower16(void* address){
unsigned int addr = (unsigned int)address;
return addr&0x8000 ? (addr&0xffff)-0x10000 : addr&0xffff;
}
static int FP_need_check;
// Variable to indicate whether the next recompiled instruction
// is a delay slot (which needs to have its registers flushed)
// and the current instruction
static int delaySlotNext, isDelaySlot;
// This should be called before the jump is recompiled
static inline int check_delaySlot(void){
if(peek_next_src() == MIPS_NOP){
get_next_src(); // Get rid of the NOP
return 0;
} else {
if(mips_is_jump(peek_next_src())) return CONVERT_WARNING;
delaySlotNext = 1;
convert(); // This just moves the delay slot instruction ahead of the branch
return 1;
}
}
#define MIPS_REG_HI 32
#define MIPS_REG_LO 33
// Initialize register mappings
void start_new_block(void){
invalidateRegisters();
invalidateConstants();
// Check if the previous instruction was a branch
// and thus whether this block begins with a delay slot
unget_last_src();
if(mips_is_jump(get_next_src())) delaySlotNext = 2;
else delaySlotNext = 0;
}
void start_new_mapping(void){
flushRegisters();
invalidateConstants();
reset_code_addr();
FP_need_check = 1;
}
static inline int signExtend(int value, int size){
int signMask = 1 << (size-1);
int negMask = 0xffffffff << (size-1);
if(value & signMask) value |= negMask;
return value;
}
static void genCmp64(int cr, int _ra, int _rb){
PowerPC_instr ppc;
if(getRegisterMapping(_ra) == MAPPING_32 ||
getRegisterMapping(_rb) == MAPPING_32){
// Here we cheat a little bit: if either of the registers are mapped
// as 32-bit, only compare the 32-bit values
int ra = mapRegister(_ra), rb = mapRegister(_rb);
GEN_CMP(ppc, cr, ra, rb);
set_next_dst(ppc);
} else {
RegMapping ra = mapRegister64(_ra), rb = mapRegister64(_rb);
GEN_CMP(ppc, cr, ra.hi, rb.hi);
set_next_dst(ppc);
// Skip low word comparison if high words are mismatched
GEN_BNE(ppc, cr, 2, 0, 0);
set_next_dst(ppc);
// Compare low words if hi words don't match
GEN_CMPL(ppc, cr, ra.lo, rb.lo);
set_next_dst(ppc);
}
}
static void genCmpi64(int cr, int _ra, short immed){
PowerPC_instr ppc;
if(getRegisterMapping(_ra) == MAPPING_32){
// If we've mapped this register as 32-bit, don't bother with 64-bit
int ra = mapRegister(_ra);
GEN_CMPI(ppc, cr, ra, immed);
set_next_dst(ppc);
} else {
RegMapping ra = mapRegister64(_ra);
GEN_CMPI(ppc, cr, ra.hi, immed < 0 ? ~0 : 0);
set_next_dst(ppc);
// Skip low word comparison if high words are mismatched
GEN_BNE(ppc, cr, 2, 0, 0);
set_next_dst(ppc);
// Compare low words if hi words don't match
GEN_CMPLI(ppc, cr, ra.lo, immed);
set_next_dst(ppc);
}
}
typedef enum { NONE=0, EQ, NE, LT, GT, LE, GE } condition;
// Branch a certain offset (possibly conditionally, linking, or likely)
// offset: N64 instructions from current N64 instruction to branch
// cond: type of branch to execute depending on cr 7
// link: if nonzero, branch and link
// likely: if nonzero, the delay slot will only be executed when cond is true
static int branch(short offset, condition cond, int link, int likely){
PowerPC_instr ppc;
int likely_id;
// Condition codes for bc (and their negations)
int bo, bi, nbo;
switch(cond){
case EQ:
bo = 0xc, nbo = 0x4, bi = 18;
break;
case NE:
bo = 0x4, nbo = 0xc, bi = 18;
break;
case LT:
bo = 0xc, nbo = 0x4, bi = 16;
break;
case GE:
bo = 0x4, nbo = 0xc, bi = 16;
break;
case GT:
bo = 0xc, nbo = 0x4, bi = 17;
break;
case LE:
bo = 0x4, nbo = 0xc, bi = 17;
break;
default:
bo = 0x14; nbo = 0x4; bi = 19;
break;
}
flushRegisters();
if(link){
// Set LR to next instruction
int lr = mapRegisterNew(MIPS_REG_LR, 1);
// lis lr, pc@ha(0)
GEN_LIS(ppc, lr, (get_src_pc()+8)>>16);
set_next_dst(ppc);
// la lr, pc@l(lr)
GEN_ORI(ppc, lr, lr, get_src_pc()+8);
set_next_dst(ppc);
flushRegisters();
}
if(likely){
// b[!cond] <past delay to update_count>
likely_id = add_jump_special(0);
GEN_BC(ppc, likely_id, 0, 0, nbo, bi);
set_next_dst(ppc);
}
// Check the delay slot, and note how big it is
PowerPC_instr* preDelay = get_curr_dst();
check_delaySlot();
int delaySlot = get_curr_dst() - preDelay;
#ifdef COMPARE_CORE
GEN_LI(ppc, R4, 1);
set_next_dst(ppc);
if(likely){
GEN_B(ppc, 2, 0, 0);
set_next_dst(ppc);
GEN_LI(ppc, R4, 0);
set_next_dst(ppc);
set_jump_special(likely_id, delaySlot+2+1);
}
#else
if(likely) set_jump_special(likely_id, delaySlot+1);
#endif
genUpdateCount(1); // Sets cr3 to (next_interupt ? Count)
#ifndef INTERPRET_BRANCH
// If we're jumping out, we need to trampoline using genJumpTo
if(is_j_out(offset, 0)){
#endif // INTEPRET_BRANCH
// b[!cond] <past jumpto & delay>
// Note: if there's a delay slot, I will branch to the branch over it
GEN_BC(ppc, JUMPTO_OFF_SIZE+1, 0, 0, nbo, bi);
set_next_dst(ppc);
genJumpTo(offset, JUMPTO_OFF);
// The branch isn't taken, but we need to check interrupts
// Load the address of the next instruction
GEN_LIS(ppc, R3, (get_src_pc()+4)>>16);
set_next_dst(ppc);
GEN_ORI(ppc, R3, R3, get_src_pc()+4);
set_next_dst(ppc);
// If taking the interrupt, return to the trampoline
GEN_BLELR(ppc, CR3, 0);
set_next_dst(ppc);
#ifndef INTERPRET_BRANCH
} else {
// last_addr = naddr
if(cond != NONE){
GEN_BC(ppc, 4, 0, 0, bo, bi);
set_next_dst(ppc);
GEN_LIS(ppc, R3, (get_src_pc()+4)>>16);
set_next_dst(ppc);
GEN_ORI(ppc, R3, R3, get_src_pc()+4);
set_next_dst(ppc);
GEN_B(ppc, 3, 0, 0);
set_next_dst(ppc);
}
GEN_LIS(ppc, R3, (get_src_pc() + (offset<<2))>>16);
set_next_dst(ppc);
GEN_ORI(ppc, R3, R3, get_src_pc() + (offset<<2));
set_next_dst(ppc);
GEN_STW(ppc, R3, SDAREL(last_addr), R13);
set_next_dst(ppc);
// If taking the interrupt, return to the trampoline
GEN_BLELR(ppc, CR3, 0);
set_next_dst(ppc);
// The actual branch
#if 0
// FIXME: Reenable this when blocks are small enough to BC within
// Make sure that pass2 uses BD/LI as appropriate
GEN_BC(ppc, add_jump(offset, 0, 0), 0, 0, bo, bi);
set_next_dst(ppc);
#else
GEN_BC(ppc, 2, 0, 0, nbo, bi);
set_next_dst(ppc);
GEN_B(ppc, add_jump(offset, 0, 0), 0, 0);
set_next_dst(ppc);
#endif
}
#endif // INTERPRET_BRANCH
// Let's still recompile the delay slot in place in case its branched to
// Unless the delay slot is in the next block, in which case there's nothing to skip
// Testing is_j_out with an offset of 0 checks whether the delay slot is out
if(delaySlot){
if(is_j_dst(0) && !is_j_out(0, 0)){
// Step over the already executed delay slot if the branch isn't taken
// b delaySlot+1
GEN_B(ppc, delaySlot+1, 0, 0);
set_next_dst(ppc);
unget_last_src();
delaySlotNext = 2;
}
} else nop_ignored();
#ifdef INTERPRET_BRANCH
return INTERPRETED;
#else // INTERPRET_BRANCH
return CONVERT_SUCCESS;
#endif
}
static int (*gen_ops[64])(MIPS_instr);
int convert(void){
int needFlush = delaySlotNext;
isDelaySlot = (delaySlotNext == 1);
delaySlotNext = 0;
MIPS_instr mips = get_next_src();
int result = gen_ops[MIPS_GET_OPCODE(mips)](mips);
if(needFlush){
flushRegisters();
invalidateConstants();
}
return result;
}
static int NI(){
return CONVERT_ERROR;
}
// -- Primary Opcodes --
static int J(MIPS_instr mips){
PowerPC_instr ppc;
unsigned int naddr = (MIPS_GET_LI(mips)<<2)|((get_src_pc()+4)&0xf0000000);
if(naddr == get_src_pc() || CANT_COMPILE_DELAY()){
// J_IDLE || virtual delay
genCallInterp(mips);
return INTERPRETED;
}
flushRegisters();
reset_code_addr();
// Check the delay slot, and note how big it is
PowerPC_instr* preDelay = get_curr_dst();
check_delaySlot();
int delaySlot = get_curr_dst() - preDelay;
#ifdef COMPARE_CORE
GEN_LI(ppc, R4, 1);
set_next_dst(ppc);
#endif
// Sets cr3 to (next_interupt ? Count)
genUpdateCount(1);
#ifdef INTERPRET_J
genJumpTo(MIPS_GET_LI(mips), JUMPTO_ADDR);
#else // INTERPRET_J
// If we're jumping out, we can't just use a branch instruction
if(is_j_out(MIPS_GET_LI(mips), 1)){
genJumpTo(MIPS_GET_LI(mips), JUMPTO_ADDR);
} else {
// last_addr = naddr
GEN_LIS(ppc, R3, naddr>>16);
set_next_dst(ppc);
GEN_ORI(ppc, R3, R3, naddr);
set_next_dst(ppc);
GEN_STW(ppc, R3, SDAREL(last_addr), R13);
set_next_dst(ppc);
// if(next_interupt <= Count) return;
GEN_BLELR(ppc, CR3, 0);
set_next_dst(ppc);
// Even though this is an absolute branch
// in pass 2, we generate a relative branch
GEN_B(ppc, add_jump(MIPS_GET_LI(mips), 1, 0), 0, 0);
set_next_dst(ppc);
}
#endif
// Let's still recompile the delay slot in place in case its branched to
if(delaySlot){ if(is_j_dst(0)){ unget_last_src(); delaySlotNext = 2; } }
else nop_ignored();
#ifdef INTERPRET_J
return INTERPRETED;
#else // INTERPRET_J
return CONVERT_SUCCESS;
#endif
}
static int JAL(MIPS_instr mips){
PowerPC_instr ppc;
unsigned int naddr = (MIPS_GET_LI(mips)<<2)|((get_src_pc()+4)&0xf0000000);
if(CANT_COMPILE_DELAY()){
genCallInterp(mips);
return INTERPRETED;
}
flushRegisters();
reset_code_addr();
// Check the delay slot, and note how big it is
PowerPC_instr* preDelay = get_curr_dst();
check_delaySlot();
int delaySlot = get_curr_dst() - preDelay;
#ifdef COMPARE_CORE
GEN_LI(ppc, R4, 1);
set_next_dst(ppc);
#endif
// Sets cr3 to (next_interupt ? Count)
genUpdateCount(1);
// Set LR to next instruction
int lr = mapRegisterNew(MIPS_REG_LR, 1);
// lis lr, pc@ha(0)
GEN_LIS(ppc, lr, (get_src_pc()+4)>>16);
set_next_dst(ppc);
// la lr, pc@l(lr)
GEN_ORI(ppc, lr, lr, get_src_pc()+4);
set_next_dst(ppc);
flushRegisters();
#ifdef INTERPRET_JAL
genJumpTo(MIPS_GET_LI(mips), JUMPTO_ADDR);
#else // INTERPRET_JAL
// If we're jumping out, we can't just use a branch instruction
if(is_j_out(MIPS_GET_LI(mips), 1)){
genJumpTo(MIPS_GET_LI(mips), JUMPTO_ADDR);
} else {
// last_addr = naddr
GEN_LIS(ppc, R3, naddr>>16);
set_next_dst(ppc);
GEN_ORI(ppc, R3, R3, naddr);
set_next_dst(ppc);
GEN_STW(ppc, R3, SDAREL(last_addr), R13);
set_next_dst(ppc);
/// if(next_interupt <= Count) return;
GEN_BLELR(ppc, CR3, 0);
set_next_dst(ppc);
// Even though this is an absolute branch
// in pass 2, we generate a relative branch
GEN_B(ppc, add_jump(MIPS_GET_LI(mips), 1, 0), 0, 0);
set_next_dst(ppc);
}
#endif
// Let's still recompile the delay slot in place in case its branched to
if(delaySlot){ if(is_j_dst(0)){ unget_last_src(); delaySlotNext = 2; } }
else nop_ignored();
#ifdef INTERPRET_JAL
return INTERPRETED;
#else // INTERPRET_JAL
return CONVERT_SUCCESS;
#endif
}
static int BEQ(MIPS_instr mips){
PowerPC_instr ppc;
if((MIPS_GET_SIMMED(mips) == -1 &&
MIPS_GET_RA(mips) == MIPS_GET_RB(mips)) ||
CANT_COMPILE_DELAY()){
// BEQ_IDLE || virtual delay
genCallInterp(mips);
return INTERPRETED;
}
genCmp64(CR4, MIPS_GET_RA(mips), MIPS_GET_RB(mips));
return branch(MIPS_GET_SIMMED(mips), EQ, 0, 0);
}
static int BNE(MIPS_instr mips){
PowerPC_instr ppc;
if(CANT_COMPILE_DELAY()){
genCallInterp(mips);
return INTERPRETED;
}
genCmp64(CR4, MIPS_GET_RA(mips), MIPS_GET_RB(mips));
return branch(MIPS_GET_SIMMED(mips), NE, 0, 0);
}
static int BLEZ(MIPS_instr mips){
PowerPC_instr ppc;
if(CANT_COMPILE_DELAY()){
genCallInterp(mips);
return INTERPRETED;
}
genCmpi64(CR4, MIPS_GET_RA(mips), 0);
return branch(MIPS_GET_SIMMED(mips), LE, 0, 0);
}
static int BGTZ(MIPS_instr mips){
PowerPC_instr ppc;
if(CANT_COMPILE_DELAY()){
genCallInterp(mips);
return INTERPRETED;
}
genCmpi64(CR4, MIPS_GET_RA(mips), 0);
return branch(MIPS_GET_SIMMED(mips), GT, 0, 0);
}
static int ADDIU(MIPS_instr mips){
PowerPC_instr ppc;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
int rs = mapRegister(_rs);
int rt = mapConstantNew(_rt, isRegisterConstant(_rs), 1);
setRegisterConstant(_rt, getRegisterConstant(_rs) + immed);
GEN_ADDI(ppc, rt, rs, immed);
set_next_dst(ppc);
return CONVERT_SUCCESS;
}
static int ADDI(MIPS_instr mips){
return ADDIU(mips);
}
static int SLTI(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_SLTI
genCallInterp(mips);
return INTERPRETED;
#else
// FIXME: Do I need to worry about 64-bit values?
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
int rs = mapRegister(_rs);
int rt = mapConstantNew(_rt, isRegisterConstant(_rs), 0);
setRegisterConstant(_rt, getRegisterConstant(_rs) < immed ? 1 : 0);
GEN_CMPI(ppc, CR0, rs, immed);
set_next_dst(ppc);
GEN_MFCR(ppc, R2);
set_next_dst(ppc);
GEN_RLWINM(ppc, rt, R2, 1, 31, 31);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int SLTIU(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_SLTIU
genCallInterp(mips);
return INTERPRETED;
#else
// FIXME: Do I need to worry about 64-bit values?
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
unsigned short immed = MIPS_GET_UIMMED(mips);
int rs = mapRegister(_rs);
int rt = mapConstantNew(_rt, isRegisterConstant(_rs), 0);
setRegisterConstant(_rt, (unsigned long)getRegisterConstant(_rs) < immed ? 1 : 0);
GEN_NOT(ppc, R0, rs);
set_next_dst(ppc);
GEN_ADDIC(ppc, R0, R0, immed);
set_next_dst(ppc);
GEN_ADDZE(ppc, rt, DYNAREG_ZERO);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int ANDI(MIPS_instr mips){
PowerPC_instr ppc;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
unsigned short immed = MIPS_GET_UIMMED(mips);
int rs = mapRegister(_rs);
int rt = mapConstantNew(_rt, isRegisterConstant(_rs), 0);
setRegisterConstant(_rt, getRegisterConstant(_rs) & immed);
GEN_ANDI(ppc, rt, rs, immed);
set_next_dst(ppc);
return CONVERT_SUCCESS;
}
static int ORI(MIPS_instr mips){
PowerPC_instr ppc;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
unsigned short immed = MIPS_GET_UIMMED(mips);
if(getRegisterMapping(_rs) == MAPPING_32){
int rs = mapRegister(_rs);
int rt = mapConstantNew(_rt, isRegisterConstant(_rs), 1);
setRegisterConstant(_rt, getRegisterConstant(_rs) | immed);
GEN_ORI(ppc, rt, rs, immed);
set_next_dst(ppc);
} else {
RegMapping rs = mapRegister64(_rs);
RegMapping rt = mapConstant64New(_rt, isRegisterConstant(_rs));
setRegisterConstant64(_rt, getRegisterConstant64(_rs) | immed);
GEN_MR(ppc, rt.hi, rs.hi);
set_next_dst(ppc);
GEN_ORI(ppc, rt.lo, rs.lo, immed);
set_next_dst(ppc);
}
return CONVERT_SUCCESS;
}
static int XORI(MIPS_instr mips){
PowerPC_instr ppc;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
unsigned short immed = MIPS_GET_UIMMED(mips);
if(getRegisterMapping(_rs) == MAPPING_32){
int rs = mapRegister(_rs);
int rt = mapConstantNew(_rt, isRegisterConstant(_rs), 1);
setRegisterConstant(_rt, getRegisterConstant(_rs) ^ immed);
GEN_XORI(ppc, rt, rs, immed);
set_next_dst(ppc);
} else {
RegMapping rs = mapRegister64(_rs);
RegMapping rt = mapConstant64New(_rt, isRegisterConstant(_rs));
setRegisterConstant64(_rt, getRegisterConstant64(_rs) ^ immed);
GEN_MR(ppc, rt.hi, rs.hi);
set_next_dst(ppc);
GEN_XORI(ppc, rt.lo, rs.lo, immed);
set_next_dst(ppc);
}
return CONVERT_SUCCESS;
}
static int LUI(MIPS_instr mips){
PowerPC_instr ppc;
int _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
int rt = mapConstantNew(_rt, 1, 1);
setRegisterConstant(_rt, immed << 16);
GEN_LIS(ppc, rt, immed);
set_next_dst(ppc);
return CONVERT_SUCCESS;
}
static int BEQL(MIPS_instr mips){
PowerPC_instr ppc;
if(CANT_COMPILE_DELAY()){
genCallInterp(mips);
return INTERPRETED;
}
genCmp64(CR4, MIPS_GET_RA(mips), MIPS_GET_RB(mips));
return branch(MIPS_GET_SIMMED(mips), EQ, 0, 1);
}
static int BNEL(MIPS_instr mips){
PowerPC_instr ppc;
if(CANT_COMPILE_DELAY()){
genCallInterp(mips);
return INTERPRETED;
}
genCmp64(CR4, MIPS_GET_RA(mips), MIPS_GET_RB(mips));
return branch(MIPS_GET_SIMMED(mips), NE, 0, 1);
}
static int BLEZL(MIPS_instr mips){
PowerPC_instr ppc;
if(CANT_COMPILE_DELAY()){
genCallInterp(mips);
return INTERPRETED;
}
genCmpi64(CR4, MIPS_GET_RA(mips), 0);
return branch(MIPS_GET_SIMMED(mips), LE, 0, 1);
}
static int BGTZL(MIPS_instr mips){
PowerPC_instr ppc;
if(CANT_COMPILE_DELAY()){
genCallInterp(mips);
return INTERPRETED;
}
genCmpi64(CR4, MIPS_GET_RA(mips), 0);
return branch(MIPS_GET_SIMMED(mips), GT, 0, 1);
}
static int DADDIU(MIPS_instr mips){
PowerPC_instr ppc;
#if defined(INTERPRET_DW) || defined(INTERPRET_DADDIU)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_DW || INTERPRET_DADDIU
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
RegMapping rs = mapRegister64(_rs);
RegMapping rt = mapConstant64New(_rt, isRegisterConstant(_rs));
setRegisterConstant64(_rt, getRegisterConstant64(_rs) + immed);
// Add the immediate to the LSW
GEN_ADDIC(ppc, rt.lo, rs.lo, immed);
set_next_dst(ppc);
// Add the MSW with the sign-extension and the carry
if(immed < 0){
GEN_ADDME(ppc, rt.hi, rs.hi);
set_next_dst(ppc);
} else {
GEN_ADDZE(ppc, rt.hi, rs.hi);
set_next_dst(ppc);
}
return CONVERT_SUCCESS;
#endif
}
static int DADDI(MIPS_instr mips){
return DADDIU(mips);
}
static int LDL(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_LDL
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_LDL
int count = 1;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
#ifdef FASTMEM
if(!isDelaySlot){
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
if(count % 2){
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_LDR)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips))
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) + 7)
break;
get_next_src();
count++;
} else {
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_LDL)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) + 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) + 8)
break;
mips = get_next_src();
count++;
}
}
}
#endif
if(count / 2) genCallDynaMem(MEM_ULD, count / 2, _rs, _rt, immed);
if(count % 2) genCallDynaMem(MEM_LDL, count % 2, MIPS_GET_RS(mips), MIPS_GET_RT(mips), MIPS_GET_SIMMED(mips));
return CONVERT_SUCCESS;
#endif
}
static int LDR(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_LDR
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_LDR
int count = 1;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
#ifdef FASTMEM
if(!isDelaySlot){
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
if(count % 2){
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_LDL)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips))
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) - 7)
break;
get_next_src();
count++;
} else {
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_LDR)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) + 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) + 8)
break;
mips = get_next_src();
count++;
}
}
}
#endif
if(count / 2) genCallDynaMem(MEM_ULD, count / 2, _rs, _rt, immed - 7);
if(count % 2) genCallDynaMem(MEM_LDR, count % 2, MIPS_GET_RS(mips), MIPS_GET_RT(mips), MIPS_GET_SIMMED(mips) - 7);
return CONVERT_SUCCESS;
#endif
}
static int LB(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_LB
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_LB
int count = 1;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
#ifdef FASTMEM
if(!isDelaySlot){
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) == MIPS_OPCODE_LB && MIPS_GET_RS(peek) == _rs && MIPS_GET_RS(peek) != _rt){
if(MIPS_GET_RT(peek) == _rt + 1 && MIPS_GET_SIMMED(peek) == immed + 1){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_LB)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) + 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) + 1)
break;
mips = get_next_src();
count++;
}
} else if(MIPS_GET_RT(peek) == _rt - 1 && MIPS_GET_SIMMED(peek) == immed - 1){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_LB)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) - 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) - 1)
break;
mips = get_next_src();
count++;
}
_rt = MIPS_GET_RT(mips);
immed = MIPS_GET_SIMMED(mips);
}
}
break;
}
}
#endif
genCallDynaMem(MEM_LB, count, _rs, _rt, immed);
return CONVERT_SUCCESS;
#endif
}
static int LH(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_LH
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_LH
int count = 1;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
#ifdef FASTMEM
if(!isDelaySlot){
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) == MIPS_OPCODE_LH && MIPS_GET_RS(peek) == _rs && MIPS_GET_RS(peek) != _rt){
if(MIPS_GET_RT(peek) == _rt + 1 && MIPS_GET_SIMMED(peek) == immed + 2){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_LH)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) + 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) + 2)
break;
mips = get_next_src();
count++;
}
} else if(MIPS_GET_RT(peek) == _rt - 1 && MIPS_GET_SIMMED(peek) == immed - 2){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_LH)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) - 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) - 2)
break;
mips = get_next_src();
count++;
}
_rt = MIPS_GET_RT(mips);
immed = MIPS_GET_SIMMED(mips);
}
}
break;
}
}
#endif
genCallDynaMem(MEM_LH, count, _rs, _rt, immed);
return CONVERT_SUCCESS;
#endif
}
static int LWL(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_LWL
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_LWL
int count = 1;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
#ifdef FASTMEM
if(!isDelaySlot){
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
if(count % 2){
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_LWR)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips))
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) + 3)
break;
get_next_src();
count++;
} else {
break;
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_LWL)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) + 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) + 4)
break;
mips = get_next_src();
count++;
}
}
}
#endif
if(count / 2) genCallDynaMem(MEM_ULW, count / 2, _rs, _rt, immed);
if(count % 2) genCallDynaMem(MEM_LWL, count % 2, MIPS_GET_RS(mips), MIPS_GET_RT(mips), MIPS_GET_SIMMED(mips));
return CONVERT_SUCCESS;
#endif
}
static int LW(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_LW
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_LW
int count = 1;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
#ifdef FASTMEM
if(!isDelaySlot){
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) == MIPS_OPCODE_LW && MIPS_GET_RS(peek) == _rs && MIPS_GET_RS(peek) != _rt){
if(MIPS_GET_RT(peek) == _rt + 1 && MIPS_GET_SIMMED(peek) == immed + 4){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_LW)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) + 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) + 4)
break;
mips = get_next_src();
count++;
}
} else if(MIPS_GET_RT(peek) == _rt - 1 && MIPS_GET_SIMMED(peek) == immed - 4){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_LW)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) - 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) - 4)
break;
mips = get_next_src();
count++;
}
_rt = MIPS_GET_RT(mips);
immed = MIPS_GET_SIMMED(mips);
}
}
break;
}
}
#endif
genCallDynaMem(MEM_LW, count, _rs, _rt, immed);
return CONVERT_SUCCESS;
#endif
}
static int LBU(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_LBU
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_LBU
int count = 1;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
#ifdef FASTMEM
if(!isDelaySlot){
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) == MIPS_OPCODE_LBU && MIPS_GET_RS(peek) == _rs && MIPS_GET_RS(peek) != _rt){
if(MIPS_GET_RT(peek) == _rt + 1 && MIPS_GET_SIMMED(peek) == immed + 1){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_LBU)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) + 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) + 1)
break;
mips = get_next_src();
count++;
}
} else if(MIPS_GET_RT(peek) == _rt - 1 && MIPS_GET_SIMMED(peek) == immed - 1){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_LBU)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) - 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) - 1)
break;
mips = get_next_src();
count++;
}
_rt = MIPS_GET_RT(mips);
immed = MIPS_GET_SIMMED(mips);
}
}
break;
}
}
#endif
genCallDynaMem(MEM_LBU, count, _rs, _rt, immed);
return CONVERT_SUCCESS;
#endif
}
static int LHU(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_LHU
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_LHU
int count = 1;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
#ifdef FASTMEM
if(!isDelaySlot){
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) == MIPS_OPCODE_LHU && MIPS_GET_RS(peek) == _rs && MIPS_GET_RS(peek) != _rt){
if(MIPS_GET_RT(peek) == _rt + 1 && MIPS_GET_SIMMED(peek) == immed + 2){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_LHU)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) + 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) + 2)
break;
mips = get_next_src();
count++;
}
} else if(MIPS_GET_RT(peek) == _rt - 1 && MIPS_GET_SIMMED(peek) == immed - 2){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_LHU)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) - 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) - 2)
break;
mips = get_next_src();
count++;
}
_rt = MIPS_GET_RT(mips);
immed = MIPS_GET_SIMMED(mips);
}
}
break;
}
}
#endif
genCallDynaMem(MEM_LHU, count, _rs, _rt, immed);
return CONVERT_SUCCESS;
#endif
}
static int LWR(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_LWR
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_LWR
int count = 1;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
#ifdef FASTMEM
if(!isDelaySlot){
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
if(count % 2){
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_LWL)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips))
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) - 3)
break;
get_next_src();
count++;
} else {
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_LWR)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) + 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) + 4)
break;
mips = get_next_src();
count++;
}
}
}
#endif
if(count / 2) genCallDynaMem(MEM_ULW, count / 2, _rs, _rt, immed - 3);
if(count % 2) genCallDynaMem(MEM_LWR, count % 2, MIPS_GET_RS(mips), MIPS_GET_RT(mips), MIPS_GET_SIMMED(mips) - 3);
return CONVERT_SUCCESS;
#endif
}
static int LWU(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_LWU
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_LWU
int count = 1;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
#ifdef FASTMEM
if(!isDelaySlot){
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) == MIPS_OPCODE_LWU && MIPS_GET_RS(peek) == _rs && MIPS_GET_RS(peek) != _rt){
if(MIPS_GET_RT(peek) == _rt + 1 && MIPS_GET_SIMMED(peek) == immed + 4){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_LWU)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) + 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) + 4)
break;
mips = get_next_src();
count++;
}
} else if(MIPS_GET_RT(peek) == _rt - 1 && MIPS_GET_SIMMED(peek) == immed - 4){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_LWU)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) - 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) - 4)
break;
mips = get_next_src();
count++;
}
_rt = MIPS_GET_RT(mips);
immed = MIPS_GET_SIMMED(mips);
}
}
break;
}
}
#endif
genCallDynaMem(MEM_LWU, count, _rs, _rt, immed);
return CONVERT_SUCCESS;
#endif
}
static int SB(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_SB
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_SB
int count = 1;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
#ifdef FASTMEM
if(!isDelaySlot){
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) == MIPS_OPCODE_SB && MIPS_GET_RS(peek) == _rs){
if(MIPS_GET_RT(peek) == _rt + 1 && MIPS_GET_SIMMED(peek) == immed + 1){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_SB)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) + 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) + 1)
break;
mips = get_next_src();
count++;
}
} else if(MIPS_GET_RT(peek) == _rt - 1 && MIPS_GET_SIMMED(peek) == immed - 1){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_SB)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) - 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) - 1)
break;
mips = get_next_src();
count++;
}
_rt = MIPS_GET_RT(mips);
immed = MIPS_GET_SIMMED(mips);
}
}
break;
}
}
#endif
genCallDynaMem(MEM_SB, count, _rs, _rt, immed);
return CONVERT_SUCCESS;
#endif
}
static int SH(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_SH
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_SH
int count = 1;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
#ifdef FASTMEM
if(!isDelaySlot){
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) == MIPS_OPCODE_SH && MIPS_GET_RS(peek) == _rs){
if(MIPS_GET_RT(peek) == _rt + 1 && MIPS_GET_SIMMED(peek) == immed + 2){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_SH)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) + 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) + 2)
break;
mips = get_next_src();
count++;
}
} else if(MIPS_GET_RT(peek) == _rt - 1 && MIPS_GET_SIMMED(peek) == immed - 2){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_SH)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) - 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) - 2)
break;
mips = get_next_src();
count++;
}
_rt = MIPS_GET_RT(mips);
immed = MIPS_GET_SIMMED(mips);
}
}
break;
}
}
#endif
genCallDynaMem(MEM_SH, count, _rs, _rt, immed);
return CONVERT_SUCCESS;
#endif
}
static int SWL(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_SWL
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_SWL
int count = 1;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
#ifdef FASTMEM
if(!isDelaySlot){
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
if(count % 2){
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_SWR)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips))
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) + 3)
break;
get_next_src();
count++;
} else {
break;
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_SWL)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) + 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) + 4)
break;
mips = get_next_src();
count++;
}
}
}
#endif
if(count / 2) genCallDynaMem(MEM_USW, count / 2, _rs, _rt, immed);
if(count % 2) genCallDynaMem(MEM_SWL, count % 2, MIPS_GET_RS(mips), MIPS_GET_RT(mips), MIPS_GET_SIMMED(mips));
return CONVERT_SUCCESS;
#endif
}
static int SW(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_SW
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_SW
int count = 1;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
#ifdef FASTMEM
if(!isDelaySlot){
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) == MIPS_OPCODE_SW && MIPS_GET_RS(peek) == _rs){
if(MIPS_GET_RT(peek) == _rt + 1 && MIPS_GET_SIMMED(peek) == immed + 4){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_SW)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) + 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) + 4)
break;
mips = get_next_src();
count++;
}
} else if(MIPS_GET_RT(peek) == _rt - 1 && MIPS_GET_SIMMED(peek) == immed - 4){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_SW)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) - 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) - 4)
break;
mips = get_next_src();
count++;
}
_rt = MIPS_GET_RT(mips);
immed = MIPS_GET_SIMMED(mips);
}
}
break;
}
}
#endif
genCallDynaMem(MEM_SW, count, _rs, _rt, immed);
return CONVERT_SUCCESS;
#endif
}
static int SDL(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_SDL
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_SDL
int count = 1;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
#ifdef FASTMEM
if(!isDelaySlot){
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
if(count % 2){
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_SDR)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips))
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) + 7)
break;
get_next_src();
count++;
} else {
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_SDL)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) + 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) + 8)
break;
mips = get_next_src();
count++;
}
}
}
#endif
if(count / 2) genCallDynaMem(MEM_USD, count / 2, _rs, _rt, immed);
if(count % 2) genCallDynaMem(MEM_SDL, count % 2, MIPS_GET_RS(mips), MIPS_GET_RT(mips), MIPS_GET_SIMMED(mips));
return CONVERT_SUCCESS;
#endif
}
static int SDR(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_SDR
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_SDR
int count = 1;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
#ifdef FASTMEM
if(!isDelaySlot){
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
if(count % 2){
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_SDL)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips))
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) - 7)
break;
get_next_src();
count++;
} else {
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_SDR)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) + 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) + 8)
break;
mips = get_next_src();
count++;
}
}
}
#endif
if(count / 2) genCallDynaMem(MEM_USD, count / 2, _rs, _rt, immed - 7);
if(count % 2) genCallDynaMem(MEM_SDR, count % 2, MIPS_GET_RS(mips), MIPS_GET_RT(mips), MIPS_GET_SIMMED(mips) - 7);
return CONVERT_SUCCESS;
#endif
}
static int SWR(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_SWR
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_SWR
int count = 1;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
#ifdef FASTMEM
if(!isDelaySlot){
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
if(count % 2){
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_SWL)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips))
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) - 3)
break;
get_next_src();
count++;
} else {
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_SWR)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) + 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) + 4)
break;
mips = get_next_src();
count++;
}
}
}
#endif
if(count / 2) genCallDynaMem(MEM_USW, count / 2, _rs, _rt, immed - 3);
if(count % 2) genCallDynaMem(MEM_SWR, count % 2, MIPS_GET_RS(mips), MIPS_GET_RT(mips), MIPS_GET_SIMMED(mips) - 3);
return CONVERT_SUCCESS;
#endif
}
static int LD(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_LD
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_LD
int count = 1;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
#ifdef FASTMEM
if(!isDelaySlot){
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) == MIPS_OPCODE_LD && MIPS_GET_RS(peek) == _rs && MIPS_GET_RS(peek) != _rt){
if(MIPS_GET_RT(peek) == _rt + 1 && MIPS_GET_SIMMED(peek) == immed + 8){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_LD)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) + 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) + 8)
break;
mips = get_next_src();
count++;
}
} else if(MIPS_GET_RT(peek) == _rt - 1 && MIPS_GET_SIMMED(peek) == immed - 8){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_LD)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RS(peek) == MIPS_GET_RT(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) - 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) - 8)
break;
mips = get_next_src();
count++;
}
_rt = MIPS_GET_RT(mips);
immed = MIPS_GET_SIMMED(mips);
}
}
break;
}
}
#endif
genCallDynaMem(MEM_LD, count, _rs, _rt, immed);
return CONVERT_SUCCESS;
#endif
}
static int SD(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_SD
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_SD
int count = 1;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
#ifdef FASTMEM
if(!isDelaySlot){
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) == MIPS_OPCODE_SD && MIPS_GET_RS(peek) == _rs){
if(MIPS_GET_RT(peek) == _rt + 1 && MIPS_GET_SIMMED(peek) == immed + 8){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_SD)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) + 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) + 8)
break;
mips = get_next_src();
count++;
}
} else if(MIPS_GET_RT(peek) == _rt - 1 && MIPS_GET_SIMMED(peek) == immed - 8){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_SD)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) - 1)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) - 8)
break;
mips = get_next_src();
count++;
}
_rt = MIPS_GET_RT(mips);
immed = MIPS_GET_SIMMED(mips);
}
}
break;
}
}
#endif
genCallDynaMem(MEM_SD, count, _rs, _rt, immed);
return CONVERT_SUCCESS;
#endif
}
static int LWC1(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_LWC1
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_LWC1
int count = 1;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
genCheckFP();
#ifdef FASTMEM
if(!isDelaySlot){
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) == MIPS_OPCODE_LWC1 && MIPS_GET_RS(peek) == _rs){
if(MIPS_GET_RT(peek) == _rt + 2 && MIPS_GET_SIMMED(peek) == immed + 4){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_LWC1)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) + 2)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) + 4)
break;
mips = get_next_src();
count++;
}
} else if(MIPS_GET_RT(peek) == _rt - 2 && MIPS_GET_SIMMED(peek) == immed - 4){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_LWC1)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) - 2)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) - 4)
break;
mips = get_next_src();
count++;
}
_rt = MIPS_GET_RT(mips);
immed = MIPS_GET_SIMMED(mips);
}
}
break;
}
}
#endif
genCallDynaMem(MEM_LWC1, count, _rs, _rt, immed);
return CONVERT_SUCCESS;
#endif
}
static int LDC1(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_LDC1
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_LDC1
int count = 1;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
genCheckFP();
#ifdef FASTMEM
if(!isDelaySlot){
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) == MIPS_OPCODE_LDC1 && MIPS_GET_RS(peek) == _rs){
if(MIPS_GET_RT(peek) == _rt + 2 && MIPS_GET_SIMMED(peek) == immed + 8){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_LDC1)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) + 2)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) + 8)
break;
mips = get_next_src();
count++;
}
} else if(MIPS_GET_RT(peek) == _rt - 2 && MIPS_GET_SIMMED(peek) == immed - 8){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_LDC1)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) - 2)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) - 8)
break;
mips = get_next_src();
count++;
}
_rt = MIPS_GET_RT(mips);
immed = MIPS_GET_SIMMED(mips);
}
}
break;
}
}
#endif
genCallDynaMem(MEM_LDC1, count, _rs, _rt, immed);
return CONVERT_SUCCESS;
#endif
}
static int SWC1(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_SWC1
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_SWC1
int count = 1;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
genCheckFP();
#ifdef FASTMEM
if(!isDelaySlot){
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) == MIPS_OPCODE_SWC1 && MIPS_GET_RS(peek) == _rs){
if(MIPS_GET_RT(peek) == _rt + 2 && MIPS_GET_SIMMED(peek) == immed + 4){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_SWC1)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) + 2)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) + 4)
break;
mips = get_next_src();
count++;
}
} else if(MIPS_GET_RT(peek) == _rt - 2 && MIPS_GET_SIMMED(peek) == immed - 4){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_SWC1)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) - 2)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) - 4)
break;
mips = get_next_src();
count++;
}
_rt = MIPS_GET_RT(mips);
immed = MIPS_GET_SIMMED(mips);
}
}
break;
}
}
#endif
genCallDynaMem(MEM_SWC1, count, _rs, _rt, immed);
return CONVERT_SUCCESS;
#endif
}
static int SDC1(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_SDC1
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_SDC1
int count = 1;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
genCheckFP();
#ifdef FASTMEM
if(!isDelaySlot){
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
MIPS_instr peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) == MIPS_OPCODE_SDC1 && MIPS_GET_RS(peek) == _rs){
if(MIPS_GET_RT(peek) == _rt + 2 && MIPS_GET_SIMMED(peek) == immed + 8){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_SDC1)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) + 2)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) + 8)
break;
mips = get_next_src();
count++;
}
} else if(MIPS_GET_RT(peek) == _rt - 2 && MIPS_GET_SIMMED(peek) == immed - 8){
mips = get_next_src();
count++;
while(has_next_src() && !is_j_dst(1)){
if(peek_next_src() == MIPS_NOP){
get_next_src();
continue;
}
peek = peek_next_src();
if(MIPS_GET_OPCODE(peek) != MIPS_OPCODE_SDC1)
break;
if(MIPS_GET_RS(peek) != MIPS_GET_RS(mips))
break;
if(MIPS_GET_RT(peek) != MIPS_GET_RT(mips) - 2)
break;
if(MIPS_GET_SIMMED(peek) != MIPS_GET_SIMMED(mips) - 8)
break;
mips = get_next_src();
count++;
}
_rt = MIPS_GET_RT(mips);
immed = MIPS_GET_SIMMED(mips);
}
}
break;
}
}
#endif
genCallDynaMem(MEM_SDC1, count, _rs, _rt, immed);
return CONVERT_SUCCESS;
#endif
}
static int CACHE(MIPS_instr mips){
PowerPC_instr ppc;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
short immed = MIPS_GET_SIMMED(mips);
switch(_rt){
case 0: // Index Invalidate
case 16: // Hit Invalidate
{
int rs = mapRegister(_rs);
flushRegisters();
if(immed || rs != R3){
GEN_ADDI(ppc, R3, rs, immed);
set_next_dst(ppc);
}
GEN_B(ppc, add_jump(&invalidate_func, 1, 1), 0, 1);
set_next_dst(ppc);
GEN_LWZ(ppc, R0, DYNAOFF_LR, R1);
set_next_dst(ppc);
GEN_MTLR(ppc, R0);
set_next_dst(ppc);
return CONVERT_SUCCESS;
}
default:
return CONVERT_ERROR;
}
}
static int LL(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_LL
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_LL
genCallDynaMem(MEM_LL, 1, MIPS_GET_RS(mips), MIPS_GET_RT(mips), MIPS_GET_SIMMED(mips));
return CONVERT_SUCCESS;
#endif
}
static int LLD(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_LLD
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_LLD
genCallDynaMem(MEM_LLD, 1, MIPS_GET_RS(mips), MIPS_GET_RT(mips), MIPS_GET_SIMMED(mips));
return CONVERT_SUCCESS;
#endif
}
static int SC(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_SC
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_SC
genCallDynaMem(MEM_SC, 1, MIPS_GET_RS(mips), MIPS_GET_RT(mips), MIPS_GET_SIMMED(mips));
return CONVERT_SUCCESS;
#endif
}
static int SCD(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_SCD
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_SCD
genCallDynaMem(MEM_SCD, 1, MIPS_GET_RS(mips), MIPS_GET_RT(mips), MIPS_GET_SIMMED(mips));
return CONVERT_SUCCESS;
#endif
}
// -- Special Functions --
static int SLL(MIPS_instr mips){
PowerPC_instr ppc;
int _rt = MIPS_GET_RT(mips), _rd = MIPS_GET_RD(mips);
int sa = MIPS_GET_SA(mips);
int rt = mapRegister(_rt);
int rd = mapConstantNew(_rd, isRegisterConstant(_rt), 1);
setRegisterConstant(_rd, (unsigned long)getRegisterConstant(_rt) << sa);
GEN_SLWI(ppc, rd, rt, sa);
set_next_dst(ppc);
return CONVERT_SUCCESS;
}
static int SRL(MIPS_instr mips){
PowerPC_instr ppc;
int _rt = MIPS_GET_RT(mips), _rd = MIPS_GET_RD(mips);
int sa = MIPS_GET_SA(mips);
int rt = mapRegister(_rt);
int rd = mapConstantNew(_rd, isRegisterConstant(_rt), 1);
setRegisterConstant(_rd, (unsigned long)getRegisterConstant(_rt) >> sa);
GEN_SRWI(ppc, rd, rt, sa);
set_next_dst(ppc);
return CONVERT_SUCCESS;
}
static int SRA(MIPS_instr mips){
PowerPC_instr ppc;
int _rt = MIPS_GET_RT(mips), _rd = MIPS_GET_RD(mips);
int sa = MIPS_GET_SA(mips);
int rt = mapRegister(_rt);
int rd = mapConstantNew(_rd, isRegisterConstant(_rt), 1);
setRegisterConstant(_rd, getRegisterConstant(_rt) >> sa);
GEN_SRAWI(ppc, rd, rt, sa);
set_next_dst(ppc);
return CONVERT_SUCCESS;
}
static int SLLV(MIPS_instr mips){
PowerPC_instr ppc;
int _rt = MIPS_GET_RT(mips), _rs = MIPS_GET_RS(mips), _rd = MIPS_GET_RD(mips);
int rt = mapRegister(_rt);
int rs = mapRegister(_rs);
int rd = mapConstantNew(_rd, isRegisterConstant(_rt) && isRegisterConstant(_rs), 1);
setRegisterConstant(_rd, (unsigned long)getRegisterConstant(_rt) << (getRegisterConstant(_rs) & 0x1F));
GEN_CLRLWI(ppc, R0, rs, 27); // Mask the lower 5-bits of rs
set_next_dst(ppc);
GEN_SLW(ppc, rd, rt, R0);
set_next_dst(ppc);
return CONVERT_SUCCESS;
}
static int SRLV(MIPS_instr mips){
PowerPC_instr ppc;
int _rt = MIPS_GET_RT(mips), _rs = MIPS_GET_RS(mips), _rd = MIPS_GET_RD(mips);
int rt = mapRegister(_rt);
int rs = mapRegister(_rs);
int rd = mapConstantNew(_rd, isRegisterConstant(_rt) && isRegisterConstant(_rs), 1);
setRegisterConstant(_rd, (unsigned long)getRegisterConstant(_rt) >> (getRegisterConstant(_rs) & 0x1F));
GEN_CLRLWI(ppc, R0, rs, 27); // Mask the lower 5-bits of rs
set_next_dst(ppc);
GEN_SRW(ppc, rd, rt, R0);
set_next_dst(ppc);
return CONVERT_SUCCESS;
}
static int SRAV(MIPS_instr mips){
PowerPC_instr ppc;
int _rt = MIPS_GET_RT(mips), _rs = MIPS_GET_RS(mips), _rd = MIPS_GET_RD(mips);
int rt = mapRegister(_rt);
int rs = mapRegister(_rs);
int rd = mapConstantNew(_rd, isRegisterConstant(_rt) && isRegisterConstant(_rs), 1);
setRegisterConstant(_rd, getRegisterConstant(_rt) >> (getRegisterConstant(_rs) & 0x1F));
GEN_CLRLWI(ppc, R0, rs, 27); // Mask the lower 5-bits of rs
set_next_dst(ppc);
GEN_SRAW(ppc, rd, rt, R0);
set_next_dst(ppc);
return CONVERT_SUCCESS;
}
static int JR(MIPS_instr mips){
PowerPC_instr ppc;
if(CANT_COMPILE_DELAY()){
genCallInterp(mips);
return INTERPRETED;
}
flushRegisters();
reset_code_addr();
GEN_STW(ppc, mapRegister(MIPS_GET_RS(mips)), SDAREL(local_rs32), R13);
set_next_dst(ppc);
// Check the delay slot, and note how big it is
PowerPC_instr* preDelay = get_curr_dst();
check_delaySlot();
int delaySlot = get_curr_dst() - preDelay;
#ifdef COMPARE_CORE
GEN_LI(ppc, R4, 1);
set_next_dst(ppc);
#endif
genUpdateCount(0);
invalidateRegisters();
#ifdef INTERPRET_JR
genJumpTo(SDAREL(local_rs32), JUMPTO_REG);
#else // INTERPRET_JR
// TODO: jr
#endif
// Let's still recompile the delay slot in place in case its branched to
if(delaySlot){ if(is_j_dst(0)){ unget_last_src(); delaySlotNext = 2; } }
else nop_ignored();
#ifdef INTERPRET_JR
return INTERPRETED;
#else // INTERPRET_JR
return CONVER_ERROR;
#endif
}
static int JALR(MIPS_instr mips){
PowerPC_instr ppc;
if(CANT_COMPILE_DELAY()){
genCallInterp(mips);
return INTERPRETED;
}
flushRegisters();
reset_code_addr();
GEN_STW(ppc, mapRegister(MIPS_GET_RS(mips)), SDAREL(local_rs32), R13);
set_next_dst(ppc);
// Check the delay slot, and note how big it is
PowerPC_instr* preDelay = get_curr_dst();
check_delaySlot();
int delaySlot = get_curr_dst() - preDelay;
#ifdef COMPARE_CORE
GEN_LI(ppc, R4, 1);
set_next_dst(ppc);
#endif
genUpdateCount(0);
// Set LR to next instruction
int rd = mapRegisterNew( MIPS_GET_RD(mips), 1 );
// lis lr, pc@ha(0)
GEN_LIS(ppc, rd, (get_src_pc()+4)>>16);
set_next_dst(ppc);
// la lr, pc@l(lr)
GEN_ORI(ppc, rd, rd, get_src_pc()+4);
set_next_dst(ppc);
flushRegisters();
#ifdef INTERPRET_JALR
genJumpTo(SDAREL(local_rs32), JUMPTO_REG);
#else // INTERPRET_JALR
// TODO: jalr
#endif
// Let's still recompile the delay slot in place in case its branched to
if(delaySlot){ if(is_j_dst(0)){ unget_last_src(); delaySlotNext = 2; } }
else nop_ignored();
#ifdef INTERPRET_JALR
return INTERPRETED;
#else // INTERPRET_JALR
return CONVERT_ERROR;
#endif
}
static int SYSCALL(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_SYSCALL
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_SYSCALL
// TODO: syscall
return CONVERT_ERROR;
#endif
}
static int BREAK(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_BREAK
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_BREAK
return CONVERT_ERROR;
#endif
}
static int SYNC(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_SYNC
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_SYNC
return CONVERT_ERROR;
#endif
}
static int MFHI(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_HILO
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_HILO
int _rd = MIPS_GET_RD(mips);
RegMapping hi = mapRegister64(MIPS_REG_HI);
RegMapping rd = mapConstant64New(_rd, isRegisterConstant(MIPS_REG_HI));
setRegisterConstant64(_rd, getRegisterConstant64(MIPS_REG_HI));
// mr rd, hi
GEN_MR(ppc, rd.lo, hi.lo);
set_next_dst(ppc);
GEN_MR(ppc, rd.hi, hi.hi);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int MTHI(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_HILO
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_HILO
int _rs = MIPS_GET_RS(mips);
RegMapping rs = mapRegister64(_rs);
RegMapping hi = mapConstant64New(MIPS_REG_HI, isRegisterConstant(_rs));
setRegisterConstant64(MIPS_REG_HI, getRegisterConstant64(_rs));
// mr hi, rs
GEN_MR(ppc, hi.lo, rs.lo);
set_next_dst(ppc);
GEN_MR(ppc, hi.hi, rs.hi);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int MFLO(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_HILO
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_HILO
int _rd = MIPS_GET_RD(mips);
RegMapping lo = mapRegister64(MIPS_REG_LO);
RegMapping rd = mapConstant64New(_rd, isRegisterConstant(MIPS_REG_LO));
setRegisterConstant64(_rd, getRegisterConstant64(MIPS_REG_LO));
// mr rd, lo
GEN_MR(ppc, rd.lo, lo.lo);
set_next_dst(ppc);
GEN_MR(ppc, rd.hi, lo.hi);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int MTLO(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_HILO
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_HILO
int _rs = MIPS_GET_RS(mips);
RegMapping rs = mapRegister64(_rs);
RegMapping lo = mapConstant64New(MIPS_REG_LO, isRegisterConstant(_rs));
setRegisterConstant64(MIPS_REG_LO, getRegisterConstant64(_rs));
// mr lo, rs
GEN_MR(ppc, lo.lo, rs.lo);
set_next_dst(ppc);
GEN_MR(ppc, lo.hi, rs.hi);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int MULT(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_MULT
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_MULT
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
int rs = mapRegister(_rs);
int rt = mapRegister(_rt);
int lo = mapConstantNew(MIPS_REG_LO, isRegisterConstant(_rs) && isRegisterConstant(_rt), 1);
int hi = mapConstantNew(MIPS_REG_HI, isRegisterConstant(_rs) && isRegisterConstant(_rt), 1);
setRegisterConstant(MIPS_REG_LO, ((long long)getRegisterConstant(_rs) * getRegisterConstant(_rt)));
setRegisterConstant(MIPS_REG_HI, ((long long)getRegisterConstant(_rs) * getRegisterConstant(_rt)) >> 32);
// Don't multiply if they're using r0
if(_rs && _rt){
// mullw lo, rs, rt
GEN_MULLW(ppc, lo, rs, rt);
set_next_dst(ppc);
// mulhw hi, rs, rt
GEN_MULHW(ppc, hi, rs, rt);
set_next_dst(ppc);
} else {
// li lo, 0
GEN_LI(ppc, lo, 0);
set_next_dst(ppc);
// li hi, 0
GEN_LI(ppc, hi, 0);
set_next_dst(ppc);
}
return CONVERT_SUCCESS;
#endif
}
static int MULTU(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_MULTU
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_MULTU
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
int rs = mapRegister(_rs);
int rt = mapRegister(_rt);
int lo = mapConstantNew(MIPS_REG_LO, isRegisterConstant(_rs) && isRegisterConstant(_rt), 1);
int hi = mapConstantNew(MIPS_REG_HI, isRegisterConstant(_rs) && isRegisterConstant(_rt), 1);
setRegisterConstant(MIPS_REG_LO, ((unsigned long long)getRegisterConstant(_rs) * getRegisterConstant(_rt)));
setRegisterConstant(MIPS_REG_HI, ((unsigned long long)getRegisterConstant(_rs) * getRegisterConstant(_rt)) >> 32);
// Don't multiply if they're using r0
if(_rs && _rt){
// mullw lo, rs, rt
GEN_MULLW(ppc, lo, rs, rt);
set_next_dst(ppc);
// mulhwu hi, rs, rt
GEN_MULHWU(ppc, hi, rs, rt);
set_next_dst(ppc);
} else {
// li lo, 0
GEN_LI(ppc, lo, 0);
set_next_dst(ppc);
// li hi, 0
GEN_LI(ppc, hi, 0);
set_next_dst(ppc);
}
return CONVERT_SUCCESS;
#endif
}
static int DIV(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_DIV
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_DIV
// This instruction computes the quotient and remainder
// and stores the results in lo and hi respectively
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
int rs = mapRegister(_rs);
int rt = mapRegister(_rt);
int lo = mapConstantNew(MIPS_REG_LO, isRegisterConstant(_rs) && isRegisterConstant(_rt), 1);
int hi = mapConstantNew(MIPS_REG_HI, isRegisterConstant(_rs) && isRegisterConstant(_rt), 1);
setRegisterConstant(MIPS_REG_LO, getRegisterConstant(_rs) / getRegisterConstant(_rt));
setRegisterConstant(MIPS_REG_HI, getRegisterConstant(_rs) % getRegisterConstant(_rt));
// Don't divide if they're using r0
if(_rs && _rt){
// divw lo, rs, rt
GEN_DIVW(ppc, lo, rs, rt);
set_next_dst(ppc);
// This is how you perform a mod in PPC
// divw lo, rs, rt
// NOTE: We already did that
// mullw hi, lo, rt
GEN_MULLW(ppc, hi, lo, rt);
set_next_dst(ppc);
// subf hi, hi, rs
GEN_SUBF(ppc, hi, hi, rs);
set_next_dst(ppc);
}
return CONVERT_SUCCESS;
#endif
}
static int DIVU(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_DIVU
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_DIVU
// This instruction computes the quotient and remainder
// and stores the results in lo and hi respectively
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips);
int rs = mapRegister(_rs);
int rt = mapRegister(_rt);
int lo = mapConstantNew(MIPS_REG_LO, isRegisterConstant(_rs) && isRegisterConstant(_rt), 1);
int hi = mapConstantNew(MIPS_REG_HI, isRegisterConstant(_rs) && isRegisterConstant(_rt), 1);
setRegisterConstant(MIPS_REG_LO, (unsigned long)getRegisterConstant(_rs) / getRegisterConstant(_rt));
setRegisterConstant(MIPS_REG_HI, (unsigned long)getRegisterConstant(_rs) % getRegisterConstant(_rt));
// Don't divide if they're using r0
if(_rs && _rt){
// divwu lo, rs, rt
GEN_DIVWU(ppc, lo, rs, rt);
set_next_dst(ppc);
// This is how you perform a mod in PPC
// divw lo, rs, rt
// NOTE: We already did that
// mullw hi, lo, rt
GEN_MULLW(ppc, hi, lo, rt);
set_next_dst(ppc);
// subf hi, hi, rs
GEN_SUBF(ppc, hi, hi, rs);
set_next_dst(ppc);
}
return CONVERT_SUCCESS;
#endif
}
static int DSLLV(MIPS_instr mips){
PowerPC_instr ppc;
#if defined(INTERPRET_DW) || defined(INTERPRET_DSLLV)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_DW || INTERPRET_DSLLV
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips), _rd = MIPS_GET_RD(mips);
int rs = mapRegister(_rs);
RegMapping rt = mapRegister64(_rt);
RegMapping rd = mapConstant64New(_rd, isRegisterConstant(_rt) && isRegisterConstant(_rs));
setRegisterConstant64(_rd, (unsigned long long)getRegisterConstant64(_rt) << (getRegisterConstant(_rs) & 0x3F));
GEN_CLRLWI(ppc, R2, rs, 26);
set_next_dst(ppc);
GEN_SUBIC_(ppc, R0, R2, 32);
set_next_dst(ppc);
GEN_BLT(ppc, CR0, 4, 0, 0);
set_next_dst(ppc);
GEN_SLW(ppc, rd.hi, rt.lo, R0);
set_next_dst(ppc);
GEN_LI(ppc, rd.lo, 0);
set_next_dst(ppc);
GEN_B(ppc, 6, 0, 0);
set_next_dst(ppc);
GEN_SUBFIC(ppc, R0, R2, 32);
set_next_dst(ppc);
GEN_SLW(ppc, rd.hi, rt.hi, R2);
set_next_dst(ppc);
GEN_SRW(ppc, R0, rt.lo, R0);
set_next_dst(ppc);
GEN_SLW(ppc, rd.lo, rt.lo, R2);
set_next_dst(ppc);
GEN_OR(ppc, rd.hi, rd.hi, R0);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int DSRLV(MIPS_instr mips){
PowerPC_instr ppc;
#if defined(INTERPRET_DW) || defined(INTERPRET_DSRLV)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_DW || INTERPRET_DSRLV
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips), _rd = MIPS_GET_RD(mips);
int rs = mapRegister(_rs);
RegMapping rt = mapRegister64(_rt);
RegMapping rd = mapConstant64New(_rd, isRegisterConstant(_rt) && isRegisterConstant(_rs));
setRegisterConstant64(_rd, (unsigned long long)getRegisterConstant64(_rt) >> (getRegisterConstant(_rs) & 0x3F));
GEN_CLRLWI(ppc, R2, rs, 26);
set_next_dst(ppc);
GEN_SUBIC_(ppc, R0, R2, 32);
set_next_dst(ppc);
GEN_BLT(ppc, CR0, 4, 0, 0);
set_next_dst(ppc);
GEN_SRW(ppc, rd.lo, rt.hi, R0);
set_next_dst(ppc);
GEN_LI(ppc, rd.hi, 0);
set_next_dst(ppc);
GEN_B(ppc, 6, 0, 0);
set_next_dst(ppc);
GEN_SUBFIC(ppc, R0, R2, 32);
set_next_dst(ppc);
GEN_SRW(ppc, rd.lo, rt.lo, R2);
set_next_dst(ppc);
GEN_SLW(ppc, R0, rt.hi, R0);
set_next_dst(ppc);
GEN_SRW(ppc, rd.hi, rt.hi, R2);
set_next_dst(ppc);
GEN_OR(ppc, rd.lo, rd.lo, R0);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int DSRAV(MIPS_instr mips){
PowerPC_instr ppc;
#if defined(INTERPRET_DW) || defined(INTERPRET_DSRAV)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_DW || INTERPRET_DSRAV
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips), _rd = MIPS_GET_RD(mips);
int rs = mapRegister(_rs);
RegMapping rt = mapRegister64(_rt);
RegMapping rd = mapConstant64New(_rd, isRegisterConstant(_rt) && isRegisterConstant(_rs));
setRegisterConstant64(_rd, getRegisterConstant64(_rt) >> (getRegisterConstant(_rs) & 0x3F));
GEN_CLRLWI(ppc, R2, rs, 26);
set_next_dst(ppc);
GEN_SUBIC_(ppc, R0, R2, 32);
set_next_dst(ppc);
GEN_BLT(ppc, CR0, 4, 0, 0);
set_next_dst(ppc);
GEN_SRAW(ppc, rd.lo, rt.hi, R0);
set_next_dst(ppc);
GEN_SRAWI(ppc, rd.hi, rt.hi, 31);
set_next_dst(ppc);
GEN_B(ppc, 6, 0, 0);
set_next_dst(ppc);
GEN_SUBFIC(ppc, R0, R2, 32);
set_next_dst(ppc);
GEN_SRW(ppc, rd.lo, rt.lo, R2);
set_next_dst(ppc);
GEN_SLW(ppc, R0, rt.hi, R0);
set_next_dst(ppc);
GEN_SRAW(ppc, rd.hi, rt.hi, R2);
set_next_dst(ppc);
GEN_OR(ppc, rd.lo, rd.lo, R0);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int DMULT(MIPS_instr mips){
PowerPC_instr ppc;
#if defined(INTERPRET_DW) || defined(INTERPRET_DMULT)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_DW || INTERPRET_DMULT
// TODO: dmult
return CONVERT_ERROR;
#endif
}
static int DMULTU(MIPS_instr mips){
PowerPC_instr ppc;
#if defined(INTERPRET_DW) || defined(INTERPRET_DMULTU)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_DW || INTERPRET_DMULTU
// TODO: dmultu
return CONVERT_ERROR;
#endif
}
static int DDIV(MIPS_instr mips){
PowerPC_instr ppc;
#if defined(INTERPRET_DW) || defined(INTERPRET_DDIV)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_DW || INTERPRET_DDIV
flushRegisters();
RegMapping rs = mapRegister64( MIPS_GET_RS(mips) );
RegMapping rt = mapRegister64( MIPS_GET_RT(mips) );
invalidateRegisters();
GEN_CMPI(ppc, CR2, rs.hi, 0);
set_next_dst(ppc);
GEN_CMPI(ppc, CR1, rt.hi, 0);
set_next_dst(ppc);
GEN_BGE(ppc, CR2, 3, 0, 0);
set_next_dst(ppc);
GEN_SUBFIC(ppc, rs.lo, rs.lo, 0);
set_next_dst(ppc);
GEN_SUBFZE(ppc, rs.hi, rs.hi);
set_next_dst(ppc);
GEN_BGE(ppc, CR1, 3, 0, 0);
set_next_dst(ppc);
GEN_SUBFIC(ppc, rt.lo, rt.lo, 0);
set_next_dst(ppc);
GEN_SUBFZE(ppc, rt.hi, rt.hi);
set_next_dst(ppc);
GEN_CRXOR(ppc, CR2*4+2, CR1*4+0, CR2*4+0);
set_next_dst(ppc);
// r7 = &reg[hi]
GEN_ADDI(ppc, R7, R13, SDAREL(reg[MIPS_REG_HI]));
set_next_dst(ppc);
// divide
GEN_B(ppc, add_jump(&__udivmoddi4, 1, 1), 0, 1);
set_next_dst(ppc);
RegMapping lo = mapRegister64New( MIPS_REG_LO );
RegMapping hi = mapRegister64( MIPS_REG_HI );
GEN_BNE(ppc, CR2, 3, 0, 0);
set_next_dst(ppc);
GEN_SUBFIC(ppc, lo.lo, lo.lo, 0);
set_next_dst(ppc);
GEN_SUBFZE(ppc, lo.hi, lo.hi);
set_next_dst(ppc);
GEN_BGE(ppc, CR2, 3, 0, 0);
set_next_dst(ppc);
GEN_SUBFIC(ppc, hi.lo, hi.lo, 0);
set_next_dst(ppc);
GEN_SUBFZE(ppc, hi.hi, hi.hi);
set_next_dst(ppc);
// Load old LR
GEN_LWZ(ppc, R0, DYNAOFF_LR, R1);
set_next_dst(ppc);
// Restore LR
GEN_MTLR(ppc, R0);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int DDIVU(MIPS_instr mips){
PowerPC_instr ppc;
#if defined(INTERPRET_DW) || defined(INTERPRET_DDIVU)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_DW || INTERPRET_DDIVU
flushRegisters();
mapRegister64( MIPS_GET_RS(mips) );
mapRegister64( MIPS_GET_RT(mips) );
invalidateRegisters();
// r7 = &reg[hi]
GEN_ADDI(ppc, R7, R13, SDAREL(reg[MIPS_REG_HI]));
set_next_dst(ppc);
// divide
GEN_B(ppc, add_jump(&__udivmoddi4, 1, 1), 0, 1);
set_next_dst(ppc);
mapRegister64New( MIPS_REG_LO );
// Load old LR
GEN_LWZ(ppc, R0, DYNAOFF_LR, R1);
set_next_dst(ppc);
// Restore LR
GEN_MTLR(ppc, R0);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int DADDU(MIPS_instr mips){
PowerPC_instr ppc;
#if defined(INTERPRET_DW) || defined(INTERPRET_DADDU)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_DW || INTERPRET_DADDU
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips), _rd = MIPS_GET_RD(mips);
RegMapping rs = mapRegister64(_rs);
RegMapping rt = mapRegister64(_rt);
RegMapping rd = mapConstant64New(_rd, isRegisterConstant(_rs) && isRegisterConstant(_rt));
setRegisterConstant64(_rd, getRegisterConstant64(_rs) + getRegisterConstant64(_rt));
GEN_ADDC(ppc, rd.lo, rs.lo, rt.lo);
set_next_dst(ppc);
GEN_ADDE(ppc, rd.hi, rs.hi, rt.hi);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int DADD(MIPS_instr mips){
return DADDU(mips);
}
static int DSUBU(MIPS_instr mips){
PowerPC_instr ppc;
#if defined(INTERPRET_DW) || defined(INTERPRET_DSUBU)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_DW || INTERPRET_DSUBU
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips), _rd = MIPS_GET_RD(mips);
RegMapping rs = mapRegister64(_rs);
RegMapping rt = mapRegister64(_rt);
RegMapping rd = mapConstant64New(_rd, isRegisterConstant(_rs) && isRegisterConstant(_rt));
setRegisterConstant64(_rd, getRegisterConstant64(_rs) - getRegisterConstant64(_rt));
GEN_SUBFC(ppc, rd.lo, rt.lo, rs.lo);
set_next_dst(ppc);
GEN_SUBFE(ppc, rd.hi, rt.hi, rs.hi);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int DSUB(MIPS_instr mips){
return DSUBU(mips);
}
static int DSLL(MIPS_instr mips){
PowerPC_instr ppc;
#if defined(INTERPRET_DW) || defined(INTERPRET_DSLL)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_DW || INTERPRET_DSLL
int _rt = MIPS_GET_RT(mips), _rd = MIPS_GET_RD(mips);
int sa = MIPS_GET_SA(mips);
RegMapping rt = mapRegister64(_rt);
RegMapping rd = mapConstant64New(_rd, isRegisterConstant(_rt));
setRegisterConstant64(_rd, (unsigned long long)getRegisterConstant64(_rt) << sa);
if(sa){
// Shift MSW left by SA
GEN_SLWI(ppc, rd.hi, rt.hi, sa);
set_next_dst(ppc);
// Extract the bits shifted out of the LSW
// Insert those bits into the MSW
GEN_RLWIMI(ppc, rd.hi, rt.lo, sa, 32-sa, 31);
set_next_dst(ppc);
// Shift LSW left by SA
GEN_SLWI(ppc, rd.lo, rt.lo, sa);
set_next_dst(ppc);
} else {
// Copy over the register
GEN_MR(ppc, rd.hi, rt.hi);
set_next_dst(ppc);
GEN_MR(ppc, rd.lo, rt.lo);
set_next_dst(ppc);
}
return CONVERT_SUCCESS;
#endif
}
static int DSRL(MIPS_instr mips){
PowerPC_instr ppc;
#if defined(INTERPRET_DW) || defined(INTERPRET_DSRL)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_DW || INTERPRET_DSRL
int _rt = MIPS_GET_RT(mips), _rd = MIPS_GET_RD(mips);
int sa = MIPS_GET_SA(mips);
RegMapping rt = mapRegister64(_rt);
RegMapping rd = mapConstant64New(_rd, isRegisterConstant(_rt));
setRegisterConstant64(_rd, (unsigned long long)getRegisterConstant64(_rt) >> sa);
if(sa){
// Shift LSW right by SA
GEN_SRWI(ppc, rd.lo, rt.lo, sa);
set_next_dst(ppc);
// Extract the bits shifted out of the MSW
// Insert those bits into the LSW
GEN_RLWIMI(ppc, rd.lo, rt.hi, 32-sa, 0, sa-1);
set_next_dst(ppc);
// Shift MSW right by SA
GEN_SRWI(ppc, rd.hi, rt.hi, sa);
set_next_dst(ppc);
} else {
// Copy over the register
GEN_MR(ppc, rd.hi, rt.hi);
set_next_dst(ppc);
GEN_MR(ppc, rd.lo, rt.lo);
set_next_dst(ppc);
}
return CONVERT_SUCCESS;
#endif
}
static int DSRA(MIPS_instr mips){
PowerPC_instr ppc;
#if defined(INTERPRET_DW) || defined(INTERPRET_DSRA)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_DW || INTERPRET_DSRA
int _rt = MIPS_GET_RT(mips), _rd = MIPS_GET_RD(mips);
int sa = MIPS_GET_SA(mips);
RegMapping rt = mapRegister64(_rt);
RegMapping rd = mapConstant64New(_rd, isRegisterConstant(_rt));
setRegisterConstant64(_rd, getRegisterConstant64(_rt) >> sa);
if(sa){
// Shift LSW right by SA
GEN_SRWI(ppc, rd.lo, rt.lo, sa);
set_next_dst(ppc);
// Extract the bits shifted out of the MSW
// Insert those bits into the LSW
GEN_RLWIMI(ppc, rd.lo, rt.hi, 32-sa, 0, sa-1);
set_next_dst(ppc);
// Shift (arithmetically) MSW right by SA
GEN_SRAWI(ppc, rd.hi, rt.hi, sa);
set_next_dst(ppc);
} else {
// Copy over the register
GEN_MR(ppc, rd.hi, rt.hi);
set_next_dst(ppc);
GEN_MR(ppc, rd.lo, rt.lo);
set_next_dst(ppc);
}
return CONVERT_SUCCESS;
#endif
}
static int DSLL32(MIPS_instr mips){
PowerPC_instr ppc;
#if defined(INTERPRET_DW) || defined(INTERPRET_DSLL32)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_DW || INTERPRET_DSLL32
int _rt = MIPS_GET_RT(mips), _rd = MIPS_GET_RD(mips);
int sa = MIPS_GET_SA(mips);
RegMapping rt = mapRegister64(_rt);
RegMapping rd = mapConstant64New(_rd, isRegisterConstant(_rt));
setRegisterConstant64(_rd, (unsigned long long)getRegisterConstant64(_rt) << (32 + sa));
// Shift LSW into MSW and by SA
GEN_SLWI(ppc, rd.hi, rt.lo, sa);
set_next_dst(ppc);
// Clear out LSW
GEN_LI(ppc, rd.lo, 0);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int DSRL32(MIPS_instr mips){
PowerPC_instr ppc;
#if defined(INTERPRET_DW) || defined(INTERPRET_DSRL32)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_DW || INTERPRET_DSRL32
int _rt = MIPS_GET_RT(mips), _rd = MIPS_GET_RD(mips);
int sa = MIPS_GET_SA(mips);
RegMapping rt = mapRegister64(_rt);
RegMapping rd = mapConstant64New(_rd, isRegisterConstant(_rt));
setRegisterConstant64(_rd, (unsigned long long)getRegisterConstant64(_rt) >> (32 + sa));
// Shift MSW into LSW and by SA
GEN_SRWI(ppc, rd.lo, rt.hi, sa);
set_next_dst(ppc);
// Clear out MSW
GEN_LI(ppc, rd.hi, 0);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int DSRA32(MIPS_instr mips){
PowerPC_instr ppc;
#if defined(INTERPRET_DW) || defined(INTERPRET_DSRA32)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_DW || INTERPRET_DSRA32
int _rt = MIPS_GET_RT(mips), _rd = MIPS_GET_RD(mips);
int sa = MIPS_GET_SA(mips);
RegMapping rt = mapRegister64(_rt);
RegMapping rd = mapConstant64New(_rd, isRegisterConstant(_rt));
setRegisterConstant64(_rd, getRegisterConstant64(_rt) >> (32 + sa));
// Shift (arithmetically) MSW into LSW and by SA
GEN_SRAWI(ppc, rd.lo, rt.hi, sa);
set_next_dst(ppc);
// Fill MSW with sign of MSW
GEN_SRAWI(ppc, rd.hi, rt.hi, 31);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int ADDU(MIPS_instr mips){
PowerPC_instr ppc;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips), _rd = MIPS_GET_RD(mips);
int rs = mapRegister(_rs);
int rt = mapRegister(_rt);
int rd = mapConstantNew(_rd, isRegisterConstant(_rs) && isRegisterConstant(_rt), 1);
setRegisterConstant(_rd, getRegisterConstant(_rs) + getRegisterConstant(_rt));
GEN_ADD(ppc, rd, rs, rt);
set_next_dst(ppc);
return CONVERT_SUCCESS;
}
static int ADD(MIPS_instr mips){
return ADDU(mips);
}
static int SUBU(MIPS_instr mips){
PowerPC_instr ppc;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips), _rd = MIPS_GET_RD(mips);
int rs = mapRegister(_rs);
int rt = mapRegister(_rt);
int rd = mapConstantNew(_rd, isRegisterConstant(_rs) && isRegisterConstant(_rt), 1);
setRegisterConstant(_rd, getRegisterConstant(_rs) - getRegisterConstant(_rt));
GEN_SUB(ppc, rd, rs, rt);
set_next_dst(ppc);
return CONVERT_SUCCESS;
}
static int SUB(MIPS_instr mips){
return SUBU(mips);
}
static int AND(MIPS_instr mips){
PowerPC_instr ppc;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips), _rd = MIPS_GET_RD(mips);
if(getRegisterMapping(_rs) == MAPPING_32 &&
getRegisterMapping(_rt) == MAPPING_32){
int rs = mapRegister(_rs);
int rt = mapRegister(_rt);
int rd = mapConstantNew(_rd, isRegisterConstant(_rs) && isRegisterConstant(_rt), 1);
setRegisterConstant(_rd, getRegisterConstant(_rs) & getRegisterConstant(_rt));
GEN_AND(ppc, rd, rs, rt);
set_next_dst(ppc);
} else {
RegMapping rs = mapRegister64(_rs);
RegMapping rt = mapRegister64(_rt);
RegMapping rd = mapConstant64New(_rd, isRegisterConstant(_rs) && isRegisterConstant(_rt));
setRegisterConstant64(_rd, getRegisterConstant64(_rs) & getRegisterConstant64(_rt));
GEN_AND(ppc, rd.hi, rs.hi, rt.hi);
set_next_dst(ppc);
GEN_AND(ppc, rd.lo, rs.lo, rt.lo);
set_next_dst(ppc);
}
return CONVERT_SUCCESS;
}
static int OR(MIPS_instr mips){
PowerPC_instr ppc;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips), _rd = MIPS_GET_RD(mips);
if(getRegisterMapping(_rs) == MAPPING_32 &&
getRegisterMapping(_rt) == MAPPING_32){
int rs = mapRegister(_rs);
int rt = mapRegister(_rt);
int rd = mapConstantNew(_rd, isRegisterConstant(_rs) && isRegisterConstant(_rt), 1);
setRegisterConstant(_rd, getRegisterConstant(_rs) | getRegisterConstant(_rt));
GEN_OR(ppc, rd, rs, rt);
set_next_dst(ppc);
} else {
RegMapping rs = mapRegister64(_rs);
RegMapping rt = mapRegister64(_rt);
RegMapping rd = mapConstant64New(_rd, isRegisterConstant(_rs) && isRegisterConstant(_rt));
setRegisterConstant64(_rd, getRegisterConstant64(_rs) | getRegisterConstant64(_rt));
GEN_OR(ppc, rd.hi, rs.hi, rt.hi);
set_next_dst(ppc);
GEN_OR(ppc, rd.lo, rs.lo, rt.lo);
set_next_dst(ppc);
}
return CONVERT_SUCCESS;
}
static int XOR(MIPS_instr mips){
PowerPC_instr ppc;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips), _rd = MIPS_GET_RD(mips);
if(getRegisterMapping(_rs) == MAPPING_32 &&
getRegisterMapping(_rt) == MAPPING_32){
int rs = mapRegister(_rs);
int rt = mapRegister(_rt);
int rd = mapConstantNew(_rd, isRegisterConstant(_rs) && isRegisterConstant(_rt), 1);
setRegisterConstant(_rd, getRegisterConstant(_rs) ^ getRegisterConstant(_rt));
GEN_XOR(ppc, rd, rs, rt);
set_next_dst(ppc);
} else {
RegMapping rs = mapRegister64(_rs);
RegMapping rt = mapRegister64(_rt);
RegMapping rd = mapConstant64New(_rd, isRegisterConstant(_rs) && isRegisterConstant(_rt));
setRegisterConstant64(_rd, getRegisterConstant64(_rs) ^ getRegisterConstant64(_rt));
GEN_XOR(ppc, rd.hi, rs.hi, rt.hi);
set_next_dst(ppc);
GEN_XOR(ppc, rd.lo, rs.lo, rt.lo);
set_next_dst(ppc);
}
return CONVERT_SUCCESS;
}
static int NOR(MIPS_instr mips){
PowerPC_instr ppc;
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips), _rd = MIPS_GET_RD(mips);
if(getRegisterMapping(_rs) == MAPPING_32 &&
getRegisterMapping(_rt) == MAPPING_32){
int rs = mapRegister(_rs);
int rt = mapRegister(_rt);
int rd = mapConstantNew(_rd, isRegisterConstant(_rs) && isRegisterConstant(_rt), 1);
setRegisterConstant(_rd, ~(getRegisterConstant(_rs) | getRegisterConstant(_rt)));
GEN_NOR(ppc, rd, rs, rt);
set_next_dst(ppc);
} else {
RegMapping rs = mapRegister64(_rs);
RegMapping rt = mapRegister64(_rt);
RegMapping rd = mapConstant64New(_rd, isRegisterConstant(_rs) && isRegisterConstant(_rt));
setRegisterConstant64(_rd, ~(getRegisterConstant64(_rs) | getRegisterConstant64(_rt)));
GEN_NOR(ppc, rd.hi, rs.hi, rt.hi);
set_next_dst(ppc);
GEN_NOR(ppc, rd.lo, rs.lo, rt.lo);
set_next_dst(ppc);
}
return CONVERT_SUCCESS;
}
static int SLT(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_SLT
genCallInterp(mips);
return INTERPRETED;
#else
// FIXME: Do I need to worry about 64-bit values?
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips), _rd = MIPS_GET_RD(mips);
int rs = mapRegister(_rs);
int rt = mapRegister(_rt);
int rd = mapConstantNew(_rd, isRegisterConstant(_rs) && isRegisterConstant(_rt), 0);
setRegisterConstant(_rd, getRegisterConstant(_rs) < getRegisterConstant(_rt));
GEN_CMP(ppc, CR0, rs, rt);
set_next_dst(ppc);
GEN_MFCR(ppc, R2);
set_next_dst(ppc);
GEN_RLWINM(ppc, rd, R2, 1, 31, 31);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int SLTU(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_SLTU
genCallInterp(mips);
return INTERPRETED;
#else
// FIXME: Do I need to worry about 64-bit values?
int _rs = MIPS_GET_RS(mips), _rt = MIPS_GET_RT(mips), _rd = MIPS_GET_RD(mips);
int rs = mapRegister(_rs);
int rt = mapRegister(_rt);
int rd = mapConstantNew(_rd, isRegisterConstant(_rs) && isRegisterConstant(_rt), 0);
setRegisterConstant(_rd, (unsigned long)getRegisterConstant(_rs) < getRegisterConstant(_rt));
GEN_NOT(ppc, R0, rs);
set_next_dst(ppc);
GEN_ADDC(ppc, R0, R0, rt);
set_next_dst(ppc);
GEN_ADDZE(ppc, rd, DYNAREG_ZERO);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int TEQ(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_TRAPS
genCallInterp(mips);
return INTERPRETED;
#else
return CONVERT_ERROR;
#endif
}
static int (*gen_special[64])(MIPS_instr) =
{
SLL , NI , SRL , SRA , SLLV , NI , SRLV , SRAV ,
JR , JALR , NI , NI , SYSCALL, BREAK , NI , SYNC ,
MFHI, MTHI , MFLO, MTLO, DSLLV , NI , DSRLV , DSRAV ,
MULT, MULTU, DIV , DIVU, DMULT , DMULTU, DDIV , DDIVU ,
ADD , ADDU , SUB , SUBU, AND , OR , XOR , NOR ,
NI , NI , SLT , SLTU, DADD , DADDU , DSUB , DSUBU ,
NI , NI , NI , NI , TEQ , NI , NI , NI ,
DSLL, NI , DSRL, DSRA, DSLL32 , NI , DSRL32, DSRA32
};
static int SPECIAL(MIPS_instr mips){
return gen_special[MIPS_GET_FUNC(mips)](mips);
}
// -- RegImmed Instructions --
// Since the RegImmed instructions are very similar:
// BLTZ, BGEZ, BLTZL, BGEZL, BLZAL, BGEZAL, BLTZALL, BGEZALL
// It's less work to handle them all in one function
static int REGIMM(MIPS_instr mips){
PowerPC_instr ppc;
int which = MIPS_GET_RT(mips);
int cond = which & 1; // t = GE, f = LT
int likely = which & 2;
int link = which & 16;
if(MIPS_GET_SIMMED(mips) == -1 || CANT_COMPILE_DELAY()){
// REGIMM_IDLE || virtual delay
genCallInterp(mips);
return INTERPRETED;
}
genCmpi64(CR4, MIPS_GET_RA(mips), 0);
return branch(MIPS_GET_SIMMED(mips), cond ? GE : LT, link, likely);
}
// -- COP0 Instructions --
static int TLBR(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_TLBR
genCallInterp(mips);
return INTERPRETED;
#else
return CONVERT_ERROR;
#endif
}
static int TLBWI(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_TLBWI
genCallInterp(mips);
return INTERPRETED;
#else
return CONVERT_ERROR;
#endif
}
static int TLBWR(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_TLBWR
genCallInterp(mips);
return INTERPRETED;
#else
return CONVERT_ERROR;
#endif
}
static int TLBP(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_TLBP
genCallInterp(mips);
return INTERPRETED;
#else
return CONVERT_ERROR;
#endif
}
static int ERET(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_ERET
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_ERET
flushRegisters();
genUpdateCount(0);
// Load Status
GEN_LWZ(ppc, R3, SDAREL(Status), R13);
set_next_dst(ppc);
// Status & 0xFFFFFFFD
GEN_RLWINM(ppc, R3, R3, 0, 31, 29);
set_next_dst(ppc);
// llbit = 0
GEN_STW(ppc, DYNAREG_ZERO, SDAREL(llbit), R13);
set_next_dst(ppc);
// Store updated Status
GEN_STW(ppc, R3, SDAREL(Status), R13);
set_next_dst(ppc);
// check_interupt()
GEN_B(ppc, add_jump(&check_interupt, 1, 1), 0, 1);
set_next_dst(ppc);
// Load the old LR
GEN_LWZ(ppc, R0, DYNAOFF_LR, R1);
set_next_dst(ppc);
// interp_addr = EPC
GEN_LWZ(ppc, R3, SDAREL(EPC), R13);
set_next_dst(ppc);
// Restore the LR
GEN_MTLR(ppc, R0);
set_next_dst(ppc);
// Return to trampoline with EPC
GEN_BLR(ppc, 0);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int (*gen_tlb[64])(MIPS_instr) =
{
NI , TLBR, TLBWI, NI, NI, NI, TLBWR, NI,
TLBP, NI , NI , NI, NI, NI, NI , NI,
NI , NI , NI , NI, NI, NI, NI , NI,
ERET, NI , NI , NI, NI, NI, NI , NI,
NI , NI , NI , NI, NI, NI, NI , NI,
NI , NI , NI , NI, NI, NI, NI , NI,
NI , NI , NI , NI, NI, NI, NI , NI,
NI , NI , NI , NI, NI, NI, NI , NI
};
static int MFC0(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_MFC0
genCallInterp(mips);
return INTERPRETED;
#else
int rt = mapRegisterNew( MIPS_GET_RT(mips), 1 );
// *rt = reg_cop0[rd]
GEN_LWZ(ppc, rt, SDAREL(reg_cop0) + MIPS_GET_RD(mips)*4, R13);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int MTC0(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_MTC0
genCallInterp(mips);
return INTERPRETED;
#else
int rt = MIPS_GET_RT(mips), rrt;
int rd = MIPS_GET_RD(mips);
switch(rd){
case 0: // Index
rrt = mapRegister(rt);
// r0 = rt & 0x8000003F
GEN_RLWINM(ppc, R0, rrt, 0, 26, 0);
set_next_dst(ppc);
// reg_cop0[rd] = r0
GEN_STW(ppc, R0, SDAREL(reg_cop0) + rd*4, R13);
set_next_dst(ppc);
return CONVERT_SUCCESS;
case 2: // EntryLo0
case 3: // EntryLo1
rrt = mapRegister(rt);
// r0 = rt & 0x3FFFFFFF
GEN_RLWINM(ppc, R0, rrt, 0, 2, 31);
set_next_dst(ppc);
// reg_cop0[rd] = r0
GEN_STW(ppc, R0, SDAREL(reg_cop0) + rd*4, R13);
set_next_dst(ppc);
return CONVERT_SUCCESS;
case 4: // Context
rrt = mapRegister(rt);
// r0 = reg_cop0[rd]
GEN_LWZ(ppc, R0, SDAREL(reg_cop0) + rd*4, R13);
set_next_dst(ppc);
// r0 = (rt & 0xFF800000) | (r0 & 0x007FFFFF)
GEN_RLWIMI(ppc, R0, rrt, 0, 0, 8);
set_next_dst(ppc);
// reg_cop0[rd] = r0
GEN_STW(ppc, R0, SDAREL(reg_cop0) + rd*4, R13);
set_next_dst(ppc);
return CONVERT_SUCCESS;
case 5: // PageMask
rrt = mapRegister(rt);
// r0 = rt & 0x01FFE000
GEN_RLWINM(ppc, R0, rrt, 0, 7, 18);
set_next_dst(ppc);
// reg_cop0[rd] = r0
GEN_STW(ppc, R0, SDAREL(reg_cop0) + rd*4, R13);
set_next_dst(ppc);
return CONVERT_SUCCESS;
case 6: // Wired
rrt = mapRegister(rt);
// r0 = 31
GEN_LI(ppc, R0, 31);
set_next_dst(ppc);
// reg_cop0[rd] = rt
GEN_STW(ppc, rrt, SDAREL(reg_cop0) + rd*4, R13);
set_next_dst(ppc);
// reg_cop0[1] = r0
GEN_STW(ppc, R0, SDAREL(Random), R13);
set_next_dst(ppc);
return CONVERT_SUCCESS;
case 10: // EntryHi
rrt = mapRegister(rt);
// r0 = rt & 0xFFFFE0FF
GEN_RLWINM(ppc, R0, rrt, 0, 24, 18);
set_next_dst(ppc);
// reg_cop0[rd] = r0
GEN_STW(ppc, R0, SDAREL(reg_cop0) + rd*4, R13);
set_next_dst(ppc);
return CONVERT_SUCCESS;
case 13: // Cause
case 14: // EPC
case 16: // Config
case 18: // WatchLo
case 19: // WatchHi
case 30: // ErrorEPC
rrt = mapRegister(rt);
// reg_cop0[rd] = rt
GEN_STW(ppc, rrt, SDAREL(reg_cop0) + rd*4, R13);
set_next_dst(ppc);
return CONVERT_SUCCESS;
case 28: // TagLo
rrt = mapRegister(rt);
// r0 = rt & 0x0FFFFFC0
GEN_RLWINM(ppc, R0, rrt, 0, 4, 25);
set_next_dst(ppc);
// reg_cop0[rd] = r0
GEN_STW(ppc, R0, SDAREL(reg_cop0) + rd*4, R13);
set_next_dst(ppc);
return CONVERT_SUCCESS;
case 29: // TagHi
// reg_cop0[rd] = 0
GEN_STW(ppc, DYNAREG_ZERO, SDAREL(reg_cop0) + rd*4, R13);
set_next_dst(ppc);
return CONVERT_SUCCESS;
case 1: // Random
case 8: // BadVAddr
case 15: // PRevID
case 27: // CacheErr
// Do nothing
return CONVERT_SUCCESS;
case 9: // Count
case 11: // Compare
case 12: // Status
default:
genCallInterp(mips);
return INTERPRETED;
}
#endif
}
static int TLB(MIPS_instr mips){
PowerPC_instr ppc;
#ifdef INTERPRET_TLB
genCallInterp(mips);
return INTERPRETED;
#else
return gen_tlb[mips&0x3f](mips);
#endif
}
static int (*gen_cop0[32])(MIPS_instr) =
{
MFC0, NI, NI, NI, MTC0, NI, NI, NI,
NI , NI, NI, NI, NI , NI, NI, NI,
TLB , NI, NI, NI, NI , NI, NI, NI,
NI , NI, NI, NI, NI , NI, NI, NI
};
static int COP0(MIPS_instr mips){
#ifdef INTERPRET_COP0
genCallInterp(mips);
return INTERPRETED;
#else
return gen_cop0[MIPS_GET_RS(mips)](mips);
#endif
}
// -- COP1 Instructions --
static int MFC1(MIPS_instr mips){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_MFC1)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP
genCheckFP();
int fs = MIPS_GET_FS(mips);
int rt = mapRegisterNew( MIPS_GET_RT(mips), 1 );
flushFPR(fs);
// r2 = reg_cop1_simple[fs]
GEN_LWZ(ppc, R2, SDAREL(reg_cop1_simple) + fs*4, R13);
set_next_dst(ppc);
// rt = *r2
GEN_LWZ(ppc, rt, 0, R2);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int DMFC1(MIPS_instr mips){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_DMFC1)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP
genCheckFP();
int fs = MIPS_GET_FS(mips);
RegMapping rt = mapRegister64New( MIPS_GET_RT(mips) );
flushFPR(fs);
// r2 = reg_cop1_double[fs]
GEN_LWZ(ppc, R2, SDAREL(reg_cop1_double) + fs*4, R13);
set_next_dst(ppc);
// rt[hi] = *r2
GEN_LWZ(ppc, rt.hi, 0, R2);
set_next_dst(ppc);
// rt[lo] = *(r2+4)
GEN_LWZ(ppc, rt.lo, 4, R2);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int CFC1(MIPS_instr mips){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_CFC1)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_CFC1
genCheckFP();
if(MIPS_GET_FS(mips) == 31){
int rt = mapRegisterNew( MIPS_GET_RT(mips), 1 );
GEN_LWZ(ppc, rt, SDAREL(FCR31), R13);
set_next_dst(ppc);
} else if(MIPS_GET_FS(mips) == 0){
int rt = mapRegisterNew( MIPS_GET_RT(mips), 0 );
GEN_LI(ppc, rt, 0x511);
set_next_dst(ppc);
}
return CONVERT_SUCCESS;
#endif
}
static int MTC1(MIPS_instr mips){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_MTC1)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP
genCheckFP();
int rt = mapRegister( MIPS_GET_RT(mips) );
int fs = MIPS_GET_FS(mips);
invalidateFPR(fs);
// r2 = reg_cop1_simple[fs]
GEN_LWZ(ppc, R2, SDAREL(reg_cop1_simple) + fs*4, R13);
set_next_dst(ppc);
// *r2 = rt
GEN_STW(ppc, rt, 0, R2);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int DMTC1(MIPS_instr mips){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_DMTC1)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP
genCheckFP();
RegMapping rt = mapRegister64( MIPS_GET_RT(mips) );
int fs = MIPS_GET_FS(mips);
invalidateFPR(fs);
GEN_LWZ(ppc, R2, SDAREL(reg_cop1_double) + fs*4, R13);
set_next_dst(ppc);
GEN_STW(ppc, rt.hi, 0, R2);
set_next_dst(ppc);
GEN_STW(ppc, rt.lo, 4, R2);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int CTC1(MIPS_instr mips){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_CTC1)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_CTC1
genCheckFP();
if(MIPS_GET_FS(mips) == 31){
int rt = mapRegister( MIPS_GET_RT(mips) );
GEN_STW(ppc, rt, SDAREL(FCR31), R13);
set_next_dst(ppc);
}
return CONVERT_SUCCESS;
#endif
}
static int BC(MIPS_instr mips){
PowerPC_instr ppc;
#if defined(INTERPRET_BC)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_BC
if(CANT_COMPILE_DELAY()){
genCallInterp(mips);
return INTERPRETED;
}
genCheckFP();
int cond = mips & 0x00010000;
int likely = mips & 0x00020000;
GEN_LWZ(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
GEN_RLWINM(ppc, R0, R0, 9, 31, 31);
set_next_dst(ppc);
GEN_CMPI(ppc, CR4, R0, 0);
set_next_dst(ppc);
return branch(MIPS_GET_SIMMED(mips), cond ? NE : EQ, 0, likely);
#endif
}
// -- Floating Point Arithmetic --
static int ADD_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_ADD)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_ADD
genCheckFP();
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
int ft = mapFPR( MIPS_GET_FT(mips), dbl );
int fd = mapFPRNew( MIPS_GET_FD(mips), dbl );
GEN_FADD(ppc, fd, fs, ft, dbl);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int SUB_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_SUB)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_SUB
genCheckFP();
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
int ft = mapFPR( MIPS_GET_FT(mips), dbl );
int fd = mapFPRNew( MIPS_GET_FD(mips), dbl );
GEN_FSUB(ppc, fd, fs, ft, dbl);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int MUL_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_MUL)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_MUL
genCheckFP();
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
int ft = mapFPR( MIPS_GET_FT(mips), dbl );
int fd = mapFPRNew( MIPS_GET_FD(mips), dbl );
GEN_FMUL(ppc, fd, fs, ft, dbl);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int DIV_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_DIV)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_DIV
genCheckFP();
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
int ft = mapFPR( MIPS_GET_FT(mips), dbl );
int fd = mapFPRNew( MIPS_GET_FD(mips), dbl );
GEN_FDIV(ppc, fd, fs, ft, dbl);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int SQRT_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_SQRT)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_SQRT
genCheckFP();
int fs = mapFPR( MIPS_GET_FS(mips), dbl ); // maps to f1 (FP argument)
flushRegisters();
if(fs != F1){
GEN_FMR(ppc, F1, fs);
set_next_dst(ppc);
}
// call sqrt
GEN_B(ppc, add_jump(dbl ? &__ieee754_sqrt : &__ieee754_sqrtf, 1, 1), 0, 1);
set_next_dst(ppc);
mapFPRNew( MIPS_GET_FD(mips), dbl ); // maps to f1 (FP return)
// Load old LR
GEN_LWZ(ppc, R0, DYNAOFF_LR, R1);
set_next_dst(ppc);
// Restore LR
GEN_MTLR(ppc, R0);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int ABS_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_ABS)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_ABS
genCheckFP();
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
int fd = mapFPRNew( MIPS_GET_FD(mips), dbl );
GEN_FABS(ppc, fd, fs);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int MOV_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_MOV)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_MOV
genCheckFP();
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
int fd = mapFPRNew( MIPS_GET_FD(mips), dbl );
GEN_FMR(ppc, fd, fs);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int NEG_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_NEG)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_NEG
genCheckFP();
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
int fd = mapFPRNew( MIPS_GET_FD(mips), dbl );
GEN_FNEG(ppc, fd, fs);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
// -- Floating Point Rounding/Conversion --
#define PPC_ROUNDING_NEAREST 0
#define PPC_ROUNDING_TRUNC 1
#define PPC_ROUNDING_CEIL 2
#define PPC_ROUNDING_FLOOR 3
static void set_rounding(int rounding_mode){
PowerPC_instr ppc;
GEN_MTFSFI(ppc, CR7, rounding_mode);
set_next_dst(ppc);
}
static void set_rounding_reg(int fs){
PowerPC_instr ppc;
GEN_MTFSF(ppc, 1, fs);
set_next_dst(ppc);
}
static int ROUND_L_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_ROUND_L)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_ROUND_L
genCheckFP();
int fd = MIPS_GET_FD(mips);
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
flushRegisters();
if(fs != F1){
GEN_FMR(ppc, F1, fs);
set_next_dst(ppc);
}
// round
GEN_B(ppc, add_jump(dbl ? &round : &roundf, 1, 1), 0, 1);
set_next_dst(ppc);
// convert
GEN_B(ppc, add_jump(dbl ? &__fixdfdi : &__fixsfdi, 1, 1), 0, 1);
set_next_dst(ppc);
// r2 = reg_cop1_double[fd]
GEN_LWZ(ppc, R2, SDAREL(reg_cop1_double) + fd*4, R13);
set_next_dst(ppc);
// Load old LR
GEN_LWZ(ppc, R0, DYNAOFF_LR, R1);
set_next_dst(ppc);
// stw r3, 0(r2)
GEN_STW(ppc, R3, 0, R2);
set_next_dst(ppc);
// Restore LR
GEN_MTLR(ppc, R0);
set_next_dst(ppc);
// stw r4, 4(r2)
GEN_STW(ppc, R4, 4, R2);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int TRUNC_L_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_TRUNC_L)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_TRUNC_L
genCheckFP();
int fd = MIPS_GET_FD(mips);
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
flushRegisters();
if(fs != F1){
GEN_FMR(ppc, F1, fs);
set_next_dst(ppc);
}
// convert
GEN_B(ppc, add_jump(dbl ? &__fixdfdi : &__fixsfdi, 1, 1), 0, 1);
set_next_dst(ppc);
// r2 = reg_cop1_double[fd]
GEN_LWZ(ppc, R2, SDAREL(reg_cop1_double) + fd*4, R13);
set_next_dst(ppc);
// Load old LR
GEN_LWZ(ppc, R0, DYNAOFF_LR, R1);
set_next_dst(ppc);
// stw r3, 0(r2)
GEN_STW(ppc, R3, 0, R2);
set_next_dst(ppc);
// Restore LR
GEN_MTLR(ppc, R0);
set_next_dst(ppc);
// stw r4, 4(r2)
GEN_STW(ppc, R4, 4, R2);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int CEIL_L_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_CEIL_L)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_CEIL_L
genCheckFP();
int fd = MIPS_GET_FD(mips);
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
flushRegisters();
if(fs != F1){
GEN_FMR(ppc, F1, fs);
set_next_dst(ppc);
}
// ceil
GEN_B(ppc, add_jump(dbl ? &ceil : &ceilf, 1, 1), 0, 1);
set_next_dst(ppc);
// convert
GEN_B(ppc, add_jump(dbl ? &__fixdfdi : &__fixsfdi, 1, 1), 0, 1);
set_next_dst(ppc);
// r2 = reg_cop1_double[fd]
GEN_LWZ(ppc, R2, SDAREL(reg_cop1_double) + fd*4, R13);
set_next_dst(ppc);
// Load old LR
GEN_LWZ(ppc, R0, DYNAOFF_LR, R1);
set_next_dst(ppc);
// stw r3, 0(r2)
GEN_STW(ppc, R3, 0, R2);
set_next_dst(ppc);
// Restore LR
GEN_MTLR(ppc, R0);
set_next_dst(ppc);
// stw r4, 4(r2)
GEN_STW(ppc, R4, 4, R2);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int FLOOR_L_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_FLOOR_L)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_FLOOR_L
genCheckFP();
int fd = MIPS_GET_FD(mips);
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
flushRegisters();
if(fs != F1){
GEN_FMR(ppc, F1, fs);
set_next_dst(ppc);
}
// round
GEN_B(ppc, add_jump(dbl ? &floor : &floorf, 1, 1), 0, 1);
set_next_dst(ppc);
// convert
GEN_B(ppc, add_jump(dbl ? &__fixdfdi : &__fixsfdi, 1, 1), 0, 1);
set_next_dst(ppc);
// r2 = reg_cop1_double[fd]
GEN_LWZ(ppc, R2, SDAREL(reg_cop1_double) + fd*4, R13);
set_next_dst(ppc);
// Load old LR
GEN_LWZ(ppc, R0, DYNAOFF_LR, R1);
set_next_dst(ppc);
// stw r3, 0(r2)
GEN_STW(ppc, R3, 0, R2);
set_next_dst(ppc);
// Restore LR
GEN_MTLR(ppc, R0);
set_next_dst(ppc);
// stw r4, 4(r2)
GEN_STW(ppc, R4, 4, R2);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int ROUND_W_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_ROUND_W)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_ROUND_W
genCheckFP();
int fd = MIPS_GET_FD(mips);
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
invalidateFPR(fd);
// fctiw f0, fs
GEN_FCTIW(ppc, F0, fs);
set_next_dst(ppc);
// r0 = reg_cop1_simple[fd]
GEN_LWZ(ppc, R0, SDAREL(reg_cop1_simple) + fd*4, R13);
set_next_dst(ppc);
// stfiwx f0, 0, r0
GEN_STFIWX(ppc, F0, 0, R0);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int TRUNC_W_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_TRUNC_W)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_TRUNC_W
genCheckFP();
int fd = MIPS_GET_FD(mips);
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
invalidateFPR(fd);
// fctiwz f0, fs
GEN_FCTIWZ(ppc, F0, fs);
set_next_dst(ppc);
// r0 = reg_cop1_simple[fd]
GEN_LWZ(ppc, R0, SDAREL(reg_cop1_simple) + fd*4, R13);
set_next_dst(ppc);
// stfiwx f0, 0, r0
GEN_STFIWX(ppc, F0, 0, R0);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int CEIL_W_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_CEIL_W)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_CEIL_W
genCheckFP();
set_rounding(PPC_ROUNDING_CEIL);
int fd = MIPS_GET_FD(mips);
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
invalidateFPR(fd);
// fctiw f0, fs
GEN_FCTIW(ppc, F0, fs);
set_next_dst(ppc);
// r0 = reg_cop1_simple[fd]
GEN_LWZ(ppc, R0, SDAREL(reg_cop1_simple) + fd*4, R13);
set_next_dst(ppc);
// stfiwx f0, 0, r0
GEN_STFIWX(ppc, F0, 0, R0);
set_next_dst(ppc);
set_rounding(PPC_ROUNDING_NEAREST);
return CONVERT_SUCCESS;
#endif
}
static int FLOOR_W_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_FLOOR_W)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_FLOOR_W
genCheckFP();
set_rounding(PPC_ROUNDING_FLOOR);
int fd = MIPS_GET_FD(mips);
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
invalidateFPR(fd);
// fctiw f0, fs
GEN_FCTIW(ppc, F0, fs);
set_next_dst(ppc);
// r0 = reg_cop1_simple[fd]
GEN_LWZ(ppc, R0, SDAREL(reg_cop1_simple) + fd*4, R13);
set_next_dst(ppc);
// stfiwx f0, 0, r0
GEN_STFIWX(ppc, F0, 0, R0);
set_next_dst(ppc);
set_rounding(PPC_ROUNDING_NEAREST);
return CONVERT_SUCCESS;
#endif
}
static int CVT_S_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_CVT_S)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_CVT_S
genCheckFP();
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
int fd = mapFPRNew( MIPS_GET_FD(mips), 0 );
GEN_FRSP(ppc, fd, fs);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int CVT_D_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_CVT_D)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_CVT_D
genCheckFP();
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
int fd = mapFPRNew( MIPS_GET_FD(mips), 1 );
GEN_FMR(ppc, fd, fs);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int CVT_W_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_CVT_W)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_CVT_W
genCheckFP();
// Set rounding mode according to FCR31
GEN_LFD(ppc, F0, SDAREL(FCR31-1), R13);
set_next_dst(ppc);
// FIXME: Here I have the potential to disable IEEE mode
// and enable inexact exceptions
set_rounding_reg(F0);
int fd = MIPS_GET_FD(mips);
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
invalidateFPR(fd);
// fctiw f0, fs
GEN_FCTIW(ppc, F0, fs);
set_next_dst(ppc);
// r0 = reg_cop1_simple[fd]
GEN_LWZ(ppc, R0, SDAREL(reg_cop1_simple) + fd*4, R13);
set_next_dst(ppc);
// stfiwx f0, 0, r0
GEN_STFIWX(ppc, F0, 0, R0);
set_next_dst(ppc);
set_rounding(PPC_ROUNDING_NEAREST);
return CONVERT_SUCCESS;
#endif
}
static int CVT_L_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_CVT_L)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_CVT_L
genCheckFP();
int fd = MIPS_GET_FD(mips);
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
flushRegisters();
if(fs != F1){
GEN_FMR(ppc, F1, fs);
set_next_dst(ppc);
}
// FIXME: I'm fairly certain this will always trunc
// convert
GEN_B(ppc, add_jump(dbl ? &__fixdfdi : &__fixsfdi, 1, 1), 0, 1);
set_next_dst(ppc);
// r2 = reg_cop1_double[fd]
GEN_LWZ(ppc, R2, SDAREL(reg_cop1_double) + fd*4, R13);
set_next_dst(ppc);
// Load old LR
GEN_LWZ(ppc, R0, DYNAOFF_LR, R1);
set_next_dst(ppc);
// stw r3, 0(r2)
GEN_STW(ppc, R3, 0, R2);
set_next_dst(ppc);
// Restore LR
GEN_MTLR(ppc, R0);
set_next_dst(ppc);
// stw r4, 4(r2)
GEN_STW(ppc, R4, 4, R2);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
// -- Floating Point Comparisons --
static int C_F_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_C_F)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_C_F
genCheckFP();
// lwz r0, 0(&fcr31)
GEN_LWZ(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
// and r0, r0, 0xff7fffff (clear cond)
GEN_RLWINM(ppc, R0, R0, 0, 9, 7);
set_next_dst(ppc);
// stw r0, 0(&fcr31)
GEN_STW(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int C_UN_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_C_UN)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_C_UN
genCheckFP();
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
int ft = mapFPR( MIPS_GET_FT(mips), dbl );
GEN_FCMPU(ppc, CR1, fs, ft);
set_next_dst(ppc);
GEN_LWZ(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
GEN_MFCR(ppc, R2);
set_next_dst(ppc);
GEN_RLWIMI(ppc, R0, R2, 31, 8, 8);
set_next_dst(ppc);
GEN_STW(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int C_EQ_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_C_EQ)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_C_EQ
genCheckFP();
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
int ft = mapFPR( MIPS_GET_FT(mips), dbl );
GEN_FCMPU(ppc, CR1, fs, ft);
set_next_dst(ppc);
GEN_LWZ(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
GEN_MFCR(ppc, R2);
set_next_dst(ppc);
GEN_RLWIMI(ppc, R0, R2, 30, 8, 8);
set_next_dst(ppc);
GEN_STW(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int C_UEQ_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_C_UEQ)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_C_UEQ
genCheckFP();
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
int ft = mapFPR( MIPS_GET_FT(mips), dbl );
GEN_FCMPU(ppc, CR1, fs, ft);
set_next_dst(ppc);
GEN_LWZ(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
GEN_CROR(ppc, CR1*4+2, CR1*4+3, CR1*4+2);
set_next_dst(ppc);
GEN_MFCR(ppc, R2);
set_next_dst(ppc);
GEN_RLWIMI(ppc, R0, R2, 30, 8, 8);
set_next_dst(ppc);
GEN_STW(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int C_OLT_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_C_OLT)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_C_OLT
genCheckFP();
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
int ft = mapFPR( MIPS_GET_FT(mips), dbl );
GEN_FCMPU(ppc, CR1, fs, ft);
set_next_dst(ppc);
GEN_LWZ(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
GEN_MFCR(ppc, R2);
set_next_dst(ppc);
GEN_RLWIMI(ppc, R0, R2, 28, 8, 8);
set_next_dst(ppc);
GEN_STW(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int C_ULT_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_C_ULT)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_C_ULT
genCheckFP();
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
int ft = mapFPR( MIPS_GET_FT(mips), dbl );
GEN_FCMPU(ppc, CR1, fs, ft);
set_next_dst(ppc);
GEN_LWZ(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
GEN_CROR(ppc, CR1*4+0, CR1*4+3, CR1*4+0);
set_next_dst(ppc);
GEN_MFCR(ppc, R2);
set_next_dst(ppc);
GEN_RLWIMI(ppc, R0, R2, 28, 8, 8);
set_next_dst(ppc);
GEN_STW(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int C_OLE_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_C_OLE)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_C_OLE
genCheckFP();
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
int ft = mapFPR( MIPS_GET_FT(mips), dbl );
GEN_FCMPU(ppc, CR1, fs, ft);
set_next_dst(ppc);
GEN_LWZ(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
GEN_CRNOR(ppc, CR1*4+2, CR1*4+3, CR1*4+1);
set_next_dst(ppc);
GEN_MFCR(ppc, R2);
set_next_dst(ppc);
GEN_RLWIMI(ppc, R0, R2, 30, 8, 8);
set_next_dst(ppc);
GEN_STW(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int C_ULE_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_C_ULE)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_C_ULE
genCheckFP();
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
int ft = mapFPR( MIPS_GET_FT(mips), dbl );
GEN_FCMPU(ppc, CR1, fs, ft);
set_next_dst(ppc);
GEN_LWZ(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
GEN_CRORC(ppc, CR1*4+2, CR1*4+3, CR1*4+1);
set_next_dst(ppc);
GEN_MFCR(ppc, R2);
set_next_dst(ppc);
GEN_RLWIMI(ppc, R0, R2, 30, 8, 8);
set_next_dst(ppc);
GEN_STW(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int C_SF_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_C_SF)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_C_SF
genCheckFP();
// lwz r0, 0(&fcr31)
GEN_LWZ(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
// and r0, r0, 0xff7fffff (clear cond)
GEN_RLWINM(ppc, R0, R0, 0, 9, 7);
set_next_dst(ppc);
// stw r0, 0(&fcr31)
GEN_STW(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int C_NGLE_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_C_NGLE)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_C_NGLE
genCheckFP();
// lwz r0, 0(&fcr31)
GEN_LWZ(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
// and r0, r0, 0xff7fffff (clear cond)
GEN_RLWINM(ppc, R0, R0, 0, 9, 7);
set_next_dst(ppc);
// stw r0, 0(&fcr31)
GEN_STW(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int C_SEQ_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_C_SEQ)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_C_SEQ
genCheckFP();
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
int ft = mapFPR( MIPS_GET_FT(mips), dbl );
GEN_FCMPU(ppc, CR1, fs, ft);
set_next_dst(ppc);
GEN_LWZ(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
GEN_MFCR(ppc, R2);
set_next_dst(ppc);
GEN_RLWIMI(ppc, R0, R2, 30, 8, 8);
set_next_dst(ppc);
GEN_STW(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int C_NGL_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_C_NGL)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_C_NGL
genCheckFP();
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
int ft = mapFPR( MIPS_GET_FT(mips), dbl );
GEN_FCMPU(ppc, CR1, fs, ft);
set_next_dst(ppc);
GEN_LWZ(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
GEN_MFCR(ppc, R2);
set_next_dst(ppc);
GEN_RLWIMI(ppc, R0, R2, 30, 8, 8);
set_next_dst(ppc);
GEN_STW(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int C_LT_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_C_LT)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_C_LT
genCheckFP();
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
int ft = mapFPR( MIPS_GET_FT(mips), dbl );
GEN_FCMPU(ppc, CR1, fs, ft);
set_next_dst(ppc);
GEN_LWZ(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
GEN_MFCR(ppc, R2);
set_next_dst(ppc);
GEN_RLWIMI(ppc, R0, R2, 28, 8, 8);
set_next_dst(ppc);
GEN_STW(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int C_NGE_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_C_NGE)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_C_NGE
genCheckFP();
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
int ft = mapFPR( MIPS_GET_FT(mips), dbl );
GEN_FCMPU(ppc, CR1, fs, ft);
set_next_dst(ppc);
GEN_LWZ(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
GEN_MFCR(ppc, R2);
set_next_dst(ppc);
GEN_RLWIMI(ppc, R0, R2, 28, 8, 8);
set_next_dst(ppc);
GEN_STW(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int C_LE_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_C_LE)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_C_LE
genCheckFP();
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
int ft = mapFPR( MIPS_GET_FT(mips), dbl );
GEN_FCMPU(ppc, CR1, fs, ft);
set_next_dst(ppc);
GEN_LWZ(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
GEN_CRNOR(ppc, CR1*4+2, CR1*4+3, CR1*4+1);
set_next_dst(ppc);
GEN_MFCR(ppc, R2);
set_next_dst(ppc);
GEN_RLWIMI(ppc, R0, R2, 30, 8, 8);
set_next_dst(ppc);
GEN_STW(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int C_NGT_FP(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_C_NGT)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_C_NGT
genCheckFP();
int fs = mapFPR( MIPS_GET_FS(mips), dbl );
int ft = mapFPR( MIPS_GET_FT(mips), dbl );
GEN_FCMPU(ppc, CR1, fs, ft);
set_next_dst(ppc);
GEN_LWZ(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
GEN_CRNOR(ppc, CR1*4+2, CR1*4+3, CR1*4+1);
set_next_dst(ppc);
GEN_MFCR(ppc, R2);
set_next_dst(ppc);
GEN_RLWIMI(ppc, R0, R2, 30, 8, 8);
set_next_dst(ppc);
GEN_STW(ppc, R0, SDAREL(FCR31), R13);
set_next_dst(ppc);
return CONVERT_SUCCESS;
#endif
}
static int (*gen_cop1_fp[64])(MIPS_instr, int) =
{
ADD_FP ,SUB_FP ,MUL_FP ,DIV_FP ,SQRT_FP ,ABS_FP ,MOV_FP ,NEG_FP ,
ROUND_L_FP,TRUNC_L_FP,CEIL_L_FP,FLOOR_L_FP,ROUND_W_FP,TRUNC_W_FP,CEIL_W_FP,FLOOR_W_FP,
NI ,NI ,NI ,NI ,NI ,NI ,NI ,NI ,
NI ,NI ,NI ,NI ,NI ,NI ,NI ,NI ,
CVT_S_FP ,CVT_D_FP ,NI ,NI ,CVT_W_FP ,CVT_L_FP ,NI ,NI ,
NI ,NI ,NI ,NI ,NI ,NI ,NI ,NI ,
C_F_FP ,C_UN_FP ,C_EQ_FP ,C_UEQ_FP ,C_OLT_FP ,C_ULT_FP ,C_OLE_FP ,C_ULE_FP ,
C_SF_FP ,C_NGLE_FP ,C_SEQ_FP ,C_NGL_FP ,C_LT_FP ,C_NGE_FP ,C_LE_FP ,C_NGT_FP
};
static int S(MIPS_instr mips){
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_S)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_S
return gen_cop1_fp[ MIPS_GET_FUNC(mips) ](mips, 0);
#endif
}
static int D(MIPS_instr mips){
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_D)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_D
return gen_cop1_fp[ MIPS_GET_FUNC(mips) ](mips, 1);
#endif
}
static const float two16 = 0x1p16;
static int CVT_FP_W(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
genCheckFP();
int fs = MIPS_GET_FS(mips);
flushFPR(fs);
int fd = mapFPRNew( MIPS_GET_FD(mips), dbl );
int tmp = mapFPRTemp();
GEN_LWZ(ppc, R2, SDAREL(reg_cop1_simple) + fs*4, R13);
set_next_dst(ppc);
GEN_LFS(ppc, F0, SDAREL(two16), R13);
set_next_dst(ppc);
GEN_PSQ_L(ppc, fd, 0, R2, QR7);
set_next_dst(ppc);
GEN_PSQ_L(ppc, tmp, 2, R2, QR5);
set_next_dst(ppc);
GEN_FMADD(ppc, fd, fd, F0, tmp, dbl);
set_next_dst(ppc);
unmapFPRTemp(tmp);
return CONVERT_SUCCESS;
}
static int W(MIPS_instr mips){
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_W)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_W
int func = MIPS_GET_FUNC(mips);
if(func == MIPS_FUNC_CVT_S_) return CVT_FP_W(mips, 0);
if(func == MIPS_FUNC_CVT_D_) return CVT_FP_W(mips, 1);
else return CONVERT_ERROR;
#endif
}
static int CVT_FP_L(MIPS_instr mips, int dbl){
PowerPC_instr ppc;
genCheckFP();
int fs = MIPS_GET_FS(mips);
flushFPR(fs);
int fd = mapFPRNew( MIPS_GET_FD(mips), dbl );
int tmp = mapFPRTemp();
GEN_LWZ(ppc, R2, SDAREL(reg_cop1_double) + fs*4, R13);
set_next_dst(ppc);
GEN_LFS(ppc, F0, SDAREL(two16), R13);
set_next_dst(ppc);
GEN_PSQ_L(ppc, fd, 0, R2, QR7);
set_next_dst(ppc);
GEN_PSQ_L(ppc, tmp, 2, R2, QR5);
set_next_dst(ppc);
GEN_FMADD(ppc, fd, fd, F0, tmp, dbl);
set_next_dst(ppc);
GEN_PSQ_L(ppc, tmp, 4, R2, QR5);
set_next_dst(ppc);
GEN_FMADD(ppc, fd, fd, F0, tmp, dbl);
set_next_dst(ppc);
GEN_PSQ_L(ppc, tmp, 6, R2, QR5);
set_next_dst(ppc);
GEN_FMADD(ppc, fd, fd, F0, tmp, dbl);
set_next_dst(ppc);
unmapFPRTemp(tmp);
return CONVERT_SUCCESS;
}
static int L(MIPS_instr mips){
#if defined(INTERPRET_FP) || defined(INTERPRET_FP_L)
genCallInterp(mips);
return INTERPRETED;
#else // INTERPRET_FP || INTERPRET_FP_L
int func = MIPS_GET_FUNC(mips);
if(func == MIPS_FUNC_CVT_S_) return CVT_FP_L(mips, 0);
if(func == MIPS_FUNC_CVT_D_) return CVT_FP_L(mips, 1);
else return CONVERT_ERROR;
#endif
}
static int (*gen_cop1[32])(MIPS_instr) =
{
MFC1, DMFC1, CFC1, NI, MTC1, DMTC1, CTC1, NI,
BC , NI , NI , NI, NI , NI , NI , NI,
S , D , NI , NI, W , L , NI , NI,
NI , NI , NI , NI, NI , NI , NI , NI
};
static int COP1(MIPS_instr mips){
return gen_cop1[MIPS_GET_RS(mips)](mips);
}
static int (*gen_ops[64])(MIPS_instr) =
{
SPECIAL, REGIMM, J , JAL , BEQ , BNE , BLEZ , BGTZ ,
ADDI , ADDIU , SLTI, SLTIU, ANDI, ORI , XORI , LUI ,
COP0 , COP1 , NI , NI , BEQL, BNEL, BLEZL, BGTZL,
DADDI , DADDIU, LDL , LDR , NI , NI , NI , NI ,
LB , LH , LWL , LW , LBU , LHU , LWR , LWU ,
SB , SH , SWL , SW , SDL , SDR , SWR , CACHE,
LL , LWC1 , NI , NI , LLD , LDC1, NI , LD ,
SC , SWC1 , NI , NI , SCD , SDC1, NI , SD
};
static void genCallInterp(MIPS_instr mips){
PowerPC_instr ppc = NEW_PPC_INSTR();
flushRegisters();
invalidateConstants();
reset_code_addr();
// Pass in whether this instruction is in the delay slot
GEN_LI(ppc, R5, isDelaySlot);
set_next_dst(ppc);
// Load our argument into r3 (mips)
GEN_LIS(ppc, R3, mips>>16);
set_next_dst(ppc);
// Load the current PC as the second arg
GEN_LIS(ppc, R4, get_src_pc()>>16);
set_next_dst(ppc);
// Load the lower halves of mips and PC
GEN_ORI(ppc, R3, R3, mips);
set_next_dst(ppc);
GEN_ORI(ppc, R4, R4, get_src_pc());
set_next_dst(ppc);
// Branch to decodeNInterpret
GEN_B(ppc, add_jump(&decodeNInterpret, 1, 1), 0, 1);
set_next_dst(ppc);
// Load the old LR
GEN_LWZ(ppc, R0, DYNAOFF_LR, R1);
set_next_dst(ppc);
// Check if the PC changed
GEN_CMPI(ppc, CR5, R3, 0);
set_next_dst(ppc);
// Restore the LR
GEN_MTLR(ppc, R0);
set_next_dst(ppc);
// if decodeNInterpret returned an address
// jumpTo it
GEN_BNELR(ppc, CR5, 0);
set_next_dst(ppc);
if(mips_is_jump(mips)) delaySlotNext = 2;
}
static void genJumpTo(unsigned int loc, unsigned int type){
PowerPC_instr ppc = NEW_PPC_INSTR();
if(type == JUMPTO_REG){
// Load the register as the return value
GEN_LWZ(ppc, R3, loc, R13);
set_next_dst(ppc);
GEN_BLR(ppc, 0);
set_next_dst(ppc);
} else {
// Calculate the destination address
loc <<= 2;
if(type == JUMPTO_OFF) loc += get_src_pc();
else loc |= get_src_pc() & 0xf0000000;
// Create space to load destination func*
set_next_dst(PPC_NOP);
set_next_dst(PPC_NOP);
// Make this function the LRU
GEN_LWZ(ppc, R2, SDAREL(nextLRU), R13);
set_next_dst(ppc);
GEN_STW(ppc, R2, offsetof(PowerPC_func, lru), DYNAREG_FUNC);
set_next_dst(ppc);
GEN_ADDI(ppc, R0, R2, 1);
set_next_dst(ppc);
GEN_STW(ppc, R0, SDAREL(nextLRU), R13);
set_next_dst(ppc);
// Load the address as the return value
GEN_LIS(ppc, R3, loc >> 16);
set_next_dst(ppc);
GEN_ORI(ppc, R3, R3, loc);
set_next_dst(ppc);
// Since we could be linking, return on interrupt
GEN_BLELR(ppc, CR3, 0);
set_next_dst(ppc);
// Store last_addr for linking
GEN_STW(ppc, R3, SDAREL(last_addr), R13);
set_next_dst(ppc);
GEN_BLR(ppc, 1);
set_next_dst(ppc);
}
}
// Updates Count, and sets cr3 to (next_interupt ? Count)
static void genUpdateCount(int checkCount){
PowerPC_instr ppc = NEW_PPC_INSTR();
#ifndef COMPARE_CORE
// Dynarec inlined code equivalent:
// lis r2, pc >> 16
GEN_LIS(ppc, R2, (get_src_pc()+4)>>16);
set_next_dst(ppc);
// lwz r0, 0(&last_addr) // r0 = last_addr
GEN_LWZ(ppc, R0, SDAREL(last_addr), R13);
set_next_dst(ppc);
// ori r2, r2, pc & 0xffff // r2 = pc
GEN_ORI(ppc, R2, R2, get_src_pc()+4);
set_next_dst(ppc);
// stw r2, 0(&last_addr) // last_addr = pc
GEN_STW(ppc, R2, SDAREL(last_addr), R13);
set_next_dst(ppc);
// subf r0, r0, r2 // r0 = pc - last_addr
GEN_SUBF(ppc, R0, R0, R2);
set_next_dst(ppc);
// lwz r2, 9*4(reg_cop0) // r2 = Count
GEN_LWZ(ppc, R2, SDAREL(Count), R13);
set_next_dst(ppc);
// srwi r0, r0, 2 // r0 = (pc - last_addr) >> 2
GEN_SRWI(ppc, R0, R0, 2);
set_next_dst(ppc);
// mulli r0, r0, count_per_op // r0 *= count_per_op
GEN_MULLI(ppc, R0, R0, count_per_op);
set_next_dst(ppc);
// add r0, r0, r2 // r0 += Count
GEN_ADD(ppc, R0, R0, R2);
set_next_dst(ppc);
if(checkCount){
// lwz r2, 0(&next_interupt) // r2 = next_interupt
GEN_LWZ(ppc, R2, SDAREL(next_interupt), R13);
set_next_dst(ppc);
}
// stw r0, 9*4(reg_cop0) // Count = r0
GEN_STW(ppc, R0, SDAREL(Count), R13);
set_next_dst(ppc);
if(checkCount){
// cmpl cr3, r2, r0 // cr3 = next_interupt ? Count
GEN_CMPL(ppc, CR3, R2, R0);
set_next_dst(ppc);
}
#else
// Load the current PC as the argument
GEN_LIS(ppc, R3, (get_src_pc()+4)>>16);
set_next_dst(ppc);
GEN_ORI(ppc, R3, R3, get_src_pc()+4);
set_next_dst(ppc);
// Call dyna_update_count
GEN_B(ppc, add_jump(&dyna_update_count, 1, 1), 0, 1);
set_next_dst(ppc);
// Load the lr
GEN_LWZ(ppc, R0, DYNAOFF_LR, R1);
set_next_dst(ppc);
GEN_MTLR(ppc, R0);
set_next_dst(ppc);
if(checkCount){
// If next_interupt <= Count (cr3)
GEN_CMPI(ppc, CR3, R3, 0);
set_next_dst(ppc);
}
#endif
}
// Check whether we need to take a FP unavailable exception
static void genCheckFP(void){
PowerPC_instr ppc;
if(FP_need_check || isDelaySlot){
flushRegisters();
reset_code_addr();
// lwz r0, 12*4(reg_cop0)
GEN_LWZ(ppc, R0, SDAREL(Status), R13);
set_next_dst(ppc);
// andis. r0, r0, 0x2000
GEN_ANDIS(ppc, R0, R0, 0x2000);
set_next_dst(ppc);
// bne cr0, end
GEN_BNE(ppc, CR0, 8, 0, 0);
set_next_dst(ppc);
// Load the current PC as arg 1 (upper half)
GEN_LIS(ppc, R3, get_src_pc()>>16);
set_next_dst(ppc);
// Pass in whether this instruction is in the delay slot as arg 2
GEN_LI(ppc, R4, isDelaySlot);
set_next_dst(ppc);
// Current PC (lower half)
GEN_ORI(ppc, R3, R3, get_src_pc());
set_next_dst(ppc);
// Call dyna_check_cop1_unusable
GEN_B(ppc, add_jump(&dyna_check_cop1_unusable, 1, 1), 0, 1);
set_next_dst(ppc);
// Load the old LR
GEN_LWZ(ppc, R0, DYNAOFF_LR, R1);
set_next_dst(ppc);
// Restore the LR
GEN_MTLR(ppc, R0);
set_next_dst(ppc);
// Return to trampoline
GEN_BLR(ppc, 0);
set_next_dst(ppc);
// Don't check for the rest of this mapping
// Unless this instruction is in a delay slot
FP_need_check = isDelaySlot;
}
}
#define check_memory() \
{ \
flushRegisters(); \
GEN_B(ppc, add_jump(&invalidate_func, 1, 1), 0, 1); \
set_next_dst(ppc); \
GEN_LWZ(ppc, R0, DYNAOFF_LR, R1); \
set_next_dst(ppc); \
GEN_MTLR(ppc, R0); \
set_next_dst(ppc); \
}
static void genCallDynaMem(memType type, int count, int _rs, int _rt, short immed){
PowerPC_instr ppc;
int isPhysical = 1, isVirtual = 1, isUncached = 1;
int isConstant = isRegisterConstant(_rs);
int constant = getRegisterConstant(_rs) + immed;
int i;
if(_rs >= MIPS_REG_K0){
isUncached = 0;
if(!isConstant){
isConstant = 2;
constant = reg[_rs] + immed;
}
}
#ifdef FASTMEM
if(isConstant){
#ifdef USE_EXPANSION
if(constant >= 0x80000000 && constant < 0x80800000){
isVirtual = 0;
isUncached = 0;
} else if(constant >= 0xA0000000 && constant < 0xA0800000)
isVirtual = 0;
#else
if(constant >= 0x80000000 && constant < 0x80400000){
isVirtual = 0;
isUncached = 0;
} else if(constant >= 0xA0000000 && constant < 0xA0400000)
isVirtual = 0;
#endif
else if(isConstant == 1)
isPhysical = 0;
}
#endif
if(type < MEM_SW || type > MEM_SD)
isUncached = 0;
int rs = mapRegister(_rs);
if(isVirtual) flushRegisters();
mapRegisterFixed(R3);
if(immed || rs != R3){
GEN_ADDI(ppc, R3, rs, immed);
set_next_dst(ppc);
}
#ifdef FASTMEM
int to_slow_id;
PowerPC_instr* ts_preCall;
if(isPhysical && isVirtual){
// If base in physical memory
GEN_XORIS(ppc, R0, R3, 0x8000);
set_next_dst(ppc);
#ifdef USE_EXPANSION
GEN_ANDIS(ppc, R0, R0, 0xDF80);
set_next_dst(ppc);
#else
GEN_ANDIS(ppc, R0, R0, 0xDFC0);
set_next_dst(ppc);
#endif
to_slow_id = add_jump_special(0);
GEN_BNE(ppc, CR0, to_slow_id, 0, 0);
set_next_dst(ppc);
ts_preCall = get_curr_dst();
}
if(isPhysical){
if(isConstant == 1){
switch(type){
case MEM_LW:
{
void* address = &rdramb[constant & 0xFFFFFC];
for(i = 0; i < count; i++){
int rt = mapRegisterNew(_rt + i, 1);
if(i == 0){
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_LWZU(ppc, rt, extractLower16(address), R2);
set_next_dst(ppc);
} else {
GEN_LWZ(ppc, rt, i*4, R2);
set_next_dst(ppc);
}
}
break;
}
case MEM_ULW:
{
void* address = &rdramb[constant & 0xFFFFFF];
for(i = 0; i < count; i++){
int rt = mapRegisterNew(_rt + i, 1);
if(i == 0){
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_LWZU(ppc, rt, extractLower16(address), R2);
set_next_dst(ppc);
} else {
GEN_LWZ(ppc, rt, i*4, R2);
set_next_dst(ppc);
}
}
break;
}
case MEM_LWU:
{
void* address = &rdramb[constant & 0xFFFFFC];
for(i = 0; i < count; i++){
int rt = mapRegisterNew(_rt + i, 0);
if(i == 0){
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_LWZU(ppc, rt, extractLower16(address), R2);
set_next_dst(ppc);
} else {
GEN_LWZ(ppc, rt, i*4, R2);
set_next_dst(ppc);
}
}
break;
}
case MEM_LH:
{
void* address = &rdramb[constant & 0xFFFFFE];
for(i = 0; i < count; i++){
int rt = mapRegisterNew(_rt + i, 1);
if(i == 0){
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_LHAU(ppc, rt, extractLower16(address), R2);
set_next_dst(ppc);
} else {
GEN_LHA(ppc, rt, i*2, R2);
set_next_dst(ppc);
}
}
break;
}
case MEM_LHU:
{
void* address = &rdramb[constant & 0xFFFFFE];
for(i = 0; i < count; i++){
int rt = mapRegisterNew(_rt + i, 0);
if(i == 0){
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_LHZU(ppc, rt, extractLower16(address), R2);
set_next_dst(ppc);
} else {
GEN_LHZ(ppc, rt, i*2, R2);
set_next_dst(ppc);
}
}
break;
}
case MEM_LB:
{
void* address = &rdramb[constant & 0xFFFFFF];
for(i = 0; i < count; i++){
int rt = mapRegisterNew(_rt + i, 1);
if(i == 0){
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_LBZU(ppc, rt, extractLower16(address), R2);
set_next_dst(ppc);
} else {
GEN_LBZ(ppc, rt, i, R2);
set_next_dst(ppc);
}
GEN_EXTSB(ppc, rt, rt);
set_next_dst(ppc);
}
break;
}
case MEM_LBU:
{
void* address = &rdramb[constant & 0xFFFFFF];
for(i = 0; i < count; i++){
int rt = mapRegisterNew(_rt + i, 0);
if(i == 0){
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_LBZU(ppc, rt, extractLower16(address), R2);
set_next_dst(ppc);
} else {
GEN_LBZ(ppc, rt, i, R2);
set_next_dst(ppc);
}
}
break;
}
case MEM_LD:
{
void* address = &rdramb[constant & 0xFFFFF8];
for(i = 0; i < count; i++){
RegMapping rt = mapRegister64New(_rt + i);
if(i == 0){
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_LWZU(ppc, rt.hi, extractLower16(address), R2);
set_next_dst(ppc);
} else {
GEN_LWZ(ppc, rt.hi, i*8, R2);
set_next_dst(ppc);
}
GEN_LWZ(ppc, rt.lo, i*8+4, R2);
set_next_dst(ppc);
}
break;
}
case MEM_ULD:
{
void* address = &rdramb[constant & 0xFFFFFF];
for(i = 0; i < count; i++){
RegMapping rt = mapRegister64New(_rt + i);
if(i == 0){
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_LWZU(ppc, rt.hi, extractLower16(address), R2);
set_next_dst(ppc);
} else {
GEN_LWZ(ppc, rt.hi, i*8, R2);
set_next_dst(ppc);
}
GEN_LWZ(ppc, rt.lo, i*8+4, R2);
set_next_dst(ppc);
}
break;
}
case MEM_LWC1:
{
void* address = &rdramb[constant & 0xFFFFFC];
for(i = 0; i < count; i++){
int rt = mapFPRNew(_rt + i*2, 0);
if(i == 0){
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_LFSU(ppc, rt, extractLower16(address), R2);
set_next_dst(ppc);
} else {
GEN_LFS(ppc, rt, i*4, R2);
set_next_dst(ppc);
}
}
break;
}
case MEM_LDC1:
{
void* address = &rdramb[constant & 0xFFFFF8];
for(i = 0; i < count; i++){
int rt = mapFPRNew(_rt + i*2, 1);
if(i == 0){
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_LFDU(ppc, rt, extractLower16(address), R2);
set_next_dst(ppc);
} else {
GEN_LFD(ppc, rt, i*8, R2);
set_next_dst(ppc);
}
}
break;
}
case MEM_LL:
{
void* address = &rdramb[constant & 0xFFFFFC];
int rt = mapRegisterNew(_rt, 1);
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_LI(ppc, R0, 1);
set_next_dst(ppc);
GEN_LWZU(ppc, rt, extractLower16(address), R2);
set_next_dst(ppc);
GEN_STW(ppc, R0, SDAREL(llbit), R13);
set_next_dst(ppc);
break;
}
case MEM_LLD:
{
void* address = &rdramb[constant & 0xFFFFF8];
RegMapping rt = mapRegister64New(_rt);
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_LI(ppc, R0, 1);
set_next_dst(ppc);
GEN_LWZU(ppc, rt.hi, extractLower16(address), R2);
set_next_dst(ppc);
GEN_LWZ(ppc, rt.lo, 4, R2);
set_next_dst(ppc);
GEN_STW(ppc, R0, SDAREL(llbit), R13);
set_next_dst(ppc);
break;
}
case MEM_LWL:
{
void* address = &rdramb[constant & 0xFFFFFF];
if((constant & 3) == 0){
int rt = mapRegisterNew(_rt, 1);
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_LWZU(ppc, rt, extractLower16(address), R2);
set_next_dst(ppc);
} else {
int rt = mapRegister(_rt);
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_LWZU(ppc, R0, extractLower16(address), R2);
set_next_dst(ppc);
GEN_RLWIMI(ppc, rt, R0, 0, 0, 31 - (constant & 3) * 8);
set_next_dst(ppc);
mapRegisterNew(_rt, 1);
}
break;
}
case MEM_LWR:
{
void* address = &rdramb[constant & 0xFFFFFF];
if((-constant & 3) == 0){
int rt = mapRegisterNew(_rt, 1);
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_LWZU(ppc, rt, extractLower16(address), R2);
set_next_dst(ppc);
} else {
int rt = mapRegister(_rt);
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_LWZU(ppc, R0, extractLower16(address), R2);
set_next_dst(ppc);
GEN_RLWIMI(ppc, rt, R0, 0, (-constant & 3) * 8, 31);
set_next_dst(ppc);
mapRegisterNew(_rt, 1);
}
break;
}
case MEM_LDL:
{
void* address = &rdramb[constant & 0xFFFFFF];
if((constant & 7) == 0){
RegMapping rt = mapRegister64New(_rt);
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_LWZU(ppc, rt.hi, extractLower16(address), R2);
set_next_dst(ppc);
GEN_LWZ(ppc, rt.lo, 4, R2);
set_next_dst(ppc);
} else if((constant & 4) == 0){
RegMapping rt = mapRegister64(_rt);
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_LWZU(ppc, rt.hi, extractLower16(address), R2);
set_next_dst(ppc);
GEN_LWZ(ppc, R0, 4, R2);
set_next_dst(ppc);
GEN_RLWIMI(ppc, rt.lo, R0, 0, 0, 31 - (constant & 3) * 8);
set_next_dst(ppc);
mapRegister64New(_rt);
} else if((constant & 3) == 0) {
RegMapping rt = mapRegister64(_rt);
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_LWZU(ppc, rt.hi, extractLower16(address), R2);
set_next_dst(ppc);
mapRegister64New(_rt);
} else {
RegMapping rt = mapRegister64(_rt);
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_LWZU(ppc, R0, extractLower16(address), R2);
set_next_dst(ppc);
GEN_RLWIMI(ppc, rt.hi, R0, 0, 0, 31 - (constant & 3) * 8);
set_next_dst(ppc);
mapRegister64New(_rt);
}
break;
}
case MEM_LDR:
{
void* address = &rdramb[constant & 0xFFFFFF];
if((-constant & 7) == 0){
RegMapping rt = mapRegister64New(_rt);
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_LWZU(ppc, rt.hi, extractLower16(address), R2);
set_next_dst(ppc);
GEN_LWZ(ppc, rt.lo, 4, R2);
set_next_dst(ppc);
} else if((-constant & 4) == 0){
RegMapping rt = mapRegister64(_rt);
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_LWZU(ppc, R0, extractLower16(address), R2);
set_next_dst(ppc);
GEN_LWZ(ppc, rt.lo, 4, R2);
set_next_dst(ppc);
GEN_RLWIMI(ppc, rt.hi, R0, 0, (-constant & 3) * 8, 31);
set_next_dst(ppc);
mapRegister64New(_rt);
} else if((-constant & 3) == 0){
RegMapping rt = mapRegister64(_rt);
GEN_LIS(ppc, R2, extractUpper16(address + 4));
set_next_dst(ppc);
GEN_LWZU(ppc, rt.lo, extractLower16(address + 4), R2);
set_next_dst(ppc);
mapRegister64New(_rt);
} else {
RegMapping rt = mapRegister64(_rt);
GEN_LIS(ppc, R2, extractUpper16(address + 4));
set_next_dst(ppc);
GEN_LWZU(ppc, R0, extractLower16(address + 4), R2);
set_next_dst(ppc);
GEN_RLWIMI(ppc, rt.lo, R0, 0, (-constant & 3) * 8, 31);
set_next_dst(ppc);
mapRegister64New(_rt);
}
break;
}
case MEM_SW:
{
void* address = &rdramb[constant & 0xFFFFFC];
for(i = 0; i < count; i++){
int rt = mapRegister(_rt + i);
if(i == 0){
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_STWU(ppc, rt, extractLower16(address), R2);
set_next_dst(ppc);
} else {
GEN_STW(ppc, rt, i*4, R2);
set_next_dst(ppc);
}
}
if(isUncached) check_memory();
break;
}
case MEM_USW:
{
void* address = &rdramb[constant & 0xFFFFFF];
for(i = 0; i < count; i++){
int rt = mapRegister(_rt + i);
if(i == 0){
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_STWU(ppc, rt, extractLower16(address), R2);
set_next_dst(ppc);
} else {
GEN_STW(ppc, rt, i*4, R2);
set_next_dst(ppc);
}
}
if(isUncached) check_memory();
break;
}
case MEM_SH:
{
void* address = &rdramb[constant & 0xFFFFFE];
for(i = 0; i < count; i++){
int rt = mapRegister(_rt + i);
if(i == 0){
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_STHU(ppc, rt, extractLower16(address), R2);
set_next_dst(ppc);
} else {
GEN_STH(ppc, rt, i*2, R2);
set_next_dst(ppc);
}
}
if(isUncached) check_memory();
break;
}
case MEM_SB:
{
void* address = &rdramb[constant & 0xFFFFFF];
for(i = 0; i < count; i++){
int rt = mapRegister(_rt + i);
if(i == 0){
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_STBU(ppc, rt, extractLower16(address), R2);
set_next_dst(ppc);
} else {
GEN_STB(ppc, rt, i, R2);
set_next_dst(ppc);
}
}
if(isUncached) check_memory();
break;
}
case MEM_SD:
{
void* address = &rdramb[constant & 0xFFFFF8];
for(i = 0; i < count; i++){
RegMapping rt = mapRegister64(_rt + i);
if(i == 0){
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_STWU(ppc, rt.hi, extractLower16(address), R2);
set_next_dst(ppc);
} else {
GEN_STW(ppc, rt.hi, i*8, R2);
set_next_dst(ppc);
}
GEN_STW(ppc, rt.lo, i*8+4, R2);
set_next_dst(ppc);
}
if(isUncached) check_memory();
break;
}
case MEM_USD:
{
void* address = &rdramb[constant & 0xFFFFFF];
for(i = 0; i < count; i++){
RegMapping rt = mapRegister64(_rt + i);
if(i == 0){
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_STWU(ppc, rt.hi, extractLower16(address), R2);
set_next_dst(ppc);
} else {
GEN_STW(ppc, rt.hi, i*8, R2);
set_next_dst(ppc);
}
GEN_STW(ppc, rt.lo, i*8+4, R2);
set_next_dst(ppc);
}
if(isUncached) check_memory();
break;
}
case MEM_SWC1:
{
void* address = &rdramb[constant & 0xFFFFFC];
for(i = 0; i < count; i++){
int rt = mapFPR(_rt + i*2, 0);
if(i == 0){
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_STFSU(ppc, rt, extractLower16(address), R2);
set_next_dst(ppc);
} else {
GEN_STFS(ppc, rt, i*4, R2);
set_next_dst(ppc);
}
}
if(isUncached) check_memory();
break;
}
case MEM_SDC1:
{
void* address = &rdramb[constant & 0xFFFFF8];
for(i = 0; i < count; i++){
int rt = mapFPR(_rt + i*2, 1);
if(i == 0){
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_STFDU(ppc, rt, extractLower16(address), R2);
set_next_dst(ppc);
} else {
GEN_STFD(ppc, rt, i*8, R2);
set_next_dst(ppc);
}
}
if(isUncached) check_memory();
break;
}
case MEM_SC:
{
void* address = &rdramb[constant & 0xFFFFFC];
int rt = mapRegister(_rt);
GEN_LWZ(ppc, R0, SDAREL(llbit), R13);
set_next_dst(ppc);
GEN_CMPLI(ppc, CR2, R0, 0);
set_next_dst(ppc);
GEN_BEQ(ppc, CR2, 6, 0, 0);
set_next_dst(ppc);
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_STWU(ppc, rt, extractLower16(address), R2);
set_next_dst(ppc);
if(isUncached) check_memory();
GEN_MFCR(ppc, R2);
set_next_dst(ppc);
GEN_RLWINM(ppc, mapRegisterNew(_rt, 0), R2, 10, 31, 31);
set_next_dst(ppc);
GEN_STW(ppc, DYNAREG_ZERO, SDAREL(llbit), R13);
set_next_dst(ppc);
break;
}
case MEM_SCD:
{
void* address = &rdramb[constant & 0xFFFFF8];
RegMapping rt = mapRegister64(_rt);
GEN_LWZ(ppc, R0, SDAREL(llbit), R13);
set_next_dst(ppc);
GEN_CMPLI(ppc, CR2, R0, 0);
set_next_dst(ppc);
GEN_BEQ(ppc, CR2, 7, 0, 0);
set_next_dst(ppc);
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_STWU(ppc, rt.hi, extractLower16(address), R2);
set_next_dst(ppc);
GEN_STW(ppc, rt.lo, 4, R2);
set_next_dst(ppc);
if(isUncached) check_memory();
GEN_MFCR(ppc, R2);
set_next_dst(ppc);
GEN_RLWINM(ppc, mapRegisterNew(_rt, 0), R2, 10, 31, 31);
set_next_dst(ppc);
GEN_STW(ppc, DYNAREG_ZERO, SDAREL(llbit), R13);
set_next_dst(ppc);
break;
}
case MEM_SWL:
{
void* address = &rdramb[constant & 0xFFFFFF];
if((constant & 3) == 0){
int rt = mapRegister(_rt);
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_STWU(ppc, rt, extractLower16(address), R2);
set_next_dst(ppc);
} else {
int rt = mapRegister(_rt);
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_LWZU(ppc, R0, extractLower16(address), R2);
set_next_dst(ppc);
GEN_RLWIMI(ppc, R0, rt, 0, 0, 31 - (constant & 3) * 8);
set_next_dst(ppc);
GEN_STW(ppc, R0, 0, R2);
set_next_dst(ppc);
}
if(isUncached) check_memory();
break;
}
case MEM_SWR:
{
void* address = &rdramb[constant & 0xFFFFFF];
if((-constant & 3) == 0){
int rt = mapRegister(_rt);
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_STWU(ppc, rt, extractLower16(address), R2);
set_next_dst(ppc);
} else {
int rt = mapRegister(_rt);
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_LWZU(ppc, R0, extractLower16(address), R2);
set_next_dst(ppc);
GEN_RLWIMI(ppc, R0, rt, 0, (-constant & 3) * 8, 31);
set_next_dst(ppc);
GEN_STW(ppc, R0, 0, R2);
set_next_dst(ppc);
}
if(isUncached) check_memory();
break;
}
case MEM_SDL:
{
void* address = &rdramb[constant & 0xFFFFFF];
if((constant & 7) == 0){
RegMapping rt = mapRegister64(_rt);
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_STWU(ppc, rt.hi, extractLower16(address), R2);
set_next_dst(ppc);
GEN_STW(ppc, rt.lo, 4, R2);
set_next_dst(ppc);
} else if((constant & 4) == 0){
RegMapping rt = mapRegister64(_rt);
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_STWU(ppc, rt.hi, extractLower16(address), R2);
set_next_dst(ppc);
GEN_LWZ(ppc, R0, 4, R2);
set_next_dst(ppc);
GEN_RLWIMI(ppc, R0, rt.lo, 0, 0, 31 - (constant & 3) * 8);
set_next_dst(ppc);
GEN_STW(ppc, R0, 4, R2);
set_next_dst(ppc);
} else if((constant & 3) == 0) {
RegMapping rt = mapRegister64(_rt);
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_STWU(ppc, rt.hi, extractLower16(address), R2);
set_next_dst(ppc);
} else {
RegMapping rt = mapRegister64(_rt);
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_LWZU(ppc, R0, extractLower16(address), R2);
set_next_dst(ppc);
GEN_RLWIMI(ppc, R0, rt.hi, 0, 0, 31 - (constant & 3) * 8);
set_next_dst(ppc);
GEN_STW(ppc, R0, 0, R2);
set_next_dst(ppc);
}
if(isUncached) check_memory();
break;
}
case MEM_SDR:
{
void* address = &rdramb[constant & 0xFFFFFF];
if((-constant & 7) == 0){
RegMapping rt = mapRegister64(_rt);
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_STWU(ppc, rt.hi, extractLower16(address), R2);
set_next_dst(ppc);
GEN_STW(ppc, rt.lo, 4, R2);
set_next_dst(ppc);
} else if((-constant & 4) == 0){
RegMapping rt = mapRegister64(_rt);
GEN_LIS(ppc, R2, extractUpper16(address));
set_next_dst(ppc);
GEN_LWZU(ppc, R0, extractLower16(address), R2);
set_next_dst(ppc);
GEN_RLWIMI(ppc, R0, rt.hi, 0, (-constant & 3) * 8, 31);
set_next_dst(ppc);
GEN_STW(ppc, R0, 0, R2);
set_next_dst(ppc);
GEN_STW(ppc, rt.lo, 4, R2);
set_next_dst(ppc);
} else if((-constant & 3) == 0) {
RegMapping rt = mapRegister64(_rt);
GEN_LIS(ppc, R2, extractUpper16(address + 4));
set_next_dst(ppc);
GEN_STWU(ppc, rt.lo, extractLower16(address + 4), R2);
set_next_dst(ppc);
} else {
RegMapping rt = mapRegister64(_rt);
GEN_LIS(ppc, R2, extractUpper16(address + 4));
set_next_dst(ppc);
GEN_LWZU(ppc, R0, extractLower16(address + 4), R2);
set_next_dst(ppc);
GEN_RLWIMI(ppc, R0, rt.lo, 0, (-constant & 3) * 8, 31);
set_next_dst(ppc);
GEN_STW(ppc, R0, 0, R2);
set_next_dst(ppc);
}
if(isUncached) check_memory();
break;
}
}
} else {
switch(type){
case MEM_LW:
{
for(i = 0; i < count; i++){
int rt = mapRegisterNew(_rt + i, 1);
if(i == 0){
GEN_RLWINM(ppc, R2, R3, 0, 8, 29);
set_next_dst(ppc);
GEN_LWZUX(ppc, rt, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
} else {
GEN_LWZ(ppc, rt, i*4, R2);
set_next_dst(ppc);
}
}
break;
}
case MEM_ULW:
{
for(i = 0; i < count; i++){
int rt = mapRegisterNew(_rt + i, 1);
if(i == 0){
GEN_RLWINM(ppc, R2, R3, 0, 8, 31);
set_next_dst(ppc);
GEN_LWZUX(ppc, rt, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
} else {
GEN_LWZ(ppc, rt, i*4, R2);
set_next_dst(ppc);
}
}
break;
}
case MEM_LWU:
{
for(i = 0; i < count; i++){
int rt = mapRegisterNew(_rt + i, 0);
if(i == 0){
GEN_RLWINM(ppc, R2, R3, 0, 8, 29);
set_next_dst(ppc);
GEN_LWZUX(ppc, rt, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
} else {
GEN_LWZ(ppc, rt, i*4, R2);
set_next_dst(ppc);
}
}
break;
}
case MEM_LH:
{
for(i = 0; i < count; i++){
int rt = mapRegisterNew(_rt + i, 1);
if(i == 0){
GEN_RLWINM(ppc, R2, R3, 0, 8, 30);
set_next_dst(ppc);
GEN_LHAUX(ppc, rt, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
} else {
GEN_LHA(ppc, rt, i*2, R2);
set_next_dst(ppc);
}
}
break;
}
case MEM_LHU:
{
for(i = 0; i < count; i++){
int rt = mapRegisterNew(_rt + i, 0);
if(i == 0){
GEN_RLWINM(ppc, R2, R3, 0, 8, 30);
set_next_dst(ppc);
GEN_LHZUX(ppc, rt, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
} else {
GEN_LHZ(ppc, rt, i*2, R2);
set_next_dst(ppc);
}
}
break;
}
case MEM_LB:
{
for(i = 0; i < count; i++){
int rt = mapRegisterNew(_rt + i, 1);
if(i == 0){
GEN_RLWINM(ppc, R2, R3, 0, 8, 31);
set_next_dst(ppc);
GEN_LBZUX(ppc, rt, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
} else {
GEN_LBZ(ppc, rt, i, R2);
set_next_dst(ppc);
}
GEN_EXTSB(ppc, rt, rt);
set_next_dst(ppc);
}
break;
}
case MEM_LBU:
{
for(i = 0; i < count; i++){
int rt = mapRegisterNew(_rt + i, 0);
if(i == 0){
GEN_RLWINM(ppc, R2, R3, 0, 8, 31);
set_next_dst(ppc);
GEN_LBZUX(ppc, rt, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
} else {
GEN_LBZ(ppc, rt, i, R2);
set_next_dst(ppc);
}
}
break;
}
case MEM_LD:
{
for(i = 0; i < count; i++){
RegMapping rt = mapRegister64New(_rt + i);
if(i == 0){
GEN_RLWINM(ppc, R2, R3, 0, 8, 28);
set_next_dst(ppc);
GEN_LWZUX(ppc, rt.hi, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
} else {
GEN_LWZ(ppc, rt.hi, i*8, R2);
set_next_dst(ppc);
}
GEN_LWZ(ppc, rt.lo, i*8+4, R2);
set_next_dst(ppc);
}
break;
}
case MEM_ULD:
{
for(i = 0; i < count; i++){
RegMapping rt = mapRegister64New(_rt + i);
if(i == 0){
GEN_RLWINM(ppc, R2, R3, 0, 8, 31);
set_next_dst(ppc);
GEN_LWZUX(ppc, rt.hi, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
} else {
GEN_LWZ(ppc, rt.hi, i*8, R2);
set_next_dst(ppc);
}
GEN_LWZ(ppc, rt.lo, i*8+4, R2);
set_next_dst(ppc);
}
break;
}
case MEM_LWC1:
{
for(i = 0; i < count; i++){
int rt = mapFPRNew(_rt + i*2, 0);
if(i == 0){
GEN_RLWINM(ppc, R2, R3, 0, 8, 29);
set_next_dst(ppc);
GEN_LFSUX(ppc, rt, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
} else {
GEN_LFS(ppc, rt, i*4, R2);
set_next_dst(ppc);
}
}
break;
}
case MEM_LDC1:
{
for(i = 0; i < count; i++){
int rt = mapFPRNew(_rt + i*2, 1);
if(i == 0){
GEN_RLWINM(ppc, R2, R3, 0, 8, 28);
set_next_dst(ppc);
GEN_LFDUX(ppc, rt, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
} else {
GEN_LFD(ppc, rt, i*8, R2);
set_next_dst(ppc);
}
}
break;
}
case MEM_LL:
{
int rt = mapRegisterNew(_rt, 1);
GEN_RLWINM(ppc, R2, R3, 0, 8, 29);
set_next_dst(ppc);
GEN_LI(ppc, R0, 1);
set_next_dst(ppc);
GEN_LWZUX(ppc, rt, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
GEN_STW(ppc, R0, SDAREL(llbit), R13);
set_next_dst(ppc);
break;
}
case MEM_LLD:
{
RegMapping rt = mapRegister64New(_rt);
GEN_RLWINM(ppc, R2, R3, 0, 8, 28);
set_next_dst(ppc);
GEN_LI(ppc, R0, 1);
set_next_dst(ppc);
GEN_LWZUX(ppc, rt.hi, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
GEN_LWZ(ppc, rt.lo, 4, R2);
set_next_dst(ppc);
GEN_STW(ppc, R0, SDAREL(llbit), R13);
set_next_dst(ppc);
break;
}
case MEM_LWL:
{
int rt = mapRegister(_rt);
int word = mapRegisterTemp();
int mask = mapRegisterTemp();
GEN_RLWINM(ppc, R2, R3, 0, 8, 31);
set_next_dst(ppc);
GEN_LWZUX(ppc, word, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
GEN_CLRLSLWI(ppc, R0, R3, 30, 3);
set_next_dst(ppc);
GEN_LI(ppc, mask, ~0);
set_next_dst(ppc);
GEN_SLW(ppc, mask, mask, R0);
set_next_dst(ppc);
GEN_ANDC(ppc, rt, rt, mask);
set_next_dst(ppc);
GEN_AND(ppc, word, word, mask);
set_next_dst(ppc);
GEN_OR(ppc, rt, rt, word);
set_next_dst(ppc);
mapRegisterNew(_rt, 1);
unmapRegisterTemp(word);
unmapRegisterTemp(mask);
break;
}
case MEM_LWR:
{
int rt = mapRegister(_rt);
int word = mapRegisterTemp();
int mask = mapRegisterTemp();
GEN_NEG(ppc, R0, R3);
set_next_dst(ppc);
GEN_RLWINM(ppc, R2, R3, 0, 8, 31);
set_next_dst(ppc);
GEN_LWZUX(ppc, word, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
GEN_CLRLSLWI(ppc, R0, R0, 30, 3);
set_next_dst(ppc);
GEN_LI(ppc, mask, ~0);
set_next_dst(ppc);
GEN_SRW(ppc, mask, mask, R0);
set_next_dst(ppc);
GEN_ANDC(ppc, rt, rt, mask);
set_next_dst(ppc);
GEN_AND(ppc, word, word, mask);
set_next_dst(ppc);
GEN_OR(ppc, rt, rt, word);
set_next_dst(ppc);
mapRegisterNew(_rt, 1);
unmapRegisterTemp(word);
unmapRegisterTemp(mask);
break;
}
case MEM_LDL:
{
RegMapping rt = mapRegister64(_rt);
int hi = mapRegisterTemp();
int lo = mapRegisterTemp();
int mask = mapRegisterTemp();
GEN_RLWINM(ppc, R2, R3, 0, 8, 31);
set_next_dst(ppc);
GEN_LWZUX(ppc, hi, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
GEN_LWZ(ppc, lo, 4, R2);
set_next_dst(ppc);
GEN_RLWINM_(ppc, mask, R3, 3, 26, 26);
set_next_dst(ppc);
GEN_CLRLSLWI(ppc, R0, R3, 30, 3);
set_next_dst(ppc);
GEN_LI(ppc, mask, ~0);
set_next_dst(ppc);
GEN_SLW(ppc, mask, mask, R0);
set_next_dst(ppc);
GEN_BNE(ppc, CR0, 6, 0, 0);
set_next_dst(ppc);
GEN_ANDC(ppc, rt.lo, rt.lo, mask);
set_next_dst(ppc);
GEN_AND(ppc, lo, lo, mask);
set_next_dst(ppc);
GEN_OR(ppc, rt.lo, rt.lo, lo);
set_next_dst(ppc);
GEN_MR(ppc, rt.hi, hi);
set_next_dst(ppc);
GEN_B(ppc, 4, 0, 0);
set_next_dst(ppc);
GEN_ANDC(ppc, rt.hi, rt.hi, mask);
set_next_dst(ppc);
GEN_AND(ppc, hi, hi, mask);
set_next_dst(ppc);
GEN_OR(ppc, rt.hi, rt.hi, hi);
set_next_dst(ppc);
mapRegister64New(_rt);
unmapRegisterTemp(hi);
unmapRegisterTemp(lo);
unmapRegisterTemp(mask);
break;
}
case MEM_LDR:
{
RegMapping rt = mapRegister64(_rt);
int hi = mapRegisterTemp();
int lo = mapRegisterTemp();
int mask = mapRegisterTemp();
GEN_NEG(ppc, R0, R3);
set_next_dst(ppc);
GEN_RLWINM(ppc, R2, R3, 0, 8, 31);
set_next_dst(ppc);
GEN_LWZUX(ppc, hi, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
GEN_LWZ(ppc, lo, 4, R2);
set_next_dst(ppc);
GEN_RLWINM_(ppc, mask, R0, 3, 26, 26);
set_next_dst(ppc);
GEN_CLRLSLWI(ppc, R0, R0, 30, 3);
set_next_dst(ppc);
GEN_LI(ppc, mask, ~0);
set_next_dst(ppc);
GEN_SRW(ppc, mask, mask, R0);
set_next_dst(ppc);
GEN_BNE(ppc, CR0, 6, 0, 0);
set_next_dst(ppc);
GEN_ANDC(ppc, rt.hi, rt.hi, mask);
set_next_dst(ppc);
GEN_AND(ppc, hi, hi, mask);
set_next_dst(ppc);
GEN_OR(ppc, rt.hi, rt.hi, hi);
set_next_dst(ppc);
GEN_MR(ppc, rt.lo, lo);
set_next_dst(ppc);
GEN_B(ppc, 4, 0, 0);
set_next_dst(ppc);
GEN_ANDC(ppc, rt.lo, rt.lo, mask);
set_next_dst(ppc);
GEN_AND(ppc, lo, lo, mask);
set_next_dst(ppc);
GEN_OR(ppc, rt.lo, rt.lo, lo);
set_next_dst(ppc);
mapRegister64New(_rt);
unmapRegisterTemp(hi);
unmapRegisterTemp(lo);
unmapRegisterTemp(mask);
break;
}
case MEM_SW:
{
for(i = 0; i < count; i++){
int rt = mapRegister(_rt + i);
if(i == 0){
GEN_RLWINM(ppc, R2, R3, 0, 8, 29);
set_next_dst(ppc);
GEN_STWUX(ppc, rt, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
} else {
GEN_STW(ppc, rt, i*4, R2);
set_next_dst(ppc);
}
}
if(isUncached) check_memory();
break;
}
case MEM_USW:
{
for(i = 0; i < count; i++){
int rt = mapRegister(_rt + i);
if(i == 0){
GEN_RLWINM(ppc, R2, R3, 0, 8, 31);
set_next_dst(ppc);
GEN_STWUX(ppc, rt, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
} else {
GEN_STW(ppc, rt, i*4, R2);
set_next_dst(ppc);
}
}
if(isUncached) check_memory();
break;
}
case MEM_SH:
{
for(i = 0; i < count; i++){
int rt = mapRegister(_rt + i);
if(i == 0){
GEN_RLWINM(ppc, R2, R3, 0, 8, 30);
set_next_dst(ppc);
GEN_STHUX(ppc, rt, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
} else {
GEN_STH(ppc, rt, i*2, R2);
set_next_dst(ppc);
}
}
if(isUncached) check_memory();
break;
}
case MEM_SB:
{
for(i = 0; i < count; i++){
int rt = mapRegister(_rt + i);
if(i == 0){
GEN_RLWINM(ppc, R2, R3, 0, 8, 31);
set_next_dst(ppc);
GEN_STBUX(ppc, rt, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
} else {
GEN_STB(ppc, rt, i, R2);
set_next_dst(ppc);
}
}
if(isUncached) check_memory();
break;
}
case MEM_SD:
{
for(i = 0; i < count; i++){
RegMapping rt = mapRegister64(_rt + i);
if(i == 0){
GEN_RLWINM(ppc, R2, R3, 0, 8, 28);
set_next_dst(ppc);
GEN_STWUX(ppc, rt.hi, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
} else {
GEN_STW(ppc, rt.hi, i*8, R2);
set_next_dst(ppc);
}
GEN_STW(ppc, rt.lo, i*8+4, R2);
set_next_dst(ppc);
}
if(isUncached) check_memory();
break;
}
case MEM_USD:
{
for(i = 0; i < count; i++){
RegMapping rt = mapRegister64(_rt + i);
if(i == 0){
GEN_RLWINM(ppc, R2, R3, 0, 8, 31);
set_next_dst(ppc);
GEN_STWUX(ppc, rt.hi, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
} else {
GEN_STW(ppc, rt.hi, i*8, R2);
set_next_dst(ppc);
}
GEN_STW(ppc, rt.lo, i*8+4, R2);
set_next_dst(ppc);
}
if(isUncached) check_memory();
break;
}
case MEM_SWC1:
{
for(i = 0; i < count; i++){
int rt = mapFPR(_rt + i*2, 0);
if(i == 0){
GEN_RLWINM(ppc, R2, R3, 0, 8, 29);
set_next_dst(ppc);
GEN_STFSUX(ppc, rt, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
} else {
GEN_STFS(ppc, rt, i*4, R2);
set_next_dst(ppc);
}
}
if(isUncached) check_memory();
break;
}
case MEM_SDC1:
{
for(i = 0; i < count; i++){
int rt = mapFPR(_rt + i*2, 1);
if(i == 0){
GEN_RLWINM(ppc, R2, R3, 0, 8, 28);
set_next_dst(ppc);
GEN_STFDUX(ppc, rt, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
} else {
GEN_STFD(ppc, rt, i*8, R2);
set_next_dst(ppc);
}
}
if(isUncached) check_memory();
break;
}
case MEM_SC:
{
int rt = mapRegister(_rt);
GEN_LWZ(ppc, R0, SDAREL(llbit), R13);
set_next_dst(ppc);
GEN_CMPLI(ppc, CR2, R0, 0);
set_next_dst(ppc);
GEN_BEQ(ppc, CR2, 6, 0, 0);
set_next_dst(ppc);
GEN_RLWINM(ppc, R2, R3, 0, 8, 29);
set_next_dst(ppc);
GEN_STWUX(ppc, rt, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
if(isUncached) check_memory();
GEN_MFCR(ppc, R2);
set_next_dst(ppc);
GEN_RLWINM(ppc, mapRegisterNew(_rt, 0), R2, 10, 31, 31);
set_next_dst(ppc);
GEN_STW(ppc, DYNAREG_ZERO, SDAREL(llbit), R13);
set_next_dst(ppc);
break;
}
case MEM_SCD:
{
RegMapping rt = mapRegister64(_rt);
GEN_LWZ(ppc, R0, SDAREL(llbit), R13);
set_next_dst(ppc);
GEN_CMPLI(ppc, CR2, R0, 0);
set_next_dst(ppc);
GEN_BEQ(ppc, CR2, 7, 0, 0);
set_next_dst(ppc);
GEN_RLWINM(ppc, R2, R3, 0, 8, 28);
set_next_dst(ppc);
GEN_STWUX(ppc, rt.hi, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
GEN_STW(ppc, rt.lo, 4, R2);
set_next_dst(ppc);
if(isUncached) check_memory();
GEN_MFCR(ppc, R2);
set_next_dst(ppc);
GEN_RLWINM(ppc, mapRegisterNew(_rt, 0), R2, 10, 31, 31);
set_next_dst(ppc);
GEN_STW(ppc, DYNAREG_ZERO, SDAREL(llbit), R13);
set_next_dst(ppc);
break;
}
case MEM_SWL:
{
int rt = mapRegister(_rt);
int word = mapRegisterTemp();
int mask = mapRegisterTemp();
GEN_RLWINM(ppc, R2, R3, 0, 8, 31);
set_next_dst(ppc);
GEN_LWZUX(ppc, word, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
GEN_CLRLSLWI(ppc, R0, R3, 30, 3);
set_next_dst(ppc);
GEN_LI(ppc, mask, ~0);
set_next_dst(ppc);
GEN_SLW(ppc, mask, mask, R0);
set_next_dst(ppc);
GEN_AND(ppc, R0, rt, mask);
set_next_dst(ppc);
GEN_ANDC(ppc, word, word, mask);
set_next_dst(ppc);
GEN_OR(ppc, word, word, R0);
set_next_dst(ppc);
GEN_STW(ppc, word, 0, R2);
set_next_dst(ppc);
if(isUncached) check_memory();
unmapRegisterTemp(word);
unmapRegisterTemp(mask);
break;
}
case MEM_SWR:
{
int rt = mapRegister(_rt);
int word = mapRegisterTemp();
int mask = mapRegisterTemp();
GEN_NEG(ppc, R0, R3);
set_next_dst(ppc);
GEN_RLWINM(ppc, R2, R3, 0, 8, 31);
set_next_dst(ppc);
GEN_LWZUX(ppc, word, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
GEN_CLRLSLWI(ppc, R0, R0, 30, 3);
set_next_dst(ppc);
GEN_LI(ppc, mask, ~0);
set_next_dst(ppc);
GEN_SRW(ppc, mask, mask, R0);
set_next_dst(ppc);
GEN_AND(ppc, R0, rt, mask);
set_next_dst(ppc);
GEN_ANDC(ppc, word, word, mask);
set_next_dst(ppc);
GEN_OR(ppc, word, word, R0);
set_next_dst(ppc);
GEN_STW(ppc, word, 0, R2);
set_next_dst(ppc);
if(isUncached) check_memory();
unmapRegisterTemp(word);
unmapRegisterTemp(mask);
break;
}
case MEM_SDL:
{
RegMapping rt = mapRegister64(_rt);
int hi = mapRegisterTemp();
int lo = mapRegisterTemp();
int mask = mapRegisterTemp();
GEN_RLWINM(ppc, R2, R3, 0, 8, 31);
set_next_dst(ppc);
GEN_LWZUX(ppc, hi, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
GEN_LWZ(ppc, lo, 4, R2);
set_next_dst(ppc);
GEN_RLWINM_(ppc, mask, R3, 3, 26, 26);
set_next_dst(ppc);
GEN_CLRLSLWI(ppc, R0, R3, 30, 3);
set_next_dst(ppc);
GEN_LI(ppc, mask, ~0);
set_next_dst(ppc);
GEN_SLW(ppc, mask, mask, R0);
set_next_dst(ppc);
GEN_BNE(ppc, CR0, 6, 0, 0);
set_next_dst(ppc);
GEN_AND(ppc, R0, rt.lo, mask);
set_next_dst(ppc);
GEN_ANDC(ppc, lo, lo, mask);
set_next_dst(ppc);
GEN_OR(ppc, lo, lo, R0);
set_next_dst(ppc);
GEN_MR(ppc, hi, rt.hi);
set_next_dst(ppc);
GEN_B(ppc, 4, 0, 0);
set_next_dst(ppc);
GEN_AND(ppc, R0, rt.hi, mask);
set_next_dst(ppc);
GEN_ANDC(ppc, hi, hi, mask);
set_next_dst(ppc);
GEN_OR(ppc, hi, hi, R0);
set_next_dst(ppc);
GEN_STW(ppc, hi, 0, R2);
set_next_dst(ppc);
GEN_STW(ppc, lo, 4, R2);
set_next_dst(ppc);
if(isUncached) check_memory();
unmapRegisterTemp(hi);
unmapRegisterTemp(lo);
unmapRegisterTemp(mask);
break;
}
case MEM_SDR:
{
RegMapping rt = mapRegister64(_rt);
int hi = mapRegisterTemp();
int lo = mapRegisterTemp();
int mask = mapRegisterTemp();
GEN_NEG(ppc, R0, R3);
set_next_dst(ppc);
GEN_RLWINM(ppc, R2, R3, 0, 8, 31);
set_next_dst(ppc);
GEN_LWZUX(ppc, hi, R2, DYNAREG_RDRAM);
set_next_dst(ppc);
GEN_LWZ(ppc, lo, 4, R2);
set_next_dst(ppc);
GEN_RLWINM_(ppc, mask, R0, 3, 26, 26);
set_next_dst(ppc);
GEN_CLRLSLWI(ppc, R0, R0, 30, 3);
set_next_dst(ppc);
GEN_LI(ppc, mask, ~0);
set_next_dst(ppc);
GEN_SRW(ppc, mask, mask, R0);
set_next_dst(ppc);
GEN_BNE(ppc, CR0, 6, 0, 0);
set_next_dst(ppc);
GEN_AND(ppc, R0, rt.hi, mask);
set_next_dst(ppc);
GEN_ANDC(ppc, hi, hi, mask);
set_next_dst(ppc);
GEN_OR(ppc, hi, hi, R0);
set_next_dst(ppc);
GEN_MR(ppc, lo, rt.lo);
set_next_dst(ppc);
GEN_B(ppc, 4, 0, 0);
set_next_dst(ppc);
GEN_AND(ppc, R0, rt.lo, mask);
set_next_dst(ppc);
GEN_ANDC(ppc, lo, lo, mask);
set_next_dst(ppc);
GEN_OR(ppc, lo, lo, R0);
set_next_dst(ppc);
GEN_STW(ppc, hi, 0, R2);
set_next_dst(ppc);
GEN_STW(ppc, lo, 4, R2);
set_next_dst(ppc);
if(isUncached) check_memory();
unmapRegisterTemp(hi);
unmapRegisterTemp(lo);
unmapRegisterTemp(mask);
break;
}
}
}
}
int not_fastmem_id;
PowerPC_instr* preCall;
if(isPhysical && isVirtual){
flushRegisters();
// Skip over else
not_fastmem_id = add_jump_special(1);
GEN_B(ppc, not_fastmem_id, 0, 0);
set_next_dst(ppc);
preCall = get_curr_dst();
int ts_callSize = get_curr_dst() - ts_preCall;
set_jump_special(to_slow_id, ts_callSize+1);
}
#endif // FASTMEM
if(isVirtual){
invalidateRegisters();
if((type != MEM_LWC1 && type != MEM_LDC1 && type < MEM_SW) || type == MEM_SC || type == MEM_SCD)
for(i = 0; i < count; i++)
invalidateConstant(_rt + i);
GEN_LI(ppc, R4, _rt);
set_next_dst(ppc);
// count passed as arg 3
GEN_LI(ppc, R5, count);
set_next_dst(ppc);
// Pass PC as arg 5 (upper half)
GEN_LIS(ppc, R7, (get_src_pc()+4)>>16);
set_next_dst(ppc);
// type passed as arg 4
GEN_LI(ppc, R6, type);
set_next_dst(ppc);
// Lower half of PC
GEN_ORI(ppc, R7, R7, get_src_pc()+4);
set_next_dst(ppc);
// isDelaySlot as arg 6
GEN_LI(ppc, R8, isDelaySlot);
set_next_dst(ppc);
// call dyna_mem
GEN_B(ppc, add_jump(&dyna_mem, 1, 1), 0, 1);
set_next_dst(ppc);
// Load old LR
GEN_LWZ(ppc, R0, DYNAOFF_LR, R1);
set_next_dst(ppc);
// Check whether we need to take an interrupt
GEN_CMPI(ppc, CR5, R3, 0);
set_next_dst(ppc);
// Restore LR
GEN_MTLR(ppc, R0);
set_next_dst(ppc);
// If so, return to trampoline
GEN_BNELR(ppc, CR5, 0);
set_next_dst(ppc);
}
#ifdef FASTMEM
if(isPhysical && isVirtual){
int callSize = get_curr_dst() - preCall;
set_jump_special(not_fastmem_id, callSize+1);
}
#endif
}
static int mips_is_jump(MIPS_instr instr){
int opcode = MIPS_GET_OPCODE(instr);
int format = MIPS_GET_RS (instr);
int func = MIPS_GET_FUNC (instr);
return (opcode == MIPS_OPCODE_J ||
opcode == MIPS_OPCODE_JAL ||
opcode == MIPS_OPCODE_BEQ ||
opcode == MIPS_OPCODE_BNE ||
opcode == MIPS_OPCODE_BLEZ ||
opcode == MIPS_OPCODE_BGTZ ||
opcode == MIPS_OPCODE_BEQL ||
opcode == MIPS_OPCODE_BNEL ||
opcode == MIPS_OPCODE_BLEZL ||
opcode == MIPS_OPCODE_BGTZL ||
opcode == MIPS_OPCODE_B ||
(opcode == MIPS_OPCODE_R &&
(func == MIPS_FUNC_JR ||
func == MIPS_FUNC_JALR)) ||
(opcode == MIPS_OPCODE_COP1 &&
format == MIPS_FRMT_BC) );
}