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; } }
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); }
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; }
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; }