void Interpreter::dcbst(UGeckoInstruction _inst) { // Cache line flush. Since we don't emulate the data cache, we don't need to do anything. // Invalidate the jit block cache on dcbst in case new code has been loaded via the data cache u32 address = Helper_Get_EA_X(_inst); JitInterface::InvalidateICache(address & ~0x1f, 32); }
// Stores Word Conditional indeXed void Interpreter::stwcxd(UGeckoInstruction inst) { const u32 address = Helper_Get_EA_X(inst); if ((address & 0b11) != 0) { GenerateAlignmentException(address); return; } if (m_reserve) { if (address == m_reserve_address) { PowerPC::Write_U32(rGPR[inst.RS], address); if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) { m_reserve = false; PowerPC::SetCRField(0, 2 | PowerPC::GetXER_SO()); return; } } } PowerPC::SetCRField(0, PowerPC::GetXER_SO()); }
// TODO: is this right? is it DSI interruptible? void Interpreter::stswx(UGeckoInstruction inst) { u32 EA = Helper_Get_EA_X(inst); if (UReg_MSR{MSR}.LE) { GenerateAlignmentException(EA); return; } u32 n = (u8)PowerPC::ppcState.xer_stringctrl; int r = inst.RS; int i = 0; while (n > 0) { PowerPC::Write_U8((rGPR[r] >> (24 - i)) & 0xFF, EA); EA++; n--; i += 8; if (i == 32) { i = 0; r = (r + 1) & 0x1f; // wrap } } }
// TODO: is this right? // FIXME: Should rollback if a DSI occurs void Interpreter::lswx(UGeckoInstruction _inst) { u32 EA = Helper_Get_EA_X(_inst); u32 n = rSPR(SPR_XER) & 0x7F; int r = _inst.RD; int i = 0; if (n > 0) { m_GPR[r] = 0; do { u32 TempValue = Memory::Read_U8(EA) << (24 - i); if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) { PanicAlert("DSI exception in lswx."); NOTICE_LOG(POWERPC, "DSI exception in lswx"); return; } m_GPR[r] |= TempValue; EA++; n--; i += 8; if (i == 32) { i = 0; r = (r + 1) & 31; m_GPR[r] = 0; } } while (n > 0); } }
// FIXME: Should rollback if a DSI occurs void Interpreter::lswx(UGeckoInstruction inst) { u32 EA = Helper_Get_EA_X(inst); if (UReg_MSR{MSR}.LE) { GenerateAlignmentException(EA); return; } // Confirmed by hardware test that the zero case doesn't zero rGPR[r] for (u32 n = 0; n < static_cast<u8>(PowerPC::ppcState.xer_stringctrl); n++) { const int reg = (inst.RD + (n >> 2)) & 0x1f; const int offset = (n & 3) << 3; if ((n & 3) == 0) rGPR[reg] = 0; const u32 temp_value = PowerPC::Read_U8(EA) << (24 - offset); if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) { PanicAlert("DSI exception in lswx."); NOTICE_LOG(POWERPC, "DSI exception in lswx"); return; } rGPR[reg] |= temp_value; EA++; } }
void Interpreter::dcbi(UGeckoInstruction _inst) { // Removes a block from data cache. Since we don't emulate the data cache, we don't need to do anything to the data cache // However, we invalidate the jit block cache on dcbi u32 address = Helper_Get_EA_X(_inst); JitInterface::InvalidateICache(address & ~0x1f, 32); }
void Interpreter::lhzx(UGeckoInstruction _inst) { u32 temp = (u32)Memory::Read_U16(Helper_Get_EA_X(_inst)); if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) { m_GPR[_inst.RD] = temp; } }
void Interpreter::dcbz(UGeckoInstruction _inst) { // HACK but works... we think if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bDCBZOFF) Memory::ClearCacheLine(Helper_Get_EA_X(_inst) & (~31)); if (!JitInterface::GetCore()) PowerPC::CheckExceptions(); }
void Interpreter::lwbrx(UGeckoInstruction _inst) { u32 temp = Common::swap32(Memory::Read_U32(Helper_Get_EA_X(_inst))); if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) { m_GPR[_inst.RD] = temp; } }
void Interpreter::dcbz(UGeckoInstruction _inst) { // HACK but works... we think if (!Core::g_CoreStartupParameter.bDCBZOFF) Memory::Memset(Helper_Get_EA_X(_inst) & (~31), 0, 32); if (!JitInterface::GetCore()) PowerPC::CheckExceptions(); }
void Interpreter::lwzx(UGeckoInstruction _inst) { u32 uAddress = Helper_Get_EA_X(_inst); u32 temp = Memory::Read_U32(uAddress); if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) { m_GPR[_inst.RD] = temp; } }
void Interpreter::lhzx(UGeckoInstruction inst) { const u32 temp = (u32)PowerPC::Read_U16(Helper_Get_EA_X(inst)); if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) { rGPR[inst.RD] = temp; } }
void Interpreter::lfsx(UGeckoInstruction _inst) { u32 uTemp = Memory::Read_U32(Helper_Get_EA_X(_inst)); if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) { double value = *(float*)&uTemp; rPS0(_inst.FD) = value; rPS1(_inst.FD) = value; } }
void Interpreter::lfsx(UGeckoInstruction _inst) { u32 uTemp = PowerPC::Read_U32(Helper_Get_EA_X(_inst)); if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) { u64 value = ConvertToDouble(uTemp); riPS0(_inst.FD) = value; riPS1(_inst.FD) = value; } }
void Interpreter::lwzx(UGeckoInstruction inst) { const u32 address = Helper_Get_EA_X(inst); const u32 temp = PowerPC::Read_U32(address); if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) { rGPR[inst.RD] = temp; } }
void Interpreter::dcbst(UGeckoInstruction inst) { // TODO: Implement some sort of L2 emulation. // TODO: Raise DSI if translation fails (except for direct-store segments). // Invalidate the JIT cache here as a heuristic to compensate for // the lack of precise L1 icache emulation in the JIT. (Portable software // should use icbi consistently, but games aren't portable.) const u32 address = Helper_Get_EA_X(inst); JitInterface::InvalidateICache(address & ~0x1f, 32, false); }
void Interpreter::stfsx(UGeckoInstruction inst) { const u32 address = Helper_Get_EA_X(inst); if ((address & 0b11) != 0) { GenerateAlignmentException(address); return; } PowerPC::Write_U32(ConvertToSingle(riPS0(inst.FS)), address); }
void Interpreter::dcbf(UGeckoInstruction _inst) { //This should tell GFX backend to throw out any cached data here // !!! SPEEDUP HACK for OSProtectRange !!! /* u32 tmp1 = PowerPC::HostRead_U32(PC+4); u32 tmp2 = PowerPC::HostRead_U32(PC+8); if ((tmp1 == 0x38630020) && (tmp2 == 0x4200fff8)) { NPC = PC + 12; }*/ u32 address = Helper_Get_EA_X(_inst); JitInterface::InvalidateICache(address & ~0x1f, 32, false); }
void Interpreter::lfdx(UGeckoInstruction inst) { const u32 address = Helper_Get_EA_X(inst); if ((address & 0b11) != 0) { GenerateAlignmentException(address); return; } const u64 temp = PowerPC::Read_U64(address); if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) riPS0(inst.FD) = temp; }
void Interpreter::ecowx(UGeckoInstruction inst) { const u32 EA = Helper_Get_EA_X(inst); if (!(PowerPC::ppcState.spr[SPR_EAR] & 0x80000000)) { GenerateDSIException(EA); return; } if (EA & 3) { GenerateAlignmentException(EA); return; } PowerPC::Write_U32(rGPR[inst.RS], EA); }
void Interpreter::lwarx(UGeckoInstruction inst) { const u32 address = Helper_Get_EA_X(inst); if ((address & 0b11) != 0) { GenerateAlignmentException(address); return; } const u32 temp = PowerPC::Read_U32(address); if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) { rGPR[inst.RD] = temp; m_reserve = true; m_reserve_address = address; } }
void Interpreter::dcbz_l(UGeckoInstruction inst) { if (!HID2.LCE) { GenerateProgramException(); return; } const u32 address = Helper_Get_EA_X(inst); if (!HID0.DCE) { GenerateAlignmentException(address); return; } // FAKE: clear memory instead of clearing the cache block PowerPC::ClearCacheLine(address & (~31)); }
void Interpreter::lfsx(UGeckoInstruction inst) { const u32 address = Helper_Get_EA_X(inst); if ((address & 0b11) != 0) { GenerateAlignmentException(address); return; } const u32 temp = PowerPC::Read_U32(address); if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) { const u64 value = ConvertToDouble(temp); riPS0(inst.FD) = value; riPS1(inst.FD) = value; } }
void Interpreter::stwcxd(UGeckoInstruction _inst) { // Stores Word Conditional indeXed u32 uAddress; if (g_bReserve) { uAddress = Helper_Get_EA_X(_inst); if (uAddress == g_reserveAddr) { Memory::Write_U32(m_GPR[_inst.RS], uAddress); if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) { g_bReserve = false; SetCRField(0, 2 | GetXER_SO()); return; } } } SetCRField(0, GetXER_SO()); }
// TODO: is this right? is it DSI interruptible? void Interpreter::stswx(UGeckoInstruction _inst) { u32 EA = Helper_Get_EA_X(_inst); u32 n = rSPR(SPR_XER) & 0x7F; int r = _inst.RS; int i = 0; while (n > 0) { Memory::Write_U8((m_GPR[r] >> (24 - i)) & 0xFF, EA); EA++; n--; i += 8; if (i == 32) { i = 0; r++; } } }
void Interpreter::dcbz(UGeckoInstruction inst) { // DCBZOFF is a hack to fix certain games which would otherwise require // accurate L2 emulation. if (SConfig::GetInstance().bDCBZOFF) return; const u32 dcbz_addr = Helper_Get_EA_X(inst); if (!HID0.DCE) { GenerateAlignmentException(dcbz_addr); return; } // Hack to stop dcbz/dcbi over low MEM1 trashing memory. if (SConfig::GetInstance().bLowDCBZHack && (dcbz_addr < 0x80008000) && (dcbz_addr >= 0x80000000)) return; // TODO: Implement some sort of L2 emulation. PowerPC::ClearCacheLine(dcbz_addr & (~31)); }
void Interpreter::dcbi(UGeckoInstruction _inst) { // Removes a block from data cache. Since we don't emulate the data cache, we don't need to do anything to the data cache // However, we invalidate the jit block cache on dcbi u32 address = Helper_Get_EA_X(_inst); JitInterface::InvalidateICache(address & ~0x1f, 32, false); // The following detects a situation where the game is writing to the dcache at the address being DMA'd. As we do not // have dcache emulation, invalid data is being DMA'd causing audio glitches. The following code detects this and // enables the DMA to complete instantly before the invalid data is written. Resident Evil 2 & 3 trigger this. u64 dma_in_progress = DSP::DMAInProgress(); if (dma_in_progress != 0) { u32 start_addr = (dma_in_progress >> 32) & Memory::RAM_MASK; u32 end_addr = (dma_in_progress & Memory::RAM_MASK) & 0xffffffff; u32 invalidated_addr = (address & Memory::RAM_MASK) & ~0x1f; if (invalidated_addr >= start_addr && invalidated_addr <= end_addr) { DSP::EnableInstantDMA(); } }
void Interpreter::stwx(UGeckoInstruction _inst) { u32 uAddress = Helper_Get_EA_X(_inst); Memory::Write_U32(m_GPR[_inst.RS], uAddress); }
void Interpreter::sthx(UGeckoInstruction _inst) { Memory::Write_U16((u16)m_GPR[_inst.RS], Helper_Get_EA_X(_inst)); }
void Interpreter::sthbrx(UGeckoInstruction _inst) { Memory::Write_U16(Common::swap16((u16)m_GPR[_inst.RS]), Helper_Get_EA_X(_inst)); }