void R4300iOp32::BLEZ() {
    m_NextInstruction = DELAY_SLOT;
    if (_GPR[m_Opcode.rs].W[0] <= 0)
    {
        m_JumpToLocation = (*_PROGRAM_COUNTER) + ((short)m_Opcode.offset << 2) + 4;
        if ((*_PROGRAM_COUNTER) == m_JumpToLocation)
        {
            if (!DelaySlotEffectsCompare(*_PROGRAM_COUNTER,m_Opcode.rs,0))
            {
                m_NextInstruction = PERMLOOP_DO_DELAY;
            }
        }
    }
    else
    {
        m_JumpToLocation = (*_PROGRAM_COUNTER) + 8;
    }
}
Exemple #2
0
void TestInterpreterJump (usf_state_t * state, uint32_t PC, uint32_t TargetPC, int32_t Reg1, int32_t Reg2) {
	if (PC != TargetPC) { return; }
	if (DelaySlotEffectsCompare(state,PC,Reg1,Reg2)) { return; }
	InPermLoop(state);
}
Exemple #3
0
int32_t DelaySlotEffectsJump (usf_state_t * state, uint32_t JumpPC) {
	OPCODE Command;

	if (!r4300i_LW_VAddr(state, JumpPC, &Command.u.Hex)) { return 1; }

	switch (Command.u.b.op) {
	case R4300i_SPECIAL:
		switch (Command.u.e.funct) {
		case R4300i_SPECIAL_JR:	return DelaySlotEffectsCompare(state,JumpPC,Command.u.b.rs,0);
		case R4300i_SPECIAL_JALR: return DelaySlotEffectsCompare(state,JumpPC,Command.u.b.rs,31);
		}
		break;
	case R4300i_REGIMM:
		switch (Command.u.b.rt) {
		case R4300i_REGIMM_BLTZ:
		case R4300i_REGIMM_BGEZ:
		case R4300i_REGIMM_BLTZL:
		case R4300i_REGIMM_BGEZL:
		case R4300i_REGIMM_BLTZAL:
		case R4300i_REGIMM_BGEZAL:
			return DelaySlotEffectsCompare(state,JumpPC,Command.u.b.rs,0);
		}
		break;
	case R4300i_JAL:
	case R4300i_SPECIAL_JALR: return DelaySlotEffectsCompare(state,JumpPC,31,0); break;
	case R4300i_J: return 0;
	case R4300i_BEQ:
	case R4300i_BNE:
	case R4300i_BLEZ:
	case R4300i_BGTZ:
		return DelaySlotEffectsCompare(state,JumpPC,Command.u.b.rs,Command.u.b.rt);
	case R4300i_CP1:
		switch (Command.u.f.fmt) {
		case R4300i_COP1_BC:
			switch (Command.u.f.ft) {
			case R4300i_COP1_BC_BCF:
			case R4300i_COP1_BC_BCT:
			case R4300i_COP1_BC_BCFL:
			case R4300i_COP1_BC_BCTL:
				{
					int32_t EffectDelaySlot;
					OPCODE NewCommand;

					if (!r4300i_LW_VAddr(state, JumpPC + 4, &NewCommand.u.Hex)) { return 1; }

					EffectDelaySlot = 0;
					if (NewCommand.u.b.op == R4300i_CP1) {
						if (NewCommand.u.f.fmt == R4300i_COP1_S && (NewCommand.u.e.funct & 0x30) == 0x30 ) {
							EffectDelaySlot = 1;
						}
						if (NewCommand.u.f.fmt == R4300i_COP1_D && (NewCommand.u.e.funct & 0x30) == 0x30 ) {
							EffectDelaySlot = 1;
						}
					}
					return EffectDelaySlot;
				}
				break;
			}
			break;
		}
		break;
	case R4300i_BEQL:
	case R4300i_BNEL:
	case R4300i_BLEZL:
	case R4300i_BGTZL:
		return DelaySlotEffectsCompare(state,JumpPC,Command.u.b.rs,Command.u.b.rt);
	}
	return 1;
}
Exemple #4
0
bool CCodeBlock::AnalyzeInstruction(uint32_t PC, uint32_t & TargetPC, uint32_t & ContinuePC, bool & LikelyBranch, bool & IncludeDelaySlot, bool & EndBlock, bool & PermLoop)
{
    TargetPC = (uint32_t)-1;
    ContinuePC = (uint32_t)-1;
    LikelyBranch = false;
    IncludeDelaySlot = false;
    EndBlock = false;
    PermLoop = false;

    OPCODE Command;
    if (!g_MMU->LW_VAddr(PC, Command.Hex))
    {
        g_Notify->BreakPoint(__FILE__, __LINE__);
        return false;
    }

#ifdef _DEBUG
    const char * Name = R4300iOpcodeName(Command.Hex, PC);
    CPU_Message("  0x%08X %s", PC, Name);
#endif
    switch (Command.op)
    {
    case R4300i_SPECIAL:
        switch (Command.funct)
        {
        case R4300i_SPECIAL_SLL:    case R4300i_SPECIAL_SRL:    case R4300i_SPECIAL_SRA:
        case R4300i_SPECIAL_SLLV:   case R4300i_SPECIAL_SRLV:   case R4300i_SPECIAL_SRAV:
        case R4300i_SPECIAL_MFHI:   case R4300i_SPECIAL_MTHI:   case R4300i_SPECIAL_MFLO:
        case R4300i_SPECIAL_MTLO:   case R4300i_SPECIAL_DSLLV:  case R4300i_SPECIAL_DSRLV:
        case R4300i_SPECIAL_DSRAV:  case R4300i_SPECIAL_ADD:    case R4300i_SPECIAL_ADDU:
        case R4300i_SPECIAL_SUB:    case R4300i_SPECIAL_SUBU:   case R4300i_SPECIAL_AND:
        case R4300i_SPECIAL_OR:     case R4300i_SPECIAL_XOR:    case R4300i_SPECIAL_NOR:
        case R4300i_SPECIAL_SLT:    case R4300i_SPECIAL_SLTU:   case R4300i_SPECIAL_DADD:
        case R4300i_SPECIAL_DADDU:  case R4300i_SPECIAL_DSUB:   case R4300i_SPECIAL_DSUBU:
        case R4300i_SPECIAL_DSLL:   case R4300i_SPECIAL_DSRL:   case R4300i_SPECIAL_DSRA:
        case R4300i_SPECIAL_DSLL32: case R4300i_SPECIAL_DSRL32: case R4300i_SPECIAL_DSRA32:
        case R4300i_SPECIAL_MULT:   case R4300i_SPECIAL_MULTU:  case R4300i_SPECIAL_DIV:
        case R4300i_SPECIAL_DIVU:   case R4300i_SPECIAL_DMULT:  case R4300i_SPECIAL_DMULTU:
        case R4300i_SPECIAL_DDIV:   case R4300i_SPECIAL_DDIVU:
            break;
        case R4300i_SPECIAL_JALR:
        case R4300i_SPECIAL_JR:
            EndBlock = true;
            IncludeDelaySlot = true;
            break;
        case R4300i_SPECIAL_SYSCALL:
        case R4300i_SPECIAL_BREAK:
            EndBlock = true;
            break;
        default:
            g_Notify->BreakPoint(__FILE__, __LINE__);
            return false;
        }
        break;
    case R4300i_REGIMM:
        switch (Command.rt)
        {
        case R4300i_REGIMM_BLTZ:
        case R4300i_REGIMM_BLTZAL:
            TargetPC = PC + ((int16_t)Command.offset << 2) + 4;
            if (TargetPC == PC + 8)
            {
                TargetPC = (uint32_t)-1;
            }
            else
            {
                if (TargetPC == PC && !DelaySlotEffectsCompare(PC, Command.rs, 0))
                {
                    PermLoop = true;
                }
                ContinuePC = PC + 8;
                IncludeDelaySlot = true;
            }
            break;
        case R4300i_REGIMM_BGEZ:
        case R4300i_REGIMM_BGEZAL:
            TargetPC = PC + ((int16_t)Command.offset << 2) + 4;
            if (TargetPC == PC + 8)
            {
                TargetPC = (uint32_t)-1;
            }
            else
            {
                if (TargetPC == PC)
                {
                    if (Command.rs == 0)
                    {
                        TargetPC = (uint32_t)-1;
                        EndBlock = true;
                    }
                    else
                    {
                        if (!DelaySlotEffectsCompare(PC, Command.rs, Command.rt))
                        {
                            PermLoop = true;
                        }
                    }
                }
                if (Command.rs != 0)
                {
                    ContinuePC = PC + 8;
                }
                IncludeDelaySlot = true;
            }
            break;
        case R4300i_REGIMM_BLTZL:
        case R4300i_REGIMM_BGEZL:
            TargetPC = PC + ((int16_t)Command.offset << 2) + 4;
            if (TargetPC == PC)
            {
                if (!DelaySlotEffectsCompare(PC, Command.rs, 0))
                {
                    PermLoop = true;
                }
            }
            ContinuePC = PC + 8;
            LikelyBranch = true;
            IncludeDelaySlot = true;
            break;
        default:
            if (Command.Hex == 0x0407000D)
            {
                EndBlock = true;
                break;
            }
            g_Notify->BreakPoint(__FILE__, __LINE__);
            return false;
        }
        break;
    case R4300i_J:
        TargetPC = (PC & 0xF0000000) + (Command.target << 2);
        if (TargetPC == PC)
        {
            PermLoop = true;
        }
        IncludeDelaySlot = true;
        break;
    case R4300i_JAL:
        EndBlock = true;
        IncludeDelaySlot = true;
        break;
    case R4300i_BEQ:
        TargetPC = PC + ((int16_t)Command.offset << 2) + 4;
        if (TargetPC == PC + 8)
        {
            TargetPC = (uint32_t)-1;
        }
        else
        {
            if (Command.rs != 0 || Command.rt != 0)
            {
                ContinuePC = PC + 8;
            }

            if (TargetPC == PC && !DelaySlotEffectsCompare(PC, Command.rs, Command.rt))
            {
                PermLoop = true;
            }
            IncludeDelaySlot = true;
        }
        break;
    case R4300i_BNE:
    case R4300i_BLEZ:
    case R4300i_BGTZ:
        TargetPC = PC + ((int16_t)Command.offset << 2) + 4;
        if (TargetPC == PC + 8)
        {
            TargetPC = (uint32_t)-1;
        }
        else
        {
            if (TargetPC == PC)
            {
                if (!DelaySlotEffectsCompare(PC, Command.rs, Command.rt))
                {
                    PermLoop = true;
                }
            }
            ContinuePC = PC + 8;
            IncludeDelaySlot = true;
        }
        break;
    case R4300i_CP0:
        switch (Command.rs)
        {
        case R4300i_COP0_MT: case R4300i_COP0_MF:
            break;
        default:
            if ((Command.rs & 0x10) != 0)
            {
                switch (Command.funct)
                {
                case R4300i_COP0_CO_TLBR: case R4300i_COP0_CO_TLBWI:
                case R4300i_COP0_CO_TLBWR: case R4300i_COP0_CO_TLBP:
                    break;
                case R4300i_COP0_CO_ERET:
                    EndBlock = true;
                    break;
                default:
                    g_Notify->BreakPoint(__FILE__, __LINE__);
                    return false;
                }
            }
            else
            {
                g_Notify->BreakPoint(__FILE__, __LINE__);
                return false;
            }
            break;
        }
        break;
    case R4300i_CP1:
        switch (Command.fmt)
        {
        case R4300i_COP1_MF:  case R4300i_COP1_DMF: case R4300i_COP1_CF: case R4300i_COP1_MT:
        case R4300i_COP1_DMT: case R4300i_COP1_CT:  case R4300i_COP1_S:  case R4300i_COP1_D:
        case R4300i_COP1_W:   case R4300i_COP1_L:
            break;
        case R4300i_COP1_BC:
            switch (Command.ft) {
            case R4300i_COP1_BC_BCF:
            case R4300i_COP1_BC_BCT:
                TargetPC = PC + ((int16_t)Command.offset << 2) + 4;
                if (TargetPC == PC + 8)
                {
                    TargetPC = (uint32_t)-1;
                }
                else
                {
                    if (TargetPC == PC)
                    {
                        g_Notify->BreakPoint(__FILE__, __LINE__);
                    }
                    ContinuePC = PC + 8;
                    IncludeDelaySlot = true;
                }
                break;
            case R4300i_COP1_BC_BCFL:
            case R4300i_COP1_BC_BCTL:
                TargetPC = PC + ((int16_t)Command.offset << 2) + 4;
                if (TargetPC == PC)
                {
                    g_Notify->BreakPoint(__FILE__, __LINE__);
                }
                ContinuePC = PC + 8;
                LikelyBranch = true;
                IncludeDelaySlot = true;
                break;
            default:
                g_Notify->BreakPoint(__FILE__, __LINE__);
            }
            break;
        default:
            g_Notify->BreakPoint(__FILE__, __LINE__);
            return false;
        }
        break;
    case R4300i_ANDI:  case R4300i_ORI:    case R4300i_XORI:  case R4300i_LUI:
    case R4300i_ADDI:  case R4300i_ADDIU:  case R4300i_SLTI:  case R4300i_SLTIU:
    case R4300i_DADDI: case R4300i_DADDIU: case R4300i_LDL:   case R4300i_LDR:
    case R4300i_LB:    case R4300i_LH:     case R4300i_LWL:   case R4300i_LW:
    case R4300i_LBU:   case R4300i_LHU:    case R4300i_LWR:   case R4300i_LWU:
    case R4300i_SB:    case R4300i_SH:     case R4300i_SWL:   case R4300i_SW:
    case R4300i_SDL:   case R4300i_SDR:    case R4300i_SWR:   case R4300i_CACHE:
    case R4300i_LL:    case R4300i_LWC1:   case R4300i_LDC1:  case R4300i_LD:
    case R4300i_SC:    case R4300i_SWC1:   case R4300i_SDC1:  case R4300i_SD:
        break;
    case R4300i_BEQL:
        TargetPC = PC + ((int16_t)Command.offset << 2) + 4;
        if (TargetPC == PC)
        {
            if (!DelaySlotEffectsCompare(PC, Command.rs, Command.rt))
            {
                PermLoop = true;
            }
        }
        if (Command.rs != 0 || Command.rt != 0)
        {
            ContinuePC = PC + 8;
        }
        IncludeDelaySlot = true;
        LikelyBranch = true;
        break;
    case R4300i_BNEL:
    case R4300i_BLEZL:
    case R4300i_BGTZL:
        TargetPC = PC + ((int16_t)Command.offset << 2) + 4;
        ContinuePC = PC + 8;
        if (TargetPC == PC)
        {
            if (!DelaySlotEffectsCompare(PC, Command.rs, Command.rt))
            {
                PermLoop = true;
            }
        }
        LikelyBranch = true;
        IncludeDelaySlot = true;
        break;
    default:
        if (Command.Hex == 0x7C1C97C0 ||
            Command.Hex == 0xF1F3F5F7)
        {
            EndBlock = true;
            break;
        }
        g_Notify->BreakPoint(__FILE__, __LINE__);
        return false;
    }
    return true;
}
static bool DelaySlotEffectsJump(uint32_t JumpPC)
{
    OPCODE Command;

    if (!g_MMU->LW_VAddr(JumpPC, Command.Hex))
    {
        return true;
    }

    switch (Command.op)
    {
    case R4300i_SPECIAL:
        switch (Command.funct)
        {
        case R4300i_SPECIAL_JR: return DelaySlotEffectsCompare(JumpPC, Command.rs, 0);
        case R4300i_SPECIAL_JALR: return DelaySlotEffectsCompare(JumpPC, Command.rs, 31);
        }
        break;
    case R4300i_REGIMM:
        switch (Command.rt)
        {
        case R4300i_REGIMM_BLTZ:
        case R4300i_REGIMM_BGEZ:
        case R4300i_REGIMM_BLTZL:
        case R4300i_REGIMM_BGEZL:
        case R4300i_REGIMM_BLTZAL:
        case R4300i_REGIMM_BGEZAL:
            return DelaySlotEffectsCompare(JumpPC, Command.rs, 0);
        }
        break;
    case R4300i_JAL:
    case R4300i_SPECIAL_JALR: return DelaySlotEffectsCompare(JumpPC, 31, 0); break;
    case R4300i_J: return false;
    case R4300i_BEQ:
    case R4300i_BNE:
    case R4300i_BLEZ:
    case R4300i_BGTZ:
        return DelaySlotEffectsCompare(JumpPC, Command.rs, Command.rt);
    case R4300i_CP1:
        switch (Command.fmt)
        {
        case R4300i_COP1_BC:
            switch (Command.ft)
            {
            case R4300i_COP1_BC_BCF:
            case R4300i_COP1_BC_BCT:
            case R4300i_COP1_BC_BCFL:
            case R4300i_COP1_BC_BCTL:
                {
                    bool EffectDelaySlot = false;
                    OPCODE NewCommand;

                    if (!g_MMU->LW_VAddr(JumpPC + 4, NewCommand.Hex))
                    {
                        return true;
                    }

                    if (NewCommand.op == R4300i_CP1)
                    {
                        if (NewCommand.fmt == R4300i_COP1_S && (NewCommand.funct & 0x30) == 0x30)
                        {
                            EffectDelaySlot = true;
                        }
                        if (NewCommand.fmt == R4300i_COP1_D && (NewCommand.funct & 0x30) == 0x30)
                        {
                            EffectDelaySlot = true;
                        }
                    }
                    return EffectDelaySlot;
                }
                break;
            }
            break;
        }
        break;
    case R4300i_BEQL:
    case R4300i_BNEL:
    case R4300i_BLEZL:
    case R4300i_BGTZL:
        return DelaySlotEffectsCompare(JumpPC, Command.rs, Command.rt);
    }
    return true;
}