Exemple #1
0
void Jit::Comp_Generic(MIPSOpcode op)
{
	FlushAll();
	MIPSInterpretFunc func = MIPSGetInterpretFunc(op);
	_dbg_assert_msg_(JIT, (MIPSGetInfo(op) & DELAYSLOT) == 0, "Cannot use interpreter for branch ops.");

	if (func)
	{
		MOV(32, M(&mips_->pc), Imm32(js.compilerPC));
		if (USE_JIT_MISSMAP)
			ABI_CallFunctionC(&JitLogMiss, op.encoding);
		else
			ABI_CallFunctionC(func, op.encoding);
	}
	else
		ERROR_LOG_REPORT(JIT, "Trying to compile instruction %08x that can't be interpreted", op.encoding);

	const MIPSInfo info = MIPSGetInfo(op);
	if ((info & IS_VFPU) != 0 && (info & VFPU_NO_PREFIX) == 0)
	{
		// If it does eat them, it'll happen in MIPSCompileOp().
		if ((info & OUT_EAT_PREFIX) == 0)
			js.PrefixUnknown();
	}
}
Exemple #2
0
bool IsRegisterUsed(u32 reg, u32 addr)
{
    while (true)
    {
        u32 op = Memory::Read_Instruction(addr);
        u32 info = MIPSGetInfo(op);

        if (
            ((info & IN_RS) ||
             (info & IN_RS_SHIFT) ||
             (info & IN_RS_ADDR))
            &&
            (MIPS_GET_RS(op) == reg)
        )
            return true;
        if ((info & IN_RT) && (MIPS_GET_RT(op) == reg))
            return true;
        if ((info & IS_CONDBRANCH))
            return true; // could also follow both paths
        if ((info & IS_JUMP))
            return true; // could also follow the path
        if ((info & OUT_RT) && (MIPS_GET_RT(op) == reg))
            return false; //the reg got clobbed! yay!
        if ((info & OUT_RD) && (MIPS_GET_RD(op) == reg))
            return false; //the reg got clobbed! yay!
        if ((info & OUT_RA) && (reg == MIPS_REG_RA))
            return false; //the reg got clobbed! yay!
        addr+=4;
    }
    return true;
}
Exemple #3
0
std::vector<int> GetInputRegs(u32 op)
{
    std::vector<int> vec;
    u32 info = MIPSGetInfo(op);
    if ((info & IS_VFPU) == 0)
    {
        if (info & IN_RS) vec.push_back(MIPS_GET_RS(op));
        if (info & IN_RT) vec.push_back(MIPS_GET_RT(op));
    }
    return vec;
}
Exemple #4
0
int GetOutReg(u32 op)
{
    u32 opinfo = MIPSGetInfo(op);
    if (opinfo & OUT_RT)
        return MIPS_GET_RT(op);
    if (opinfo & OUT_RD)
        return MIPS_GET_RD(op);
    if (opinfo & OUT_RA)
        return MIPS_REG_RA;
    return -1;
}
Exemple #5
0
void Jit::EatInstruction(u32 op)
{
	u32 info = MIPSGetInfo(op);
	_dbg_assert_msg_(JIT, !(info & DELAYSLOT), "Never eat a branch op.");
	_dbg_assert_msg_(JIT, !js.inDelaySlot, "Never eat an instruction inside a delayslot.");

	CheckJitBreakpoint(js.compilerPC + 4, 0);
	js.numInstructions++;
	js.compilerPC += 4;
	js.downcountAmount += MIPSGetInstructionCycleEstimate(op);
}
Exemple #6
0
std::vector<int> GetOutputRegs(u32 op)
{
    std::vector<int> vec;
    u32 info = MIPSGetInfo(op);
    if ((info & IS_VFPU) == 0)
    {
        if (info & OUT_RD) vec.push_back(MIPS_GET_RD(op));
        if (info & OUT_RT) vec.push_back(MIPS_GET_RT(op));
        if (info & OUT_RA) vec.push_back(MIPS_REG_RA);
    }
    return vec;
}
Exemple #7
0
void Jit::Comp_Generic(u32 op)
{
	FlushAll();
	MIPSInterpretFunc func = MIPSGetInterpretFunc(op);
	_dbg_assert_msg_(JIT, (MIPSGetInfo(op) & DELAYSLOT) == 0, "Cannot use interpreter for branch ops.");

	if (func)
	{
		MOV(32, M(&mips_->pc), Imm32(js.compilerPC));
		if (USE_JIT_MISSMAP)
			ABI_CallFunctionC((void *)&JitLogMiss, op);
		else
			ABI_CallFunctionC((void *)func, op);
	}
	else
		_dbg_assert_msg_(JIT, 0, "Trying to compile instruction that can't be interpreted");

	// Might have eaten prefixes, hard to tell...
	if ((MIPSGetInfo(op) & IS_VFPU) != 0)
		js.PrefixStart();
}
Exemple #8
0
void MipsJit::EatInstruction(MIPSOpcode op) {
	MIPSInfo info = MIPSGetInfo(op);
	if (info & DELAYSLOT) {
		ERROR_LOG_REPORT_ONCE(ateDelaySlot, JIT, "Ate a branch op.");
	}
	if (js.inDelaySlot) {
		ERROR_LOG_REPORT_ONCE(ateInDelaySlot, JIT, "Ate an instruction inside a delay slot.");
	}

	js.numInstructions++;
	js.compilerPC += 4;
	js.downcountAmount += MIPSGetInstructionCycleEstimate(op);
}
	u32 GetSureBranchTarget(u32 addr)
	{
		MIPSOpcode op = Memory::Read_Instruction(addr, true);
		if (op != 0)
		{
			MIPSInfo info = MIPSGetInfo(op);
			if ((info & IS_CONDBRANCH) && !(info & (IN_FPUFLAG | IS_VFPU)))
			{
				bool sure;
				bool takeBranch;
				switch (info & CONDTYPE_MASK)
				{
				case CONDTYPE_EQ:
					sure = _RS == _RT;
					takeBranch = true;
					break;

				case CONDTYPE_NE:
					sure = _RS == _RT;
					takeBranch = false;
					break;

				case CONDTYPE_LEZ:
				case CONDTYPE_GEZ:
					sure = _RS == 0;
					takeBranch = true;
					break;

				case CONDTYPE_LTZ:
				case CONDTYPE_GTZ:
					sure = _RS == 0;
					takeBranch = false;
					break;

				default:
					sure = false;
				}

				if (sure && takeBranch)
					return addr + 4 + ((signed short)(op&0xFFFF)<<2);
				else if (sure && !takeBranch)
					return addr + 8;
				else
					return INVALIDTARGET;
			}
			else
				return INVALIDTARGET;
		}
		else
			return INVALIDTARGET;
	}
Exemple #10
0
bool IsDelaySlotNice(u32 branch, u32 delayslot)
{
    int outReg = GetOutReg(delayslot);
    if (outReg != -1)
    {
        if (ReadsFromReg(branch, outReg))
        {
            return false; //evil :(
        }
        else
        {
            return false; //aggh this should be true but doesn't work
        }
    }
    else
    {
        // Check for FPU flag
        if ((MIPSGetInfo(delayslot) & OUT_FPUFLAG) && (MIPSGetInfo(branch) & IN_FPUFLAG))
            return false;

        return true; //nice :)
    }
}
	u32 GetBranchTargetNoRA(u32 addr, MIPSOpcode op)
	{
		if (op != 0)
		{
			MIPSInfo info = MIPSGetInfo(op);
			if ((info & IS_CONDBRANCH) && !(info & OUT_RA))
			{
				return addr + 4 + ((signed short)(op&0xFFFF)<<2);
			}
			else
				return INVALIDTARGET;
		}
		else
			return INVALIDTARGET;
	}
Exemple #12
0
bool ReadsFromReg(u32 op, u32 reg)
{
    u32 opinfo = MIPSGetInfo(op);
    if (opinfo & IN_RT)
    {
        if (MIPS_GET_RT(opinfo) == reg)
            return true;
    }
    if (opinfo & (IN_RS | IN_RS_ADDR | IN_RS_SHIFT))
    {
        if (MIPS_GET_RS(opinfo) == reg)
            return true;
    }
    return false; //TODO: there are more cases!
}
Exemple #13
0
	u32 GetBranchTarget(u32 addr)
	{
		u32 op = Memory::Read_Instruction(addr);
		if (op)
		{
			u32 info = MIPSGetInfo(op);
			if (info & IS_CONDBRANCH)
			{
				return addr + ((signed short)(op&0xFFFF)<<2);
			}
			else
				return INVALIDTARGET;	
		}
		else
			return INVALIDTARGET;
	}
	u32 GetJumpTarget(u32 addr)
	{
		MIPSOpcode op = Memory::Read_Instruction(addr, true);
		if (op != 0)
		{
			MIPSInfo info = MIPSGetInfo(op);
			if ((info & IS_JUMP) && (info & IN_IMM26))
			{
				u32 target = (addr & 0xF0000000) | ((op&0x03FFFFFF) << 2);
				return target;
			}
			else
				return INVALIDTARGET;
		}
		else
			return INVALIDTARGET;
	}
Exemple #15
0
void FakeJit::Comp_Generic(MIPSOpcode op)
{
	FlushAll();
	MIPSInterpretFunc func = MIPSGetInterpretFunc(op);
	if (func)
	{
		SaveDowncount();
		RestoreDowncount();
	}

	const MIPSInfo info = MIPSGetInfo(op);
	if ((info & IS_VFPU) != 0 && (info & VFPU_NO_PREFIX) == 0)
	{
		// If it does eat them, it'll happen in MIPSCompileOp().
		if ((info & OUT_EAT_PREFIX) == 0)
			js.PrefixUnknown();
	}
}
Exemple #16
0
	u32 GetSureBranchTarget(u32 addr)
	{
		u32 op = Memory::Read_Instruction(addr);
		if (op)
		{
			u32 info = MIPSGetInfo(op);
			if (info & IS_CONDBRANCH)
			{
				//TODO: safer check
				if ((op & 0xFFFF0000) == 0x10000000)
					return addr + ((signed short)(op&0xFFFF)<<2);
				else
					return INVALIDTARGET;
			}
			else
				return INVALIDTARGET;
		}
		else
			return INVALIDTARGET;
	}
Exemple #17
0
void HashFunctions()
{
    for (vector<Function>::iterator iter = functions.begin(); iter!=functions.end(); iter++)
    {
        Function &f=*iter;
        u32 hash = 0x1337babe;
        for (u32 addr = f.start; addr <= f.end; addr++)
        {
            u32 validbits = 0xFFFFFFFF;
            u32 instr = Memory::Read_Instruction(addr);
            u32 flags = MIPSGetInfo(instr);
            if (flags & IN_IMM16)
                validbits&=~0xFFFF;
            if (flags & IN_IMM26)
                validbits&=~0x3FFFFFF;
            hash = _rotl(hash,13);
            hash ^= (instr&validbits);
        }
        f.hash=hash;
        f.hasHash=true;
    }
}
Exemple #18
0
void MipsJit::Comp_Generic(MIPSOpcode op)
{
	FlushAll();
	MIPSInterpretFunc func = MIPSGetInterpretFunc(op);
	if (func)
	{
		//SaveDowncount();
		RestoreRoundingMode();
		// Move Imm32(js.compilerPC) in to M(&mips_->pc)
		QuickCallFunction(V1, (void *)func);
		ApplyRoundingMode();
		//RestoreDowncount();
	}

	const MIPSInfo info = MIPSGetInfo(op);
	if ((info & IS_VFPU) != 0 && (info & VFPU_NO_PREFIX) == 0)
	{
		// If it does eat them, it'll happen in MIPSCompileOp().
		if ((info & OUT_EAT_PREFIX) == 0)
			js.PrefixUnknown();
	}
}
	bool IsBranch(MIPSOpcode op) {
		return (MIPSGetInfo(op) & IS_CONDBRANCH) == IS_CONDBRANCH;
	}
Exemple #20
0
void Analyze(u32 address)
{
    //set everything to -1 (FF)
    memset(regAnal, 255, sizeof(AnalysisResults)*32);
    for (int i=0; i<32; i++)
    {
        regAnal[i].used=false;
        regAnal[i].readCount=0;
        regAnal[i].writeCount=0;
        regAnal[i].readAsAddrCount=0;
    }

    u32 addr = address;
    bool exitFlag = false;
    while (true)
    {
        u32 op = Memory::Read_Instruction(addr);
        u32 info = MIPSGetInfo(op);

        for (int reg=0; reg < 32; reg++)
        {
            int rs = MIPS_GET_RS(op);
            int rt = MIPS_GET_RT(op);
            int rd = MIPS_GET_RD(op);

            if (
                ((info & IN_RS) && (rs == reg)) ||
                ((info & IN_RS_SHIFT) && (rs == reg)) ||
                ((info & IN_RT) && (rt == reg)))
            {
                if (regAnal[reg].firstRead == -1)
                    regAnal[reg].firstRead = addr;
                regAnal[reg].lastRead = addr;
                regAnal[reg].readCount++;
                regAnal[reg].used=true;
            }
            if (
                ((info & IN_RS_ADDR) && (rs == reg))
            )
            {
                if (regAnal[reg].firstReadAsAddr == -1)
                    regAnal[reg].firstReadAsAddr = addr;
                regAnal[reg].lastReadAsAddr = addr;
                regAnal[reg].readAsAddrCount++;
                regAnal[reg].used=true;
            }
            if (
                ((info & OUT_RT) && (rt == reg)) ||
                ((info & OUT_RD) && (rd == reg)) ||
                ((info & OUT_RA) && (reg == MIPS_REG_RA))
            )
            {
                if (regAnal[reg].firstWrite == -1)
                    regAnal[reg].firstWrite = addr;
                regAnal[reg].lastWrite = addr;
                regAnal[reg].writeCount++;
                regAnal[reg].used=true;
            }
        }

        if (exitFlag) //delay slot done, let's quit!
            break;

        if ((info & IS_JUMP) || (info & IS_CONDBRANCH))
        {
            exitFlag = true; // now do the delay slot
        }

        addr += 4;
    }

    int numUsedRegs=0;
    static int totalUsedRegs=0;
    static int numAnalyzings=0;
    for (int i=0; i<32; i++)
    {
        if (regAnal[i].used)
            numUsedRegs++;
    }
    totalUsedRegs+=numUsedRegs;
    numAnalyzings++;
    DEBUG_LOG(CPU,"[ %08x ] Used regs: %i	 Average: %f",address,numUsedRegs,(float)totalUsedRegs/(float)numAnalyzings);
}
	bool IsVFPUBranch(MIPSOpcode op) {
		return (MIPSGetInfo(op) & (IS_VFPU | IS_CONDBRANCH)) == (IS_VFPU | IS_CONDBRANCH);
	}
Exemple #22
0
void DisassemblyFunction::load()
{
	generateBranchLines();

	// gather all branch targets
	std::set<u32> branchTargets;
	for (size_t i = 0; i < lines.size(); i++)
	{
		switch (lines[i].type)
		{
		case LINE_DOWN:
			branchTargets.insert(lines[i].second);
			break;
		case LINE_UP:
			branchTargets.insert(lines[i].first);
			break;
		default:
			break;
		}
	}
	
	DebugInterface* cpu = DisassemblyManager::getCpu();
	u32 funcPos = address;
	u32 funcEnd = address+size;

	u32 nextData = symbolMap.GetNextSymbolAddress(funcPos-1,ST_DATA);
	u32 opcodeSequenceStart = funcPos;
	while (funcPos < funcEnd)
	{
		if (funcPos == nextData)
		{
			if (opcodeSequenceStart != funcPos)
				addOpcodeSequence(opcodeSequenceStart,funcPos);

			DisassemblyData* data = new DisassemblyData(funcPos,symbolMap.GetDataSize(funcPos),symbolMap.GetDataType(funcPos));
			entries[funcPos] = data;
			lineAddresses.push_back(funcPos);
			funcPos += data->getTotalSize();

			nextData = symbolMap.GetNextSymbolAddress(funcPos-1,ST_DATA);
			opcodeSequenceStart = funcPos;
			continue;
		}

		// force align
		if (funcPos % 4)
		{
			u32 nextPos = (funcPos+3) & ~3;

			DisassemblyComment* comment = new DisassemblyComment(funcPos,nextPos-funcPos,".align","4");
			entries[funcPos] = comment;
			lineAddresses.push_back(funcPos);
			
			funcPos = nextPos;
			opcodeSequenceStart = funcPos;
			continue;
		}

		MIPSAnalyst::MipsOpcodeInfo opInfo = MIPSAnalyst::GetOpcodeInfo(cpu,funcPos);
		u32 opAddress = funcPos;
		funcPos += 4;

		// skip branches and their delay slots
		if (opInfo.isBranch)
		{
			funcPos += 4;
			continue;
		}

		// lui
		if (MIPS_GET_OP(opInfo.encodedOpcode) == 0x0F && funcPos < funcEnd && funcPos != nextData)
		{
			MIPSOpcode next = Memory::Read_Instruction(funcPos);
			MIPSInfo nextInfo = MIPSGetInfo(next);

			u32 immediate = ((opInfo.encodedOpcode & 0xFFFF) << 16) + (s16)(next.encoding & 0xFFFF);
			int rt = MIPS_GET_RT(opInfo.encodedOpcode);

			int nextRs = MIPS_GET_RS(next.encoding);
			int nextRt = MIPS_GET_RT(next.encoding);

			// both rs and rt of the second op have to match rt of the first,
			// otherwise there may be hidden consequences if the macro is displayed.
			// also, don't create a macro if something branches into the middle of it
			if (nextRs == rt && nextRt == rt && branchTargets.find(funcPos) == branchTargets.end())
			{
				DisassemblyMacro* macro = NULL;
				switch (MIPS_GET_OP(next.encoding))
				{
				case 0x09:	// addiu
					macro = new DisassemblyMacro(opAddress);
					macro->setMacroLi(immediate,rt);
					funcPos += 4;
					break;
				case 0x20:	// lb
				case 0x21:	// lh
				case 0x23:	// lw
				case 0x24:	// lbu
				case 0x25:	// lhu
				case 0x28:	// sb
				case 0x29:	// sh
				case 0x2B:	// sw
					macro = new DisassemblyMacro(opAddress);
					
					int dataSize;
					switch (nextInfo & MEMTYPE_MASK) {
					case MEMTYPE_BYTE:
						dataSize = 1;
						break;
					case MEMTYPE_HWORD:
						dataSize = 2;
						break;
					case MEMTYPE_WORD:
					case MEMTYPE_FLOAT:
						dataSize = 4;
						break;
					case MEMTYPE_VQUAD:
						dataSize = 16;
						break;
					default:
						return;
					}

					macro->setMacroMemory(MIPSGetName(next),immediate,rt,dataSize);
					funcPos += 4;
					break;
				}

				if (macro != NULL)
				{
					if (opcodeSequenceStart != opAddress)
						addOpcodeSequence(opcodeSequenceStart,opAddress);

					entries[opAddress] = macro;
					for (int i = 0; i < macro->getNumLines(); i++)
					{
						lineAddresses.push_back(macro->getLineAddress(i));
					}

					opcodeSequenceStart = funcPos;
					continue;
				}
			}
		}

		// just a normal opcode
	}

	if (opcodeSequenceStart != funcPos)
		addOpcodeSequence(opcodeSequenceStart,funcPos);
}