diff --git a/rpcs3/Emu/Cell/ErrorCodes.h b/rpcs3/Emu/Cell/ErrorCodes.h
index 05445a6aa0..15c0698bb8 100644
--- a/rpcs3/Emu/Cell/ErrorCodes.h
+++ b/rpcs3/Emu/Cell/ErrorCodes.h
@@ -110,9 +110,12 @@ struct ppu_error_code
 	{
 	}
 
+	// Helper
+	enum class not_an_error : s32 {};
+
 	// Silence any error
-	constexpr ppu_error_code(s32 value, const std::nothrow_t&)
-		: value(value)
+	constexpr ppu_error_code(not_an_error value)
+		: value(static_cast<s32>(value))
 	{
 	}
 
@@ -124,7 +127,7 @@ struct ppu_error_code
 };
 
 // Helper macro for silencing possible error checks on returning ppu_error_code values
-#define NOT_AN_ERROR(value) { static_cast<s32>(value), std::nothrow }
+#define NOT_AN_ERROR(...) static_cast<ppu_error_code::not_an_error>(__VA_ARGS__)
 
 template<typename T, typename>
 struct ppu_gpr_cast_impl;
diff --git a/rpcs3/Emu/Cell/Modules/cellAdec.cpp b/rpcs3/Emu/Cell/Modules/cellAdec.cpp
index b6acc1f23c..6214c8fb41 100644
--- a/rpcs3/Emu/Cell/Modules/cellAdec.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellAdec.cpp
@@ -15,7 +15,9 @@ extern "C"
 #include "cellPamf.h"
 #include "cellAdec.h"
 
-LOG_CHANNEL(cellAdec);
+#include <thread>
+
+logs::channel cellAdec("cellAdec", logs::level::notice);
 
 AudioDecoder::AudioDecoder(s32 type, u32 addr, u32 size, vm::ptr<CellAdecCbMsg> func, u32 arg)
 	: type(type)
@@ -468,7 +470,7 @@ void adecOpen(u32 adec_id) // TODO: call from the constructor
 
 	adec.adecCb->cpu_init();
 	adec.adecCb->state -= cpu_state::stop;
-	adec.adecCb->lock_notify();
+	(*adec.adecCb)->lock_notify();
 }
 
 bool adecCheckType(s32 type)
@@ -569,7 +571,7 @@ s32 cellAdecClose(u32 handle)
 	{
 		CHECK_EMU_STATUS;
 
-		std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
+		std::this_thread::sleep_for(1ms); // hack
 	}
 
 	idm::remove<PPUThread>(adec->adecCb->id);
@@ -682,7 +684,7 @@ s32 cellAdecGetPcm(u32 handle, vm::ptr<float> outBuffer)
 	AdecFrame af;
 	if (!adec->frames.try_pop(af))
 	{
-		//std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
+		//std::this_thread::sleep_for(1ms); // hack
 		return CELL_ADEC_ERROR_EMPTY;
 	}
 
@@ -798,7 +800,7 @@ s32 cellAdecGetPcmItem(u32 handle, vm::pptr<CellAdecPcmItem> pcmItem)
 	AdecFrame af;
 	if (!adec->frames.try_peek(af))
 	{
-		//std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
+		//std::this_thread::sleep_for(1ms); // hack
 		return CELL_ADEC_ERROR_EMPTY;
 	}
 
diff --git a/rpcs3/Emu/Cell/Modules/cellAtrac.cpp b/rpcs3/Emu/Cell/Modules/cellAtrac.cpp
index d251fe9bcb..0a6fb4360e 100644
--- a/rpcs3/Emu/Cell/Modules/cellAtrac.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellAtrac.cpp
@@ -4,7 +4,7 @@
 
 #include "cellAtrac.h"
 
-LOG_CHANNEL(cellAtrac);
+logs::channel cellAtrac("cellAtrac", logs::level::notice);
 
 s32 cellAtracSetDataAndGetMemSize(vm::ptr<CellAtracHandle> pHandle, vm::ptr<u8> pucBufferAddr, u32 uiReadByte, u32 uiBufferByte, vm::ptr<u32> puiWorkMemByte)
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellAtracMulti.cpp b/rpcs3/Emu/Cell/Modules/cellAtracMulti.cpp
index 75e1263f62..c7dac5b60b 100644
--- a/rpcs3/Emu/Cell/Modules/cellAtracMulti.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellAtracMulti.cpp
@@ -4,7 +4,7 @@
 
 #include "cellAtracMulti.h"
 
-LOG_CHANNEL(cellAtracMulti);
+logs::channel cellAtracMulti("cellAtracMulti", logs::level::notice);
 
 s32 cellAtracMultiSetDataAndGetMemSize(vm::ptr<CellAtracMultiHandle> pHandle, vm::ptr<u8> pucBufferAddr, u32 uiReadByte, u32 uiBufferByte, u32 uiOutputChNum, vm::ptr<s32> piTrackArray, vm::ptr<u32> puiWorkMemByte)
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellAudio.cpp b/rpcs3/Emu/Cell/Modules/cellAudio.cpp
index 9a119a0865..a6364a6ed0 100644
--- a/rpcs3/Emu/Cell/Modules/cellAudio.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellAudio.cpp
@@ -1,4 +1,5 @@
 #include "stdafx.h"
+#include "Utilities/Config.h"
 #include "Emu/System.h"
 #include "Emu/IdManager.h"
 #include "Emu/Cell/PPUModule.h"
@@ -8,7 +9,9 @@
 #include "Emu/Audio/AudioThread.h"
 #include "cellAudio.h"
 
-LOG_CHANNEL(cellAudio);
+#include <thread>
+
+logs::channel cellAudio("cellAudio", logs::level::notice);
 
 cfg::bool_entry g_cfg_audio_dump_to_file(cfg::root.audio, "Dump to file");
 cfg::bool_entry g_cfg_audio_convert_to_u16(cfg::root.audio, "Convert to 16 bit");
diff --git a/rpcs3/Emu/Cell/Modules/cellAudioOut.cpp b/rpcs3/Emu/Cell/Modules/cellAudioOut.cpp
index 8383a7657f..0472272b0a 100644
--- a/rpcs3/Emu/Cell/Modules/cellAudioOut.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellAudioOut.cpp
@@ -3,7 +3,7 @@
 
 #include "cellAudioOut.h"
 
-extern _log::channel cellSysutil;
+extern logs::channel cellSysutil;
 
 s32 cellAudioOutGetSoundAvailability(u32 audioOut, u32 type, u32 fs, u32 option)
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellAvconfExt.cpp b/rpcs3/Emu/Cell/Modules/cellAvconfExt.cpp
index 7a005dc34a..fc7bb16c26 100644
--- a/rpcs3/Emu/Cell/Modules/cellAvconfExt.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellAvconfExt.cpp
@@ -6,7 +6,7 @@
 #include "cellAudioOut.h"
 #include "cellVideoOut.h"
 
-LOG_CHANNEL(cellAvconfExt);
+logs::channel cellAvconfExt("cellAvconfExt", logs::level::notice);
 
 vm::gvar<f32> g_gamma; // TODO
 
diff --git a/rpcs3/Emu/Cell/Modules/cellBgdl.cpp b/rpcs3/Emu/Cell/Modules/cellBgdl.cpp
index b83c0fa791..8847bafebd 100644
--- a/rpcs3/Emu/Cell/Modules/cellBgdl.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellBgdl.cpp
@@ -2,7 +2,7 @@
 #include "Emu/System.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellBGDL);
+logs::channel cellBGDL("cellBGDL", logs::level::notice);
 
 // Return Codes
 enum
diff --git a/rpcs3/Emu/Cell/Modules/cellCamera.cpp b/rpcs3/Emu/Cell/Modules/cellCamera.cpp
index 6a2c491a43..9c445f1a65 100644
--- a/rpcs3/Emu/Cell/Modules/cellCamera.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellCamera.cpp
@@ -1,11 +1,12 @@
 #include "stdafx.h"
+#include "Utilities/Config.h"
 #include "Emu/IdManager.h"
 #include "Emu/System.h"
 #include "Emu/Cell/PPUModule.h"
 
 #include "cellCamera.h"
 
-LOG_CHANNEL(cellCamera);
+logs::channel cellCamera("cellCamera", logs::level::notice);
 
 cfg::map_entry<bool> g_cfg_camera(cfg::root.io, "Camera",
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellCelp8Enc.cpp b/rpcs3/Emu/Cell/Modules/cellCelp8Enc.cpp
index bb0b24b9ef..b834d9b57d 100644
--- a/rpcs3/Emu/Cell/Modules/cellCelp8Enc.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellCelp8Enc.cpp
@@ -2,7 +2,7 @@
 #include "Emu/System.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellCelp8Enc);
+logs::channel cellCelp8Enc("cellCelp8Enc", logs::level::notice);
 
 // Return Codes
 enum
diff --git a/rpcs3/Emu/Cell/Modules/cellCelpEnc.cpp b/rpcs3/Emu/Cell/Modules/cellCelpEnc.cpp
index bb551877bb..0cd61d2504 100644
--- a/rpcs3/Emu/Cell/Modules/cellCelpEnc.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellCelpEnc.cpp
@@ -2,7 +2,7 @@
 #include "Emu/System.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellCelpEnc);
+logs::channel cellCelpEnc("cellCelpEnc", logs::level::notice);
 
 // Return Codes
 enum
diff --git a/rpcs3/Emu/Cell/Modules/cellDaisy.cpp b/rpcs3/Emu/Cell/Modules/cellDaisy.cpp
index bd82c4d31b..4f37bc46e7 100644
--- a/rpcs3/Emu/Cell/Modules/cellDaisy.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellDaisy.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellDaisy);
+logs::channel cellDaisy("cellDaisy", logs::level::notice);
 
 s32 _ZN4cell5Daisy17LFQueue2PushCloseEPNS0_8LFQueue2EPFiPvjE()
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellDmux.cpp b/rpcs3/Emu/Cell/Modules/cellDmux.cpp
index cb86cb76bb..7ea8c97263 100644
--- a/rpcs3/Emu/Cell/Modules/cellDmux.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellDmux.cpp
@@ -6,7 +6,9 @@
 #include "cellPamf.h"
 #include "cellDmux.h"
 
-LOG_CHANNEL(cellDmux);
+#include <thread>
+
+logs::channel cellDmux("cellDmux", logs::level::notice);
 
 PesHeader::PesHeader(DemuxerStream& stream)
 	: pts(CODEC_TS_INVALID)
@@ -142,7 +144,7 @@ void ElementaryStream::push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool ra
 	u32 addr;
 	{
 		std::lock_guard<std::mutex> lock(m_mutex);
-		ASSERT(!is_full(size));
+		VERIFY(!is_full(size));
 
 		if (put + size + 128 > memAddr + memSize)
 		{
@@ -183,7 +185,7 @@ void ElementaryStream::push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool ra
 		put_count++;
 	}
 
-	ASSERT(entries.push(addr, &dmux->is_closed));
+	VERIFY(entries.push(addr, &dmux->is_closed));
 }
 
 void ElementaryStream::push(DemuxerStream& stream, u32 size)
@@ -447,7 +449,7 @@ void dmuxOpen(u32 dmux_id) // TODO: call from the constructor
 						if (es.raw_data.size() > 1024 * 1024)
 						{
 							stream = backup;
-							std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
+							std::this_thread::sleep_for(1ms); // hack
 							continue;
 						}
 
@@ -543,7 +545,7 @@ void dmuxOpen(u32 dmux_id) // TODO: call from the constructor
 						if (es.isfull(old_size))
 						{
 							stream = backup;
-							std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
+							std::this_thread::sleep_for(1ms); // hack
 							continue;
 						}
 
@@ -711,7 +713,7 @@ void dmuxOpen(u32 dmux_id) // TODO: call from the constructor
 					{
 						if (Emu.IsStopped() || dmux.is_closed) break;
 
-						std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
+						std::this_thread::sleep_for(1ms); // hack
 					}
 
 					es.push_au(old_size, es.last_dts, es.last_pts, stream.userdata, false, 0);
@@ -759,7 +761,7 @@ void dmuxOpen(u32 dmux_id) // TODO: call from the constructor
 
 	dmux.dmuxCb->cpu_init();
 	dmux.dmuxCb->state -= cpu_state::stop;
-	dmux.dmuxCb->lock_notify();
+	(*dmux.dmuxCb)->lock_notify();
 }
 
 s32 cellDmuxQueryAttr(vm::cptr<CellDmuxType> type, vm::ptr<CellDmuxAttr> attr)
@@ -865,7 +867,7 @@ s32 cellDmuxClose(u32 handle)
 			return CELL_OK;
 		}
 
-		std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
+		std::this_thread::sleep_for(1ms); // hack
 	}
 
 	idm::remove<PPUThread>(dmux->dmuxCb->id);
@@ -886,7 +888,7 @@ s32 cellDmuxSetStream(u32 handle, u32 streamAddress, u32 streamSize, b8 disconti
 
 	if (dmux->is_running.exchange(true))
 	{
-		//std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
+		//std::this_thread::sleep_for(1ms); // hack
 		return CELL_DMUX_ERROR_BUSY;
 	}
 
@@ -943,7 +945,7 @@ s32 cellDmuxResetStreamAndWaitDone(u32 handle)
 			cellDmux.warning("cellDmuxResetStreamAndWaitDone(%d) aborted", handle);
 			return CELL_OK;
 		}
-		std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
+		std::this_thread::sleep_for(1ms); // hack
 	}
 
 	return CELL_OK;
diff --git a/rpcs3/Emu/Cell/Modules/cellFiber.cpp b/rpcs3/Emu/Cell/Modules/cellFiber.cpp
index ba744dc37a..8229bb859d 100644
--- a/rpcs3/Emu/Cell/Modules/cellFiber.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellFiber.cpp
@@ -4,7 +4,7 @@
 
 #include "cellFiber.h"
 
-LOG_CHANNEL(cellFiber);
+logs::channel cellFiber("cellFiber", logs::level::notice);
 
 s32 _cellFiberPpuInitialize()
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellFont.cpp b/rpcs3/Emu/Cell/Modules/cellFont.cpp
index 0d3f10c2a5..cc3df1b933 100644
--- a/rpcs3/Emu/Cell/Modules/cellFont.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellFont.cpp
@@ -8,7 +8,7 @@
 
 #include "cellFont.h"
 
-LOG_CHANNEL(cellFont);
+logs::channel cellFont("cellFont", logs::level::notice);
 
 // Functions
 s32 cellFontInitializeWithRevision(u64 revisionFlags, vm::ptr<CellFontConfig> config)
diff --git a/rpcs3/Emu/Cell/Modules/cellFontFT.cpp b/rpcs3/Emu/Cell/Modules/cellFontFT.cpp
index 5821d440c6..20b3167a9f 100644
--- a/rpcs3/Emu/Cell/Modules/cellFontFT.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellFontFT.cpp
@@ -3,7 +3,7 @@
 
 #include "cellFontFT.h"
 
-LOG_CHANNEL(cellFontFT);
+logs::channel cellFontFT("cellFontFT", logs::level::notice);
 
 s32 cellFontInitLibraryFreeTypeWithRevision(u64 revisionFlags, vm::ptr<CellFontLibraryConfigFT> config, vm::pptr<CellFontLibrary> lib)
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellFs.cpp b/rpcs3/Emu/Cell/Modules/cellFs.cpp
index 220df6262a..1ac9a05dfe 100644
--- a/rpcs3/Emu/Cell/Modules/cellFs.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellFs.cpp
@@ -8,7 +8,7 @@
 
 #include "Utilities/StrUtil.h"
 
-LOG_CHANNEL(cellFs);
+logs::channel cellFs("cellFs", logs::level::notice);
 
 s32 cellFsOpen(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, vm::cptr<void> arg, u64 size)
 {
@@ -527,7 +527,7 @@ s32 cellFsStReadStart(u32 fd, u64 offset, u64 size)
 				}
 			}
 
-			file->cv.wait_for(lock, std::chrono::milliseconds(1));
+			file->cv.wait_for(lock, 1ms);
 		}
 
 		file->st_status.compare_and_swap(SSS_STOPPED, SSS_INITIALIZED);
@@ -688,7 +688,7 @@ s32 cellFsStReadWait(u32 fd, u64 size)
 	{
 		CHECK_EMU_STATUS;
 
-		file->cv.wait_for(lock, std::chrono::milliseconds(1));
+		file->cv.wait_for(lock, 1ms);
 	}
 	
 	return CELL_OK;
diff --git a/rpcs3/Emu/Cell/Modules/cellGame.cpp b/rpcs3/Emu/Cell/Modules/cellGame.cpp
index 632d72000b..32bace6827 100644
--- a/rpcs3/Emu/Cell/Modules/cellGame.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellGame.cpp
@@ -10,7 +10,9 @@
 #include "Loader/PSF.h"
 #include "Utilities/StrUtil.h"
 
-LOG_CHANNEL(cellGame);
+#include <thread>
+
+logs::channel cellGame("cellGame", logs::level::notice);
 
 // Normal content directory (if is_temporary is not involved):
 // contentInfo = dir
@@ -308,7 +310,7 @@ ppu_error_code cellGameContentPermit(vm::ptr<char[CELL_GAME_PATH_MAX]> contentIn
 		}
 
 		// Create PARAM.SFO
-		fs::file(dir + "/PARAM.SFO", fs::rewrite).write(psf::save_object(prm->sfo));
+		psf::save_object(fs::file(dir + "/PARAM.SFO", fs::rewrite), prm->sfo);
 
 		// Disable deletion
 		prm->is_temporary = false;
@@ -555,7 +557,7 @@ ppu_error_code cellGameGetParamString(s32 id, vm::ptr<char> buf, u32 bufsize)
 	std::string&& value = psf::get_string(prm->sfo, key);
 	value.resize(bufsize - 1);
 
-	std::copy_n(value.c_str(), value.size() + 1, buf.get_ptr());
+	std::memcpy(buf.get_ptr(), value.c_str(), bufsize);
 
 	return CELL_OK;
 }
diff --git a/rpcs3/Emu/Cell/Modules/cellGameExec.cpp b/rpcs3/Emu/Cell/Modules/cellGameExec.cpp
index 9367db8796..411f51043a 100644
--- a/rpcs3/Emu/Cell/Modules/cellGameExec.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellGameExec.cpp
@@ -3,7 +3,7 @@
 
 #include "cellGame.h"
 
-LOG_CHANNEL(cellGameExec);
+logs::channel cellGameExec("cellGameExec", logs::level::notice);
 
 s32 cellGameSetExitParam()
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp b/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp
index cb290a71a1..962218925c 100644
--- a/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp
@@ -8,7 +8,9 @@
 #include "Emu/RSX/GSRender.h"
 #include "cellGcmSys.h"
 
-LOG_CHANNEL(cellGcmSys);
+#include <thread>
+
+logs::channel cellGcmSys("cellGcmSys", logs::level::notice);
 
 extern s32 cellGcmCallback(vm::ptr<CellGcmContextData> context, u32 count);
 
@@ -933,7 +935,7 @@ s32 cellGcmMapEaIoAddressWithFlags(u32 ea, u32 io, u32 size, u32 flags)
 {
 	cellGcmSys.warning("cellGcmMapEaIoAddressWithFlags(ea=0x%x, io=0x%x, size=0x%x, flags=0x%x)", ea, io, size, flags);
 
-	ASSERT(flags == 2 /*CELL_GCM_IOMAP_FLAG_STRICT_ORDERING*/);
+	VERIFY(flags == 2 /*CELL_GCM_IOMAP_FLAG_STRICT_ORDERING*/);
 
 	return gcmMapEaIoAddress(ea, io, size, true);
 }
@@ -1257,7 +1259,7 @@ static std::pair<u32, u32> getNextCommandBufferBeginEnd(u32 current)
 static u32 getOffsetFromAddress(u32 address)
 {
 	const u32 upper = offsetTable.ioAddress[address >> 20]; // 12 bits
-	Expects(upper != 0xFFFF);
+	EXPECTS(upper != 0xFFFF);
 	return (upper << 20) | (address & 0xFFFFF);
 }
 
diff --git a/rpcs3/Emu/Cell/Modules/cellGem.cpp b/rpcs3/Emu/Cell/Modules/cellGem.cpp
index f10e41ea58..a33cd86879 100644
--- a/rpcs3/Emu/Cell/Modules/cellGem.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellGem.cpp
@@ -4,7 +4,7 @@
 
 #include "cellGem.h"
 
-LOG_CHANNEL(cellGem);
+logs::channel cellGem("cellGem", logs::level::notice);
 
 struct gem_t
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellGifDec.cpp b/rpcs3/Emu/Cell/Modules/cellGifDec.cpp
index 64c10ca7cf..f5420ed299 100644
--- a/rpcs3/Emu/Cell/Modules/cellGifDec.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellGifDec.cpp
@@ -9,7 +9,7 @@
 #include "Emu/Cell/lv2/sys_fs.h"
 #include "cellGifDec.h"
 
-LOG_CHANNEL(cellGifDec);
+logs::channel cellGifDec("cellGifDec", logs::level::notice);
 
 // cellGifDec aliases (only for cellGifDec.cpp)
 using PPMainHandle = vm::pptr<GifDecoder>;
diff --git a/rpcs3/Emu/Cell/Modules/cellHttp.cpp b/rpcs3/Emu/Cell/Modules/cellHttp.cpp
index 46328b1cf7..e8036bdc30 100644
--- a/rpcs3/Emu/Cell/Modules/cellHttp.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellHttp.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellHttp);
+logs::channel cellHttp("cellHttp", logs::level::notice);
 
 s32 cellHttpInit()
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellHttpUtil.cpp b/rpcs3/Emu/Cell/Modules/cellHttpUtil.cpp
index 35c7c5328c..c68c4344ce 100644
--- a/rpcs3/Emu/Cell/Modules/cellHttpUtil.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellHttpUtil.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellHttpUtil);
+logs::channel cellHttpUtil("cellHttpUtil", logs::level::notice);
 
 s32 cellHttpUtilParseUri()
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellImejp.cpp b/rpcs3/Emu/Cell/Modules/cellImejp.cpp
index 278103fd3f..4a56d547de 100644
--- a/rpcs3/Emu/Cell/Modules/cellImejp.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellImejp.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellImeJp);
+logs::channel cellImeJp("cellImeJp", logs::level::notice);
 
 // Return Codes
 enum
diff --git a/rpcs3/Emu/Cell/Modules/cellJpgDec.cpp b/rpcs3/Emu/Cell/Modules/cellJpgDec.cpp
index 3fcb2a967e..2cfc9f5efc 100644
--- a/rpcs3/Emu/Cell/Modules/cellJpgDec.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellJpgDec.cpp
@@ -9,7 +9,7 @@
 #include "Emu/Cell/lv2/sys_fs.h"
 #include "cellJpgDec.h"
 
-LOG_CHANNEL(cellJpgDec);
+logs::channel cellJpgDec("cellJpgDec", logs::level::notice);
 
 s32 cellJpgDecCreate(u32 mainHandle, u32 threadInParam, u32 threadOutParam)
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellJpgEnc.cpp b/rpcs3/Emu/Cell/Modules/cellJpgEnc.cpp
index 605a04e930..96a46b3900 100644
--- a/rpcs3/Emu/Cell/Modules/cellJpgEnc.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellJpgEnc.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellJpgEnc);
+logs::channel cellJpgEnc("cellJpgEnc", logs::level::notice);
 
 // Error Codes
 enum
diff --git a/rpcs3/Emu/Cell/Modules/cellKb.cpp b/rpcs3/Emu/Cell/Modules/cellKb.cpp
index a4647993b1..08d69ae94d 100644
--- a/rpcs3/Emu/Cell/Modules/cellKb.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellKb.cpp
@@ -6,7 +6,7 @@
 #include "Emu/Io/KeyboardHandler.h"
 #include "cellKb.h"
 
-extern _log::channel sys_io;
+extern logs::channel sys_io;
 
 s32 cellKbInit(u32 max_connect)
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellKey2char.cpp b/rpcs3/Emu/Cell/Modules/cellKey2char.cpp
index 3a51a3c347..9ca2554aea 100644
--- a/rpcs3/Emu/Cell/Modules/cellKey2char.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellKey2char.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellKey2char);
+logs::channel cellKey2char("cellKey2char", logs::level::notice);
 
 // Return Codes
 enum
diff --git a/rpcs3/Emu/Cell/Modules/cellL10n.cpp b/rpcs3/Emu/Cell/Modules/cellL10n.cpp
index 73ec6cad6c..7dbc9c3da5 100644
--- a/rpcs3/Emu/Cell/Modules/cellL10n.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellL10n.cpp
@@ -14,7 +14,7 @@ typedef const char *HostCode;
 
 #include "cellL10n.h"
 
-LOG_CHANNEL(cellL10n);
+logs::channel cellL10n("cellL10n", logs::level::notice);
 
 // Translate code id to code name. some codepage may has another name.
 // If this makes your compilation fail, try replace the string code with one in "iconv -l"
diff --git a/rpcs3/Emu/Cell/Modules/cellMic.cpp b/rpcs3/Emu/Cell/Modules/cellMic.cpp
index b0cd2b8ba7..059d508642 100644
--- a/rpcs3/Emu/Cell/Modules/cellMic.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellMic.cpp
@@ -4,7 +4,7 @@
 
 #include "cellMic.h"
 
-LOG_CHANNEL(cellMic);
+logs::channel cellMic("cellMic", logs::level::notice);
 
 s32 cellMicInit()
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellMouse.cpp b/rpcs3/Emu/Cell/Modules/cellMouse.cpp
index e9cea73dc8..fd91435ed9 100644
--- a/rpcs3/Emu/Cell/Modules/cellMouse.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellMouse.cpp
@@ -6,7 +6,7 @@
 #include "Emu/Io/MouseHandler.h"
 #include "cellMouse.h"
 
-extern _log::channel sys_io;
+extern logs::channel sys_io;
 
 s32 cellMouseInit(u32 max_connect)
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp b/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp
index 880a126d1c..e4c7fe221c 100644
--- a/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp
@@ -6,7 +6,9 @@
 #include "cellSysutil.h"
 #include "cellMsgDialog.h"
 
-extern _log::channel cellSysutil;
+#include <thread>
+
+extern logs::channel cellSysutil;
 
 s32 cellMsgDialogOpen()
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellMusic.cpp b/rpcs3/Emu/Cell/Modules/cellMusic.cpp
index 6fe8cd4146..7cd839bfdd 100644
--- a/rpcs3/Emu/Cell/Modules/cellMusic.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellMusic.cpp
@@ -5,7 +5,7 @@
 
 #include "cellMusic.h"
 
-LOG_CHANNEL(cellMusic);
+logs::channel cellMusic("cellMusic", logs::level::notice);
 
 struct music2_t
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellMusicDecode.cpp b/rpcs3/Emu/Cell/Modules/cellMusicDecode.cpp
index dcb43e75a8..f850afa90d 100644
--- a/rpcs3/Emu/Cell/Modules/cellMusicDecode.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellMusicDecode.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellMusicDecode);
+logs::channel cellMusicDecode("cellMusicDecode", logs::level::notice);
 
 // Return Codes
 enum
diff --git a/rpcs3/Emu/Cell/Modules/cellMusicExport.cpp b/rpcs3/Emu/Cell/Modules/cellMusicExport.cpp
index 0c614e907e..924306c3b3 100644
--- a/rpcs3/Emu/Cell/Modules/cellMusicExport.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellMusicExport.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellMusicExport);
+logs::channel cellMusicExport("cellMusicExport", logs::level::notice);
 
 // Return Codes
 enum
diff --git a/rpcs3/Emu/Cell/Modules/cellNetCtl.cpp b/rpcs3/Emu/Cell/Modules/cellNetCtl.cpp
index 65ceda8e18..4114c89444 100644
--- a/rpcs3/Emu/Cell/Modules/cellNetCtl.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellNetCtl.cpp
@@ -1,4 +1,5 @@
 #include "stdafx.h"
+#include "Utilities/Config.h"
 #include "Emu/System.h"
 #include "Emu/Cell/PPUModule.h"
 
@@ -7,7 +8,7 @@
 
 #include "Utilities/StrUtil.h"
 
-LOG_CHANNEL(cellNetCtl);
+logs::channel cellNetCtl("cellNetCtl", logs::level::notice);
 
 cfg::map_entry<s32> g_cfg_net_status(cfg::root.net, "Connection status",
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp b/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp
index ccc0c51f7f..605d59578a 100644
--- a/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellOskDialog);
+logs::channel cellOskDialog("cellOskDialog", logs::level::notice);
 
 s32 cellOskDialogLoadAsync()
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellOvis.cpp b/rpcs3/Emu/Cell/Modules/cellOvis.cpp
index 49e22da87f..2b4716f959 100644
--- a/rpcs3/Emu/Cell/Modules/cellOvis.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellOvis.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellOvis);
+logs::channel cellOvis("cellOvis", logs::level::notice);
 
 // Return Codes
 enum
diff --git a/rpcs3/Emu/Cell/Modules/cellPad.cpp b/rpcs3/Emu/Cell/Modules/cellPad.cpp
index f0441cc739..bed38f18de 100644
--- a/rpcs3/Emu/Cell/Modules/cellPad.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellPad.cpp
@@ -6,7 +6,7 @@
 #include "Emu/Io/PadHandler.h"
 #include "cellPad.h"
 
-extern _log::channel sys_io;
+extern logs::channel sys_io;
 
 s32 cellPadInit(u32 max_connect)
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellPamf.cpp b/rpcs3/Emu/Cell/Modules/cellPamf.cpp
index fcd64720b6..a4a05d92f7 100644
--- a/rpcs3/Emu/Cell/Modules/cellPamf.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellPamf.cpp
@@ -12,12 +12,12 @@ bool squeue_test_exit()
 	return Emu.IsStopped();
 }
 
-LOG_CHANNEL(cellPamf);
+logs::channel cellPamf("cellPamf", logs::level::notice);
 
 s32 pamfStreamTypeToEsFilterId(u8 type, u8 ch, CellCodecEsFilterId& pEsFilterId)
 {
 	// convert type and ch to EsFilterId
-	Expects(ch < 16);
+	EXPECTS(ch < 16);
 	pEsFilterId.supplementalInfo1 = type == CELL_PAMF_STREAM_TYPE_AVC;
 	pEsFilterId.supplementalInfo2 = 0;
 	
@@ -117,7 +117,7 @@ s32 pamfStreamTypeToEsFilterId(u8 type, u8 ch, CellCodecEsFilterId& pEsFilterId)
 u8 pamfGetStreamType(vm::ptr<CellPamfReader> pSelf, u32 stream)
 {
 	// TODO: get stream type correctly
-	Expects(stream < (u32)pSelf->pAddr->stream_count);
+	EXPECTS(stream < (u32)pSelf->pAddr->stream_count);
 	auto& header = pSelf->pAddr->stream_headers[stream];
 
 	switch (header.type)
@@ -138,7 +138,7 @@ u8 pamfGetStreamType(vm::ptr<CellPamfReader> pSelf, u32 stream)
 u8 pamfGetStreamChannel(vm::ptr<CellPamfReader> pSelf, u32 stream)
 {
 	// TODO: get stream channel correctly
-	Expects(stream < (u32)pSelf->pAddr->stream_count);
+	EXPECTS(stream < (u32)pSelf->pAddr->stream_count);
 	auto& header = pSelf->pAddr->stream_headers[stream];
 
 	switch (header.type)
@@ -146,29 +146,29 @@ u8 pamfGetStreamChannel(vm::ptr<CellPamfReader> pSelf, u32 stream)
 	case 0x1b: // AVC
 	case 0x02: // M2V
 	{
-		Expects((header.fid_major & 0xf0) == 0xe0 && header.fid_minor == 0);
+		EXPECTS((header.fid_major & 0xf0) == 0xe0 && header.fid_minor == 0);
 		return header.fid_major % 16;
 	}
 		
 	case 0xdc: // ATRAC3PLUS
 	{
-		Expects(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0);
+		EXPECTS(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0);
 		return header.fid_minor % 16;
 	}
 		
 	case 0x80: // LPCM
 	{
-		Expects(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x40);
+		EXPECTS(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x40);
 		return header.fid_minor % 16;
 	}
 	case 0x81: // AC3
 	{
-		Expects(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x30);
+		EXPECTS(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x30);
 		return header.fid_minor % 16;
 	}
 	case 0xdd:
 	{
-		Expects(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x20);
+		EXPECTS(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x20);
 		return header.fid_minor % 16;
 	}
 	}
@@ -454,7 +454,7 @@ s32 cellPamfReaderGetEsFilterId(vm::ptr<CellPamfReader> pSelf, vm::ptr<CellCodec
 
 	// always returns CELL_OK
 
-	Expects((u32)pSelf->stream < (u32)pSelf->pAddr->stream_count);
+	EXPECTS((u32)pSelf->stream < (u32)pSelf->pAddr->stream_count);
 	auto& header = pSelf->pAddr->stream_headers[pSelf->stream];
 	pEsFilterId->filterIdMajor = header.fid_major;
 	pEsFilterId->filterIdMinor = header.fid_minor;
@@ -467,7 +467,7 @@ s32 cellPamfReaderGetStreamInfo(vm::ptr<CellPamfReader> pSelf, vm::ptr<void> pIn
 {
 	cellPamf.warning("cellPamfReaderGetStreamInfo(pSelf=*0x%x, pInfo=*0x%x, size=%d)", pSelf, pInfo, size);
 
-	Expects((u32)pSelf->stream < (u32)pSelf->pAddr->stream_count);
+	EXPECTS((u32)pSelf->stream < (u32)pSelf->pAddr->stream_count);
 	auto& header = pSelf->pAddr->stream_headers[pSelf->stream];
 	const u8 type = pamfGetStreamType(pSelf, pSelf->stream);
 	const u8 ch = pamfGetStreamChannel(pSelf, pSelf->stream);
diff --git a/rpcs3/Emu/Cell/Modules/cellPamf.h b/rpcs3/Emu/Cell/Modules/cellPamf.h
index 4dd45b3256..60d042e77e 100644
--- a/rpcs3/Emu/Cell/Modules/cellPamf.h
+++ b/rpcs3/Emu/Cell/Modules/cellPamf.h
@@ -400,6 +400,8 @@ CHECK_SIZE(CellPamfReader, 128);
 
 s32 cellPamfReaderInitialize(vm::ptr<CellPamfReader> pSelf, vm::cptr<PamfHeader> pAddr, u64 fileSize, u32 attribute);
 
+#include <mutex>
+#include <condition_variable>
 
 extern const std::function<bool()> SQUEUE_ALWAYS_EXIT;
 extern const std::function<bool()> SQUEUE_NEVER_EXIT;
@@ -462,8 +464,8 @@ public:
 
 		while (u32 res = m_sync.atomic_op([&pos](squeue_sync_var_t& sync) -> u32
 		{
-			Expects(sync.count <= sq_size);
-			Expects(sync.position < sq_size);
+			EXPECTS(sync.count <= sq_size);
+			EXPECTS(sync.position < sq_size);
 
 			if (sync.push_lock)
 			{
@@ -492,9 +494,9 @@ public:
 
 		m_sync.atomic_op([](squeue_sync_var_t& sync)
 		{
-			Expects(sync.count <= sq_size);
-			Expects(sync.position < sq_size);
-			Expects(sync.push_lock);
+			EXPECTS(sync.count <= sq_size);
+			EXPECTS(sync.position < sq_size);
+			EXPECTS(sync.push_lock);
 			sync.push_lock = 0;
 			sync.count++;
 		});
@@ -525,8 +527,8 @@ public:
 
 		while (u32 res = m_sync.atomic_op([&pos](squeue_sync_var_t& sync) -> u32
 		{
-			Expects(sync.count <= sq_size);
-			Expects(sync.position < sq_size);
+			EXPECTS(sync.count <= sq_size);
+			EXPECTS(sync.position < sq_size);
 
 			if (!sync.count)
 			{
@@ -555,9 +557,9 @@ public:
 
 		m_sync.atomic_op([](squeue_sync_var_t& sync)
 		{
-			Expects(sync.count <= sq_size);
-			Expects(sync.position < sq_size);
-			Expects(sync.pop_lock);
+			EXPECTS(sync.count <= sq_size);
+			EXPECTS(sync.position < sq_size);
+			EXPECTS(sync.pop_lock);
 			sync.pop_lock = 0;
 			sync.position++;
 			sync.count--;
@@ -589,13 +591,13 @@ public:
 
 	bool peek(T& data, u32 start_pos, const std::function<bool()>& test_exit)
 	{
-		Expects(start_pos < sq_size);
+		EXPECTS(start_pos < sq_size);
 		u32 pos = 0;
 
 		while (u32 res = m_sync.atomic_op([&pos, start_pos](squeue_sync_var_t& sync) -> u32
 		{
-			Expects(sync.count <= sq_size);
-			Expects(sync.position < sq_size);
+			EXPECTS(sync.count <= sq_size);
+			EXPECTS(sync.position < sq_size);
 
 			if (sync.count <= start_pos)
 			{
@@ -624,9 +626,9 @@ public:
 
 		m_sync.atomic_op([](squeue_sync_var_t& sync)
 		{
-			Expects(sync.count <= sq_size);
-			Expects(sync.position < sq_size);
-			Expects(sync.pop_lock);
+			EXPECTS(sync.count <= sq_size);
+			EXPECTS(sync.position < sq_size);
+			EXPECTS(sync.pop_lock);
 			sync.pop_lock = 0;
 		});
 
@@ -665,7 +667,7 @@ public:
 	public:
 		T& operator [] (u32 index)
 		{
-			Expects(index < m_count);
+			EXPECTS(index < m_count);
 			index += m_pos;
 			index = index < sq_size ? index : index - sq_size;
 			return m_data[index];
@@ -678,8 +680,8 @@ public:
 
 		while (m_sync.atomic_op([&pos, &count](squeue_sync_var_t& sync) -> u32
 		{
-			Expects(sync.count <= sq_size);
-			Expects(sync.position < sq_size);
+			EXPECTS(sync.count <= sq_size);
+			EXPECTS(sync.position < sq_size);
 
 			if (sync.pop_lock || sync.push_lock)
 			{
@@ -701,9 +703,9 @@ public:
 
 		m_sync.atomic_op([](squeue_sync_var_t& sync)
 		{
-			Expects(sync.count <= sq_size);
-			Expects(sync.position < sq_size);
-			Expects(sync.pop_lock && sync.push_lock);
+			EXPECTS(sync.count <= sq_size);
+			EXPECTS(sync.position < sq_size);
+			EXPECTS(sync.pop_lock && sync.push_lock);
 			sync.pop_lock = 0;
 			sync.push_lock = 0;
 		});
@@ -716,8 +718,8 @@ public:
 	{
 		while (m_sync.atomic_op([](squeue_sync_var_t& sync) -> u32
 		{
-			Expects(sync.count <= sq_size);
-			Expects(sync.position < sq_size);
+			EXPECTS(sync.count <= sq_size);
+			EXPECTS(sync.position < sq_size);
 
 			if (sync.pop_lock || sync.push_lock)
 			{
diff --git a/rpcs3/Emu/Cell/Modules/cellPhotoDecode.cpp b/rpcs3/Emu/Cell/Modules/cellPhotoDecode.cpp
index 90f759f1e4..6d971b8b1c 100644
--- a/rpcs3/Emu/Cell/Modules/cellPhotoDecode.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellPhotoDecode.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellPhotoDecode);
+logs::channel cellPhotoDecode("cellPhotoDecode", logs::level::notice);
 
 // Return Codes
 enum
diff --git a/rpcs3/Emu/Cell/Modules/cellPhotoExport.cpp b/rpcs3/Emu/Cell/Modules/cellPhotoExport.cpp
index 3b9f4a6381..dd1d76396d 100644
--- a/rpcs3/Emu/Cell/Modules/cellPhotoExport.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellPhotoExport.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellPhotoExport);
+logs::channel cellPhotoExport("cellPhotoExport", logs::level::notice);
 
 // Return Codes
 enum
diff --git a/rpcs3/Emu/Cell/Modules/cellPhotoImport.cpp b/rpcs3/Emu/Cell/Modules/cellPhotoImport.cpp
index 4bb17ce497..5813848716 100644
--- a/rpcs3/Emu/Cell/Modules/cellPhotoImport.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellPhotoImport.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellPhotoImportUtil);
+logs::channel cellPhotoImportUtil("cellPhotoImportUtil", logs::level::notice);
 
 // Return Codes
 enum
diff --git a/rpcs3/Emu/Cell/Modules/cellPngDec.cpp b/rpcs3/Emu/Cell/Modules/cellPngDec.cpp
index 431170548e..82b8038ee5 100644
--- a/rpcs3/Emu/Cell/Modules/cellPngDec.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellPngDec.cpp
@@ -7,7 +7,7 @@
 #include "png.h"
 #include "cellPngDec.h"
 
-LOG_CHANNEL(cellPngDec);
+logs::channel cellPngDec("cellPngDec", logs::level::notice);
 
 // cellPngDec aliases to improve readability
 using PPHandle           = vm::pptr<PngHandle>;
diff --git a/rpcs3/Emu/Cell/Modules/cellPngEnc.cpp b/rpcs3/Emu/Cell/Modules/cellPngEnc.cpp
index a1efb70795..5ccf49dadb 100644
--- a/rpcs3/Emu/Cell/Modules/cellPngEnc.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellPngEnc.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellPngEnc);
+logs::channel cellPngEnc("cellPngEnc", logs::level::notice);
 
 // Error Codes
 enum
diff --git a/rpcs3/Emu/Cell/Modules/cellPrint.cpp b/rpcs3/Emu/Cell/Modules/cellPrint.cpp
index b0a37969cd..648237c75f 100644
--- a/rpcs3/Emu/Cell/Modules/cellPrint.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellPrint.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellPrint);
+logs::channel cellPrint("cellPrint", logs::level::notice);
 
 // Error Codes
 enum
diff --git a/rpcs3/Emu/Cell/Modules/cellRec.cpp b/rpcs3/Emu/Cell/Modules/cellRec.cpp
index ce3aa50e99..5d61b2d8c8 100644
--- a/rpcs3/Emu/Cell/Modules/cellRec.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellRec.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellRec);
+logs::channel cellRec("cellRec", logs::level::notice);
 
 s32 cellRecOpen()
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellRemotePlay.cpp b/rpcs3/Emu/Cell/Modules/cellRemotePlay.cpp
index 0c7983bb12..fdd9c072cb 100644
--- a/rpcs3/Emu/Cell/Modules/cellRemotePlay.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellRemotePlay.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellRemotePlay);
+logs::channel cellRemotePlay("cellRemotePlay", logs::level::notice);
 
 s32 cellRemotePlayGetStatus()
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellResc.cpp b/rpcs3/Emu/Cell/Modules/cellResc.cpp
index 00e1a5f8f9..182bfd0e14 100644
--- a/rpcs3/Emu/Cell/Modules/cellResc.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellResc.cpp
@@ -6,7 +6,7 @@
 #include "Emu/RSX/GCM.h"
 #include "cellResc.h"
 
-LOG_CHANNEL(cellResc);
+logs::channel cellResc("cellResc", logs::level::notice);
 
 s32 cellRescInit(vm::ptr<CellRescInitConfig> initConfig)
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellRtc.cpp b/rpcs3/Emu/Cell/Modules/cellRtc.cpp
index 8648da34ee..0c53abf9f4 100644
--- a/rpcs3/Emu/Cell/Modules/cellRtc.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellRtc.cpp
@@ -3,7 +3,7 @@
 
 #include "cellRtc.h"
 
-LOG_CHANNEL(cellRtc);
+logs::channel cellRtc("cellRtc", logs::level::notice);
 
 s64 convertToUNIXTime(u16 seconds, u16 minutes, u16 hours, u16 days, s32 years)
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellRudp.cpp b/rpcs3/Emu/Cell/Modules/cellRudp.cpp
index f72f07fa01..c7ae11dfda 100644
--- a/rpcs3/Emu/Cell/Modules/cellRudp.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellRudp.cpp
@@ -5,7 +5,7 @@
 
 #include "cellRudp.h"
 
-LOG_CHANNEL(cellRudp);
+logs::channel cellRudp("cellRudp", logs::level::notice);
 
 struct rudp_t
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellSail.cpp b/rpcs3/Emu/Cell/Modules/cellSail.cpp
index 8193c663ff..970bd2a324 100644
--- a/rpcs3/Emu/Cell/Modules/cellSail.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellSail.cpp
@@ -5,7 +5,7 @@
 #include "cellSail.h"
 #include "cellPamf.h"
 
-LOG_CHANNEL(cellSail);
+logs::channel cellSail("cellSail", logs::level::notice);
 
 void playerBoot(vm::ptr<CellSailPlayer> pSelf, u64 userParam)
 {
@@ -818,7 +818,7 @@ s32 cellSailPlayerCreateDescriptor(vm::ptr<CellSailPlayer> pSelf, s32 streamType
 					u32 buffer = vm::alloc(size, vm::main);
 					auto bufPtr = vm::cptr<PamfHeader>::make(buffer);
 					PamfHeader *buf = const_cast<PamfHeader*>(bufPtr.get_ptr());
-					ASSERT(f.read(buf, size) == size);
+					VERIFY(f.read(buf, size) == size);
 					u32 sp_ = vm::alloc(sizeof(CellPamfReader), vm::main);
 					auto sp = vm::ptr<CellPamfReader>::make(sp_);
 					u32 reader = cellPamfReaderInitialize(sp, bufPtr, size, 0);
diff --git a/rpcs3/Emu/Cell/Modules/cellSailRec.cpp b/rpcs3/Emu/Cell/Modules/cellSailRec.cpp
index 7840bc8461..e7c7b7b306 100644
--- a/rpcs3/Emu/Cell/Modules/cellSailRec.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellSailRec.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellSailRec);
+logs::channel cellSailRec("cellSailRec", logs::level::notice);
 
 // Error Codes
 enum
diff --git a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp
index 97389a9a41..b55023b667 100644
--- a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp
@@ -7,7 +7,9 @@
 #include "Loader/PSF.h"
 #include "Utilities/StrUtil.h"
 
-LOG_CHANNEL(cellSaveData);
+#include <algorithm>
+
+logs::channel cellSaveData("cellSaveData", logs::level::notice);
 
 // cellSaveData aliases (only for cellSaveData.cpp)
 using PSetList = vm::ptr<CellSaveDataSetList>;
@@ -609,7 +611,7 @@ static never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version,
 	// Write PARAM.SFO
 	if (psf.size())
 	{
-		fs::file(sfo_path, fs::rewrite).write(psf::save_object(psf));
+		psf::save_object(fs::file(sfo_path, fs::rewrite), psf);
 	}
 
 	return CELL_OK;
diff --git a/rpcs3/Emu/Cell/Modules/cellScreenshot.cpp b/rpcs3/Emu/Cell/Modules/cellScreenshot.cpp
index b062a1d5e8..613fa93f11 100644
--- a/rpcs3/Emu/Cell/Modules/cellScreenshot.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellScreenshot.cpp
@@ -4,7 +4,7 @@
 
 #include "cellScreenshot.h"
 
-LOG_CHANNEL(cellScreenshot);
+logs::channel cellScreenshot("cellScreenshot", logs::level::notice);
 
 s32 cellScreenShotSetParameter() //const CellScreenShotSetParam *param
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellSearch.cpp b/rpcs3/Emu/Cell/Modules/cellSearch.cpp
index 6c9e43fc6c..e1e199f450 100644
--- a/rpcs3/Emu/Cell/Modules/cellSearch.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellSearch.cpp
@@ -4,7 +4,7 @@
 
 #include "cellSearch.h"
 
-LOG_CHANNEL(cellSearch);
+logs::channel cellSearch("cellSearch", logs::level::notice);
 
 s32 cellSearchInitialize(CellSearchMode mode, u32 container, vm::ptr<CellSearchSystemCallback> func, vm::ptr<u32> userData)
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellSheap.cpp b/rpcs3/Emu/Cell/Modules/cellSheap.cpp
index fe8ac83558..314178e1eb 100644
--- a/rpcs3/Emu/Cell/Modules/cellSheap.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellSheap.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellSheap);
+logs::channel cellSheap("cellSheap", logs::level::notice);
 
 // Return Codes
 enum
diff --git a/rpcs3/Emu/Cell/Modules/cellSpudll.cpp b/rpcs3/Emu/Cell/Modules/cellSpudll.cpp
index 5aeaa9ae77..9d7b095223 100644
--- a/rpcs3/Emu/Cell/Modules/cellSpudll.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellSpudll.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellSpudll);
+logs::channel cellSpudll("cellSpudll", logs::level::notice);
 
 s32 cellSpudllGetImageSize(vm::ptr<u32> psize, vm::cptr<void> so_elf, vm::cptr<struct CellSpudllHandleConfig> config)
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellSpurs.cpp b/rpcs3/Emu/Cell/Modules/cellSpurs.cpp
index d20b448ce4..db522166bb 100644
--- a/rpcs3/Emu/Cell/Modules/cellSpurs.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellSpurs.cpp
@@ -15,7 +15,7 @@
 #include "sysPrxForUser.h"
 #include "cellSpurs.h"
 
-LOG_CHANNEL(cellSpurs);
+logs::channel cellSpurs("cellSpurs", logs::level::notice);
 
 // TODO
 struct cell_error_t
@@ -30,6 +30,28 @@ struct cell_error_t
 
 #define CHECK_SUCCESS(expr) if (cell_error_t error{expr}) throw fmt::exception("Failure: %s -> 0x%x" HERE, #expr, error.value)
 
+static u32 ppu_thread_create(u32 entry, u64 arg, s32 prio, u32 stacksize, const std::string& name, std::function<void(PPUThread&)> task)
+{
+	const auto ppu = idm::make_ptr<PPUThread>(name);
+
+	ppu->prio = prio;
+	ppu->stack_size = stacksize;
+	ppu->custom_task = std::move(task);
+	ppu->cpu_init();
+
+	if (entry)
+	{
+		ppu->pc = vm::read32(entry);
+		ppu->GPR[2] = vm::read32(entry + 4); // rtoc
+	}
+
+	ppu->GPR[3] = arg;
+	ppu->state -= cpu_state::stop;
+	(*ppu)->lock_notify();
+
+	return ppu->id;
+}
+
 //----------------------------------------------------------------------------
 // Function prototypes
 //----------------------------------------------------------------------------
@@ -588,7 +610,7 @@ void _spurs::handler_entry(PPUThread& ppu, vm::ptr<CellSpurs> spurs)
 
 		if ((spurs->flags1 & SF1_EXIT_IF_NO_WORK) == 0)
 		{
-			ASSERT(spurs->handlerExiting == 1);
+			VERIFY(spurs->handlerExiting == 1);
 
 			return sys_ppu_thread_exit(ppu, 0);
 		}
@@ -651,16 +673,16 @@ s32 _spurs::wakeup_shutdown_completion_waiter(PPUThread& ppu, vm::ptr<CellSpurs>
 	{
 		wklF->hook(ppu, spurs, wid, wklF->hookArg);
 
-		ASSERT(wklEvent->load() & 0x01);
-		ASSERT(wklEvent->load() & 0x02);
-		ASSERT((wklEvent->load() & 0x20) == 0);
+		VERIFY(wklEvent->load() & 0x01);
+		VERIFY(wklEvent->load() & 0x02);
+		VERIFY((wklEvent->load() & 0x20) == 0);
 		wklEvent->fetch_or(0x20);
 	}
 
 	s32 rc = CELL_OK;
 	if (!wklF->hook || wklEvent->load() & 0x10)
 	{
-		ASSERT(wklF->x28 == 2);
+		VERIFY(wklF->x28 == 2);
 		rc = sys_semaphore_post((u32)wklF->sem, 1);
 	}
 
@@ -1027,7 +1049,7 @@ s32 _spurs::initialize(PPUThread& ppu, vm::ptr<CellSpurs> spurs, u32 revision, u
 
 	// Import SPURS kernel
 	spurs->spuImg.type        = SYS_SPU_IMAGE_TYPE_USER;
-	spurs->spuImg.segs        = { vm::alloc(0x40000, vm::main), vm::addr };
+	spurs->spuImg.segs        = vm::cast(vm::alloc(0x40000, vm::main));
 	spurs->spuImg.entry_point = isSecond ? CELL_SPURS_KERNEL2_ENTRY_ADDR : CELL_SPURS_KERNEL1_ENTRY_ADDR;
 	spurs->spuImg.nsegs       = 1;
 
@@ -2117,8 +2139,8 @@ s32 _spurs::add_workload(vm::ptr<CellSpurs> spurs, vm::ptr<u32> wid, vm::cptr<vo
 	u32 index = wnum & 0xf;
 	if (wnum <= 15)
 	{
-		ASSERT((spurs->wklCurrentContention[wnum] & 0xf) == 0);
-		ASSERT((spurs->wklPendingContention[wnum] & 0xf) == 0);
+		VERIFY((spurs->wklCurrentContention[wnum] & 0xf) == 0);
+		VERIFY((spurs->wklPendingContention[wnum] & 0xf) == 0);
 		spurs->wklState1[wnum] = 1;
 		spurs->wklStatus1[wnum] = 0;
 		spurs->wklEvent1[wnum] = 0;
@@ -2153,8 +2175,8 @@ s32 _spurs::add_workload(vm::ptr<CellSpurs> spurs, vm::ptr<u32> wid, vm::cptr<vo
 	}
 	else
 	{
-		ASSERT((spurs->wklCurrentContention[index] & 0xf0) == 0);
-		ASSERT((spurs->wklPendingContention[index] & 0xf0) == 0);
+		VERIFY((spurs->wklCurrentContention[index] & 0xf0) == 0);
+		VERIFY((spurs->wklPendingContention[index] & 0xf0) == 0);
 		spurs->wklState2[index] = 1;
 		spurs->wklStatus2[index] = 0;
 		spurs->wklEvent2[index] = 0;
@@ -2233,7 +2255,7 @@ s32 _spurs::add_workload(vm::ptr<CellSpurs> spurs, vm::ptr<u32> wid, vm::cptr<vo
 		v = mask | (0x80000000u >> wnum);
 	});
 
-	ASSERT(res_wkl <= 31);
+	VERIFY(res_wkl <= 31);
 	spurs->wklState(wnum).exchange(2);
 	spurs->sysSrvMsgUpdateWorkload.exchange(0xff);
 	spurs->sysSrvMessage.exchange(0xff);
diff --git a/rpcs3/Emu/Cell/Modules/cellSpursJq.cpp b/rpcs3/Emu/Cell/Modules/cellSpursJq.cpp
index b5d85f2d5c..5be8826002 100644
--- a/rpcs3/Emu/Cell/Modules/cellSpursJq.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellSpursJq.cpp
@@ -8,7 +8,7 @@
 #include "cellSpurs.h"
 #include "cellSpursJq.h"
 
-LOG_CHANNEL(cellSpursJq);
+logs::channel cellSpursJq("cellSpursJq", logs::level::notice);
 
 s32 cellSpursJobQueueAttributeInitialize()
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp b/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp
index 7739b1efc3..26ef8ba13c 100644
--- a/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp
@@ -9,11 +9,15 @@
 #include "Emu/Cell/lv2/sys_spu.h"
 #include "cellSpurs.h"
 
+#include <thread>
+
 //----------------------------------------------------------------------------
 // Externs
 //----------------------------------------------------------------------------
 
-extern _log::channel cellSpurs;
+extern logs::channel cellSpurs;
+
+extern std::mutex& get_current_thread_mutex();
 
 //----------------------------------------------------------------------------
 // Function prototypes
@@ -685,7 +689,7 @@ bool spursKernelEntry(SPUThread& spu)
 {
 	while (true)
 	{
-		std::this_thread::sleep_for(std::chrono::milliseconds(100));
+		std::this_thread::sleep_for(100ms);
 		CHECK_EMU_STATUS;
 	}
 
@@ -861,7 +865,7 @@ void spursSysServiceIdleHandler(SPUThread& spu, SpursKernelContext* ctxt)
 			// The system service blocks by making a reservation and waiting on the lock line reservation lost event.
 			CHECK_EMU_STATUS;
 			if (!lock) lock.lock();
-			get_current_thread_cv().wait_for(lock, std::chrono::milliseconds(1));
+			get_current_thread_cv().wait_for(lock, 1ms);
 			continue;
 		}
 
diff --git a/rpcs3/Emu/Cell/Modules/cellSsl.cpp b/rpcs3/Emu/Cell/Modules/cellSsl.cpp
index ab14c7fedd..daa0707378 100644
--- a/rpcs3/Emu/Cell/Modules/cellSsl.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellSsl.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellSsl);
+logs::channel cellSsl("cellSsl", logs::level::notice);
 
 s32 cellSslInit()
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellStorage.cpp b/rpcs3/Emu/Cell/Modules/cellStorage.cpp
index 894f33cf4a..cc498d6471 100644
--- a/rpcs3/Emu/Cell/Modules/cellStorage.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellStorage.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-extern _log::channel cellSysutil;
+extern logs::channel cellSysutil;
 
 s32 cellStorageDataImportMove()
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellSubdisplay.cpp b/rpcs3/Emu/Cell/Modules/cellSubdisplay.cpp
index 6f971a4923..3e978e0dcc 100644
--- a/rpcs3/Emu/Cell/Modules/cellSubdisplay.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellSubdisplay.cpp
@@ -3,7 +3,7 @@
 
 #include "cellSubdisplay.h"
 
-LOG_CHANNEL(cellSubdisplay);
+logs::channel cellSubdisplay("cellSubdisplay", logs::level::notice);
 
 s32 cellSubDisplayInit()
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellSync.cpp b/rpcs3/Emu/Cell/Modules/cellSync.cpp
index eb1f4fc716..1dc29dfb85 100644
--- a/rpcs3/Emu/Cell/Modules/cellSync.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellSync.cpp
@@ -8,7 +8,9 @@
 
 #include "Emu/Memory/wait_engine.h"
 
-LOG_CHANNEL(cellSync);
+#include <thread>
+
+logs::channel cellSync("cellSync", logs::level::notice);
 
 namespace _sync
 {
@@ -32,12 +34,12 @@ ppu_error_code cellSyncMutexInitialize(vm::ptr<CellSyncMutex> mutex)
 {
 	cellSync.trace("cellSyncMutexInitialize(mutex=*0x%x)", mutex);
 
-	if (!mutex)
+	if (UNLIKELY(!mutex))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!mutex.aligned())
+	if (UNLIKELY(!mutex.aligned()))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -51,12 +53,12 @@ ppu_error_code cellSyncMutexLock(vm::ptr<CellSyncMutex> mutex)
 {
 	cellSync.trace("cellSyncMutexLock(mutex=*0x%x)", mutex);
 
-	if (!mutex)
+	if (UNLIKELY(!mutex))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!mutex.aligned())
+	if (UNLIKELY(!mutex.aligned()))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -76,12 +78,12 @@ ppu_error_code cellSyncMutexTryLock(vm::ptr<CellSyncMutex> mutex)
 {
 	cellSync.trace("cellSyncMutexTryLock(mutex=*0x%x)", mutex);
 
-	if (!mutex)
+	if (UNLIKELY(!mutex))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!mutex.aligned())
+	if (UNLIKELY(!mutex.aligned()))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -98,12 +100,12 @@ ppu_error_code cellSyncMutexUnlock(vm::ptr<CellSyncMutex> mutex)
 {
 	cellSync.trace("cellSyncMutexUnlock(mutex=*0x%x)", mutex);
 
-	if (!mutex)
+	if (UNLIKELY(!mutex))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!mutex.aligned())
+	if (UNLIKELY(!mutex.aligned()))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -119,17 +121,17 @@ ppu_error_code cellSyncBarrierInitialize(vm::ptr<CellSyncBarrier> barrier, u16 t
 {
 	cellSync.trace("cellSyncBarrierInitialize(barrier=*0x%x, total_count=%d)", barrier, total_count);
 
-	if (!barrier)
+	if (UNLIKELY(!barrier))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!barrier.aligned())
+	if (UNLIKELY(!barrier.aligned()))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
 
-	if (!total_count || total_count > 32767)
+	if (UNLIKELY(!total_count || total_count > 32767))
 	{
 		return CELL_SYNC_ERROR_INVAL;
 	}
@@ -144,12 +146,12 @@ ppu_error_code cellSyncBarrierNotify(vm::ptr<CellSyncBarrier> barrier)
 {
 	cellSync.trace("cellSyncBarrierNotify(barrier=*0x%x)", barrier);
 
-	if (!barrier)
+	if (UNLIKELY(!barrier))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!barrier.aligned())
+	if (UNLIKELY(!barrier.aligned()))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -165,12 +167,12 @@ ppu_error_code cellSyncBarrierTryNotify(vm::ptr<CellSyncBarrier> barrier)
 {
 	cellSync.trace("cellSyncBarrierTryNotify(barrier=*0x%x)", barrier);
 
-	if (!barrier)
+	if (UNLIKELY(!barrier))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!barrier.aligned())
+	if (UNLIKELY(!barrier.aligned()))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -191,12 +193,12 @@ ppu_error_code cellSyncBarrierWait(vm::ptr<CellSyncBarrier> barrier)
 {
 	cellSync.trace("cellSyncBarrierWait(barrier=*0x%x)", barrier);
 
-	if (!barrier)
+	if (UNLIKELY(!barrier))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!barrier.aligned())
+	if (UNLIKELY(!barrier.aligned()))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -214,12 +216,12 @@ ppu_error_code cellSyncBarrierTryWait(vm::ptr<CellSyncBarrier> barrier)
 {
 	cellSync.trace("cellSyncBarrierTryWait(barrier=*0x%x)", barrier);
 
-	if (!barrier)
+	if (UNLIKELY(!barrier))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!barrier.aligned())
+	if (UNLIKELY(!barrier.aligned()))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -240,17 +242,17 @@ ppu_error_code cellSyncRwmInitialize(vm::ptr<CellSyncRwm> rwm, vm::ptr<void> buf
 {
 	cellSync.trace("cellSyncRwmInitialize(rwm=*0x%x, buffer=*0x%x, buffer_size=0x%x)", rwm, buffer, buffer_size);
 
-	if (!rwm || !buffer)
+	if (UNLIKELY(!rwm || !buffer))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!rwm.aligned() || buffer % 128)
+	if (UNLIKELY(!rwm.aligned() || buffer % 128))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
 
-	if (buffer_size % 128 || buffer_size > 0x4000)
+	if (UNLIKELY(buffer_size % 128 || buffer_size > 0x4000))
 	{
 		return CELL_SYNC_ERROR_INVAL;
 	}
@@ -269,12 +271,12 @@ ppu_error_code cellSyncRwmRead(vm::ptr<CellSyncRwm> rwm, vm::ptr<void> buffer)
 {
 	cellSync.trace("cellSyncRwmRead(rwm=*0x%x, buffer=*0x%x)", rwm, buffer);
 
-	if (!rwm || !buffer)
+	if (UNLIKELY(!rwm || !buffer))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!rwm.aligned())
+	if (UNLIKELY(!rwm.aligned()))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -300,12 +302,12 @@ ppu_error_code cellSyncRwmTryRead(vm::ptr<CellSyncRwm> rwm, vm::ptr<void> buffer
 {
 	cellSync.trace("cellSyncRwmTryRead(rwm=*0x%x, buffer=*0x%x)", rwm, buffer);
 
-	if (!rwm || !buffer)
+	if (UNLIKELY(!rwm || !buffer))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!rwm.aligned())
+	if (UNLIKELY(!rwm.aligned()))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -334,12 +336,12 @@ ppu_error_code cellSyncRwmWrite(vm::ptr<CellSyncRwm> rwm, vm::cptr<void> buffer)
 {
 	cellSync.trace("cellSyncRwmWrite(rwm=*0x%x, buffer=*0x%x)", rwm, buffer);
 
-	if (!rwm || !buffer)
+	if (UNLIKELY(!rwm || !buffer))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!rwm.aligned())
+	if (UNLIKELY(!rwm.aligned()))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -365,12 +367,12 @@ ppu_error_code cellSyncRwmTryWrite(vm::ptr<CellSyncRwm> rwm, vm::cptr<void> buff
 {
 	cellSync.trace("cellSyncRwmTryWrite(rwm=*0x%x, buffer=*0x%x)", rwm, buffer);
 
-	if (!rwm || !buffer)
+	if (UNLIKELY(!rwm || !buffer))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!rwm.aligned())
+	if (UNLIKELY(!rwm.aligned()))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -396,22 +398,22 @@ ppu_error_code cellSyncQueueInitialize(vm::ptr<CellSyncQueue> queue, vm::ptr<u8>
 {
 	cellSync.trace("cellSyncQueueInitialize(queue=*0x%x, buffer=*0x%x, size=0x%x, depth=0x%x)", queue, buffer, size, depth);
 
-	if (!queue)
+	if (UNLIKELY(!queue))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (size && !buffer)
+	if (UNLIKELY(size && !buffer))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!queue.aligned() || buffer % 16)
+	if (UNLIKELY(!queue.aligned() || buffer % 16))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
 
-	if (!depth || size % 16)
+	if (UNLIKELY(!depth || size % 16))
 	{
 		return CELL_SYNC_ERROR_INVAL;
 	}
@@ -431,12 +433,12 @@ ppu_error_code cellSyncQueuePush(vm::ptr<CellSyncQueue> queue, vm::cptr<void> bu
 {
 	cellSync.trace("cellSyncQueuePush(queue=*0x%x, buffer=*0x%x)", queue, buffer);
 
-	if (!queue || !buffer)
+	if (UNLIKELY(!queue || !buffer))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!queue.aligned())
+	if (UNLIKELY(!queue.aligned()))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -462,12 +464,12 @@ ppu_error_code cellSyncQueueTryPush(vm::ptr<CellSyncQueue> queue, vm::cptr<void>
 {
 	cellSync.trace("cellSyncQueueTryPush(queue=*0x%x, buffer=*0x%x)", queue, buffer);
 
-	if (!queue || !buffer)
+	if (UNLIKELY(!queue || !buffer))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!queue.aligned())
+	if (UNLIKELY(!queue.aligned()))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -496,12 +498,12 @@ ppu_error_code cellSyncQueuePop(vm::ptr<CellSyncQueue> queue, vm::ptr<void> buff
 {
 	cellSync.trace("cellSyncQueuePop(queue=*0x%x, buffer=*0x%x)", queue, buffer);
 
-	if (!queue || !buffer)
+	if (UNLIKELY(!queue || !buffer))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!queue.aligned())
+	if (UNLIKELY(!queue.aligned()))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -527,12 +529,12 @@ ppu_error_code cellSyncQueueTryPop(vm::ptr<CellSyncQueue> queue, vm::ptr<void> b
 {
 	cellSync.trace("cellSyncQueueTryPop(queue=*0x%x, buffer=*0x%x)", queue, buffer);
 
-	if (!queue || !buffer)
+	if (UNLIKELY(!queue || !buffer))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!queue.aligned())
+	if (UNLIKELY(!queue.aligned()))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -561,12 +563,12 @@ ppu_error_code cellSyncQueuePeek(vm::ptr<CellSyncQueue> queue, vm::ptr<void> buf
 {
 	cellSync.trace("cellSyncQueuePeek(queue=*0x%x, buffer=*0x%x)", queue, buffer);
 
-	if (!queue || !buffer)
+	if (UNLIKELY(!queue || !buffer))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!queue.aligned())
+	if (UNLIKELY(!queue.aligned()))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -592,12 +594,12 @@ ppu_error_code cellSyncQueueTryPeek(vm::ptr<CellSyncQueue> queue, vm::ptr<void>
 {
 	cellSync.trace("cellSyncQueueTryPeek(queue=*0x%x, buffer=*0x%x)", queue, buffer);
 
-	if (!queue || !buffer)
+	if (UNLIKELY(!queue || !buffer))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!queue.aligned())
+	if (UNLIKELY(!queue.aligned()))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -626,12 +628,12 @@ ppu_error_code cellSyncQueueSize(vm::ptr<CellSyncQueue> queue)
 {
 	cellSync.trace("cellSyncQueueSize(queue=*0x%x)", queue);
 
-	if (!queue)
+	if (UNLIKELY(!queue))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!queue.aligned())
+	if (UNLIKELY(!queue.aligned()))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -645,12 +647,12 @@ ppu_error_code cellSyncQueueClear(vm::ptr<CellSyncQueue> queue)
 {
 	cellSync.trace("cellSyncQueueClear(queue=*0x%x)", queue);
 
-	if (!queue)
+	if (UNLIKELY(!queue))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!queue.aligned())
+	if (UNLIKELY(!queue.aligned()))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -713,30 +715,30 @@ ppu_error_code cellSyncLFQueueInitialize(vm::ptr<CellSyncLFQueue> queue, vm::cpt
 {
 	cellSync.warning("cellSyncLFQueueInitialize(queue=*0x%x, buffer=*0x%x, size=0x%x, depth=0x%x, direction=%d, eaSignal=*0x%x)", queue, buffer, size, depth, direction, eaSignal);
 
-	if (!queue)
+	if (UNLIKELY(!queue))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
 	if (size)
 	{
-		if (!buffer)
+		if (UNLIKELY(!buffer))
 		{
 			return CELL_SYNC_ERROR_NULL_POINTER;
 		}
 
-		if (size > 0x4000 || size % 16)
+		if (UNLIKELY(size > 0x4000 || size % 16))
 		{
 			return CELL_SYNC_ERROR_INVAL;
 		}
 	}
 
-	if (!depth || depth > 0x7fff || direction > 3)
+	if (UNLIKELY(!depth || depth > 0x7fff || direction > 3))
 	{
 		return CELL_SYNC_ERROR_INVAL;
 	}
 
-	if (!queue.aligned() || buffer % 16)
+	if (UNLIKELY(!queue.aligned() || buffer % 16))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -764,7 +766,7 @@ ppu_error_code cellSyncLFQueueInitialize(vm::ptr<CellSyncLFQueue> queue, vm::cpt
 
 		if (old)
 		{
-			if (sdk_ver > 0x17ffff && old != 2)
+			if (UNLIKELY(sdk_ver > 0x17ffff && old != 2))
 			{
 				return CELL_SYNC_ERROR_STAT;
 			}
@@ -777,7 +779,7 @@ ppu_error_code cellSyncLFQueueInitialize(vm::ptr<CellSyncLFQueue> queue, vm::cpt
 			{
 				for (const auto& data : vm::_ref<u64[16]>(queue.addr()))
 				{
-					if (data)
+					if (UNLIKELY(data))
 					{
 						return CELL_SYNC_ERROR_STAT;
 					}
@@ -793,14 +795,14 @@ ppu_error_code cellSyncLFQueueInitialize(vm::ptr<CellSyncLFQueue> queue, vm::cpt
 
 	if (old_value == 2)
 	{
-		if (queue->m_size != size || queue->m_depth != depth || queue->m_buffer != buffer)
+		if (UNLIKELY(queue->m_size != size || queue->m_depth != depth || queue->m_buffer != buffer))
 		{
 			return CELL_SYNC_ERROR_INVAL;
 		}
 
 		if (sdk_ver > 0x17ffff)
 		{
-			if (queue->m_eaSignal != eaSignal || queue->m_direction != direction)
+			if (UNLIKELY(queue->m_eaSignal != eaSignal || queue->m_direction != direction))
 			{
 				return CELL_SYNC_ERROR_INVAL;
 			}
@@ -822,7 +824,7 @@ ppu_error_code _cellSyncLFQueueGetPushPointer(PPUThread& ppu, vm::ptr<CellSyncLF
 {
 	cellSync.warning("_cellSyncLFQueueGetPushPointer(queue=*0x%x, pointer=*0x%x, isBlocking=%d, useEventQueue=%d)", queue, pointer, isBlocking, useEventQueue);
 
-	if (queue->m_direction != CELL_SYNC_QUEUE_PPU2SPU)
+	if (UNLIKELY(queue->m_direction != CELL_SYNC_QUEUE_PPU2SPU))
 	{
 		return CELL_SYNC_ERROR_PERM;
 	}
@@ -906,7 +908,7 @@ ppu_error_code _cellSyncLFQueueGetPushPointer(PPUThread& ppu, vm::ptr<CellSyncLF
 			}
 		}
 
-		ASSERT(sys_event_queue_receive(ppu, queue->m_eq_id, vm::null, 0) == CELL_OK);
+		VERIFY(sys_event_queue_receive(ppu, queue->m_eq_id, vm::null, 0) == CELL_OK);
 		var1 = 1;
 	}
 }
@@ -923,7 +925,7 @@ ppu_error_code _cellSyncLFQueueCompletePushPointer(PPUThread& ppu, vm::ptr<CellS
 {
 	cellSync.warning("_cellSyncLFQueueCompletePushPointer(queue=*0x%x, pointer=%d, fpSendSignal=*0x%x)", queue, pointer, fpSendSignal);
 
-	if (queue->m_direction != CELL_SYNC_QUEUE_PPU2SPU)
+	if (UNLIKELY(queue->m_direction != CELL_SYNC_QUEUE_PPU2SPU))
 	{
 		return CELL_SYNC_ERROR_PERM;
 	}
@@ -997,7 +999,7 @@ ppu_error_code _cellSyncLFQueueCompletePushPointer(PPUThread& ppu, vm::ptr<CellS
 
 			if (var9 > 1 && (u32)var8 > 1)
 			{
-				ASSERT(16 - var2 <= 1);
+				VERIFY(16 - var2 <= 1);
 			}
 
 			s32 var11 = (pack >> 10) & 0x1f;
@@ -1029,11 +1031,11 @@ ppu_error_code _cellSyncLFQueueCompletePushPointer(PPUThread& ppu, vm::ptr<CellS
 
 		if (queue->push2.compare_and_swap_test(old, push2))
 		{
-			ASSERT(var2 + var4 < 16);
+			VERIFY(var2 + var4 < 16);
 			if (var6 != -1)
 			{
-				ASSERT(queue->push3.compare_and_swap_test(old2, push3));
-				ASSERT(fpSendSignal);
+				VERIFY(queue->push3.compare_and_swap_test(old2, push3));
+				VERIFY(fpSendSignal);
 				return NOT_AN_ERROR(fpSendSignal(ppu, (u32)queue->m_eaSignal.addr(), var6));
 			}
 			else
@@ -1064,12 +1066,12 @@ ppu_error_code _cellSyncLFQueuePushBody(PPUThread& ppu, vm::ptr<CellSyncLFQueue>
 	// cellSyncLFQueuePush has 1 in isBlocking param, cellSyncLFQueueTryPush has 0
 	cellSync.warning("_cellSyncLFQueuePushBody(queue=*0x%x, buffer=*0x%x, isBlocking=%d)", queue, buffer, isBlocking);
 
-	if (!queue || !buffer)
+	if (UNLIKELY(!queue || !buffer))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!queue.aligned() || buffer % 16)
+	if (UNLIKELY(!queue.aligned() || buffer % 16))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -1098,7 +1100,7 @@ ppu_error_code _cellSyncLFQueuePushBody(PPUThread& ppu, vm::ptr<CellSyncLFQueue>
 			break;
 		}
 
-		std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
+		std::this_thread::sleep_for(1ms); // hack
 	}
 
 	const s32 depth = queue->m_depth;
@@ -1121,7 +1123,7 @@ ppu_error_code _cellSyncLFQueueGetPopPointer(PPUThread& ppu, vm::ptr<CellSyncLFQ
 {
 	cellSync.warning("_cellSyncLFQueueGetPopPointer(queue=*0x%x, pointer=*0x%x, isBlocking=%d, arg4=%d, useEventQueue=%d)", queue, pointer, isBlocking, arg4, useEventQueue);
 
-	if (queue->m_direction != CELL_SYNC_QUEUE_SPU2PPU)
+	if (UNLIKELY(queue->m_direction != CELL_SYNC_QUEUE_SPU2PPU))
 	{
 		return CELL_SYNC_ERROR_PERM;
 	}
@@ -1205,7 +1207,7 @@ ppu_error_code _cellSyncLFQueueGetPopPointer(PPUThread& ppu, vm::ptr<CellSyncLFQ
 			}
 		}
 
-		ASSERT(sys_event_queue_receive(ppu, queue->m_eq_id, vm::null, 0) == CELL_OK);
+		VERIFY(sys_event_queue_receive(ppu, queue->m_eq_id, vm::null, 0) == CELL_OK);
 		var1 = 1;
 	}
 }
@@ -1223,7 +1225,7 @@ ppu_error_code _cellSyncLFQueueCompletePopPointer(PPUThread& ppu, vm::ptr<CellSy
 	// arguments copied from _cellSyncLFQueueCompletePushPointer + unknown argument (noQueueFull taken from LFQueue2CompletePopPointer)
 	cellSync.warning("_cellSyncLFQueueCompletePopPointer(queue=*0x%x, pointer=%d, fpSendSignal=*0x%x, noQueueFull=%d)", queue, pointer, fpSendSignal, noQueueFull);
 
-	if (queue->m_direction != CELL_SYNC_QUEUE_SPU2PPU)
+	if (UNLIKELY(queue->m_direction != CELL_SYNC_QUEUE_SPU2PPU))
 	{
 		return CELL_SYNC_ERROR_PERM;
 	}
@@ -1301,7 +1303,7 @@ ppu_error_code _cellSyncLFQueueCompletePopPointer(PPUThread& ppu, vm::ptr<CellSy
 
 			if (var9 > 1 && (u32)var8 > 1)
 			{
-				ASSERT(16 - var2 <= 1);
+				VERIFY(16 - var2 <= 1);
 			}
 
 			s32 var11 = (pack >> 10) & 0x1f;
@@ -1331,8 +1333,8 @@ ppu_error_code _cellSyncLFQueueCompletePopPointer(PPUThread& ppu, vm::ptr<CellSy
 		{
 			if (var6 != -1)
 			{
-				ASSERT(queue->pop3.compare_and_swap_test(old2, pop3));
-				ASSERT(fpSendSignal);
+				VERIFY(queue->pop3.compare_and_swap_test(old2, pop3));
+				VERIFY(fpSendSignal);
 				return NOT_AN_ERROR(fpSendSignal(ppu, (u32)queue->m_eaSignal.addr(), var6));
 			}
 			else
@@ -1363,12 +1365,12 @@ ppu_error_code _cellSyncLFQueuePopBody(PPUThread& ppu, vm::ptr<CellSyncLFQueue>
 	// cellSyncLFQueuePop has 1 in isBlocking param, cellSyncLFQueueTryPop has 0
 	cellSync.warning("_cellSyncLFQueuePopBody(queue=*0x%x, buffer=*0x%x, isBlocking=%d)", queue, buffer, isBlocking);
 
-	if (!queue || !buffer)
+	if (UNLIKELY(!queue || !buffer))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!queue.aligned() || buffer % 16)
+	if (UNLIKELY(!queue.aligned() || buffer % 16))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -1397,7 +1399,7 @@ ppu_error_code _cellSyncLFQueuePopBody(PPUThread& ppu, vm::ptr<CellSyncLFQueue>
 			break;
 		}
 
-		std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
+		std::this_thread::sleep_for(1ms); // hack
 	}
 
 	const s32 depth = queue->m_depth;
@@ -1420,12 +1422,12 @@ ppu_error_code cellSyncLFQueueClear(vm::ptr<CellSyncLFQueue> queue)
 {
 	cellSync.warning("cellSyncLFQueueClear(queue=*0x%x)", queue);
 
-	if (!queue)
+	if (UNLIKELY(!queue))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!queue.aligned())
+	if (UNLIKELY(!queue.aligned()))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -1471,12 +1473,12 @@ ppu_error_code cellSyncLFQueueSize(vm::ptr<CellSyncLFQueue> queue, vm::ptr<u32>
 {
 	cellSync.warning("cellSyncLFQueueSize(queue=*0x%x, size=*0x%x)", queue, size);
 
-	if (!queue || !size)
+	if (UNLIKELY(!queue || !size))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!queue.aligned())
+	if (UNLIKELY(!queue.aligned()))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -1508,12 +1510,12 @@ ppu_error_code cellSyncLFQueueDepth(vm::ptr<CellSyncLFQueue> queue, vm::ptr<u32>
 {
 	cellSync.trace("cellSyncLFQueueDepth(queue=*0x%x, depth=*0x%x)", queue, depth);
 
-	if (!queue || !depth)
+	if (UNLIKELY(!queue || !depth))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!queue.aligned())
+	if (UNLIKELY(!queue.aligned()))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -1527,12 +1529,12 @@ ppu_error_code _cellSyncLFQueueGetSignalAddress(vm::cptr<CellSyncLFQueue> queue,
 {
 	cellSync.trace("_cellSyncLFQueueGetSignalAddress(queue=*0x%x, ppSignal=**0x%x)", queue, ppSignal);
 
-	if (!queue || !ppSignal)
+	if (UNLIKELY(!queue || !ppSignal))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!queue.aligned())
+	if (UNLIKELY(!queue.aligned()))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -1546,12 +1548,12 @@ ppu_error_code cellSyncLFQueueGetDirection(vm::cptr<CellSyncLFQueue> queue, vm::
 {
 	cellSync.trace("cellSyncLFQueueGetDirection(queue=*0x%x, direction=*0x%x)", queue, direction);
 
-	if (!queue || !direction)
+	if (UNLIKELY(!queue || !direction))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!queue.aligned())
+	if (UNLIKELY(!queue.aligned()))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
@@ -1565,12 +1567,12 @@ ppu_error_code cellSyncLFQueueGetEntrySize(vm::cptr<CellSyncLFQueue> queue, vm::
 {
 	cellSync.trace("cellSyncLFQueueGetEntrySize(queue=*0x%x, entry_size=*0x%x)", queue, entry_size);
 
-	if (!queue || !entry_size)
+	if (UNLIKELY(!queue || !entry_size))
 	{
 		return CELL_SYNC_ERROR_NULL_POINTER;
 	}
 
-	if (!queue.aligned())
+	if (UNLIKELY(!queue.aligned()))
 	{
 		return CELL_SYNC_ERROR_ALIGN;
 	}
diff --git a/rpcs3/Emu/Cell/Modules/cellSync2.cpp b/rpcs3/Emu/Cell/Modules/cellSync2.cpp
index 21673c5012..27e28faff9 100644
--- a/rpcs3/Emu/Cell/Modules/cellSync2.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellSync2.cpp
@@ -6,7 +6,7 @@
 
 #include "Utilities/StrUtil.h"
 
-LOG_CHANNEL(cellSync2);
+logs::channel cellSync2("cellSync2", logs::level::notice);
 
 vm::gvar<CellSync2CallerThreadType> gCellSync2CallerThreadTypePpuThread;
 vm::gvar<CellSync2Notifier> gCellSync2NotifierPpuThread;
diff --git a/rpcs3/Emu/Cell/Modules/cellSysconf.cpp b/rpcs3/Emu/Cell/Modules/cellSysconf.cpp
index 3685f8f1ef..c43d66f9eb 100644
--- a/rpcs3/Emu/Cell/Modules/cellSysconf.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellSysconf.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellSysconf);
+logs::channel cellSysconf("cellSysconf", logs::level::notice);
 
 s32 cellSysconfAbort()
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellSysmodule.cpp b/rpcs3/Emu/Cell/Modules/cellSysmodule.cpp
index b4718e11dc..99be319178 100644
--- a/rpcs3/Emu/Cell/Modules/cellSysmodule.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellSysmodule.cpp
@@ -2,7 +2,7 @@
 #include "Emu/System.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellSysmodule);
+logs::channel cellSysmodule("cellSysmodule", logs::level::notice);
 
 enum
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellSysutil.cpp b/rpcs3/Emu/Cell/Modules/cellSysutil.cpp
index 1e92f757ae..ce21bcb7dc 100644
--- a/rpcs3/Emu/Cell/Modules/cellSysutil.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellSysutil.cpp
@@ -1,4 +1,5 @@
 #include "stdafx.h"
+#include "Utilities/Config.h"
 #include "Emu/System.h"
 #include "Emu/IdManager.h"
 #include "Emu/Cell/PPUModule.h"
@@ -7,7 +8,7 @@
 
 #include "Utilities/StrUtil.h"
 
-LOG_CHANNEL(cellSysutil);
+logs::channel cellSysutil("cellSysutil", logs::level::notice);
 
 // Temporarily
 using sys_callbacks_t = std::array<std::pair<vm::ptr<CellSysutilCallback>, vm::ptr<void>>, 4>;
@@ -53,43 +54,47 @@ cfg::map_entry<s32> g_cfg_sys_language(cfg::root.sys, "Language",
 	{ "English (UK)", CELL_SYSUTIL_LANG_ENGLISH_GB },
 });
 
-static const char* get_systemparam_id_name(s32 id)
-{
-	static thread_local char tls_id_name[16]; // for test
-
-	switch (id)
-	{
-	case CELL_SYSUTIL_SYSTEMPARAM_ID_LANG: return "ID_LANG";
-	case CELL_SYSUTIL_SYSTEMPARAM_ID_ENTER_BUTTON_ASSIGN: return "ID_ENTER_BUTTON_ASSIGN";
-	case CELL_SYSUTIL_SYSTEMPARAM_ID_DATE_FORMAT: return "ID_DATE_FORMAT";
-	case CELL_SYSUTIL_SYSTEMPARAM_ID_TIME_FORMAT: return "ID_TIME_FORMAT";
-	case CELL_SYSUTIL_SYSTEMPARAM_ID_TIMEZONE: return "ID_TIMEZONE";
-	case CELL_SYSUTIL_SYSTEMPARAM_ID_SUMMERTIME: return "ID_SUMMERTIME";
-	case CELL_SYSUTIL_SYSTEMPARAM_ID_GAME_PARENTAL_LEVEL: return "ID_GAME_PARENTAL_LEVEL";
-	case CELL_SYSUTIL_SYSTEMPARAM_ID_GAME_PARENTAL_LEVEL0_RESTRICT: return "ID_GAME_PARENTAL_LEVEL0_RESTRICT";
-	case CELL_SYSUTIL_SYSTEMPARAM_ID_CURRENT_USER_HAS_NP_ACCOUNT: return "ID_CURRENT_USER_HAS_NP_ACCOUNT";
-	case CELL_SYSUTIL_SYSTEMPARAM_ID_CAMERA_PLFREQ: return "ID_CAMERA_PLFREQ";
-	case CELL_SYSUTIL_SYSTEMPARAM_ID_PAD_RUMBLE: return "ID_PAD_RUMBLE";
-	case CELL_SYSUTIL_SYSTEMPARAM_ID_KEYBOARD_TYPE: return "ID_KEYBOARD_TYPE";
-	case CELL_SYSUTIL_SYSTEMPARAM_ID_JAPANESE_KEYBOARD_ENTRY_METHOD: return "ID_JAPANESE_KEYBOARD_ENTRY_METHOD";
-	case CELL_SYSUTIL_SYSTEMPARAM_ID_CHINESE_KEYBOARD_ENTRY_METHOD: return "ID_CHINESE_KEYBOARD_ENTRY_METHOD";
-	case CELL_SYSUTIL_SYSTEMPARAM_ID_PAD_AUTOOFF: return "ID_PAD_AUTOOFF";
-	case CELL_SYSUTIL_SYSTEMPARAM_ID_NICKNAME: return "ID_NICKNAME";
-	case CELL_SYSUTIL_SYSTEMPARAM_ID_CURRENT_USERNAME: return "ID_CURRENT_USERNAME";
-	}
-
-	std::snprintf(tls_id_name, sizeof(tls_id_name), "0x%04X", id);
-	return tls_id_name;
-}
-
 enum class systemparam_id_name : s32 {};
 
 template<>
 struct unveil<systemparam_id_name, void>
 {
-	static inline const char* get(systemparam_id_name arg)
+	struct temp
 	{
-		return get_systemparam_id_name((s32)arg);
+		s32 value;
+		char buf[12];
+
+		temp(systemparam_id_name value)
+			: value(s32(value))
+		{
+		}
+	};
+
+	static inline const char* get(temp&& in)
+	{
+		switch (in.value)
+		{
+		case CELL_SYSUTIL_SYSTEMPARAM_ID_LANG: return "ID_LANG";
+		case CELL_SYSUTIL_SYSTEMPARAM_ID_ENTER_BUTTON_ASSIGN: return "ID_ENTER_BUTTON_ASSIGN";
+		case CELL_SYSUTIL_SYSTEMPARAM_ID_DATE_FORMAT: return "ID_DATE_FORMAT";
+		case CELL_SYSUTIL_SYSTEMPARAM_ID_TIME_FORMAT: return "ID_TIME_FORMAT";
+		case CELL_SYSUTIL_SYSTEMPARAM_ID_TIMEZONE: return "ID_TIMEZONE";
+		case CELL_SYSUTIL_SYSTEMPARAM_ID_SUMMERTIME: return "ID_SUMMERTIME";
+		case CELL_SYSUTIL_SYSTEMPARAM_ID_GAME_PARENTAL_LEVEL: return "ID_GAME_PARENTAL_LEVEL";
+		case CELL_SYSUTIL_SYSTEMPARAM_ID_GAME_PARENTAL_LEVEL0_RESTRICT: return "ID_GAME_PARENTAL_LEVEL0_RESTRICT";
+		case CELL_SYSUTIL_SYSTEMPARAM_ID_CURRENT_USER_HAS_NP_ACCOUNT: return "ID_CURRENT_USER_HAS_NP_ACCOUNT";
+		case CELL_SYSUTIL_SYSTEMPARAM_ID_CAMERA_PLFREQ: return "ID_CAMERA_PLFREQ";
+		case CELL_SYSUTIL_SYSTEMPARAM_ID_PAD_RUMBLE: return "ID_PAD_RUMBLE";
+		case CELL_SYSUTIL_SYSTEMPARAM_ID_KEYBOARD_TYPE: return "ID_KEYBOARD_TYPE";
+		case CELL_SYSUTIL_SYSTEMPARAM_ID_JAPANESE_KEYBOARD_ENTRY_METHOD: return "ID_JAPANESE_KEYBOARD_ENTRY_METHOD";
+		case CELL_SYSUTIL_SYSTEMPARAM_ID_CHINESE_KEYBOARD_ENTRY_METHOD: return "ID_CHINESE_KEYBOARD_ENTRY_METHOD";
+		case CELL_SYSUTIL_SYSTEMPARAM_ID_PAD_AUTOOFF: return "ID_PAD_AUTOOFF";
+		case CELL_SYSUTIL_SYSTEMPARAM_ID_NICKNAME: return "ID_NICKNAME";
+		case CELL_SYSUTIL_SYSTEMPARAM_ID_CURRENT_USERNAME: return "ID_CURRENT_USERNAME";
+		}
+
+		std::snprintf(in.buf, sizeof(in.buf), "!0x%04X", in.value);
+		return in.buf;
 	}
 };
 
@@ -170,7 +175,7 @@ s32 cellSysutilGetSystemParamInt(s32 id, vm::ptr<s32> value)
 
 s32 cellSysutilGetSystemParamString(s32 id, vm::ptr<char> buf, u32 bufsize)
 {
-	cellSysutil.trace("cellSysutilGetSystemParamString(id=0x%x(%s), buf=*0x%x, bufsize=%d)", id, get_systemparam_id_name(id), buf, bufsize);
+	cellSysutil.trace("cellSysutilGetSystemParamString(id=0x%x(%s), buf=*0x%x, bufsize=%d)", id, systemparam_id_name(id), buf, bufsize);
 
 	memset(buf.get_ptr(), 0, bufsize);
 
@@ -255,7 +260,7 @@ s32 cellSysCacheMount(vm::ptr<CellSysCacheParam> param)
 	cellSysutil.warning("cellSysCacheMount(param=*0x%x)", param);
 
 	const std::string& cache_id = param->cacheId;
-	ASSERT(cache_id.size() < sizeof(param->cacheId));
+	VERIFY(cache_id.size() < sizeof(param->cacheId));
 	
 	const std::string& cache_path = "/dev_hdd1/cache/" + cache_id + '/';
 	strcpy_trunc(param->getCachePath, cache_path);
diff --git a/rpcs3/Emu/Cell/Modules/cellSysutilAp.cpp b/rpcs3/Emu/Cell/Modules/cellSysutilAp.cpp
index f8c6d1668f..d989ceb55d 100644
--- a/rpcs3/Emu/Cell/Modules/cellSysutilAp.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellSysutilAp.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellSysutilAp);
+logs::channel cellSysutilAp("cellSysutilAp", logs::level::notice);
 
 // Return Codes
 enum
diff --git a/rpcs3/Emu/Cell/Modules/cellSysutilAvc.cpp b/rpcs3/Emu/Cell/Modules/cellSysutilAvc.cpp
index 24b78da7b4..fee4207eee 100644
--- a/rpcs3/Emu/Cell/Modules/cellSysutilAvc.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellSysutilAvc.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellSysutilAvc);
+logs::channel cellSysutilAvc("cellSysutilAvc", logs::level::notice);
 
 s32 cellSysutilAvcByeRequest()
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellSysutilAvc2.cpp b/rpcs3/Emu/Cell/Modules/cellSysutilAvc2.cpp
index c88ffd32d5..1acf10e32d 100644
--- a/rpcs3/Emu/Cell/Modules/cellSysutilAvc2.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellSysutilAvc2.cpp
@@ -5,7 +5,7 @@
 #include "sceNp2.h"
 #include "cellSysutilAvc2.h"
 
-LOG_CHANNEL(cellSysutilAvc2);
+logs::channel cellSysutilAvc2("cellSysutilAvc2", logs::level::notice);
 
 s32 cellSysutilAvc2GetPlayerInfo()
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellSysutilMisc.cpp b/rpcs3/Emu/Cell/Modules/cellSysutilMisc.cpp
index e009f8e0bc..109e7a817a 100644
--- a/rpcs3/Emu/Cell/Modules/cellSysutilMisc.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellSysutilMisc.cpp
@@ -2,7 +2,7 @@
 #include "Emu/System.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellSysutilMisc);
+logs::channel cellSysutilMisc("cellSysutilMisc", logs::level::notice);
 
 // License areas
 enum
diff --git a/rpcs3/Emu/Cell/Modules/cellUsbd.cpp b/rpcs3/Emu/Cell/Modules/cellUsbd.cpp
index 607277c74e..d998d9387c 100644
--- a/rpcs3/Emu/Cell/Modules/cellUsbd.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellUsbd.cpp
@@ -3,7 +3,7 @@
 #include "Emu/Cell/PPUModule.h"
 #include "cellUsbd.h"
 
-LOG_CHANNEL(cellUsbd);
+logs::channel cellUsbd("cellUsbd", logs::level::notice);
 
 s32 cellUsbdInit()
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellUsbpspcm.cpp b/rpcs3/Emu/Cell/Modules/cellUsbpspcm.cpp
index ccd4cae8bb..88267a3468 100644
--- a/rpcs3/Emu/Cell/Modules/cellUsbpspcm.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellUsbpspcm.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellUsbPspcm);
+logs::channel cellUsbPspcm("cellUsbPspcm", logs::level::notice);
 
 // Return Codes
 enum
diff --git a/rpcs3/Emu/Cell/Modules/cellUserInfo.cpp b/rpcs3/Emu/Cell/Modules/cellUserInfo.cpp
index 790d6b9eab..9c6e3f0d85 100644
--- a/rpcs3/Emu/Cell/Modules/cellUserInfo.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellUserInfo.cpp
@@ -6,7 +6,7 @@
 
 #include "Utilities/StrUtil.h"
 
-LOG_CHANNEL(cellUserInfo);
+logs::channel cellUserInfo("cellUserInfo", logs::level::notice);
 
 s32 cellUserInfoGetStat(u32 id, vm::ptr<CellUserInfoUserStat> stat)
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellVdec.cpp b/rpcs3/Emu/Cell/Modules/cellVdec.cpp
index 2192d6f4c9..47bc12d9ca 100644
--- a/rpcs3/Emu/Cell/Modules/cellVdec.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellVdec.cpp
@@ -16,7 +16,9 @@ extern "C"
 #include "cellPamf.h"
 #include "cellVdec.h"
 
-LOG_CHANNEL(cellVdec);
+#include <thread>
+
+logs::channel cellVdec("cellVdec", logs::level::notice);
 
 vm::gvar<s32> _cell_vdec_prx_ver; // ???
 
@@ -541,7 +543,7 @@ void vdecOpen(u32 vdec_id) // TODO: call from the constructor
 
 	vdec.vdecCb->cpu_init();
 	vdec.vdecCb->state -= cpu_state::stop;
-	vdec.vdecCb->lock_notify();
+	(*vdec.vdecCb)->lock_notify();
 }
 
 s32 cellVdecQueryAttr(vm::cptr<CellVdecType> type, vm::ptr<CellVdecAttr> attr)
@@ -594,7 +596,7 @@ s32 cellVdecClose(u32 handle)
 	{
 		CHECK_EMU_STATUS;
 
-		std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
+		std::this_thread::sleep_for(1ms); // hack
 	}
 
 	idm::remove<PPUThread>(vdec->vdecCb->id);
@@ -676,7 +678,7 @@ s32 cellVdecGetPicture(u32 handle, vm::cptr<CellVdecPicFormat> format, vm::ptr<u
 	VdecFrame vf;
 	if (!vdec->frames.try_pop(vf))
 	{
-		//std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
+		//std::this_thread::sleep_for(1ms); // hack
 		return CELL_VDEC_ERROR_EMPTY;
 	}
 
@@ -800,13 +802,13 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr<CellVdecPicItem> picItem)
 	VdecFrame vf;
 	if (!vdec->frames.try_peek(vf))
 	{
-		//std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
+		//std::this_thread::sleep_for(1ms); // hack
 		return CELL_VDEC_ERROR_EMPTY;
 	}
 
 	AVFrame& frame = *vf.data;
 
-	const vm::ptr<CellVdecPicItem> info{ vdec->memAddr + vdec->memBias, vm::addr };
+	const vm::ptr<CellVdecPicItem> info = vm::cast(vdec->memAddr + vdec->memBias);
 
 	vdec->memBias += 512;
 	if (vdec->memBias + 512 > vdec->memSize)
@@ -834,7 +836,7 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr<CellVdecPicItem> picItem)
 
 	if (vdec->type == CELL_VDEC_CODEC_TYPE_AVC)
 	{
-		const vm::ptr<CellVdecAvcInfo> avc{ info.addr() + SIZE_32(CellVdecPicItem), vm::addr };
+		const vm::ptr<CellVdecAvcInfo> avc = vm::cast(info.addr() + SIZE_32(CellVdecPicItem));
 
 		avc->horizontalSize = frame.width;
 		avc->verticalSize = frame.height;
diff --git a/rpcs3/Emu/Cell/Modules/cellVideoExport.cpp b/rpcs3/Emu/Cell/Modules/cellVideoExport.cpp
index 266d8abc45..90034a357f 100644
--- a/rpcs3/Emu/Cell/Modules/cellVideoExport.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellVideoExport.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellVideoExport);
+logs::channel cellVideoExport("cellVideoExport", logs::level::notice);
 
 s32 cellVideoExportProgress()
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellVideoOut.cpp b/rpcs3/Emu/Cell/Modules/cellVideoOut.cpp
index a3a2ba826c..27aa431d0b 100644
--- a/rpcs3/Emu/Cell/Modules/cellVideoOut.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellVideoOut.cpp
@@ -1,10 +1,11 @@
 #include "stdafx.h"
+#include "Utilities/Config.h"
 #include "Emu/System.h"
 #include "Emu/Cell/PPUModule.h"
 
 #include "cellVideoOut.h"
 
-extern _log::channel cellSysutil;
+extern logs::channel cellSysutil;
 
 cfg::map_entry<u8> g_cfg_video_out_resolution(cfg::root.video, "Resolution", "1280x720",
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellVideoUpload.cpp b/rpcs3/Emu/Cell/Modules/cellVideoUpload.cpp
index f41f52a573..5ab0c7ba5c 100644
--- a/rpcs3/Emu/Cell/Modules/cellVideoUpload.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellVideoUpload.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellVideoUpload);
+logs::channel cellVideoUpload("cellVideoUpload", logs::level::notice);
 
 s32 cellVideoUploadInitialize()
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellVoice.cpp b/rpcs3/Emu/Cell/Modules/cellVoice.cpp
index 83c227faa9..b9ae6d2331 100644
--- a/rpcs3/Emu/Cell/Modules/cellVoice.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellVoice.cpp
@@ -2,7 +2,7 @@
 #include "Emu/System.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(cellVoice);
+logs::channel cellVoice("cellVoice", logs::level::notice);
 
 // Error Codes
 enum
diff --git a/rpcs3/Emu/Cell/Modules/cellVpost.cpp b/rpcs3/Emu/Cell/Modules/cellVpost.cpp
index d42d4febbc..a8bdcbef42 100644
--- a/rpcs3/Emu/Cell/Modules/cellVpost.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellVpost.cpp
@@ -10,7 +10,7 @@ extern "C"
 
 #include "cellVpost.h"
 
-LOG_CHANNEL(cellVpost);
+logs::channel cellVpost("cellVpost", logs::level::notice);
 
 s32 cellVpostQueryAttr(vm::cptr<CellVpostCfgParam> cfgParam, vm::ptr<CellVpostAttr> attr)
 {
diff --git a/rpcs3/Emu/Cell/Modules/cellWebBrowser.cpp b/rpcs3/Emu/Cell/Modules/cellWebBrowser.cpp
index 4f0877a095..999056a52d 100644
--- a/rpcs3/Emu/Cell/Modules/cellWebBrowser.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellWebBrowser.cpp
@@ -3,7 +3,7 @@
 
 #include "cellWebBrowser.h"
 
-extern _log::channel cellSysutil;
+extern logs::channel cellSysutil;
 
 s32 cellWebBrowserActivate()
 {
diff --git a/rpcs3/Emu/Cell/Modules/libmixer.cpp b/rpcs3/Emu/Cell/Modules/libmixer.cpp
index 2813a039bb..932d20e67e 100644
--- a/rpcs3/Emu/Cell/Modules/libmixer.cpp
+++ b/rpcs3/Emu/Cell/Modules/libmixer.cpp
@@ -5,9 +5,11 @@
 
 #include "cellAudio.h"
 #include "libmixer.h"
-#include <cmath>
 
-LOG_CHANNEL(libmixer);
+#include <cmath>
+#include <thread>
+
+logs::channel libmixer("libmixer", logs::level::notice);
 
 // TODO: use fxm
 SurMixerConfig g_surmx;
@@ -332,7 +334,7 @@ s32 cellSurMixerCreate(vm::cptr<CellSurMixerConfig> config)
 
 			if (g_surmx.mixcount > (port.tag + 0)) // adding positive value (1-15): preemptive buffer filling (hack)
 			{
-				std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
+				std::this_thread::sleep_for(1ms); // hack
 				continue;
 			}
 
@@ -448,7 +450,7 @@ s32 cellSurMixerCreate(vm::cptr<CellSurMixerConfig> config)
 
 	ppu->cpu_init();
 	ppu->state -= cpu_state::stop;
-	ppu->lock_notify();
+	(*ppu)->lock_notify();
 
 	return CELL_OK;
 }
diff --git a/rpcs3/Emu/Cell/Modules/libsnd3.cpp b/rpcs3/Emu/Cell/Modules/libsnd3.cpp
index 861039754d..f76ffdc839 100644
--- a/rpcs3/Emu/Cell/Modules/libsnd3.cpp
+++ b/rpcs3/Emu/Cell/Modules/libsnd3.cpp
@@ -3,7 +3,7 @@
 
 #include "libsnd3.h"
 
-LOG_CHANNEL(libsnd3);
+logs::channel libsnd3("libsnd3", logs::level::notice);
 
 s32 cellSnd3Init(u32 maxVoice, u32 samples, vm::ptr<CellSnd3RequestQueueCtx> queue)
 {
diff --git a/rpcs3/Emu/Cell/Modules/libsynth2.cpp b/rpcs3/Emu/Cell/Modules/libsynth2.cpp
index 532932a2d7..98d123487e 100644
--- a/rpcs3/Emu/Cell/Modules/libsynth2.cpp
+++ b/rpcs3/Emu/Cell/Modules/libsynth2.cpp
@@ -3,7 +3,7 @@
 
 #include "libsynth2.h"
 
-LOG_CHANNEL(libsynth2);
+logs::channel libsynth2("libsynth2", logs::level::notice);
 
 s32 cellSoundSynth2Config(s16 param, s32 value)
 {
diff --git a/rpcs3/Emu/Cell/Modules/sceNp.cpp b/rpcs3/Emu/Cell/Modules/sceNp.cpp
index 80c682eeed..a1cd7c7ede 100644
--- a/rpcs3/Emu/Cell/Modules/sceNp.cpp
+++ b/rpcs3/Emu/Cell/Modules/sceNp.cpp
@@ -6,7 +6,7 @@
 #include "Crypto/unedat.h"
 #include "sceNp.h"
 
-LOG_CHANNEL(sceNp);
+logs::channel sceNp("sceNp", logs::level::notice);
 
 s32 sceNpInit(u32 poolsize, vm::ptr<void> poolptr)
 {
diff --git a/rpcs3/Emu/Cell/Modules/sceNp2.cpp b/rpcs3/Emu/Cell/Modules/sceNp2.cpp
index c424aaf877..653c4a5295 100644
--- a/rpcs3/Emu/Cell/Modules/sceNp2.cpp
+++ b/rpcs3/Emu/Cell/Modules/sceNp2.cpp
@@ -4,7 +4,7 @@
 #include "sceNp.h"
 #include "sceNp2.h"
 
-LOG_CHANNEL(sceNp2);
+logs::channel sceNp2("sceNp2", logs::level::notice);
 
 s32 sceNp2Init(u32 poolsize, vm::ptr<void> poolptr)
 {
diff --git a/rpcs3/Emu/Cell/Modules/sceNpClans.cpp b/rpcs3/Emu/Cell/Modules/sceNpClans.cpp
index e3d7daca27..eb3e3bed8a 100644
--- a/rpcs3/Emu/Cell/Modules/sceNpClans.cpp
+++ b/rpcs3/Emu/Cell/Modules/sceNpClans.cpp
@@ -5,7 +5,7 @@
 #include "sceNp.h"
 #include "sceNpClans.h"
 
-LOG_CHANNEL(sceNpClans);
+logs::channel sceNpClans("sceNpClans", logs::level::notice);
 
 s32 sceNpClansInit(vm::ptr<SceNpCommunicationId> commId, vm::ptr<SceNpCommunicationPassphrase> passphrase, vm::ptr<void> pool, vm::ptr<u32> poolSize, u32 flags)
 {
diff --git a/rpcs3/Emu/Cell/Modules/sceNpCommerce2.cpp b/rpcs3/Emu/Cell/Modules/sceNpCommerce2.cpp
index ba8f47ce7e..5b9b9e50d0 100644
--- a/rpcs3/Emu/Cell/Modules/sceNpCommerce2.cpp
+++ b/rpcs3/Emu/Cell/Modules/sceNpCommerce2.cpp
@@ -3,7 +3,7 @@
 
 #include "sceNpCommerce2.h"
 
-LOG_CHANNEL(sceNpCommerce2);
+logs::channel sceNpCommerce2("sceNpCommerce2", logs::level::notice);
 
 s32 sceNpCommerce2ExecuteStoreBrowse()
 {
diff --git a/rpcs3/Emu/Cell/Modules/sceNpSns.cpp b/rpcs3/Emu/Cell/Modules/sceNpSns.cpp
index 15dc2c7153..552b69807a 100644
--- a/rpcs3/Emu/Cell/Modules/sceNpSns.cpp
+++ b/rpcs3/Emu/Cell/Modules/sceNpSns.cpp
@@ -3,7 +3,7 @@
 
 #include "sceNpSns.h"
 
-LOG_CHANNEL(sceNpSns);
+logs::channel sceNpSns("sceNpSns", logs::level::notice);
 
 s32 sceNpSnsFbInit(vm::ptr<const SceNpSnsFbInitParams> params)
 {
diff --git a/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp b/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp
index f81d2b535d..1f011f2b2b 100644
--- a/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp
+++ b/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp
@@ -12,7 +12,7 @@
 
 #include "Utilities/StrUtil.h"
 
-LOG_CHANNEL(sceNpTrophy);
+logs::channel sceNpTrophy("sceNpTrophy", logs::level::notice);
 
 struct trophy_context_t
 {
@@ -269,7 +269,7 @@ s32 sceNpTrophyGetGameInfo(u32 context, u32 handle, vm::ptr<SceNpTrophyGameDetai
 	const std::string& path = vfs::get("/dev_hdd0/home/00000001/trophy/" + ctxt->trp_name + "/TROPCONF.SFM");
 	
 	// TODO: rXmlDocument can open only real file
-	ASSERT(!fs::get_virtual_device(path)); 
+	VERIFY(!fs::get_virtual_device(path)); 
 	rXmlDocument doc;
 	doc.Load(path);
 
@@ -399,7 +399,7 @@ s32 sceNpTrophyGetTrophyInfo(u32 context, u32 handle, s32 trophyId, vm::ptr<SceN
 	const std::string& path = vfs::get("/dev_hdd0/home/00000001/trophy/" + ctxt->trp_name + "/TROPCONF.SFM");
 
 	// TODO: rXmlDocument can open only real file
-	ASSERT(!fs::get_virtual_device(path));
+	VERIFY(!fs::get_virtual_device(path));
 	rXmlDocument doc; 
 	doc.Load(path);
 
diff --git a/rpcs3/Emu/Cell/Modules/sceNpTus.cpp b/rpcs3/Emu/Cell/Modules/sceNpTus.cpp
index 1ee55bf9f6..932f667f51 100644
--- a/rpcs3/Emu/Cell/Modules/sceNpTus.cpp
+++ b/rpcs3/Emu/Cell/Modules/sceNpTus.cpp
@@ -4,7 +4,7 @@
 #include "sceNp.h"
 #include "sceNpTus.h"
 
-LOG_CHANNEL(sceNpTus);
+logs::channel sceNpTus("sceNpTus", logs::level::notice);
 
 s32 sceNpTusInit()
 {
diff --git a/rpcs3/Emu/Cell/Modules/sceNpUtil.cpp b/rpcs3/Emu/Cell/Modules/sceNpUtil.cpp
index 0dc924f80a..0d99b7e843 100644
--- a/rpcs3/Emu/Cell/Modules/sceNpUtil.cpp
+++ b/rpcs3/Emu/Cell/Modules/sceNpUtil.cpp
@@ -4,7 +4,7 @@
 #include "sceNp.h"
 #include "sceNpUtil.h"
 
-LOG_CHANNEL(sceNpUtil);
+logs::channel sceNpUtil("sceNpUtil", logs::level::notice);
 
 s32 sceNpUtilBandwidthTestInitStart(u32 prio, size_t stack)
 {
diff --git a/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp b/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp
index b531810687..d82f10ac30 100644
--- a/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp
+++ b/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp
@@ -6,7 +6,7 @@
 #include "Emu/Cell/lv2/sys_process.h"
 #include "sysPrxForUser.h"
 
-LOG_CHANNEL(sysPrxForUser);
+logs::channel sysPrxForUser("sysPrxForUser", logs::level::notice);
 
 extern u64 get_system_time();
 
diff --git a/rpcs3/Emu/Cell/Modules/sys_game.cpp b/rpcs3/Emu/Cell/Modules/sys_game.cpp
index 1c2d47b368..974ad7d3ee 100644
--- a/rpcs3/Emu/Cell/Modules/sys_game.cpp
+++ b/rpcs3/Emu/Cell/Modules/sys_game.cpp
@@ -4,7 +4,7 @@
 
 #include "sysPrxForUser.h"
 
-extern _log::channel sysPrxForUser;
+extern logs::channel sysPrxForUser;
 
 void sys_game_process_exitspawn(vm::cptr<char> path, u32 argv_addr, u32 envp_addr, u32 data_addr, u32 data_size, u32 prio, u64 flags)
 {
diff --git a/rpcs3/Emu/Cell/Modules/sys_heap.cpp b/rpcs3/Emu/Cell/Modules/sys_heap.cpp
index 13b344fd2f..7d711f0f22 100644
--- a/rpcs3/Emu/Cell/Modules/sys_heap.cpp
+++ b/rpcs3/Emu/Cell/Modules/sys_heap.cpp
@@ -5,7 +5,7 @@
 
 #include "sysPrxForUser.h"
 
-extern _log::channel sysPrxForUser;
+extern logs::channel sysPrxForUser;
 
 struct HeapInfo
 {
diff --git a/rpcs3/Emu/Cell/Modules/sys_io.cpp b/rpcs3/Emu/Cell/Modules/sys_io.cpp
index 11d2202e5d..7a5dad63b0 100644
--- a/rpcs3/Emu/Cell/Modules/sys_io.cpp
+++ b/rpcs3/Emu/Cell/Modules/sys_io.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-LOG_CHANNEL(sys_io);
+logs::channel sys_io("sys_io", logs::level::notice);
 
 extern void cellPad_init();
 extern void cellKb_init();
diff --git a/rpcs3/Emu/Cell/Modules/sys_libc.cpp b/rpcs3/Emu/Cell/Modules/sys_libc.cpp
index 74fabd32b0..38195675d8 100644
--- a/rpcs3/Emu/Cell/Modules/sys_libc.cpp
+++ b/rpcs3/Emu/Cell/Modules/sys_libc.cpp
@@ -3,7 +3,7 @@
 #include "Emu/Cell/PPUModule.h"
 #include "Emu/Cell/PPUOpcodes.h"
 
-LOG_CHANNEL(sys_libc);
+logs::channel sys_libc("sys_libc", logs::level::notice);
 
 namespace sys_libc_func
 {
diff --git a/rpcs3/Emu/Cell/Modules/sys_libc_.cpp b/rpcs3/Emu/Cell/Modules/sys_libc_.cpp
index 15be5a9f46..97b1045823 100644
--- a/rpcs3/Emu/Cell/Modules/sys_libc_.cpp
+++ b/rpcs3/Emu/Cell/Modules/sys_libc_.cpp
@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "Emu/Cell/PPUModule.h"
 
-extern _log::channel sysPrxForUser;
+extern logs::channel sysPrxForUser;
 
 extern fs::file g_tty;
 
diff --git a/rpcs3/Emu/Cell/Modules/sys_lv2dbg.cpp b/rpcs3/Emu/Cell/Modules/sys_lv2dbg.cpp
index 791e29ceed..eaa1c38f26 100644
--- a/rpcs3/Emu/Cell/Modules/sys_lv2dbg.cpp
+++ b/rpcs3/Emu/Cell/Modules/sys_lv2dbg.cpp
@@ -5,7 +5,7 @@
 
 #include "sys_lv2dbg.h"
 
-LOG_CHANNEL(sys_lv2dbg);
+logs::channel sys_lv2dbg("sys_lv2dbg", logs::level::notice);
 
 s32 sys_dbg_read_ppu_thread_context(u64 id, vm::ptr<sys_dbg_ppu_thread_context_t> ppu_context)
 {
diff --git a/rpcs3/Emu/Cell/Modules/sys_lwcond_.cpp b/rpcs3/Emu/Cell/Modules/sys_lwcond_.cpp
index 7b4b019a8d..4d3e0e5518 100644
--- a/rpcs3/Emu/Cell/Modules/sys_lwcond_.cpp
+++ b/rpcs3/Emu/Cell/Modules/sys_lwcond_.cpp
@@ -7,7 +7,7 @@
 #include "Emu/Cell/lv2/sys_lwcond.h"
 #include "sysPrxForUser.h"
 
-extern _log::channel sysPrxForUser;
+extern logs::channel sysPrxForUser;
 
 s32 sys_lwcond_create(vm::ptr<sys_lwcond_t> lwcond, vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwcond_attribute_t> attr)
 {
diff --git a/rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp b/rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp
index 7cbaab6dba..7050e97aa5 100644
--- a/rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp
+++ b/rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp
@@ -7,7 +7,7 @@
 #include "Emu/Cell/lv2/sys_lwmutex.h"
 #include "sysPrxForUser.h"
 
-extern _log::channel sysPrxForUser;
+extern logs::channel sysPrxForUser;
 
 s32 sys_lwmutex_create(vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmutex_attribute_t> attr)
 {
diff --git a/rpcs3/Emu/Cell/Modules/sys_mempool.cpp b/rpcs3/Emu/Cell/Modules/sys_mempool.cpp
index 99763b4b1f..b4f748485b 100644
--- a/rpcs3/Emu/Cell/Modules/sys_mempool.cpp
+++ b/rpcs3/Emu/Cell/Modules/sys_mempool.cpp
@@ -5,7 +5,7 @@
 
 #include "sysPrxForUser.h"
 
-extern _log::channel sysPrxForUser;
+extern logs::channel sysPrxForUser;
 
 using sys_mempool_t = u32;
 
diff --git a/rpcs3/Emu/Cell/Modules/sys_mmapper_.cpp b/rpcs3/Emu/Cell/Modules/sys_mmapper_.cpp
index 37830aea71..e07618022e 100644
--- a/rpcs3/Emu/Cell/Modules/sys_mmapper_.cpp
+++ b/rpcs3/Emu/Cell/Modules/sys_mmapper_.cpp
@@ -5,7 +5,7 @@
 #include "Emu/Cell/lv2/sys_mmapper.h"
 #include "sysPrxForUser.h"
 
-extern _log::channel sysPrxForUser;
+extern logs::channel sysPrxForUser;
 
 void sysPrxForUser_sys_mmapper_init()
 {
diff --git a/rpcs3/Emu/Cell/Modules/sys_net.cpp b/rpcs3/Emu/Cell/Modules/sys_net.cpp
index abe038f6c4..126dfd515c 100644
--- a/rpcs3/Emu/Cell/Modules/sys_net.cpp
+++ b/rpcs3/Emu/Cell/Modules/sys_net.cpp
@@ -14,7 +14,7 @@
 #include <unistd.h>
 #endif
 
-LOG_CHANNEL(libnet);
+logs::channel libnet("libnet", logs::level::notice);
 
 // We map host sockets to sequential IDs to return as FDs because syscalls using
 // socketselect(), etc. expect socket FDs to be under 1024.
@@ -127,7 +127,7 @@ namespace sys_net
 		{
 			g_tls_net_data.set(vm::alloc(sizeof(decltype(g_tls_net_data)::type), vm::main));
 
-			thread_ctrl::at_exit([addr = g_tls_net_data.addr()]
+			thread_ctrl::atexit([addr = g_tls_net_data.addr()]
 			{
 				vm::dealloc_verbose_nothrow(addr, vm::main);
 			});
diff --git a/rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp b/rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp
index f339fa8407..b37289ec3f 100644
--- a/rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp
+++ b/rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp
@@ -5,7 +5,7 @@
 #include "Emu/Cell/lv2/sys_ppu_thread.h"
 #include "sysPrxForUser.h"
 
-extern _log::channel sysPrxForUser;
+extern logs::channel sysPrxForUser;
 
 extern u32 ppu_alloc_tls();
 extern void ppu_free_tls(u32 addr);
diff --git a/rpcs3/Emu/Cell/Modules/sys_prx_.cpp b/rpcs3/Emu/Cell/Modules/sys_prx_.cpp
index 1b2fac8523..70ba08027c 100644
--- a/rpcs3/Emu/Cell/Modules/sys_prx_.cpp
+++ b/rpcs3/Emu/Cell/Modules/sys_prx_.cpp
@@ -5,7 +5,7 @@
 #include "Emu/Cell/lv2/sys_prx.h"
 #include "sysPrxForUser.h"
 
-extern _log::channel sysPrxForUser;
+extern logs::channel sysPrxForUser;
 
 s64 sys_prx_exitspawn_with_level()
 {
diff --git a/rpcs3/Emu/Cell/Modules/sys_spinlock.cpp b/rpcs3/Emu/Cell/Modules/sys_spinlock.cpp
index 9ec0c65ff8..47a5986fe1 100644
--- a/rpcs3/Emu/Cell/Modules/sys_spinlock.cpp
+++ b/rpcs3/Emu/Cell/Modules/sys_spinlock.cpp
@@ -6,7 +6,7 @@
 
 #include "Emu/Memory/wait_engine.h"
 
-extern _log::channel sysPrxForUser;
+extern logs::channel sysPrxForUser;
 
 void sys_spinlock_initialize(vm::ptr<atomic_be_t<u32>> lock)
 {
diff --git a/rpcs3/Emu/Cell/Modules/sys_spu_.cpp b/rpcs3/Emu/Cell/Modules/sys_spu_.cpp
index 3d2c0e6863..111ce221de 100644
--- a/rpcs3/Emu/Cell/Modules/sys_spu_.cpp
+++ b/rpcs3/Emu/Cell/Modules/sys_spu_.cpp
@@ -7,7 +7,7 @@
 #include "Crypto/unself.h"
 #include "sysPrxForUser.h"
 
-extern _log::channel sysPrxForUser;
+extern logs::channel sysPrxForUser;
 
 extern u64 get_system_time();
 
@@ -59,7 +59,7 @@ s32 sys_spu_image_close(vm::ptr<sys_spu_image_t> img)
 		return CELL_EINVAL;
 	}
 
-	ASSERT(vm::dealloc(img->segs.addr(), vm::main)); // Current rough implementation
+	VERIFY(vm::dealloc(img->segs.addr(), vm::main)); // Current rough implementation
 	return CELL_OK;
 }
 
diff --git a/rpcs3/Emu/Cell/PPUCallback.cpp b/rpcs3/Emu/Cell/PPUCallback.cpp
index f1652f4d66..3f29de1945 100644
--- a/rpcs3/Emu/Cell/PPUCallback.cpp
+++ b/rpcs3/Emu/Cell/PPUCallback.cpp
@@ -6,6 +6,8 @@
 #include "PPUThread.h"
 #include "PPUCallback.h"
 
+#include <condition_variable>
+
 void CallbackManager::Register(check_cb_t func)
 {
 	std::lock_guard<std::mutex> lock(m_mutex);
@@ -24,9 +26,11 @@ void CallbackManager::Async(async_cb_t func)
 
 	m_async_cb.emplace(std::move(func));
 
-	m_cb_thread->notify();
+	(*m_cb_thread)->notify();
 }
 
+extern std::condition_variable& get_current_thread_cv();
+
 CallbackManager::check_cb_t CallbackManager::Check()
 {
 	std::lock_guard<std::mutex> lock(m_mutex);
diff --git a/rpcs3/Emu/Cell/PPUCallback.h b/rpcs3/Emu/Cell/PPUCallback.h
index 66b3ce2449..42fe061830 100644
--- a/rpcs3/Emu/Cell/PPUCallback.h
+++ b/rpcs3/Emu/Cell/PPUCallback.h
@@ -193,6 +193,7 @@ template<typename RT, typename... T> inline RT cb_call(PPUThread& CPU, u32 pc, u
 }
 
 #include <queue>
+#include <mutex>
 
 class CallbackManager
 {
diff --git a/rpcs3/Emu/Cell/PPUDisAsm.cpp b/rpcs3/Emu/Cell/PPUDisAsm.cpp
index 31a1cfa48d..2d2f93e8d9 100644
--- a/rpcs3/Emu/Cell/PPUDisAsm.cpp
+++ b/rpcs3/Emu/Cell/PPUDisAsm.cpp
@@ -10,16 +10,6 @@ u32 PPUDisAsm::disasm(u32 pc)
 	return 4;
 }
 
-void PPUDisAsm::TDI(ppu_opcode_t op)
-{
-	DisAsm_INT1_R1_IMM("tdi", op.bo, op.ra, op.simm16);
-}
-
-void PPUDisAsm::TWI(ppu_opcode_t op)
-{
-	DisAsm_INT1_R1_IMM("twi", op.bo, op.ra, op.simm16);
-}
-
 void PPUDisAsm::MFVSCR(ppu_opcode_t op)
 {
 	DisAsm_V1("mfvscr", op.vd);
@@ -740,6 +730,16 @@ void PPUDisAsm::VXOR(ppu_opcode_t op)
 	DisAsm_V3("vxor", op.vd, op.va, op.vb);
 }
 
+void PPUDisAsm::TDI(ppu_opcode_t op)
+{
+	DisAsm_INT1_R1_IMM("tdi", op.bo, op.ra, op.simm16);
+}
+
+void PPUDisAsm::TWI(ppu_opcode_t op)
+{
+	DisAsm_INT1_R1_IMM("twi", op.bo, op.ra, op.simm16);
+}
+
 void PPUDisAsm::MULLI(ppu_opcode_t op)
 {
 	DisAsm_R2_IMM("mulli", op.rd, op.ra, op.simm16);
@@ -1949,6 +1949,16 @@ void PPUDisAsm::LWA(ppu_opcode_t op)
 	DisAsm_R2_IMM("lwa", op.rd, op.ra, op.ds * 4);
 }
 
+void PPUDisAsm::STD(ppu_opcode_t op)
+{
+	DisAsm_R2_IMM("std", op.rs, op.ra, op.ds * 4);
+}
+
+void PPUDisAsm::STDU(ppu_opcode_t op)
+{
+	DisAsm_R2_IMM("stdu", op.rs, op.ra, op.ds * 4);
+}
+
 void PPUDisAsm::FDIVS(ppu_opcode_t op)
 {
 	DisAsm_F3_RC("fdivs", op.frd, op.fra, op.frb, op.rc);
@@ -1999,16 +2009,6 @@ void PPUDisAsm::FNMADDS(ppu_opcode_t op)
 	DisAsm_F4_RC("fnmadds", op.frd, op.fra, op.frc, op.frb, op.rc);
 }
 
-void PPUDisAsm::STD(ppu_opcode_t op)
-{
-	DisAsm_R2_IMM("std", op.rs, op.ra, op.ds * 4);
-}
-
-void PPUDisAsm::STDU(ppu_opcode_t op)
-{
-	DisAsm_R2_IMM("stdu", op.rs, op.ra, op.ds * 4);
-}
-
 void PPUDisAsm::MTFSB1(ppu_opcode_t op)
 {
 	Write(fmt::format("mtfsb1%s %d", op.rc ? "." : "", op.crbd));
diff --git a/rpcs3/Emu/Cell/PPUDisAsm.h b/rpcs3/Emu/Cell/PPUDisAsm.h
index 7138bfe519..37d969a728 100644
--- a/rpcs3/Emu/Cell/PPUDisAsm.h
+++ b/rpcs3/Emu/Cell/PPUDisAsm.h
@@ -243,8 +243,6 @@ private:
 public:
 	u32 disasm(u32 pc) override;
 
-	void TDI(ppu_opcode_t op);
-	void TWI(ppu_opcode_t op);
 	void MFVSCR(ppu_opcode_t op);
 	void MTVSCR(ppu_opcode_t op);
 	void VADDCUW(ppu_opcode_t op);
@@ -389,6 +387,8 @@ public:
 	void VUPKLSB(ppu_opcode_t op);
 	void VUPKLSH(ppu_opcode_t op);
 	void VXOR(ppu_opcode_t op);
+	void TDI(ppu_opcode_t op);
+	void TWI(ppu_opcode_t op);
 	void MULLI(ppu_opcode_t op);
 	void SUBFIC(ppu_opcode_t op);
 	void CMPLI(ppu_opcode_t op);
@@ -582,6 +582,8 @@ public:
 	void LD(ppu_opcode_t op);
 	void LDU(ppu_opcode_t op);
 	void LWA(ppu_opcode_t op);
+	void STD(ppu_opcode_t op);
+	void STDU(ppu_opcode_t op);
 	void FDIVS(ppu_opcode_t op);
 	void FSUBS(ppu_opcode_t op);
 	void FADDS(ppu_opcode_t op);
@@ -592,8 +594,6 @@ public:
 	void FMSUBS(ppu_opcode_t op);
 	void FNMSUBS(ppu_opcode_t op);
 	void FNMADDS(ppu_opcode_t op);
-	void STD(ppu_opcode_t op);
-	void STDU(ppu_opcode_t op);
 	void MTFSB1(ppu_opcode_t op);
 	void MCRFS(ppu_opcode_t op);
 	void MTFSB0(ppu_opcode_t op);
diff --git a/rpcs3/Emu/Cell/PPUInterpreter.cpp b/rpcs3/Emu/Cell/PPUInterpreter.cpp
index 5601971adf..c15b27762d 100644
--- a/rpcs3/Emu/Cell/PPUInterpreter.cpp
+++ b/rpcs3/Emu/Cell/PPUInterpreter.cpp
@@ -2,6 +2,7 @@
 #include "Emu/System.h"
 #include "PPUThread.h"
 #include "PPUInterpreter.h"
+
 #include <cmath>
 
 // TODO: fix rol8 and rol16 for __GNUG__ (probably with __asm__)
@@ -147,70 +148,44 @@ public:
 }
 const g_ppu_scale_table;
 
-void ppu_interpreter::TDI(PPUThread& ppu, ppu_opcode_t op)
-{
-	const s64 a = ppu.GPR[op.ra], b = op.simm16;
-	const u64 a_ = a, b_ = b;
-
-	if (((op.bo & 0x10) && a < b) ||
-		((op.bo & 0x8) && a > b) ||
-		((op.bo & 0x4) && a == b) ||
-		((op.bo & 0x2) && a_ < b_) ||
-		((op.bo & 0x1) && a_ > b_))
-	{
-		throw std::runtime_error("Trap!" HERE);
-	}
-}
-
-void ppu_interpreter::TWI(PPUThread& ppu, ppu_opcode_t op)
-{
-	const s32 a = u32(ppu.GPR[op.ra]), b = op.simm16;
-	const u32 a_ = a, b_ = b;
-
-	if (((op.bo & 0x10) && a < b) ||
-		((op.bo & 0x8) && a > b) ||
-		((op.bo & 0x4) && a == b) ||
-		((op.bo & 0x2) && a_ < b_) ||
-		((op.bo & 0x1) && a_ > b_))
-	{
-		throw std::runtime_error("Trap!" HERE);
-	}
-}
-
-
-void ppu_interpreter::MFVSCR(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::MFVSCR(PPUThread& ppu, ppu_opcode_t op)
 {
 	throw std::runtime_error("MFVSCR" HERE);
 }
 
-void ppu_interpreter::MTVSCR(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::MTVSCR(PPUThread& ppu, ppu_opcode_t op)
 {
 	LOG_WARNING(PPU, "MTVSCR");
+	return true;
 }
 
-void ppu_interpreter::VADDCUW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VADDCUW(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto a = ppu.VR[op.va].vi;
 	const auto b = ppu.VR[op.vb].vi;
 	ppu.VR[op.vd].vi = _mm_srli_epi32(_mm_cmpgt_epi32(_mm_xor_si128(b, _mm_set1_epi32(0x80000000)), _mm_xor_si128(a, _mm_set1_epi32(0x7fffffff))), 31);
+	return true;
 }
 
-void ppu_interpreter::VADDFP(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VADDFP(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd] = v128::addfs(ppu.VR[op.va], ppu.VR[op.vb]);
+	return true;
 }
 
-void ppu_interpreter::VADDSBS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VADDSBS(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_adds_epi8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi);
+	return true;
 }
 
-void ppu_interpreter::VADDSHS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VADDSHS(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_adds_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi);
+	return true;
 }
 
-void ppu_interpreter::VADDSWS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VADDSWS(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto a = ppu.VR[op.va];
 	const auto b = ppu.VR[op.vb];
@@ -219,51 +194,60 @@ void ppu_interpreter::VADDSWS(PPUThread& ppu, ppu_opcode_t op)
 	const auto x = _mm_srai_epi32(m.vi, 31); // saturation mask
 	const auto y = _mm_srai_epi32(_mm_and_si128(s.vi, m.vi), 31); // positive saturation mask
 	ppu.VR[op.vd].vi = _mm_xor_si128(_mm_xor_si128(_mm_srli_epi32(x, 1), y), _mm_or_si128(s.vi, x));
+	return true;
 }
 
-void ppu_interpreter::VADDUBM(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VADDUBM(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd] = v128::add8(ppu.VR[op.va], ppu.VR[op.vb]);
+	return true;
 }
 
-void ppu_interpreter::VADDUBS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VADDUBS(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_adds_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi);
+	return true;
 }
 
-void ppu_interpreter::VADDUHM(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VADDUHM(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd] = v128::add16(ppu.VR[op.va], ppu.VR[op.vb]);
+	return true;
 }
 
-void ppu_interpreter::VADDUHS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VADDUHS(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_adds_epu16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi);
+	return true;
 }
 
-void ppu_interpreter::VADDUWM(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VADDUWM(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd] = v128::add32(ppu.VR[op.va], ppu.VR[op.vb]);
+	return true;
 }
 
-void ppu_interpreter::VADDUWS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VADDUWS(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto a = ppu.VR[op.va].vi;
 	const auto b = ppu.VR[op.vb].vi;
 	ppu.VR[op.vd].vi = _mm_or_si128(_mm_add_epi32(a, b), _mm_cmpgt_epi32(_mm_xor_si128(b, _mm_set1_epi32(0x80000000)), _mm_xor_si128(a, _mm_set1_epi32(0x7fffffff))));
+	return true;
 }
 
-void ppu_interpreter::VAND(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VAND(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd] = ppu.VR[op.va] & ppu.VR[op.vb];
+	return true;
 }
 
-void ppu_interpreter::VANDC(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VANDC(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd] = v128::andnot(ppu.VR[op.vb], ppu.VR[op.va]);
+	return true;
 }
 
-void ppu_interpreter::VAVGSB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VAVGSB(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto a = ppu.VR[op.va];
 	const auto b = v128::add8(ppu.VR[op.vb], v128::from8p(1)); // add 1
@@ -271,9 +255,10 @@ void ppu_interpreter::VAVGSB(PPUThread& ppu, ppu_opcode_t op)
 	const auto sign = v128::from8p(0x80);
 	const auto overflow = (((a ^ summ) & (b ^ summ)) ^ summ ^ v128::eq8(b, sign)) & sign; // calculate msb
 	ppu.VR[op.vd].vi = _mm_or_si128(overflow.vi, _mm_srli_epi64(summ.vi, 1));
+	return true;
 }
 
-void ppu_interpreter::VAVGSH(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VAVGSH(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto a = ppu.VR[op.va];
 	const auto b = v128::add16(ppu.VR[op.vb], v128::from16p(1)); // add 1
@@ -281,9 +266,10 @@ void ppu_interpreter::VAVGSH(PPUThread& ppu, ppu_opcode_t op)
 	const auto sign = v128::from16p(0x8000);
 	const auto overflow = (((a ^ summ) & (b ^ summ)) ^ summ ^ v128::eq16(b, sign)) & sign; // calculate msb
 	ppu.VR[op.vd].vi = _mm_or_si128(overflow.vi, _mm_srli_epi16(summ.vi, 1));
+	return true;
 }
 
-void ppu_interpreter::VAVGSW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VAVGSW(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto a = ppu.VR[op.va];
 	const auto b = v128::add32(ppu.VR[op.vb], v128::from32p(1)); // add 1
@@ -291,40 +277,46 @@ void ppu_interpreter::VAVGSW(PPUThread& ppu, ppu_opcode_t op)
 	const auto sign = v128::from32p(0x80000000);
 	const auto overflow = (((a ^ summ) & (b ^ summ)) ^ summ ^ v128::eq32(b, sign)) & sign; // calculate msb
 	ppu.VR[op.vd].vi = _mm_or_si128(overflow.vi, _mm_srli_epi32(summ.vi, 1));
+	return true;
 }
 
-void ppu_interpreter::VAVGUB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VAVGUB(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_avg_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi);
+	return true;
 }
 
-void ppu_interpreter::VAVGUH(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VAVGUH(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_avg_epu16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi);
+	return true;
 }
 
-void ppu_interpreter::VAVGUW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VAVGUW(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto a = ppu.VR[op.va];
 	const auto b = ppu.VR[op.vb];
 	const auto summ = v128::add32(v128::add32(a, b), v128::from32p(1));
 	const auto carry = _mm_xor_si128(_mm_slli_epi32(sse_cmpgt_epu32(summ.vi, a.vi), 31), _mm_set1_epi32(0x80000000));
 	ppu.VR[op.vd].vi = _mm_or_si128(carry, _mm_srli_epi32(summ.vi, 1));
+	return true;
 }
 
-void ppu_interpreter::VCFSX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VCFSX(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vf = _mm_mul_ps(_mm_cvtepi32_ps(ppu.VR[op.vb].vi), g_ppu_scale_table[0 - op.vuimm]);
+	return true;
 }
 
-void ppu_interpreter::VCFUX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VCFUX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto b = ppu.VR[op.vb].vi;
 	const auto fix = _mm_and_ps(_mm_castsi128_ps(_mm_srai_epi32(b, 31)), _mm_set1_ps(0x80000000));
 	ppu.VR[op.vd].vf = _mm_mul_ps(_mm_add_ps(_mm_cvtepi32_ps(_mm_and_si128(b, _mm_set1_epi32(0x7fffffff))), fix), g_ppu_scale_table[0 - op.vuimm]);
+	return true;
 }
 
-void ppu_interpreter::VCMPBFP(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VCMPBFP(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto a = ppu.VR[op.va].vf;
 	const auto b = ppu.VR[op.vb].vf;
@@ -333,154 +325,179 @@ void ppu_interpreter::VCMPBFP(PPUThread& ppu, ppu_opcode_t op)
 	const auto cmp2 = _mm_cmpnge_ps(a, _mm_xor_ps(b, sign));
 	ppu.VR[op.vd].vf = _mm_or_ps(_mm_and_ps(cmp1, sign), _mm_and_ps(cmp2, _mm_castsi128_ps(_mm_set1_epi32(0x40000000))));
 	if (UNLIKELY(op.oe)) ppu.SetCR(6, false, false, _mm_movemask_ps(_mm_or_ps(cmp1, cmp2)) == 0, false);
+	return true;
 }
 
-void ppu_interpreter::VCMPEQFP(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VCMPEQFP(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto rmask = _mm_movemask_ps(ppu.VR[op.vd].vf = _mm_cmpeq_ps(ppu.VR[op.va].vf, ppu.VR[op.vb].vf));
 	if (UNLIKELY(op.oe)) ppu.SetCR(6, rmask == 0xf, false, rmask == 0, false);
+	return true;
 }
 
-void ppu_interpreter::VCMPEQUB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VCMPEQUB(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto rmask = _mm_movemask_epi8((ppu.VR[op.vd] = v128::eq8(ppu.VR[op.va], ppu.VR[op.vb])).vi);
 	if (UNLIKELY(op.oe)) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false);
+	return true;
 }
 
-void ppu_interpreter::VCMPEQUH(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VCMPEQUH(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto rmask = _mm_movemask_epi8((ppu.VR[op.vd] = v128::eq16(ppu.VR[op.va], ppu.VR[op.vb])).vi);
 	if (UNLIKELY(op.oe)) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false);
+	return true;
 }
 
-void ppu_interpreter::VCMPEQUW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VCMPEQUW(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto rmask = _mm_movemask_epi8((ppu.VR[op.vd] = v128::eq32(ppu.VR[op.va], ppu.VR[op.vb])).vi);
 	if (UNLIKELY(op.oe)) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false);
+	return true;
 }
 
-void ppu_interpreter::VCMPGEFP(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VCMPGEFP(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto rmask = _mm_movemask_ps(ppu.VR[op.vd].vf = _mm_cmpge_ps(ppu.VR[op.va].vf, ppu.VR[op.vb].vf));
 	if (UNLIKELY(op.oe)) ppu.SetCR(6, rmask == 0xf, false, rmask == 0, false);
+	return true;
 }
 
-void ppu_interpreter::VCMPGTFP(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VCMPGTFP(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto rmask = _mm_movemask_ps(ppu.VR[op.vd].vf = _mm_cmpgt_ps(ppu.VR[op.va].vf, ppu.VR[op.vb].vf));
 	if (UNLIKELY(op.oe)) ppu.SetCR(6, rmask == 0xf, false, rmask == 0, false);
+	return true;
 }
 
-void ppu_interpreter::VCMPGTSB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VCMPGTSB(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto rmask = _mm_movemask_epi8(ppu.VR[op.vd].vi = _mm_cmpgt_epi8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi));
 	if (UNLIKELY(op.oe)) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false);
+	return true;
 }
 
-void ppu_interpreter::VCMPGTSH(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VCMPGTSH(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto rmask = _mm_movemask_epi8(ppu.VR[op.vd].vi = _mm_cmpgt_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi));
 	if (UNLIKELY(op.oe)) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false);
+	return true;
 }
 
-void ppu_interpreter::VCMPGTSW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VCMPGTSW(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto rmask = _mm_movemask_epi8(ppu.VR[op.vd].vi = _mm_cmpgt_epi32(ppu.VR[op.va].vi, ppu.VR[op.vb].vi));
 	if (UNLIKELY(op.oe)) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false);
+	return true;
 }
 
-void ppu_interpreter::VCMPGTUB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VCMPGTUB(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto rmask = _mm_movemask_epi8(ppu.VR[op.vd].vi = sse_cmpgt_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi));
 	if (UNLIKELY(op.oe)) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false);
+	return true;
 }
 
-void ppu_interpreter::VCMPGTUH(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VCMPGTUH(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto rmask = _mm_movemask_epi8(ppu.VR[op.vd].vi = sse_cmpgt_epu16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi));
 	if (UNLIKELY(op.oe)) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false);
+	return true;
 }
 
-void ppu_interpreter::VCMPGTUW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VCMPGTUW(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto rmask = _mm_movemask_epi8(ppu.VR[op.vd].vi = sse_cmpgt_epu32(ppu.VR[op.va].vi, ppu.VR[op.vb].vi));
 	if (UNLIKELY(op.oe)) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false);
+	return true;
 }
 
-void ppu_interpreter::VCTSXS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VCTSXS(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto scaled = _mm_mul_ps(ppu.VR[op.vb].vf, g_ppu_scale_table[op.vuimm]);
 	ppu.VR[op.vd].vi = _mm_xor_si128(_mm_cvttps_epi32(scaled), _mm_castps_si128(_mm_cmpge_ps(scaled, _mm_set1_ps(0x80000000))));
+	return true;
 }
 
-void ppu_interpreter::VCTUXS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VCTUXS(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto scaled1 = _mm_max_ps(_mm_mul_ps(ppu.VR[op.vb].vf, g_ppu_scale_table[op.vuimm]), _mm_set1_ps(0.0f));
 	const auto scaled2 = _mm_and_ps(_mm_sub_ps(scaled1, _mm_set1_ps(0x80000000)), _mm_cmpge_ps(scaled1, _mm_set1_ps(0x80000000)));
 	ppu.VR[op.vd].vi = _mm_or_si128(_mm_or_si128(_mm_cvttps_epi32(scaled1), _mm_cvttps_epi32(scaled2)), _mm_castps_si128(_mm_cmpge_ps(scaled1, _mm_set1_ps(0x100000000))));
+	return true;
 }
 
-void ppu_interpreter::VEXPTEFP(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VEXPTEFP(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vf = sse_exp2_ps(ppu.VR[op.vb].vf);
+	return true;
 }
 
-void ppu_interpreter::VLOGEFP(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VLOGEFP(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vf = sse_log2_ps(ppu.VR[op.vb].vf);
+	return true;
 }
 
-void ppu_interpreter::VMADDFP(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMADDFP(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vf = _mm_add_ps(_mm_mul_ps(ppu.VR[op.va].vf, ppu.VR[op.vc].vf), ppu.VR[op.vb].vf);
+	return true;
 }
 
-void ppu_interpreter::VMAXFP(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMAXFP(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vf = _mm_max_ps(ppu.VR[op.va].vf, ppu.VR[op.vb].vf);
+	return true;
 }
 
-void ppu_interpreter::VMAXSB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMAXSB(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto a = ppu.VR[op.va].vi;
 	const auto b = ppu.VR[op.vb].vi;
 	const auto m = _mm_cmpgt_epi8(a, b);
 	ppu.VR[op.vd].vi = _mm_or_si128(_mm_and_si128(m, a), _mm_andnot_si128(m, b));
+	return true;
 }
 
-void ppu_interpreter::VMAXSH(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMAXSH(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_max_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi);
+	return true;
 }
 
-void ppu_interpreter::VMAXSW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMAXSW(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto a = ppu.VR[op.va].vi;
 	const auto b = ppu.VR[op.vb].vi;
 	const auto m = _mm_cmpgt_epi32(a, b);
 	ppu.VR[op.vd].vi = _mm_or_si128(_mm_and_si128(m, a), _mm_andnot_si128(m, b));
+	return true;
 }
 
-void ppu_interpreter::VMAXUB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMAXUB(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_max_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi);
+	return true;
 }
 
-void ppu_interpreter::VMAXUH(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMAXUH(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto mask = _mm_set1_epi32(0x80008000);
 	ppu.VR[op.vd].vi = _mm_xor_si128(_mm_max_epi16(_mm_xor_si128(ppu.VR[op.va].vi, mask), _mm_xor_si128(ppu.VR[op.vb].vi, mask)), mask);
+	return true;
 }
 
-void ppu_interpreter::VMAXUW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMAXUW(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto a = ppu.VR[op.va].vi;
 	const auto b = ppu.VR[op.vb].vi;
 	const auto m = sse_cmpgt_epu32(a, b);
 	ppu.VR[op.vd].vi = _mm_or_si128(_mm_and_si128(m, a), _mm_andnot_si128(m, b));
+	return true;
 }
 
-void ppu_interpreter::VMHADDSHS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMHADDSHS(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto a = ppu.VR[op.va].vi;
 	const auto b = ppu.VR[op.vb].vi;
@@ -488,9 +505,10 @@ void ppu_interpreter::VMHADDSHS(PPUThread& ppu, ppu_opcode_t op)
 	const auto m = _mm_or_si128(_mm_srli_epi16(_mm_mullo_epi16(a, b), 15), _mm_slli_epi16(_mm_mulhi_epi16(a, b), 1));
 	const auto s = _mm_cmpeq_epi16(m, _mm_set1_epi16(-0x8000)); // detect special case (positive 0x8000)
 	ppu.VR[op.vd].vi = _mm_adds_epi16(_mm_adds_epi16(_mm_xor_si128(m, s), c), _mm_srli_epi16(s, 15));
+	return true;
 }
 
-void ppu_interpreter::VMHRADDSHS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMHRADDSHS(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto a = ppu.VR[op.va].vi;
 	const auto b = ppu.VR[op.vb].vi;
@@ -498,89 +516,104 @@ void ppu_interpreter::VMHRADDSHS(PPUThread& ppu, ppu_opcode_t op)
 	const auto m = _mm_mulhrs_epi16(a, b);
 	const auto s = _mm_cmpeq_epi16(m, _mm_set1_epi16(-0x8000)); // detect special case (positive 0x8000)
 	ppu.VR[op.vd].vi = _mm_adds_epi16(_mm_adds_epi16(_mm_xor_si128(m, s), c), _mm_srli_epi16(s, 15));
+	return true;
 }
 
-void ppu_interpreter::VMINFP(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMINFP(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vf = _mm_min_ps(ppu.VR[op.va].vf, ppu.VR[op.vb].vf);
+	return true;
 }
 
-void ppu_interpreter::VMINSB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMINSB(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto a = ppu.VR[op.va].vi;
 	const auto b = ppu.VR[op.vb].vi;
 	const auto m = _mm_cmpgt_epi8(a, b);
 	ppu.VR[op.vd].vi = _mm_or_si128(_mm_andnot_si128(m, a), _mm_and_si128(m, b));
+	return true;
 }
 
-void ppu_interpreter::VMINSH(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMINSH(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_min_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi);
+	return true;
 }
 
-void ppu_interpreter::VMINSW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMINSW(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto a = ppu.VR[op.va].vi;
 	const auto b = ppu.VR[op.vb].vi;
 	const auto m = _mm_cmpgt_epi32(a, b);
 	ppu.VR[op.vd].vi = _mm_or_si128(_mm_andnot_si128(m, a), _mm_and_si128(m, b));
+	return true;
 }
 
-void ppu_interpreter::VMINUB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMINUB(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_min_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi);
+	return true;
 }
 
-void ppu_interpreter::VMINUH(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMINUH(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto mask = _mm_set1_epi32(0x80008000);
 	ppu.VR[op.vd].vi = _mm_xor_si128(_mm_min_epi16(_mm_xor_si128(ppu.VR[op.va].vi, mask), _mm_xor_si128(ppu.VR[op.vb].vi, mask)), mask);
+	return true;
 }
 
-void ppu_interpreter::VMINUW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMINUW(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto a = ppu.VR[op.va].vi;
 	const auto b = ppu.VR[op.vb].vi;
 	const auto m = sse_cmpgt_epu32(a, b);
 	ppu.VR[op.vd].vi = _mm_or_si128(_mm_andnot_si128(m, a), _mm_and_si128(m, b));
+	return true;
 }
 
-void ppu_interpreter::VMLADDUHM(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMLADDUHM(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_add_epi16(_mm_mullo_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi), ppu.VR[op.vc].vi);
+	return true;
 }
 
-void ppu_interpreter::VMRGHB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMRGHB(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_unpackhi_epi8(ppu.VR[op.vb].vi, ppu.VR[op.va].vi);
+	return true;
 }
 
-void ppu_interpreter::VMRGHH(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMRGHH(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_unpackhi_epi16(ppu.VR[op.vb].vi, ppu.VR[op.va].vi);
+	return true;
 }
 
-void ppu_interpreter::VMRGHW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMRGHW(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_unpackhi_epi32(ppu.VR[op.vb].vi, ppu.VR[op.va].vi);
+	return true;
 }
 
-void ppu_interpreter::VMRGLB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMRGLB(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_unpacklo_epi8(ppu.VR[op.vb].vi, ppu.VR[op.va].vi);
+	return true;
 }
 
-void ppu_interpreter::VMRGLH(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMRGLH(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_unpacklo_epi16(ppu.VR[op.vb].vi, ppu.VR[op.va].vi);
+	return true;
 }
 
-void ppu_interpreter::VMRGLW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMRGLW(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_unpacklo_epi32(ppu.VR[op.vb].vi, ppu.VR[op.va].vi);
+	return true;
 }
 
-void ppu_interpreter::VMSUMMBM(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMSUMMBM(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto a = ppu.VR[op.va].vi; // signed bytes
 	const auto b = ppu.VR[op.vb].vi; // unsigned bytes
@@ -592,14 +625,16 @@ void ppu_interpreter::VMSUMMBM(PPUThread& ppu, ppu_opcode_t op)
 	const auto sh = _mm_madd_epi16(ah, bh);
 	const auto sl = _mm_madd_epi16(al, bl);
 	ppu.VR[op.vd].vi = _mm_add_epi32(_mm_add_epi32(c, sh), sl);
+	return true;
 }
 
-void ppu_interpreter::VMSUMSHM(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMSUMSHM(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_add_epi32(_mm_madd_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi), ppu.VR[op.vc].vi);
+	return true;
 }
 
-void ppu_interpreter::VMSUMSHS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMSUMSHS(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const auto& a = ppu.VR[op.va];
@@ -631,9 +666,10 @@ void ppu_interpreter::VMSUMSHS(PPUThread& ppu, ppu_opcode_t op)
 
 		d._s32[w] = saturated;
 	}
+	return true;
 }
 
-void ppu_interpreter::VMSUMUBM(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMSUMUBM(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto a = ppu.VR[op.va].vi;
 	const auto b = ppu.VR[op.vb].vi;
@@ -646,9 +682,10 @@ void ppu_interpreter::VMSUMUBM(PPUThread& ppu, ppu_opcode_t op)
 	const auto sh = _mm_madd_epi16(ah, bh);
 	const auto sl = _mm_madd_epi16(al, bl);
 	ppu.VR[op.vd].vi = _mm_add_epi32(_mm_add_epi32(c, sh), sl);
+	return true;
 }
 
-void ppu_interpreter::VMSUMUHM(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMSUMUHM(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto a = ppu.VR[op.va].vi;
 	const auto b = ppu.VR[op.vb].vi;
@@ -658,9 +695,10 @@ void ppu_interpreter::VMSUMUHM(PPUThread& ppu, ppu_opcode_t op)
 	const auto ls = _mm_add_epi32(_mm_srli_epi32(ml, 16), _mm_and_si128(ml, _mm_set1_epi32(0x0000ffff)));
 	const auto hs = _mm_add_epi32(_mm_slli_epi32(mh, 16), _mm_and_si128(mh, _mm_set1_epi32(0xffff0000)));
 	ppu.VR[op.vd].vi = _mm_add_epi32(_mm_add_epi32(c, ls), hs);
+	return true;
 }
 
-void ppu_interpreter::VMSUMUHS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMSUMUHS(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const auto& a = ppu.VR[op.va];
@@ -688,83 +726,96 @@ void ppu_interpreter::VMSUMUHS(PPUThread& ppu, ppu_opcode_t op)
 
 		d._u32[w] = saturated;
 	}
+	return true;
 }
 
-void ppu_interpreter::VMULESB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMULESB(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_mullo_epi16(_mm_srai_epi16(ppu.VR[op.va].vi, 8), _mm_srai_epi16(ppu.VR[op.vb].vi, 8));
+	return true;
 }
 
-void ppu_interpreter::VMULESH(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMULESH(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_madd_epi16(_mm_srli_epi32(ppu.VR[op.va].vi, 16), _mm_srli_epi32(ppu.VR[op.vb].vi, 16));
+	return true;
 }
 
-void ppu_interpreter::VMULEUB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMULEUB(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_mullo_epi16(_mm_srli_epi16(ppu.VR[op.va].vi, 8), _mm_srli_epi16(ppu.VR[op.vb].vi, 8));
+	return true;
 }
 
-void ppu_interpreter::VMULEUH(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMULEUH(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto a = ppu.VR[op.va].vi;
 	const auto b = ppu.VR[op.vb].vi;
 	const auto ml = _mm_mullo_epi16(a, b);
 	const auto mh = _mm_mulhi_epu16(a, b);
 	ppu.VR[op.vd].vi = _mm_or_si128(_mm_srli_epi32(ml, 16), _mm_and_si128(mh, _mm_set1_epi32(0xffff0000)));
+	return true;
 }
 
-void ppu_interpreter::VMULOSB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMULOSB(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_mullo_epi16(_mm_srai_epi16(_mm_slli_epi16(ppu.VR[op.va].vi, 8), 8), _mm_srai_epi16(_mm_slli_epi16(ppu.VR[op.vb].vi, 8), 8));
+	return true;
 }
 
-void ppu_interpreter::VMULOSH(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMULOSH(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto mask = _mm_set1_epi32(0x0000ffff);
 	ppu.VR[op.vd].vi = _mm_madd_epi16(_mm_and_si128(ppu.VR[op.va].vi, mask), _mm_and_si128(ppu.VR[op.vb].vi, mask));
+	return true;
 }
 
-void ppu_interpreter::VMULOUB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMULOUB(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto mask = _mm_set1_epi16(0x00ff);
 	ppu.VR[op.vd].vi = _mm_mullo_epi16(_mm_and_si128(ppu.VR[op.va].vi, mask), _mm_and_si128(ppu.VR[op.vb].vi, mask));
+	return true;
 }
 
-void ppu_interpreter::VMULOUH(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VMULOUH(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto a = ppu.VR[op.va].vi;
 	const auto b = ppu.VR[op.vb].vi;
 	const auto ml = _mm_mullo_epi16(a, b);
 	const auto mh = _mm_mulhi_epu16(a, b);
 	ppu.VR[op.vd].vi = _mm_or_si128(_mm_slli_epi32(mh, 16), _mm_and_si128(ml, _mm_set1_epi32(0x0000ffff)));
+	return true;
 }
 
-void ppu_interpreter::VNMSUBFP(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VNMSUBFP(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vf = _mm_sub_ps(ppu.VR[op.vb].vf, _mm_mul_ps(ppu.VR[op.va].vf, ppu.VR[op.vc].vf));
+	return true;
 }
 
-void ppu_interpreter::VNOR(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VNOR(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd] = ~(ppu.VR[op.va] | ppu.VR[op.vb]);
+	return true;
 }
 
-void ppu_interpreter::VOR(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VOR(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd] = ppu.VR[op.va] | ppu.VR[op.vb];
+	return true;
 }
 
-void ppu_interpreter::VPERM(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VPERM(PPUThread& ppu, ppu_opcode_t op)
 {
 	const auto index = _mm_andnot_si128(ppu.VR[op.vc].vi, _mm_set1_epi8(0x1f));
 	const auto mask = _mm_cmpgt_epi8(index, _mm_set1_epi8(0xf));
 	const auto sa = _mm_shuffle_epi8(ppu.VR[op.va].vi, index);
 	const auto sb = _mm_shuffle_epi8(ppu.VR[op.vb].vi, index);
 	ppu.VR[op.vd].vi = _mm_or_si128(_mm_and_si128(mask, sa), _mm_andnot_si128(mask, sb));
+	return true;
 }
 
-void ppu_interpreter::VPKPX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VPKPX(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	v128 VA = ppu.VR[op.va];
@@ -783,24 +834,28 @@ void ppu_interpreter::VPKPX(PPUThread& ppu, ppu_opcode_t op)
 		d._u16[3 - h] = (bb7 << 15) | (bb8 << 10) | (bb16 << 5) | bb24;
 		d._u16[4 + (3 - h)] = (ab7 << 15) | (ab8 << 10) | (ab16 << 5) | ab24;
 	}
+	return true;
 }
 
-void ppu_interpreter::VPKSHSS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VPKSHSS(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_packs_epi16(ppu.VR[op.vb].vi, ppu.VR[op.va].vi);
+	return true;
 }
 
-void ppu_interpreter::VPKSHUS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VPKSHUS(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_packus_epi16(ppu.VR[op.vb].vi, ppu.VR[op.va].vi);
+	return true;
 }
 
-void ppu_interpreter::VPKSWSS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VPKSWSS(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_packs_epi32(ppu.VR[op.vb].vi, ppu.VR[op.va].vi);
+	return true;
 }
 
-void ppu_interpreter::VPKSWUS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VPKSWUS(PPUThread& ppu, ppu_opcode_t op)
 {
 	//ppu.VR[op.vd].vi = _mm_packus_epi32(ppu.VR[op.vb].vi, ppu.VR[op.va].vi);
 	auto& d = ppu.VR[op.vd];
@@ -834,9 +889,10 @@ void ppu_interpreter::VPKSWUS(PPUThread& ppu, ppu_opcode_t op)
 
 		d._u16[h] = result;
 	}
+	return true;
 }
 
-void ppu_interpreter::VPKUHUM(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VPKUHUM(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	v128 VA = ppu.VR[op.va];
@@ -846,9 +902,10 @@ void ppu_interpreter::VPKUHUM(PPUThread& ppu, ppu_opcode_t op)
 		d._u8[b + 8] = VA._u8[b * 2];
 		d._u8[b] = VB._u8[b * 2];
 	}
+	return true;
 }
 
-void ppu_interpreter::VPKUHUS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VPKUHUS(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	v128 VA = ppu.VR[op.va];
@@ -873,9 +930,10 @@ void ppu_interpreter::VPKUHUS(PPUThread& ppu, ppu_opcode_t op)
 
 		d._u8[b] = (u8)result;
 	}
+	return true;
 }
 
-void ppu_interpreter::VPKUWUM(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VPKUWUM(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	v128 VA = ppu.VR[op.va];
@@ -885,9 +943,10 @@ void ppu_interpreter::VPKUWUM(PPUThread& ppu, ppu_opcode_t op)
 		d._u16[h + 4] = VA._u16[h * 2];
 		d._u16[h] = VB._u16[h * 2];
 	}
+	return true;
 }
 
-void ppu_interpreter::VPKUWUS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VPKUWUS(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	v128 VA = ppu.VR[op.va];
@@ -912,58 +971,64 @@ void ppu_interpreter::VPKUWUS(PPUThread& ppu, ppu_opcode_t op)
 
 		d._u16[h] = result;
 	}
+	return true;
 }
 
-void ppu_interpreter::VREFP(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VREFP(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vf = _mm_rcp_ps(ppu.VR[op.vb].vf);
+	return true;
 }
 
-void ppu_interpreter::VRFIM(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VRFIM(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const auto& b = ppu.VR[op.vb];
 
 	for (uint w = 0; w < 4; w++)
 	{
-		d._f[w] = floorf(b._f[w]);
+		d._f[w] = std::floor(b._f[w]);
 	}
+	return true;
 }
 
-void ppu_interpreter::VRFIN(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VRFIN(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const auto& b = ppu.VR[op.vb];
 
 	for (uint w = 0; w < 4; w++)
 	{
-		d._f[w] = nearbyintf(b._f[w]);
+		d._f[w] = std::nearbyint(b._f[w]);
 	}
+	return true;
 }
 
-void ppu_interpreter::VRFIP(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VRFIP(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const auto& b = ppu.VR[op.vb];
 
 	for (uint w = 0; w < 4; w++)
 	{
-		d._f[w] = ceilf(b._f[w]);
+		d._f[w] = std::ceil(b._f[w]);
 	}
+	return true;
 }
 
-void ppu_interpreter::VRFIZ(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VRFIZ(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const auto& b = ppu.VR[op.vb];
 
 	for (uint w = 0; w < 4; w++)
 	{
-		d._f[w] = truncf(b._f[w]);
+		d._f[w] = std::truncf(b._f[w]);
 	}
+	return true;
 }
 
-void ppu_interpreter::VRLB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VRLB(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const auto& a = ppu.VR[op.va];
@@ -973,9 +1038,10 @@ void ppu_interpreter::VRLB(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._u8[i] = rol8(a._u8[i], b._u8[i] & 0x7);
 	}
+	return true;
 }
 
-void ppu_interpreter::VRLH(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VRLH(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const auto& a = ppu.VR[op.va];
@@ -985,9 +1051,10 @@ void ppu_interpreter::VRLH(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._u16[i] = rol16(a._u16[i], b._u8[i * 2] & 0xf);
 	}
+	return true;
 }
 
-void ppu_interpreter::VRLW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VRLW(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const auto& a = ppu.VR[op.va];
@@ -997,14 +1064,16 @@ void ppu_interpreter::VRLW(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._u32[w] = rol32(a._u32[w], b._u8[w * 4] & 0x1f);
 	}
+	return true;
 }
 
-void ppu_interpreter::VRSQRTEFP(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VRSQRTEFP(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vf = _mm_rsqrt_ps(ppu.VR[op.vb].vf);
+	return true;
 }
 
-void ppu_interpreter::VSEL(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSEL(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const auto& a = ppu.VR[op.va];
@@ -1012,9 +1081,10 @@ void ppu_interpreter::VSEL(PPUThread& ppu, ppu_opcode_t op)
 	const auto& c = ppu.VR[op.vc];
 
 	d = (b & c) | v128::andnot(c, a);
+	return true;
 }
 
-void ppu_interpreter::VSL(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSL(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	v128 VA = ppu.VR[op.va];
@@ -1025,9 +1095,10 @@ void ppu_interpreter::VSL(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._u8[b] = (VA._u8[b] << sh) | (VA._u8[b - 1] >> (8 - sh));
 	}
+	return true;
 }
 
-void ppu_interpreter::VSLB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSLB(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const auto& a = ppu.VR[op.va];
@@ -1037,9 +1108,10 @@ void ppu_interpreter::VSLB(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._u8[i] = a._u8[i] << (b._u8[i] & 0x7);
 	}
+	return true;
 }
 
-void ppu_interpreter::VSLDOI(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSLDOI(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	u8 tmpSRC[32];
@@ -1050,9 +1122,10 @@ void ppu_interpreter::VSLDOI(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._u8[15 - b] = tmpSRC[31 - (b + op.vsh)];
 	}
+	return true;
 }
 
-void ppu_interpreter::VSLH(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSLH(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const auto& a = ppu.VR[op.va];
@@ -1062,9 +1135,10 @@ void ppu_interpreter::VSLH(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._u16[h] = a._u16[h] << (b._u16[h] & 0xf);
 	}
+	return true;
 }
 
-void ppu_interpreter::VSLO(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSLO(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	v128 VA = ppu.VR[op.va];
@@ -1076,9 +1150,10 @@ void ppu_interpreter::VSLO(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._u8[15 - b] = VA._u8[15 - (b + nShift)];
 	}
+	return true;
 }
 
-void ppu_interpreter::VSLW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSLW(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const auto& a = ppu.VR[op.va];
@@ -1088,9 +1163,10 @@ void ppu_interpreter::VSLW(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._u32[w] = a._u32[w] << (b._u32[w] & 0x1f);
 	}
+	return true;
 }
 
-void ppu_interpreter::VSPLTB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSPLTB(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	u8 byte = ppu.VR[op.vb]._u8[15 - op.vuimm];
@@ -1099,12 +1175,13 @@ void ppu_interpreter::VSPLTB(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._u8[b] = byte;
 	}
+	return true;
 }
 
-void ppu_interpreter::VSPLTH(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSPLTH(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
-	Expects(op.vuimm < 8);
+	EXPECTS(op.vuimm < 8);
 
 	u16 hword = ppu.VR[op.vb]._u16[7 - op.vuimm];
 
@@ -1112,9 +1189,10 @@ void ppu_interpreter::VSPLTH(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._u16[h] = hword;
 	}
+	return true;
 }
 
-void ppu_interpreter::VSPLTISB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSPLTISB(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const s8 imm = op.vsimm;
@@ -1123,9 +1201,10 @@ void ppu_interpreter::VSPLTISB(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._u8[b] = imm;
 	}
+	return true;
 }
 
-void ppu_interpreter::VSPLTISH(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSPLTISH(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const s16 imm = op.vsimm;
@@ -1134,9 +1213,10 @@ void ppu_interpreter::VSPLTISH(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._u16[h] = imm;
 	}
+	return true;
 }
 
-void ppu_interpreter::VSPLTISW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSPLTISW(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const s32 imm = op.vsimm;
@@ -1145,12 +1225,13 @@ void ppu_interpreter::VSPLTISW(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._u32[w] = imm;
 	}
+	return true;
 }
 
-void ppu_interpreter::VSPLTW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSPLTW(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
-	Expects(op.vuimm < 4);
+	EXPECTS(op.vuimm < 4);
 
 	u32 word = ppu.VR[op.vb]._u32[3 - op.vuimm];
 
@@ -1158,9 +1239,10 @@ void ppu_interpreter::VSPLTW(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._u32[w] = word;
 	}
+	return true;
 }
 
-void ppu_interpreter::VSR(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSR(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	v128 VA = ppu.VR[op.va];
@@ -1171,9 +1253,10 @@ void ppu_interpreter::VSR(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._u8[b] = (VA._u8[b] >> sh) | (VA._u8[b + 1] << (8 - sh));
 	}
+	return true;
 }
 
-void ppu_interpreter::VSRAB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSRAB(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const auto& a = ppu.VR[op.va];
@@ -1183,9 +1266,10 @@ void ppu_interpreter::VSRAB(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._s8[i] = a._s8[i] >> (b._u8[i] & 0x7);
 	}
+	return true;
 }
 
-void ppu_interpreter::VSRAH(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSRAH(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const auto& a = ppu.VR[op.va];
@@ -1195,9 +1279,10 @@ void ppu_interpreter::VSRAH(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._s16[h] = a._s16[h] >> (b._u16[h] & 0xf);
 	}
+	return true;
 }
 
-void ppu_interpreter::VSRAW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSRAW(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const auto& a = ppu.VR[op.va];
@@ -1207,9 +1292,10 @@ void ppu_interpreter::VSRAW(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._s32[w] = a._s32[w] >> (b._u32[w] & 0x1f);
 	}
+	return true;
 }
 
-void ppu_interpreter::VSRB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSRB(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const auto& a = ppu.VR[op.va];
@@ -1219,9 +1305,10 @@ void ppu_interpreter::VSRB(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._u8[i] = a._u8[i] >> (b._u8[i] & 0x7);
 	}
+	return true;
 }
 
-void ppu_interpreter::VSRH(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSRH(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const auto& a = ppu.VR[op.va];
@@ -1231,9 +1318,10 @@ void ppu_interpreter::VSRH(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._u16[h] = a._u16[h] >> (b._u16[h] & 0xf);
 	}
+	return true;
 }
 
-void ppu_interpreter::VSRO(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSRO(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	v128 VA = ppu.VR[op.va];
@@ -1245,9 +1333,10 @@ void ppu_interpreter::VSRO(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._u8[b] = VA._u8[b + nShift];
 	}
+	return true;
 }
 
-void ppu_interpreter::VSRW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSRW(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const auto& a = ppu.VR[op.va];
@@ -1257,9 +1346,10 @@ void ppu_interpreter::VSRW(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._u32[w] = a._u32[w] >> (b._u32[w] & 0x1f);
 	}
+	return true;
 }
 
-void ppu_interpreter::VSUBCUW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSUBCUW(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const auto& a = ppu.VR[op.va];
@@ -1269,24 +1359,28 @@ void ppu_interpreter::VSUBCUW(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._u32[w] = a._u32[w] < b._u32[w] ? 0 : 1;
 	}
+	return true;
 }
 
-void ppu_interpreter::VSUBFP(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSUBFP(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd] = v128::subfs(ppu.VR[op.va], ppu.VR[op.vb]);
+	return true;
 }
 
-void ppu_interpreter::VSUBSBS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSUBSBS(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_subs_epi8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi);
+	return true;
 }
 
-void ppu_interpreter::VSUBSHS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSUBSHS(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_subs_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi);
+	return true;
 }
 
-void ppu_interpreter::VSUBSWS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSUBSWS(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const auto& a = ppu.VR[op.va];
@@ -1307,34 +1401,40 @@ void ppu_interpreter::VSUBSWS(PPUThread& ppu, ppu_opcode_t op)
 		else
 			d._s32[w] = (s32)result;
 	}
+	return true;
 }
 
-void ppu_interpreter::VSUBUBM(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSUBUBM(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd] = v128::sub8(ppu.VR[op.va], ppu.VR[op.vb]);
+	return true;
 }
 
-void ppu_interpreter::VSUBUBS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSUBUBS(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_subs_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi);
+	return true;
 }
 
-void ppu_interpreter::VSUBUHM(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSUBUHM(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd] = v128::sub16(ppu.VR[op.va], ppu.VR[op.vb]);
+	return true;
 }
 
-void ppu_interpreter::VSUBUHS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSUBUHS(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd].vi = _mm_subs_epu16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi);
+	return true;
 }
 
-void ppu_interpreter::VSUBUWM(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSUBUWM(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd] = v128::sub32(ppu.VR[op.va], ppu.VR[op.vb]);
+	return true;
 }
 
-void ppu_interpreter::VSUBUWS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSUBUWS(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const auto& a = ppu.VR[op.va];
@@ -1351,9 +1451,10 @@ void ppu_interpreter::VSUBUWS(PPUThread& ppu, ppu_opcode_t op)
 		else
 			d._u32[w] = (u32)result;
 	}
+	return true;
 }
 
-void ppu_interpreter::VSUMSWS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSUMSWS(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const auto& a = ppu.VR[op.va];
@@ -1377,9 +1478,10 @@ void ppu_interpreter::VSUMSWS(PPUThread& ppu, ppu_opcode_t op)
 	}
 	else
 		d._s32[0] = (s32)sum;
+	return true;
 }
 
-void ppu_interpreter::VSUM2SWS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSUM2SWS(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const auto& a = ppu.VR[op.va];
@@ -1402,9 +1504,10 @@ void ppu_interpreter::VSUM2SWS(PPUThread& ppu, ppu_opcode_t op)
 	}
 	d._s32[1] = 0;
 	d._s32[3] = 0;
+	return true;
 }
 
-void ppu_interpreter::VSUM4SBS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSUM4SBS(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const auto& a = ppu.VR[op.va];
@@ -1430,9 +1533,10 @@ void ppu_interpreter::VSUM4SBS(PPUThread& ppu, ppu_opcode_t op)
 		else
 			d._s32[w] = (s32)sum;
 	}
+	return true;
 }
 
-void ppu_interpreter::VSUM4SHS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSUM4SHS(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const auto& a = ppu.VR[op.va];
@@ -1458,9 +1562,10 @@ void ppu_interpreter::VSUM4SHS(PPUThread& ppu, ppu_opcode_t op)
 		else
 			d._s32[w] = (s32)sum;
 	}
+	return true;
 }
 
-void ppu_interpreter::VSUM4UBS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VSUM4UBS(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	const auto& a = ppu.VR[op.va];
@@ -1482,9 +1587,10 @@ void ppu_interpreter::VSUM4UBS(PPUThread& ppu, ppu_opcode_t op)
 		else
 			d._u32[w] = (u32)sum;
 	}
+	return true;
 }
 
-void ppu_interpreter::VUPKHPX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VUPKHPX(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	v128 VB = ppu.VR[op.vb];
@@ -1495,9 +1601,10 @@ void ppu_interpreter::VUPKHPX(PPUThread& ppu, ppu_opcode_t op)
 		d._u8[w * 4 + 1] = ((VB._u8[8 + w * 2 + 1] & 0x3) << 3) | ((VB._u8[8 + w * 2 + 0] >> 5) & 0x7);
 		d._u8[w * 4 + 0] = VB._u8[8 + w * 2 + 0] & 0x1f;
 	}
+	return true;
 }
 
-void ppu_interpreter::VUPKHSB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VUPKHSB(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	v128 VB = ppu.VR[op.vb];
@@ -1505,9 +1612,10 @@ void ppu_interpreter::VUPKHSB(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._s16[h] = VB._s8[8 + h];
 	}
+	return true;
 }
 
-void ppu_interpreter::VUPKHSH(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VUPKHSH(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	v128 VB = ppu.VR[op.vb];
@@ -1515,9 +1623,10 @@ void ppu_interpreter::VUPKHSH(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._s32[w] = VB._s16[4 + w];
 	}
+	return true;
 }
 
-void ppu_interpreter::VUPKLPX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VUPKLPX(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	v128 VB = ppu.VR[op.vb];
@@ -1528,9 +1637,10 @@ void ppu_interpreter::VUPKLPX(PPUThread& ppu, ppu_opcode_t op)
 		d._u8[w * 4 + 1] = ((VB._u8[w * 2 + 1] & 0x3) << 3) | ((VB._u8[w * 2 + 0] >> 5) & 0x7);
 		d._u8[w * 4 + 0] = VB._u8[w * 2 + 0] & 0x1f;
 	}
+	return true;
 }
 
-void ppu_interpreter::VUPKLSB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VUPKLSB(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	v128 VB = ppu.VR[op.vb];
@@ -1538,9 +1648,10 @@ void ppu_interpreter::VUPKLSB(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._s16[h] = VB._s8[h];
 	}
+	return true;
 }
 
-void ppu_interpreter::VUPKLSH(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VUPKLSH(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto& d = ppu.VR[op.vd];
 	v128 VB = ppu.VR[op.vb];
@@ -1548,28 +1659,66 @@ void ppu_interpreter::VUPKLSH(PPUThread& ppu, ppu_opcode_t op)
 	{
 		d._s32[w] = VB._s16[w];
 	}
+	return true;
 }
 
-void ppu_interpreter::VXOR(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::VXOR(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.VR[op.vd] = ppu.VR[op.va] ^ ppu.VR[op.vb];
+	return true;
 }
 
-void ppu_interpreter::MULLI(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::TDI(PPUThread& ppu, ppu_opcode_t op)
+{
+	const s64 a = ppu.GPR[op.ra], b = op.simm16;
+	const u64 a_ = a, b_ = b;
+
+	if (((op.bo & 0x10) && a < b) ||
+		((op.bo & 0x8) && a > b) ||
+		((op.bo & 0x4) && a == b) ||
+		((op.bo & 0x2) && a_ < b_) ||
+		((op.bo & 0x1) && a_ > b_))
+	{
+		throw std::runtime_error("Trap!" HERE);
+	}
+
+	return true;
+}
+
+bool ppu_interpreter::TWI(PPUThread& ppu, ppu_opcode_t op)
+{
+	const s32 a = u32(ppu.GPR[op.ra]), b = op.simm16;
+	const u32 a_ = a, b_ = b;
+
+	if (((op.bo & 0x10) && a < b) ||
+		((op.bo & 0x8) && a > b) ||
+		((op.bo & 0x4) && a == b) ||
+		((op.bo & 0x2) && a_ < b_) ||
+		((op.bo & 0x1) && a_ > b_))
+	{
+		throw std::runtime_error("Trap!" HERE);
+	}
+
+	return true;
+}
+
+bool ppu_interpreter::MULLI(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.rd] = (s64)ppu.GPR[op.ra] * op.simm16;
+	return true;
 }
 
-void ppu_interpreter::SUBFIC(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::SUBFIC(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 a = ppu.GPR[op.ra];
 	const s64 i = op.simm16;
 	const auto r = add64_flags(~a, i, 1);
 	ppu.GPR[op.rd] = r.result;
 	ppu.CA = r.carry;
+	return true;
 }
 
-void ppu_interpreter::CMPLI(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::CMPLI(PPUThread& ppu, ppu_opcode_t op)
 {
 	if (op.l10)
 	{
@@ -1579,9 +1728,10 @@ void ppu_interpreter::CMPLI(PPUThread& ppu, ppu_opcode_t op)
 	{
 		ppu.SetCR<u32>(op.crfd, u32(ppu.GPR[op.ra]), op.uimm16);
 	}
+	return true;
 }
 
-void ppu_interpreter::CMPI(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::CMPI(PPUThread& ppu, ppu_opcode_t op)
 {
 	if (op.l10)
 	{
@@ -1591,9 +1741,10 @@ void ppu_interpreter::CMPI(PPUThread& ppu, ppu_opcode_t op)
 	{
 		ppu.SetCR<s32>(op.crfd, u32(ppu.GPR[op.ra]), op.simm16);
 	}
+	return true;
 }
 
-void ppu_interpreter::ADDIC(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::ADDIC(PPUThread& ppu, ppu_opcode_t op)
 {
 	const s64 a = ppu.GPR[op.ra];
 	const s64 i = op.simm16;
@@ -1601,19 +1752,22 @@ void ppu_interpreter::ADDIC(PPUThread& ppu, ppu_opcode_t op)
 	ppu.GPR[op.rd] = r.result;
 	ppu.CA = r.carry;
 	if (UNLIKELY(op.main & 1)) ppu.SetCR<s64>(0, r.result, 0);
+	return true;
 }
 
-void ppu_interpreter::ADDI(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::ADDI(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.rd] = op.ra ? ((s64)ppu.GPR[op.ra] + op.simm16) : op.simm16;
+	return true;
 }
 
-void ppu_interpreter::ADDIS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::ADDIS(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.rd] = op.ra ? ((s64)ppu.GPR[op.ra] + (op.simm16 << 16)) : (op.simm16 << 16);
+	return true;
 }
 
-void ppu_interpreter::BC(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::BC(PPUThread& ppu, ppu_opcode_t op)
 {
 	const bool bo0 = (op.bo & 0x10) != 0;
 	const bool bo1 = (op.bo & 0x08) != 0;
@@ -1627,40 +1781,50 @@ void ppu_interpreter::BC(PPUThread& ppu, ppu_opcode_t op)
 
 	if (ctr_ok && cond_ok)
 	{
-		const u32 nextLR = ppu.PC + 4;
-		ppu.PC = ppu_branch_target((op.aa ? 0 : ppu.PC), op.simm16) - 4;
+		const u32 nextLR = ppu.pc + 4;
+		ppu.pc = ppu_branch_target((op.aa ? 0 : ppu.pc), op.simm16);
 		if (op.lk) ppu.LR = nextLR;
+		return false;
+	}
+	else
+	{
+		return true;
 	}
 }
 
-void ppu_interpreter::HACK(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::HACK(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu_execute_function(ppu, op.opcode & 0x3ffffff);
+	return true;
 }
 
-void ppu_interpreter::SC(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::SC(PPUThread& ppu, ppu_opcode_t op)
 {
 	switch (u32 lv = op.lev)
 	{
 	case 0x0: ppu_execute_syscall(ppu, ppu.GPR[11]); break;
 	default: throw fmt::exception("SC lv%u", lv);
 	}
+
+	return true;
 }
 
-void ppu_interpreter::B(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::B(PPUThread& ppu, ppu_opcode_t op)
 {
-	const u32 nextLR = ppu.PC + 4;
-	ppu.PC = ppu_branch_target(op.aa ? 0 : ppu.PC, op.ll) - 4;
+	const u32 nextLR = ppu.pc + 4;
+	ppu.pc = ppu_branch_target(op.aa ? 0 : ppu.pc, op.ll);
 	if (op.lk) ppu.LR = nextLR;
+	return false;
 }
 
-void ppu_interpreter::MCRF(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::MCRF(PPUThread& ppu, ppu_opcode_t op)
 {
 	CHECK_SIZE(PPUThread::CR, 32);
 	reinterpret_cast<u32*>(ppu.CR)[op.crfd] = reinterpret_cast<u32*>(ppu.CR)[op.crfs];
+	return true;
 }
 
-void ppu_interpreter::BCLR(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::BCLR(PPUThread& ppu, ppu_opcode_t op)
 {
 	const bool bo0 = (op.bo & 0x10) != 0;
 	const bool bo1 = (op.bo & 0x08) != 0;
@@ -1674,156 +1838,188 @@ void ppu_interpreter::BCLR(PPUThread& ppu, ppu_opcode_t op)
 
 	if (ctr_ok && cond_ok)
 	{
-		const u32 nextLR = ppu.PC + 4;
-		ppu.PC = ppu_branch_target(0, (u32)ppu.LR) - 4;
+		const u32 nextLR = ppu.pc + 4;
+		ppu.pc = ppu_branch_target(0, (u32)ppu.LR);
 		if (op.lk) ppu.LR = nextLR;
+		return false;
+	}
+	else
+	{
+		return true;
 	}
 }
 
-void ppu_interpreter::CRNOR(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::CRNOR(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.CR[op.crbd] = (ppu.CR[op.crba] | ppu.CR[op.crbb]) ^ true;
+	return true;
 }
 
-void ppu_interpreter::CRANDC(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::CRANDC(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.CR[op.crbd] = ppu.CR[op.crba] & (ppu.CR[op.crbb] ^ true);
+	return true;
 }
 
-void ppu_interpreter::ISYNC(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::ISYNC(PPUThread& ppu, ppu_opcode_t op)
 {
 	_mm_mfence();
+	return true;
 }
 
-void ppu_interpreter::CRXOR(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::CRXOR(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.CR[op.crbd] = ppu.CR[op.crba] ^ ppu.CR[op.crbb];
+	return true;
 }
 
-void ppu_interpreter::CRNAND(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::CRNAND(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.CR[op.crbd] = (ppu.CR[op.crba] & ppu.CR[op.crbb]) ^ true;
+	return true;
 }
 
-void ppu_interpreter::CRAND(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::CRAND(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.CR[op.crbd] = ppu.CR[op.crba] & ppu.CR[op.crbb];
+	return true;
 }
 
-void ppu_interpreter::CREQV(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::CREQV(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.CR[op.crbd] = (ppu.CR[op.crba] ^ ppu.CR[op.crbb]) ^ true;
+	return true;
 }
 
-void ppu_interpreter::CRORC(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::CRORC(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.CR[op.crbd] = ppu.CR[op.crba] | (ppu.CR[op.crbb] ^ true);
+	return true;
 }
 
-void ppu_interpreter::CROR(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::CROR(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.CR[op.crbd] = ppu.CR[op.crba] | ppu.CR[op.crbb];
+	return true;
 }
 
-void ppu_interpreter::BCCTR(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::BCCTR(PPUThread& ppu, ppu_opcode_t op)
 {
 	if (op.bo & 0x10 || ppu.CR[op.bi] == ((op.bo & 0x8) != 0))
 	{
-		const u32 nextLR = ppu.PC + 4;
-		ppu.PC = ppu_branch_target(0, (u32)ppu.CTR) - 4;
+		const u32 nextLR = ppu.pc + 4;
+		ppu.pc = ppu_branch_target(0, (u32)ppu.CTR);
 		if (op.lk) ppu.LR = nextLR;
+		return false;
 	}
+	
+	return true;
 }
 
-void ppu_interpreter::RLWIMI(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::RLWIMI(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 mask = ppu_rotate_mask(32 + op.mb32, 32 + op.me32);
 	ppu.GPR[op.ra] = (ppu.GPR[op.ra] & ~mask) | (dup32(rol32(u32(ppu.GPR[op.rs]), op.sh32)) & mask);
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::RLWINM(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::RLWINM(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = dup32(rol32(u32(ppu.GPR[op.rs]), op.sh32)) & ppu_rotate_mask(32 + op.mb32, 32 + op.me32);
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::RLWNM(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::RLWNM(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = dup32(rol32(u32(ppu.GPR[op.rs]), ppu.GPR[op.rb] & 0x1f)) & ppu_rotate_mask(32 + op.mb32, 32 + op.me32);
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::ORI(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::ORI(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = ppu.GPR[op.rs] | op.uimm16;
+	return true;
 }
 
-void ppu_interpreter::ORIS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::ORIS(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = ppu.GPR[op.rs] | ((u64)op.uimm16 << 16);
+	return true;
 }
 
-void ppu_interpreter::XORI(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::XORI(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = ppu.GPR[op.rs] ^ op.uimm16;
+	return true;
 }
 
-void ppu_interpreter::XORIS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::XORIS(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = ppu.GPR[op.rs] ^ ((u64)op.uimm16 << 16);
+	return true;
 }
 
-void ppu_interpreter::ANDI(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::ANDI(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = ppu.GPR[op.rs] & op.uimm16;
 	ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::ANDIS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::ANDIS(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = ppu.GPR[op.rs] & ((u64)op.uimm16 << 16);
 	ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::RLDICL(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::RLDICL(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = rol64(ppu.GPR[op.rs], op.sh64) & (~0ull >> op.mbe64);
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::RLDICR(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::RLDICR(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = rol64(ppu.GPR[op.rs], op.sh64) & (~0ull << (op.mbe64 ^ 63));
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::RLDIC(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::RLDIC(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = rol64(ppu.GPR[op.rs], op.sh64) & ppu_rotate_mask(op.mbe64, op.sh64 ^ 63);
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::RLDIMI(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::RLDIMI(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 mask = ppu_rotate_mask(op.mbe64, op.sh64 ^ 63);
 	ppu.GPR[op.ra] = (ppu.GPR[op.ra] & ~mask) | (rol64(ppu.GPR[op.rs], op.sh64) & mask);
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::RLDCL(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::RLDCL(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = rol64(ppu.GPR[op.rs], ppu.GPR[op.rb] & 0x3f) & (~0ull >> op.mbe64);
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::RLDCR(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::RLDCR(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = rol64(ppu.GPR[op.rs], ppu.GPR[op.rb] & 0x3f) & (~0ull << (op.mbe64 ^ 63));
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::CMP(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::CMP(PPUThread& ppu, ppu_opcode_t op)
 {
 	if (op.l10)
 	{
@@ -1833,9 +2029,10 @@ void ppu_interpreter::CMP(PPUThread& ppu, ppu_opcode_t op)
 	{
 		ppu.SetCR<s32>(op.crfd, u32(ppu.GPR[op.ra]), u32(ppu.GPR[op.rb]));
 	}
+	return true;
 }
 
-void ppu_interpreter::TW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::TW(PPUThread& ppu, ppu_opcode_t op)
 {
 	s32 a = (s32)ppu.GPR[op.ra];
 	s32 b = (s32)ppu.GPR[op.rb];
@@ -1848,9 +2045,11 @@ void ppu_interpreter::TW(PPUThread& ppu, ppu_opcode_t op)
 	{
 		throw std::runtime_error("Trap!" HERE);
 	}
+
+	return true;
 }
 
-void ppu_interpreter::LVSL(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LVSL(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 
@@ -1876,15 +2075,17 @@ void ppu_interpreter::LVSL(PPUThread& ppu, ppu_opcode_t op)
 
 	ppu.VR[op.vd]._u64[0] = lvsl_values[addr & 0xf][0];
 	ppu.VR[op.vd]._u64[1] = lvsl_values[addr & 0xf][1];
+	return true;
 }
 
-void ppu_interpreter::LVEBX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LVEBX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	ppu.VR[op.vd]._u8[15 - (addr & 0xf)] = vm::read8(vm::cast(addr, HERE));
+	return true;
 }
 
-void ppu_interpreter::SUBFC(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::SUBFC(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 RA = ppu.GPR[op.ra];
 	const u64 RB = ppu.GPR[op.rb];
@@ -1893,15 +2094,17 @@ void ppu_interpreter::SUBFC(PPUThread& ppu, ppu_opcode_t op)
 	ppu.CA = r.carry;
 	if (UNLIKELY(op.oe)) ppu.SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != ppu.GPR[op.rd] >> 63));
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, r.result, 0);
+	return true;
 }
 
-void ppu_interpreter::MULHDU(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::MULHDU(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.rd] = UMULH64(ppu.GPR[op.ra], ppu.GPR[op.rb]);
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.rd], 0);
+	return true;
 }
 
-void ppu_interpreter::ADDC(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::ADDC(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 RA = ppu.GPR[op.ra];
 	const u64 RB = ppu.GPR[op.rb];
@@ -1910,17 +2113,19 @@ void ppu_interpreter::ADDC(PPUThread& ppu, ppu_opcode_t op)
 	ppu.CA = r.carry;
 	if (UNLIKELY(op.oe)) ppu.SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != ppu.GPR[op.rd] >> 63));
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, r.result, 0);
+	return true;
 }
 
-void ppu_interpreter::MULHWU(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::MULHWU(PPUThread& ppu, ppu_opcode_t op)
 {
 	u32 a = (u32)ppu.GPR[op.ra];
 	u32 b = (u32)ppu.GPR[op.rb];
 	ppu.GPR[op.rd] = ((u64)a * (u64)b) >> 32;
 	if (UNLIKELY(op.rc)) ppu.SetCR(0, false, false, false, ppu.SO);
+	return true;
 }
 
-void ppu_interpreter::MFOCRF(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::MFOCRF(PPUThread& ppu, ppu_opcode_t op)
 {
 	if (op.l11)
 	{
@@ -1940,9 +2145,10 @@ void ppu_interpreter::MFOCRF(PPUThread& ppu, ppu_opcode_t op)
 
 		ppu.GPR[op.rd] = (mh << 16) | ml;
 	}
+	return true;
 }
 
-void ppu_interpreter::LWARX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LWARX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 
@@ -1950,46 +2156,53 @@ void ppu_interpreter::LWARX(PPUThread& ppu, ppu_opcode_t op)
 	vm::reservation_acquire(&value, vm::cast(addr, HERE), SIZE_32(value));
 
 	ppu.GPR[op.rd] = value;
+	return true;
 }
 
-void ppu_interpreter::LDX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LDX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	ppu.GPR[op.rd] = vm::read64(vm::cast(addr, HERE));
+	return true;
 }
 
-void ppu_interpreter::LWZX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LWZX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	ppu.GPR[op.rd] = vm::read32(vm::cast(addr, HERE));
+	return true;
 }
 
-void ppu_interpreter::SLW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::SLW(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = u32(ppu.GPR[op.rs] << (ppu.GPR[op.rb] & 0x3f));
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::CNTLZW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::CNTLZW(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = cntlz32(u32(ppu.GPR[op.rs]));
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::SLD(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::SLD(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u32 n = ppu.GPR[op.rb];
 	ppu.GPR[op.ra] = UNLIKELY(n & 0x40) ? 0 : ppu.GPR[op.rs] << n;
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::AND(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::AND(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = ppu.GPR[op.rs] & ppu.GPR[op.rb];
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::CMPL(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::CMPL(PPUThread& ppu, ppu_opcode_t op)
 {
 	if (op.l10)
 	{
@@ -1999,9 +2212,10 @@ void ppu_interpreter::CMPL(PPUThread& ppu, ppu_opcode_t op)
 	{
 		ppu.SetCR<u32>(op.crfd, u32(ppu.GPR[op.ra]), u32(ppu.GPR[op.rb]));
 	}
+	return true;
 }
 
-void ppu_interpreter::LVSR(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LVSR(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 
@@ -2027,54 +2241,62 @@ void ppu_interpreter::LVSR(PPUThread& ppu, ppu_opcode_t op)
 
 	ppu.VR[op.vd]._u64[0] = lvsr_values[addr & 0xf][0];
 	ppu.VR[op.vd]._u64[1] = lvsr_values[addr & 0xf][1];
+	return true;
 }
 
-void ppu_interpreter::LVEHX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LVEHX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~1ULL;
 	ppu.VR[op.vd]._u16[7 - ((addr >> 1) & 0x7)] = vm::read16(vm::cast(addr, HERE));
+	return true;
 }
 
-void ppu_interpreter::SUBF(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::SUBF(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 RA = ppu.GPR[op.ra];
 	const u64 RB = ppu.GPR[op.rb];
 	ppu.GPR[op.rd] = RB - RA;
 	if (UNLIKELY(op.oe)) ppu.SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != ppu.GPR[op.rd] >> 63));
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.rd], 0);
+	return true;
 }
 
-void ppu_interpreter::LDUX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LDUX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb];
 	ppu.GPR[op.rd] = vm::read64(vm::cast(addr, HERE));
 	ppu.GPR[op.ra] = addr;
+	return true;
 }
 
-void ppu_interpreter::DCBST(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::DCBST(PPUThread& ppu, ppu_opcode_t op)
 {
+	return true;
 }
 
-void ppu_interpreter::LWZUX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LWZUX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb];
 	ppu.GPR[op.rd] = vm::read32(vm::cast(addr, HERE));
 	ppu.GPR[op.ra] = addr;
+	return true;
 }
 
-void ppu_interpreter::CNTLZD(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::CNTLZD(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = cntlz64(ppu.GPR[op.rs]);
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::ANDC(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::ANDC(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = ppu.GPR[op.rs] & ~ppu.GPR[op.rb];
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::TD(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::TD(PPUThread& ppu, ppu_opcode_t op)
 {
 	const s64 a = ppu.GPR[op.ra], b = ppu.GPR[op.rb];
 	const u64 a_ = a, b_ = b;
@@ -2087,29 +2309,34 @@ void ppu_interpreter::TD(PPUThread& ppu, ppu_opcode_t op)
 	{
 		throw std::runtime_error("Trap!" HERE);
 	}
+
+	return true;
 }
 
-void ppu_interpreter::LVEWX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LVEWX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~3ULL;
 	ppu.VR[op.vd]._u32[3 - ((addr >> 2) & 0x3)] = vm::read32(vm::cast(addr, HERE));
+	return true;
 }
 
-void ppu_interpreter::MULHD(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::MULHD(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.rd] = MULH64(ppu.GPR[op.ra], ppu.GPR[op.rb]);
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.rd], 0);
+	return true;
 }
 
-void ppu_interpreter::MULHW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::MULHW(PPUThread& ppu, ppu_opcode_t op)
 {
 	s32 a = (s32)ppu.GPR[op.ra];
 	s32 b = (s32)ppu.GPR[op.rb];
 	ppu.GPR[op.rd] = ((s64)a * (s64)b) >> 32;
 	if (UNLIKELY(op.rc)) ppu.SetCR(0, false, false, false, ppu.SO);
+	return true;
 }
 
-void ppu_interpreter::LDARX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LDARX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 
@@ -2117,53 +2344,61 @@ void ppu_interpreter::LDARX(PPUThread& ppu, ppu_opcode_t op)
 	vm::reservation_acquire(&value, vm::cast(addr, HERE), SIZE_32(value));
 
 	ppu.GPR[op.rd] = value;
+	return true;
 }
 
-void ppu_interpreter::DCBF(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::DCBF(PPUThread& ppu, ppu_opcode_t op)
 {
+	return true;
 }
 
-void ppu_interpreter::LBZX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LBZX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	ppu.GPR[op.rd] = vm::read8(vm::cast(addr, HERE));
+	return true;
 }
 
-void ppu_interpreter::LVX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LVX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~0xfull;
 	ppu.VR[op.vd] = vm::_ref<v128>(vm::cast(addr, HERE));
+	return true;
 }
 
-void ppu_interpreter::NEG(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::NEG(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 RA = ppu.GPR[op.ra];
 	ppu.GPR[op.rd] = 0 - RA;
 	if (UNLIKELY(op.oe)) ppu.SetOV((~RA >> 63 == 0) && (~RA >> 63 != ppu.GPR[op.rd] >> 63));
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.rd], 0);
+	return true;
 }
 
-void ppu_interpreter::LBZUX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LBZUX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb];
 	ppu.GPR[op.rd] = vm::read8(vm::cast(addr, HERE));
 	ppu.GPR[op.ra] = addr;
+	return true;
 }
 
-void ppu_interpreter::NOR(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::NOR(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = ~(ppu.GPR[op.rs] | ppu.GPR[op.rb]);
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::STVEBX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STVEBX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	const u8 eb = addr & 0xf;
 	vm::write8(vm::cast(addr, HERE), ppu.VR[op.vs]._u8[15 - eb]);
+	return true;
 }
 
-void ppu_interpreter::SUBFE(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::SUBFE(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 RA = ppu.GPR[op.ra];
 	const u64 RB = ppu.GPR[op.rb];
@@ -2172,9 +2407,10 @@ void ppu_interpreter::SUBFE(PPUThread& ppu, ppu_opcode_t op)
 	ppu.CA = r.carry;
 	if (UNLIKELY(op.oe)) ppu.SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != ppu.GPR[op.rd] >> 63));
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, r.result, 0);
+	return true;
 }
 
-void ppu_interpreter::ADDE(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::ADDE(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 RA = ppu.GPR[op.ra];
 	const u64 RB = ppu.GPR[op.rb];
@@ -2183,9 +2419,10 @@ void ppu_interpreter::ADDE(PPUThread& ppu, ppu_opcode_t op)
 	ppu.CA = r.carry;
 	if (UNLIKELY(op.oe)) ppu.SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != ppu.GPR[op.rd] >> 63));
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, r.result, 0);
+	return true;
 }
 
-void ppu_interpreter::MTOCRF(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::MTOCRF(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 s = ppu.GPR[op.rs];
 
@@ -2219,57 +2456,65 @@ void ppu_interpreter::MTOCRF(PPUThread& ppu, ppu_opcode_t op)
 			}
 		}
 	}
+	return true;
 }
 
-void ppu_interpreter::STDX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STDX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	vm::write64(vm::cast(addr, HERE), ppu.GPR[op.rs]);
+	return true;
 }
 
-void ppu_interpreter::STWCX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STWCX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 
 	const be_t<u32> value = (u32)ppu.GPR[op.rs];
 	ppu.SetCR(0, false, false, vm::reservation_update(vm::cast(addr, HERE), &value, SIZE_32(value)), ppu.SO);
+	return true;
 }
 
-void ppu_interpreter::STWX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STWX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[op.rs]);
+	return true;
 }
 
-void ppu_interpreter::STVEHX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STVEHX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~1ULL;
 	const u8 eb = (addr & 0xf) >> 1;
 	vm::write16(vm::cast(addr, HERE), ppu.VR[op.vs]._u16[7 - eb]);
+	return true;
 }
 
-void ppu_interpreter::STDUX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STDUX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb];
 	vm::write64(vm::cast(addr, HERE), ppu.GPR[op.rs]);
 	ppu.GPR[op.ra] = addr;
+	return true;
 }
 
-void ppu_interpreter::STWUX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STWUX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb];
 	vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[op.rs]);
 	ppu.GPR[op.ra] = addr;
+	return true;
 }
 
-void ppu_interpreter::STVEWX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STVEWX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~3ULL;
 	const u8 eb = (addr & 0xf) >> 2;
 	vm::write32(vm::cast(addr, HERE), ppu.VR[op.vs]._u32[3 - eb]);
+	return true;
 }
 
-void ppu_interpreter::SUBFZE(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::SUBFZE(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 RA = ppu.GPR[op.ra];
 	const auto r = add64_flags(~RA, 0, ppu.CA);
@@ -2277,9 +2522,10 @@ void ppu_interpreter::SUBFZE(PPUThread& ppu, ppu_opcode_t op)
 	ppu.CA = r.carry;
 	if (UNLIKELY(op.oe)) ppu.SetOV((~RA >> 63 == 0) && (~RA >> 63 != ppu.GPR[op.rd] >> 63));
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, r.result, 0);
+	return true;
 }
 
-void ppu_interpreter::ADDZE(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::ADDZE(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 RA = ppu.GPR[op.ra];
 	const auto r = add64_flags(RA, 0, ppu.CA);
@@ -2287,29 +2533,33 @@ void ppu_interpreter::ADDZE(PPUThread& ppu, ppu_opcode_t op)
 	ppu.CA = r.carry;
 	if (UNLIKELY(op.oe)) ppu.SetOV((RA >> 63 == 0) && (RA >> 63 != ppu.GPR[op.rd] >> 63));
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, r.result, 0);
+	return true;
 }
 
-void ppu_interpreter::STDCX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STDCX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 
 	const be_t<u64> value = ppu.GPR[op.rs];
 	ppu.SetCR(0, false, false, vm::reservation_update(vm::cast(addr, HERE), &value, SIZE_32(value)), ppu.SO);
+	return true;
 }
 
-void ppu_interpreter::STBX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STBX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	vm::write8(vm::cast(addr, HERE), (u8)ppu.GPR[op.rs]);
+	return true;
 }
 
-void ppu_interpreter::STVX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STVX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~0xfull;
 	vm::_ref<v128>(vm::cast(addr, HERE)) = ppu.VR[op.vs];
+	return true;
 }
 
-void ppu_interpreter::MULLD(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::MULLD(PPUThread& ppu, ppu_opcode_t op)
 {
 	const s64 RA = ppu.GPR[op.ra];
 	const s64 RB = ppu.GPR[op.rb];
@@ -2320,9 +2570,10 @@ void ppu_interpreter::MULLD(PPUThread& ppu, ppu_opcode_t op)
 		ppu.SetOV(high != s64(ppu.GPR[op.rd]) >> 63);
 	}
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.rd], 0);
+	return true;
 }
 
-void ppu_interpreter::SUBFME(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::SUBFME(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 RA = ppu.GPR[op.ra];
 	const auto r = add64_flags(~RA, ~0ull, ppu.CA);
@@ -2330,9 +2581,10 @@ void ppu_interpreter::SUBFME(PPUThread& ppu, ppu_opcode_t op)
 	ppu.CA = r.carry;
 	if (UNLIKELY(op.oe)) ppu.SetOV((~RA >> 63 == 1) && (~RA >> 63 != ppu.GPR[op.rd] >> 63));
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, r.result, 0);
+	return true;
 }
 
-void ppu_interpreter::ADDME(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::ADDME(PPUThread& ppu, ppu_opcode_t op)
 {
 	const s64 RA = ppu.GPR[op.ra];
 	const auto r = add64_flags(RA, ~0ull, ppu.CA);
@@ -2340,110 +2592,125 @@ void ppu_interpreter::ADDME(PPUThread& ppu, ppu_opcode_t op)
 	ppu.CA = r.carry;
 	if (UNLIKELY(op.oe)) ppu.SetOV((u64(RA) >> 63 == 1) && (u64(RA) >> 63 != ppu.GPR[op.rd] >> 63));
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, r.result, 0);
+	return true;
 }
 
-void ppu_interpreter::MULLW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::MULLW(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.rd] = (s64)((s64)(s32)ppu.GPR[op.ra] * (s64)(s32)ppu.GPR[op.rb]);
 	if (UNLIKELY(op.oe)) ppu.SetOV(s64(ppu.GPR[op.rd]) < s64(-1) << 31 || s64(ppu.GPR[op.rd]) >= s64(1) << 31);
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::DCBTST(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::DCBTST(PPUThread& ppu, ppu_opcode_t op)
 {
+	return true;
 }
 
-void ppu_interpreter::STBUX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STBUX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb];
 	vm::write8(vm::cast(addr, HERE), (u8)ppu.GPR[op.rs]);
 	ppu.GPR[op.ra] = addr;
+	return true;
 }
 
-void ppu_interpreter::ADD(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::ADD(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 RA = ppu.GPR[op.ra];
 	const u64 RB = ppu.GPR[op.rb];
 	ppu.GPR[op.rd] = RA + RB;
 	if (UNLIKELY(op.oe)) ppu.SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != ppu.GPR[op.rd] >> 63));
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.rd], 0);
+	return true;
 }
 
-void ppu_interpreter::DCBT(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::DCBT(PPUThread& ppu, ppu_opcode_t op)
 {
+	return true;
 }
 
-void ppu_interpreter::LHZX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LHZX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	ppu.GPR[op.rd] = vm::read16(vm::cast(addr, HERE));
+	return true;
 }
 
-void ppu_interpreter::EQV(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::EQV(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = ~(ppu.GPR[op.rs] ^ ppu.GPR[op.rb]);
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::ECIWX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::ECIWX(PPUThread& ppu, ppu_opcode_t op)
 {
 	throw std::runtime_error("ECIWX" HERE);
 }
 
-void ppu_interpreter::LHZUX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LHZUX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	ppu.GPR[op.rd] = vm::read16(vm::cast(addr, HERE));
 	ppu.GPR[op.ra] = addr;
+	return true;
 }
 
-void ppu_interpreter::XOR(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::XOR(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = ppu.GPR[op.rs] ^ ppu.GPR[op.rb];
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::MFSPR(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::MFSPR(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5);
 
 	switch (n)
 	{
-	case 0x001: ppu.GPR[op.rd] = u32{ ppu.SO } << 31 | ppu.OV << 30 | ppu.CA << 29 | ppu.XCNT; return;
-	case 0x008: ppu.GPR[op.rd] = ppu.LR; return;
-	case 0x009: ppu.GPR[op.rd] = ppu.CTR; return;
-	case 0x100: ppu.GPR[op.rd] = ppu.VRSAVE; return;
+	case 0x001: ppu.GPR[op.rd] = u32{ ppu.SO } << 31 | ppu.OV << 30 | ppu.CA << 29 | ppu.XCNT; break;
+	case 0x008: ppu.GPR[op.rd] = ppu.LR; break;
+	case 0x009: ppu.GPR[op.rd] = ppu.CTR; break;
+	case 0x100: ppu.GPR[op.rd] = ppu.VRSAVE; break;
 
-	case 0x10C: ppu.GPR[op.rd] = get_timebased_time() & 0xffffffff; return;
-	case 0x10D: ppu.GPR[op.rd] = get_timebased_time() >> 32; return;
+	case 0x10C: ppu.GPR[op.rd] = get_timebased_time() & 0xffffffff; break;
+	case 0x10D: ppu.GPR[op.rd] = get_timebased_time() >> 32; break;
+	default: throw fmt::exception("MFSPR 0x%x" HERE, n);
 	}
 
-	throw fmt::exception("MFSPR 0x%x" HERE, n);
+	return true;
 }
 
-void ppu_interpreter::LWAX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LWAX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	ppu.GPR[op.rd] = (s64)(s32)vm::read32(vm::cast(addr, HERE));
+	return true;
 }
 
-void ppu_interpreter::DST(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::DST(PPUThread& ppu, ppu_opcode_t op)
 {
+	return true;
 }
 
-void ppu_interpreter::LHAX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LHAX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	ppu.GPR[op.rd] = (s64)(s16)vm::read16(vm::cast(addr, HERE));
+	return true;
 }
 
-void ppu_interpreter::LVXL(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LVXL(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~0xfull;
 	ppu.VR[op.vd] = vm::_ref<v128>(vm::cast(addr, HERE));
+	return true;
 }
 
-void ppu_interpreter::MFTB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::MFTB(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5);
 
@@ -2453,75 +2720,86 @@ void ppu_interpreter::MFTB(PPUThread& ppu, ppu_opcode_t op)
 	case 0x10D: ppu.GPR[op.rd] = get_timebased_time() >> 32; break;
 	default: throw fmt::exception("MFSPR 0x%x" HERE, n);
 	}
+
+	return true;
 }
 
-void ppu_interpreter::LWAUX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LWAUX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	ppu.GPR[op.rd] = (s64)(s32)vm::read32(vm::cast(addr, HERE));
 	ppu.GPR[op.ra] = addr;
+	return true;
 }
 
-void ppu_interpreter::DSTST(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::DSTST(PPUThread& ppu, ppu_opcode_t op)
 {
+	return true;
 }
 
-void ppu_interpreter::LHAUX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LHAUX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	ppu.GPR[op.rd] = (s64)(s16)vm::read16(vm::cast(addr, HERE));
 	ppu.GPR[op.ra] = addr;
+	return true;
 }
 
-void ppu_interpreter::STHX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STHX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	vm::write16(vm::cast(addr, HERE), (u16)ppu.GPR[op.rs]);
+	return true;
 }
 
-void ppu_interpreter::ORC(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::ORC(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = ppu.GPR[op.rs] | ~ppu.GPR[op.rb];
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::ECOWX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::ECOWX(PPUThread& ppu, ppu_opcode_t op)
 {
 	throw std::runtime_error("ECOWX" HERE);
 }
 
-void ppu_interpreter::STHUX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STHUX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb];
 	vm::write16(vm::cast(addr, HERE), (u16)ppu.GPR[op.rs]);
 	ppu.GPR[op.ra] = addr;
+	return true;
 }
 
-void ppu_interpreter::OR(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::OR(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = ppu.GPR[op.rs] | ppu.GPR[op.rb];
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::DIVDU(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::DIVDU(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 RA = ppu.GPR[op.ra];
 	const u64 RB = ppu.GPR[op.rb];
 	ppu.GPR[op.rd] = RB == 0 ? 0 : RA / RB;
 	if (UNLIKELY(op.oe)) ppu.SetOV(RB == 0);
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.rd], 0);
+	return true;
 }
 
-void ppu_interpreter::DIVWU(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::DIVWU(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u32 RA = (u32)ppu.GPR[op.ra];
 	const u32 RB = (u32)ppu.GPR[op.rb];
 	ppu.GPR[op.rd] = RB == 0 ? 0 : RA / RB;
 	if (UNLIKELY(op.oe)) ppu.SetOV(RB == 0);
 	if (UNLIKELY(op.rc)) ppu.SetCR(0, false, false, false, ppu.SO);
+	return true;
 }
 
-void ppu_interpreter::MTSPR(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::MTSPR(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5);
 
@@ -2534,33 +2812,37 @@ void ppu_interpreter::MTSPR(PPUThread& ppu, ppu_opcode_t op)
 		ppu.OV = (value & 0x40000000) != 0;
 		ppu.CA = (value & 0x20000000) != 0;
 		ppu.XCNT = value & 0x7f;
-		return;
+		break;
 	}
-	case 0x008: ppu.LR = ppu.GPR[op.rs]; return;
-	case 0x009: ppu.CTR = ppu.GPR[op.rs]; return;
-	case 0x100: ppu.VRSAVE = (u32)ppu.GPR[op.rs]; return;
+	case 0x008: ppu.LR = ppu.GPR[op.rs]; break;
+	case 0x009: ppu.CTR = ppu.GPR[op.rs]; break;
+	case 0x100: ppu.VRSAVE = (u32)ppu.GPR[op.rs]; break;
+	default: throw fmt::exception("MTSPR 0x%x" HERE, n);
 	}
 
-	throw fmt::exception("MTSPR 0x%x" HERE, n);
+	return true;
 }
 
-void ppu_interpreter::DCBI(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::DCBI(PPUThread& ppu, ppu_opcode_t op)
 {
+	return true;
 }
 
-void ppu_interpreter::NAND(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::NAND(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = ~(ppu.GPR[op.rs] & ppu.GPR[op.rb]);
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::STVXL(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STVXL(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~0xfull;
 	vm::_ref<v128>(vm::cast(addr, HERE)) = ppu.VR[op.vs];
+	return true;
 }
 
-void ppu_interpreter::DIVD(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::DIVD(PPUThread& ppu, ppu_opcode_t op)
 {
 	const s64 RA = ppu.GPR[op.ra];
 	const s64 RB = ppu.GPR[op.rb];
@@ -2568,9 +2850,10 @@ void ppu_interpreter::DIVD(PPUThread& ppu, ppu_opcode_t op)
 	ppu.GPR[op.rd] = o ? 0 : RA / RB;
 	if (UNLIKELY(op.oe)) ppu.SetOV(o);
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.rd], 0);
+	return true;
 }
 
-void ppu_interpreter::DIVW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::DIVW(PPUThread& ppu, ppu_opcode_t op)
 {
 	const s32 RA = (s32)ppu.GPR[op.ra];
 	const s32 RB = (s32)ppu.GPR[op.rb];
@@ -2578,24 +2861,27 @@ void ppu_interpreter::DIVW(PPUThread& ppu, ppu_opcode_t op)
 	ppu.GPR[op.rd] = o ? 0 : u32(RA / RB);
 	if (UNLIKELY(op.oe)) ppu.SetOV(o);
 	if (UNLIKELY(op.rc)) ppu.SetCR(0, false, false, false, ppu.SO);
+	return true;
 }
 
-void ppu_interpreter::LVLX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LVLX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	const u32 eb = addr & 0xf;
 
 	ppu.VR[op.vd].clear();
 	for (u32 i = 0; i < 16u - eb; ++i) ppu.VR[op.vd]._u8[15 - i] = vm::read8(vm::cast(addr + i, HERE));
+	return true;
 }
 
-void ppu_interpreter::LDBRX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LDBRX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	ppu.GPR[op.rd] = vm::_ref<le_t<u64>>(vm::cast(addr, HERE));
+	return true;
 }
 
-void ppu_interpreter::LSWX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LSWX(PPUThread& ppu, ppu_opcode_t op)
 {
 	u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	u32 count = ppu.XCNT & 0x7f;
@@ -2613,43 +2899,49 @@ void ppu_interpreter::LSWX(PPUThread& ppu, ppu_opcode_t op)
 		}
 		ppu.GPR[op.rd] = value;
 	}
+	return true;
 }
 
-void ppu_interpreter::LWBRX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LWBRX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	ppu.GPR[op.rd] = vm::_ref<le_t<u32>>(vm::cast(addr, HERE));
+	return true;
 }
 
-void ppu_interpreter::LFSX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LFSX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	ppu.FPR[op.frd] = vm::_ref<f32>(vm::cast(addr, HERE));
+	return true;
 }
 
-void ppu_interpreter::SRW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::SRW(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = (ppu.GPR[op.rs] & 0xffffffff) >> (ppu.GPR[op.rb] & 0x3f);
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::SRD(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::SRD(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u32 n = ppu.GPR[op.rb];
 	ppu.GPR[op.ra] = UNLIKELY(n & 0x40) ? 0 : ppu.GPR[op.rs] >> n;
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::LVRX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LVRX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	const u8 eb = addr & 0xf;
 
 	ppu.VR[op.vd].clear();
 	for (u32 i = 16 - eb; i < 16; ++i) ppu.VR[op.vd]._u8[15 - i] = vm::read8(vm::cast(addr + i - 16, HERE));
+	return true;
 }
 
-void ppu_interpreter::LSWI(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LSWI(PPUThread& ppu, ppu_opcode_t op)
 {
 	u64 addr = op.ra ? ppu.GPR[op.ra] : 0;
 	u64 N = op.rb ? op.rb : 32;
@@ -2678,48 +2970,55 @@ void ppu_interpreter::LSWI(PPUThread& ppu, ppu_opcode_t op)
 		}
 		reg = (reg + 1) % 32;
 	}
+	return true;
 }
 
-void ppu_interpreter::LFSUX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LFSUX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb];
 	ppu.FPR[op.frd] = vm::_ref<f32>(vm::cast(addr, HERE));
 	ppu.GPR[op.ra] = addr;
+	return true;
 }
 
-void ppu_interpreter::SYNC(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::SYNC(PPUThread& ppu, ppu_opcode_t op)
 {
 	_mm_mfence();
+	return true;
 }
 
-void ppu_interpreter::LFDX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LFDX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	ppu.FPR[op.frd] = vm::_ref<f64>(vm::cast(addr, HERE));
+	return true;
 }
 
-void ppu_interpreter::LFDUX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LFDUX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb];
 	ppu.FPR[op.frd] = vm::_ref<f64>(vm::cast(addr, HERE));
 	ppu.GPR[op.ra] = addr;
+	return true;
 }
 
-void ppu_interpreter::STVLX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STVLX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	const u32 eb = addr & 0xf;
 
 	for (u32 i = 0; i < 16u - eb; ++i) vm::write8(vm::cast(addr + i, HERE), ppu.VR[op.vs]._u8[15 - i]);
+	return true;
 }
 
-void ppu_interpreter::STDBRX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STDBRX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	vm::_ref<le_t<u64>>(vm::cast(addr, HERE)) = ppu.GPR[op.rs];
+	return true;
 }
 
-void ppu_interpreter::STSWX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STSWX(PPUThread& ppu, ppu_opcode_t op)
 {
 	u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	u32 count = ppu.XCNT & 0x7F;
@@ -2736,36 +3035,41 @@ void ppu_interpreter::STSWX(PPUThread& ppu, ppu_opcode_t op)
 			vm::write8(vm::cast(addr + byte, HERE), byte_value);
 		}
 	}
+	return true;
 }
 
-void ppu_interpreter::STWBRX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STWBRX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	vm::_ref<le_t<u32>>(vm::cast(addr, HERE)) = (u32)ppu.GPR[op.rs];
+	return true;
 }
 
-void ppu_interpreter::STFSX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STFSX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	vm::_ref<f32>(vm::cast(addr, HERE)) = static_cast<float>(ppu.FPR[op.frs]);
+	return true;
 }
 
-void ppu_interpreter::STVRX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STVRX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	const u8 eb = addr & 0xf;
 
 	for (u32 i = 16 - eb; i < 16; ++i) vm::write8(vm::cast(addr + i - 16, HERE), ppu.VR[op.vs]._u8[15 - i]);
+	return true;
 }
 
-void ppu_interpreter::STFSUX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STFSUX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb];
 	vm::_ref<f32>(vm::cast(addr, HERE)) = static_cast<float>(ppu.FPR[op.frs]);
 	ppu.GPR[op.ra] = addr;
+	return true;
 }
 
-void ppu_interpreter::STSWI(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STSWI(PPUThread& ppu, ppu_opcode_t op)
 {
 	u64 addr = op.ra ? ppu.GPR[op.ra] : 0;
 	u64 N = op.rb ? op.rb : 32;
@@ -2792,37 +3096,42 @@ void ppu_interpreter::STSWI(PPUThread& ppu, ppu_opcode_t op)
 		}
 		reg = (reg + 1) % 32;
 	}
+	return true;
 }
 
-void ppu_interpreter::STFDX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STFDX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	vm::_ref<f64>(vm::cast(addr, HERE)) = ppu.FPR[op.frs];
+	return true;
 }
 
-void ppu_interpreter::STFDUX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STFDUX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb];
 	vm::_ref<f64>(vm::cast(addr, HERE)) = ppu.FPR[op.frs];
 	ppu.GPR[op.ra] = addr;
+	return true;
 }
 
-void ppu_interpreter::LVLXL(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LVLXL(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	const u32 eb = addr & 0xf;
 
 	ppu.VR[op.vd].clear();
 	for (u32 i = 0; i < 16u - eb; ++i) ppu.VR[op.vd]._u8[15 - i] = vm::read8(vm::cast(addr + i, HERE));
+	return true;
 }
 
-void ppu_interpreter::LHBRX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LHBRX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	ppu.GPR[op.rd] = vm::_ref<le_t<u16>>(vm::cast(addr, HERE));
+	return true;
 }
 
-void ppu_interpreter::SRAW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::SRAW(PPUThread& ppu, ppu_opcode_t op)
 {
 	s32 RS = (s32)ppu.GPR[op.rs];
 	u8 shift = ppu.GPR[op.rb] & 63;
@@ -2838,9 +3147,10 @@ void ppu_interpreter::SRAW(PPUThread& ppu, ppu_opcode_t op)
 	}
 
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::SRAD(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::SRAD(PPUThread& ppu, ppu_opcode_t op)
 {
 	s64 RS = ppu.GPR[op.rs];
 	u8 shift = ppu.GPR[op.rb] & 127;
@@ -2856,31 +3166,35 @@ void ppu_interpreter::SRAD(PPUThread& ppu, ppu_opcode_t op)
 	}
 
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::LVRXL(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LVRXL(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	const u8 eb = addr & 0xf;
 
 	ppu.VR[op.vd].clear();
 	for (u32 i = 16 - eb; i < 16; ++i) ppu.VR[op.vd]._u8[15 - i] = vm::read8(vm::cast(addr + i - 16, HERE));
+	return true;
 }
 
-void ppu_interpreter::DSS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::DSS(PPUThread& ppu, ppu_opcode_t op)
 {
+	return true;
 }
 
-void ppu_interpreter::SRAWI(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::SRAWI(PPUThread& ppu, ppu_opcode_t op)
 {
 	s32 RS = (u32)ppu.GPR[op.rs];
 	ppu.GPR[op.ra] = RS >> op.sh32;
 	ppu.CA = (RS < 0) && ((u32)(ppu.GPR[op.ra] << op.sh32) != RS);
 
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::SRADI(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::SRADI(PPUThread& ppu, ppu_opcode_t op)
 {
 	auto sh = op.sh64;
 	s64 RS = ppu.GPR[op.rs];
@@ -2888,361 +3202,417 @@ void ppu_interpreter::SRADI(PPUThread& ppu, ppu_opcode_t op)
 	ppu.CA = (RS < 0) && ((ppu.GPR[op.ra] << sh) != RS);
 
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::EIEIO(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::EIEIO(PPUThread& ppu, ppu_opcode_t op)
 {
 	_mm_mfence();
+	return true;
 }
 
-void ppu_interpreter::STVLXL(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STVLXL(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	const u32 eb = addr & 0xf;
 
 	for (u32 i = 0; i < 16u - eb; ++i) vm::write8(vm::cast(addr + i, HERE), ppu.VR[op.vs]._u8[15 - i]);
+	return true;
 }
 
-void ppu_interpreter::STHBRX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STHBRX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	vm::_ref<le_t<u16>>(vm::cast(addr, HERE)) = (u16)ppu.GPR[op.rs];
+	return true;
 }
 
-void ppu_interpreter::EXTSH(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::EXTSH(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = (s64)(s16)ppu.GPR[op.rs];
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::STVRXL(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STVRXL(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	const u8 eb = addr & 0xf;
 
 	for (u32 i = 16 - eb; i < 16; ++i) vm::write8(vm::cast(addr + i - 16, HERE), ppu.VR[op.vs]._u8[15 - i]);
+	return true;
 }
 
-void ppu_interpreter::EXTSB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::EXTSB(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = (s64)(s8)ppu.GPR[op.rs];
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::STFIWX(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STFIWX(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 	vm::write32(vm::cast(addr, HERE), (u32&)ppu.FPR[op.frs]);
+	return true;
 }
 
-void ppu_interpreter::EXTSW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::EXTSW(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.GPR[op.ra] = (s64)(s32)ppu.GPR[op.rs];
 	if (UNLIKELY(op.rc)) ppu.SetCR<s64>(0, ppu.GPR[op.ra], 0);
+	return true;
 }
 
-void ppu_interpreter::ICBI(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::ICBI(PPUThread& ppu, ppu_opcode_t op)
 {
+	return true;
 }
 
-void ppu_interpreter::DCBZ(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::DCBZ(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb];
 
 	std::memset(vm::base(vm::cast(addr, HERE) & ~127), 0, 128);
+	return true;
 }
 
-void ppu_interpreter::LWZ(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LWZ(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16;
 	ppu.GPR[op.rd] = vm::read32(vm::cast(addr, HERE));
+	return true;
 }
 
-void ppu_interpreter::LWZU(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LWZU(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = ppu.GPR[op.ra] + op.simm16;
 	ppu.GPR[op.rd] = vm::read32(vm::cast(addr, HERE));
 	ppu.GPR[op.ra] = addr;
+	return true;
 }
 
-void ppu_interpreter::LBZ(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LBZ(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16;
 	ppu.GPR[op.rd] = vm::read8(vm::cast(addr, HERE));
+	return true;
 }
 
-void ppu_interpreter::LBZU(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LBZU(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = ppu.GPR[op.ra] + op.simm16;
 	ppu.GPR[op.rd] = vm::read8(vm::cast(addr, HERE));
 	ppu.GPR[op.ra] = addr;
+	return true;
 }
 
-void ppu_interpreter::STW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STW(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16;
 	vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[op.rs]);
+	return true;
 }
 
-void ppu_interpreter::STWU(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STWU(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = ppu.GPR[op.ra] + op.simm16;
 	vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[op.rs]);
 	ppu.GPR[op.ra] = addr;
+	return true;
 }
 
-void ppu_interpreter::STB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STB(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16;
 	vm::write8(vm::cast(addr, HERE), (u8)ppu.GPR[op.rs]);
+	return true;
 }
 
-void ppu_interpreter::STBU(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STBU(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = ppu.GPR[op.ra] + op.simm16;
 	vm::write8(vm::cast(addr, HERE), (u8)ppu.GPR[op.rs]);
 	ppu.GPR[op.ra] = addr;
+	return true;
 }
 
-void ppu_interpreter::LHZ(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LHZ(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16;
 	ppu.GPR[op.rd] = vm::read16(vm::cast(addr, HERE));
+	return true;
 }
 
-void ppu_interpreter::LHZU(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LHZU(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = ppu.GPR[op.ra] + op.simm16;
 	ppu.GPR[op.rd] = vm::read16(vm::cast(addr, HERE));
 	ppu.GPR[op.ra] = addr;
+	return true;
 }
 
-void ppu_interpreter::LHA(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LHA(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16;
 	ppu.GPR[op.rd] = (s64)(s16)vm::read16(vm::cast(addr, HERE));
+	return true;
 }
 
-void ppu_interpreter::LHAU(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LHAU(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = ppu.GPR[op.ra] + op.simm16;
 	ppu.GPR[op.rd] = (s64)(s16)vm::read16(vm::cast(addr, HERE));
 	ppu.GPR[op.ra] = addr;
+	return true;
 }
 
-void ppu_interpreter::STH(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STH(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16;
 	vm::write16(vm::cast(addr, HERE), (u16)ppu.GPR[op.rs]);
+	return true;
 }
 
-void ppu_interpreter::STHU(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STHU(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = ppu.GPR[op.ra] + op.simm16;
 	vm::write16(vm::cast(addr, HERE), (u16)ppu.GPR[op.rs]);
 	ppu.GPR[op.ra] = addr;
+	return true;
 }
 
-void ppu_interpreter::LMW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LMW(PPUThread& ppu, ppu_opcode_t op)
 {
 	u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16;
 	for (u32 i = op.rd; i<32; ++i, addr += 4)
 	{
 		ppu.GPR[i] = vm::read32(vm::cast(addr, HERE));
 	}
+	return true;
 }
 
-void ppu_interpreter::STMW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STMW(PPUThread& ppu, ppu_opcode_t op)
 {
 	u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16;
 	for (u32 i = op.rs; i<32; ++i, addr += 4)
 	{
 		vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[i]);
 	}
+	return true;
 }
 
-void ppu_interpreter::LFS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LFS(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16;
 	ppu.FPR[op.frd] = vm::_ref<f32>(vm::cast(addr, HERE));
+	return true;
 }
 
-void ppu_interpreter::LFSU(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LFSU(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = ppu.GPR[op.ra] + op.simm16;
 	ppu.FPR[op.frd] = vm::_ref<f32>(vm::cast(addr, HERE));
 	ppu.GPR[op.ra] = addr;
+	return true;
 }
 
-void ppu_interpreter::LFD(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LFD(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16;
 	ppu.FPR[op.frd] = vm::_ref<f64>(vm::cast(addr, HERE));
+	return true;
 }
 
-void ppu_interpreter::LFDU(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LFDU(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = ppu.GPR[op.ra] + op.simm16;
 	ppu.FPR[op.frd] = vm::_ref<f64>(vm::cast(addr, HERE));
 	ppu.GPR[op.ra] = addr;
+	return true;
 }
 
-void ppu_interpreter::STFS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STFS(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16;
 	vm::_ref<f32>(vm::cast(addr, HERE)) = static_cast<float>(ppu.FPR[op.frs]);
+	return true;
 }
 
-void ppu_interpreter::STFSU(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STFSU(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = ppu.GPR[op.ra] + op.simm16;
 	vm::_ref<f32>(vm::cast(addr, HERE)) = static_cast<float>(ppu.FPR[op.frs]);
 	ppu.GPR[op.ra] = addr;
+	return true;
 }
 
-void ppu_interpreter::STFD(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STFD(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16;
 	vm::_ref<f64>(vm::cast(addr, HERE)) = ppu.FPR[op.frs];
+	return true;
 }
 
-void ppu_interpreter::STFDU(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STFDU(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = ppu.GPR[op.ra] + op.simm16;
 	vm::_ref<f64>(vm::cast(addr, HERE)) = ppu.FPR[op.frs];
 	ppu.GPR[op.ra] = addr;
+	return true;
 }
 
-void ppu_interpreter::LD(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LD(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = (op.simm16 & ~3) + (op.ra ? ppu.GPR[op.ra] : 0);
 	ppu.GPR[op.rd] = vm::read64(vm::cast(addr, HERE));
+	return true;
 }
 
-void ppu_interpreter::LDU(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LDU(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = ppu.GPR[op.ra] + (op.simm16 & ~3);
 	ppu.GPR[op.rd] = vm::read64(vm::cast(addr, HERE));
 	ppu.GPR[op.ra] = addr;
+	return true;
 }
 
-void ppu_interpreter::LWA(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::LWA(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = (op.simm16 & ~3) + (op.ra ? ppu.GPR[op.ra] : 0);
 	ppu.GPR[op.rd] = (s64)(s32)vm::read32(vm::cast(addr, HERE));
+	return true;
 }
 
-void ppu_interpreter::STD(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STD(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = (op.simm16 & ~3) + (op.ra ? ppu.GPR[op.ra] : 0);
 	vm::write64(vm::cast(addr, HERE), ppu.GPR[op.rs]);
+	return true;
 }
 
-void ppu_interpreter::STDU(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::STDU(PPUThread& ppu, ppu_opcode_t op)
 {
 	const u64 addr = ppu.GPR[op.ra] + (op.simm16 & ~3);
 	vm::write64(vm::cast(addr, HERE), ppu.GPR[op.rs]);
 	ppu.GPR[op.ra] = addr;
+	return true;
 }
 
-void ppu_interpreter::FDIVS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FDIVS(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] / ppu.FPR[op.frb]);
-	ASSERT(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FSUBS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FSUBS(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] - ppu.FPR[op.frb]);
-	ASSERT(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FADDS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FADDS(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] + ppu.FPR[op.frb]);
-	ASSERT(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FSQRTS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FSQRTS(PPUThread& ppu, ppu_opcode_t op)
 {
-	ppu.FPR[op.frd] = f32(sqrt(ppu.FPR[op.frb]));
-	ASSERT(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	ppu.FPR[op.frd] = f32(std::sqrt(ppu.FPR[op.frb]));
+	VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FRES(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FRES(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.FPR[op.frd] = f32(1.0 / ppu.FPR[op.frb]);
-	ASSERT(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FMULS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FMULS(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] * ppu.FPR[op.frc]);
-	ASSERT(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FMADDS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FMADDS(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] * ppu.FPR[op.frc] + ppu.FPR[op.frb]);
-	ASSERT(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FMSUBS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FMSUBS(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] * ppu.FPR[op.frc] - ppu.FPR[op.frb]);
-	ASSERT(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FNMSUBS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FNMSUBS(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.FPR[op.frd] = f32(-(ppu.FPR[op.fra] * ppu.FPR[op.frc]) + ppu.FPR[op.frb]);
-	ASSERT(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FNMADDS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FNMADDS(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.FPR[op.frd] = f32(-(ppu.FPR[op.fra] * ppu.FPR[op.frc]) - ppu.FPR[op.frb]);
-	ASSERT(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::MTFSB1(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::MTFSB1(PPUThread& ppu, ppu_opcode_t op)
 {
 	LOG_WARNING(PPU, "MTFSB1");
 	if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::MCRFS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::MCRFS(PPUThread& ppu, ppu_opcode_t op)
 {
 	LOG_WARNING(PPU, "MCRFS");
 	ppu.SetCR(op.crfd, false, false, false, false);
+	return true;
 }
 
-void ppu_interpreter::MTFSB0(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::MTFSB0(PPUThread& ppu, ppu_opcode_t op)
 {
 	LOG_WARNING(PPU, "MTFSB0");
 	if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::MTFSFI(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::MTFSFI(PPUThread& ppu, ppu_opcode_t op)
 {
 	LOG_WARNING(PPU, "MTFSFI");
 	if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::MFFS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::MFFS(PPUThread& ppu, ppu_opcode_t op)
 {
 	LOG_WARNING(PPU, "MFFS");
 	ppu.FPR[op.frd] = 0.0;
 	if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::MTFSF(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::MTFSF(PPUThread& ppu, ppu_opcode_t op)
 {
 	LOG_WARNING(PPU, "MTFSF");
 	if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FCMPU(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FCMPU(PPUThread& ppu, ppu_opcode_t op)
 {
 	const f64 a = ppu.FPR[op.fra];
 	const f64 b = ppu.FPR[op.frb];
@@ -3251,141 +3621,163 @@ void ppu_interpreter::FCMPU(PPUThread& ppu, ppu_opcode_t op)
 	ppu.FE = a == b;
 	//ppu.FU = a != a || b != b;
 	ppu.SetCR(op.crfd, ppu.FL, ppu.FG, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FRSP(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FRSP(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.FPR[op.frd] = f32(ppu.FPR[op.frb]);
-	ASSERT(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FCTIW(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FCTIW(PPUThread& ppu, ppu_opcode_t op)
 {
-	(s32&)ppu.FPR[op.frd] = lrint(ppu.FPR[op.frb]);
-	ASSERT(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	(s32&)ppu.FPR[op.frd] = std::lrint(ppu.FPR[op.frb]);
+	VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FCTIWZ(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FCTIWZ(PPUThread& ppu, ppu_opcode_t op)
 {
 	(s32&)ppu.FPR[op.frd] = static_cast<s32>(ppu.FPR[op.frb]);
-	ASSERT(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FDIV(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FDIV(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.FPR[op.frd] = ppu.FPR[op.fra] / ppu.FPR[op.frb];
-	ASSERT(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FSUB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FSUB(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.FPR[op.frd] = ppu.FPR[op.fra] - ppu.FPR[op.frb];
-	ASSERT(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FADD(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FADD(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.FPR[op.frd] = ppu.FPR[op.fra] + ppu.FPR[op.frb];
-	ASSERT(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FSQRT(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FSQRT(PPUThread& ppu, ppu_opcode_t op)
 {
-	ppu.FPR[op.frd] = sqrt(ppu.FPR[op.frb]);
-	ASSERT(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	ppu.FPR[op.frd] = std::sqrt(ppu.FPR[op.frb]);
+	VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FSEL(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FSEL(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.FPR[op.frd] = ppu.FPR[op.fra] >= 0.0 ? ppu.FPR[op.frc] : ppu.FPR[op.frb];
 	if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FMUL(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FMUL(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.FPR[op.frd] = ppu.FPR[op.fra] * ppu.FPR[op.frc];
-	ASSERT(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FRSQRTE(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FRSQRTE(PPUThread& ppu, ppu_opcode_t op)
 {
-	ppu.FPR[op.frd] = 1.0 / sqrt(ppu.FPR[op.frb]);
-	ASSERT(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	ppu.FPR[op.frd] = 1.0 / std::sqrt(ppu.FPR[op.frb]);
+	VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FMSUB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FMSUB(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.FPR[op.frd] = ppu.FPR[op.fra] * ppu.FPR[op.frc] - ppu.FPR[op.frb];
-	ASSERT(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FMADD(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FMADD(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.FPR[op.frd] = ppu.FPR[op.fra] * ppu.FPR[op.frc] + ppu.FPR[op.frb];
-	ASSERT(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FNMSUB(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FNMSUB(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.FPR[op.frd] = -(ppu.FPR[op.fra] * ppu.FPR[op.frc]) + ppu.FPR[op.frb];
-	ASSERT(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FNMADD(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FNMADD(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.FPR[op.frd] = -(ppu.FPR[op.fra] * ppu.FPR[op.frc]) - ppu.FPR[op.frb];
-	ASSERT(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FCMPO(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FCMPO(PPUThread& ppu, ppu_opcode_t op)
 {
 	return FCMPU(ppu, op);
+	return true;
 }
 
-void ppu_interpreter::FNEG(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FNEG(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.FPR[op.frd] = -ppu.FPR[op.frb];
 	if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FMR(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FMR(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.FPR[op.frd] = ppu.FPR[op.frb];
 	if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FNABS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FNABS(PPUThread& ppu, ppu_opcode_t op)
 {
-	ppu.FPR[op.frd] = -fabs(ppu.FPR[op.frb]);
+	ppu.FPR[op.frd] = -std::fabs(ppu.FPR[op.frb]);
 	if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FABS(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FABS(PPUThread& ppu, ppu_opcode_t op)
 {
-	ppu.FPR[op.frd] = fabs(ppu.FPR[op.frb]);
+	ppu.FPR[op.frd] = std::fabs(ppu.FPR[op.frb]);
 	if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FCTID(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FCTID(PPUThread& ppu, ppu_opcode_t op)
 {
-	(s64&)ppu.FPR[op.frd] = llrint(ppu.FPR[op.frb]);
-	ASSERT(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	(s64&)ppu.FPR[op.frd] = std::llrint(ppu.FPR[op.frb]);
+	VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FCTIDZ(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FCTIDZ(PPUThread& ppu, ppu_opcode_t op)
 {
 	(s64&)ppu.FPR[op.frd] = static_cast<s64>(ppu.FPR[op.frb]);
-	ASSERT(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-void ppu_interpreter::FCFID(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::FCFID(PPUThread& ppu, ppu_opcode_t op)
 {
 	ppu.FPR[op.frd] = static_cast<double>((s64&)ppu.FPR[op.frb]);
-	ASSERT(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU);
+	return true;
 }
 
-
-void ppu_interpreter::UNK(PPUThread& ppu, ppu_opcode_t op)
+bool ppu_interpreter::UNK(PPUThread& ppu, ppu_opcode_t op)
 {
 	throw fmt::exception("Unknown/Illegal opcode: 0x%08x" HERE, op.opcode);
 }
diff --git a/rpcs3/Emu/Cell/PPUInterpreter.h b/rpcs3/Emu/Cell/PPUInterpreter.h
index ddca283103..e1c54db3cc 100644
--- a/rpcs3/Emu/Cell/PPUInterpreter.h
+++ b/rpcs3/Emu/Cell/PPUInterpreter.h
@@ -4,392 +4,390 @@
 
 class PPUThread;
 
-using ppu_inter_func_t = void(*)(PPUThread& ppu, ppu_opcode_t op);
-
 struct ppu_interpreter
 {
-	static void TDI(PPUThread&, ppu_opcode_t);
-	static void TWI(PPUThread&, ppu_opcode_t);
-	static void MFVSCR(PPUThread&, ppu_opcode_t);
-	static void MTVSCR(PPUThread&, ppu_opcode_t);
-	static void VADDCUW(PPUThread&, ppu_opcode_t);
-	static void VADDFP(PPUThread&, ppu_opcode_t);
-	static void VADDSBS(PPUThread&, ppu_opcode_t);
-	static void VADDSHS(PPUThread&, ppu_opcode_t);
-	static void VADDSWS(PPUThread&, ppu_opcode_t);
-	static void VADDUBM(PPUThread&, ppu_opcode_t);
-	static void VADDUBS(PPUThread&, ppu_opcode_t);
-	static void VADDUHM(PPUThread&, ppu_opcode_t);
-	static void VADDUHS(PPUThread&, ppu_opcode_t);
-	static void VADDUWM(PPUThread&, ppu_opcode_t);
-	static void VADDUWS(PPUThread&, ppu_opcode_t);
-	static void VAND(PPUThread&, ppu_opcode_t);
-	static void VANDC(PPUThread&, ppu_opcode_t);
-	static void VAVGSB(PPUThread&, ppu_opcode_t);
-	static void VAVGSH(PPUThread&, ppu_opcode_t);
-	static void VAVGSW(PPUThread&, ppu_opcode_t);
-	static void VAVGUB(PPUThread&, ppu_opcode_t);
-	static void VAVGUH(PPUThread&, ppu_opcode_t);
-	static void VAVGUW(PPUThread&, ppu_opcode_t);
-	static void VCFSX(PPUThread&, ppu_opcode_t);
-	static void VCFUX(PPUThread&, ppu_opcode_t);
-	static void VCMPBFP(PPUThread&, ppu_opcode_t);
-	static void VCMPEQFP(PPUThread&, ppu_opcode_t);
-	static void VCMPEQUB(PPUThread&, ppu_opcode_t);
-	static void VCMPEQUH(PPUThread&, ppu_opcode_t);
-	static void VCMPEQUW(PPUThread&, ppu_opcode_t);
-	static void VCMPGEFP(PPUThread&, ppu_opcode_t);
-	static void VCMPGTFP(PPUThread&, ppu_opcode_t);
-	static void VCMPGTSB(PPUThread&, ppu_opcode_t);
-	static void VCMPGTSH(PPUThread&, ppu_opcode_t);
-	static void VCMPGTSW(PPUThread&, ppu_opcode_t);
-	static void VCMPGTUB(PPUThread&, ppu_opcode_t);
-	static void VCMPGTUH(PPUThread&, ppu_opcode_t);
-	static void VCMPGTUW(PPUThread&, ppu_opcode_t);
-	static void VCTSXS(PPUThread&, ppu_opcode_t);
-	static void VCTUXS(PPUThread&, ppu_opcode_t);
-	static void VEXPTEFP(PPUThread&, ppu_opcode_t);
-	static void VLOGEFP(PPUThread&, ppu_opcode_t);
-	static void VMADDFP(PPUThread&, ppu_opcode_t);
-	static void VMAXFP(PPUThread&, ppu_opcode_t);
-	static void VMAXSB(PPUThread&, ppu_opcode_t);
-	static void VMAXSH(PPUThread&, ppu_opcode_t);
-	static void VMAXSW(PPUThread&, ppu_opcode_t);
-	static void VMAXUB(PPUThread&, ppu_opcode_t);
-	static void VMAXUH(PPUThread&, ppu_opcode_t);
-	static void VMAXUW(PPUThread&, ppu_opcode_t);
-	static void VMHADDSHS(PPUThread&, ppu_opcode_t);
-	static void VMHRADDSHS(PPUThread&, ppu_opcode_t);
-	static void VMINFP(PPUThread&, ppu_opcode_t);
-	static void VMINSB(PPUThread&, ppu_opcode_t);
-	static void VMINSH(PPUThread&, ppu_opcode_t);
-	static void VMINSW(PPUThread&, ppu_opcode_t);
-	static void VMINUB(PPUThread&, ppu_opcode_t);
-	static void VMINUH(PPUThread&, ppu_opcode_t);
-	static void VMINUW(PPUThread&, ppu_opcode_t);
-	static void VMLADDUHM(PPUThread&, ppu_opcode_t);
-	static void VMRGHB(PPUThread&, ppu_opcode_t);
-	static void VMRGHH(PPUThread&, ppu_opcode_t);
-	static void VMRGHW(PPUThread&, ppu_opcode_t);
-	static void VMRGLB(PPUThread&, ppu_opcode_t);
-	static void VMRGLH(PPUThread&, ppu_opcode_t);
-	static void VMRGLW(PPUThread&, ppu_opcode_t);
-	static void VMSUMMBM(PPUThread&, ppu_opcode_t);
-	static void VMSUMSHM(PPUThread&, ppu_opcode_t);
-	static void VMSUMSHS(PPUThread&, ppu_opcode_t);
-	static void VMSUMUBM(PPUThread&, ppu_opcode_t);
-	static void VMSUMUHM(PPUThread&, ppu_opcode_t);
-	static void VMSUMUHS(PPUThread&, ppu_opcode_t);
-	static void VMULESB(PPUThread&, ppu_opcode_t);
-	static void VMULESH(PPUThread&, ppu_opcode_t);
-	static void VMULEUB(PPUThread&, ppu_opcode_t);
-	static void VMULEUH(PPUThread&, ppu_opcode_t);
-	static void VMULOSB(PPUThread&, ppu_opcode_t);
-	static void VMULOSH(PPUThread&, ppu_opcode_t);
-	static void VMULOUB(PPUThread&, ppu_opcode_t);
-	static void VMULOUH(PPUThread&, ppu_opcode_t);
-	static void VNMSUBFP(PPUThread&, ppu_opcode_t);
-	static void VNOR(PPUThread&, ppu_opcode_t);
-	static void VOR(PPUThread&, ppu_opcode_t);
-	static void VPERM(PPUThread&, ppu_opcode_t);
-	static void VPKPX(PPUThread&, ppu_opcode_t);
-	static void VPKSHSS(PPUThread&, ppu_opcode_t);
-	static void VPKSHUS(PPUThread&, ppu_opcode_t);
-	static void VPKSWSS(PPUThread&, ppu_opcode_t);
-	static void VPKSWUS(PPUThread&, ppu_opcode_t);
-	static void VPKUHUM(PPUThread&, ppu_opcode_t);
-	static void VPKUHUS(PPUThread&, ppu_opcode_t);
-	static void VPKUWUM(PPUThread&, ppu_opcode_t);
-	static void VPKUWUS(PPUThread&, ppu_opcode_t);
-	static void VREFP(PPUThread&, ppu_opcode_t);
-	static void VRFIM(PPUThread&, ppu_opcode_t);
-	static void VRFIN(PPUThread&, ppu_opcode_t);
-	static void VRFIP(PPUThread&, ppu_opcode_t);
-	static void VRFIZ(PPUThread&, ppu_opcode_t);
-	static void VRLB(PPUThread&, ppu_opcode_t);
-	static void VRLH(PPUThread&, ppu_opcode_t);
-	static void VRLW(PPUThread&, ppu_opcode_t);
-	static void VRSQRTEFP(PPUThread&, ppu_opcode_t);
-	static void VSEL(PPUThread&, ppu_opcode_t);
-	static void VSL(PPUThread&, ppu_opcode_t);
-	static void VSLB(PPUThread&, ppu_opcode_t);
-	static void VSLDOI(PPUThread&, ppu_opcode_t);
-	static void VSLH(PPUThread&, ppu_opcode_t);
-	static void VSLO(PPUThread&, ppu_opcode_t);
-	static void VSLW(PPUThread&, ppu_opcode_t);
-	static void VSPLTB(PPUThread&, ppu_opcode_t);
-	static void VSPLTH(PPUThread&, ppu_opcode_t);
-	static void VSPLTISB(PPUThread&, ppu_opcode_t);
-	static void VSPLTISH(PPUThread&, ppu_opcode_t);
-	static void VSPLTISW(PPUThread&, ppu_opcode_t);
-	static void VSPLTW(PPUThread&, ppu_opcode_t);
-	static void VSR(PPUThread&, ppu_opcode_t);
-	static void VSRAB(PPUThread&, ppu_opcode_t);
-	static void VSRAH(PPUThread&, ppu_opcode_t);
-	static void VSRAW(PPUThread&, ppu_opcode_t);
-	static void VSRB(PPUThread&, ppu_opcode_t);
-	static void VSRH(PPUThread&, ppu_opcode_t);
-	static void VSRO(PPUThread&, ppu_opcode_t);
-	static void VSRW(PPUThread&, ppu_opcode_t);
-	static void VSUBCUW(PPUThread&, ppu_opcode_t);
-	static void VSUBFP(PPUThread&, ppu_opcode_t);
-	static void VSUBSBS(PPUThread&, ppu_opcode_t);
-	static void VSUBSHS(PPUThread&, ppu_opcode_t);
-	static void VSUBSWS(PPUThread&, ppu_opcode_t);
-	static void VSUBUBM(PPUThread&, ppu_opcode_t);
-	static void VSUBUBS(PPUThread&, ppu_opcode_t);
-	static void VSUBUHM(PPUThread&, ppu_opcode_t);
-	static void VSUBUHS(PPUThread&, ppu_opcode_t);
-	static void VSUBUWM(PPUThread&, ppu_opcode_t);
-	static void VSUBUWS(PPUThread&, ppu_opcode_t);
-	static void VSUMSWS(PPUThread&, ppu_opcode_t);
-	static void VSUM2SWS(PPUThread&, ppu_opcode_t);
-	static void VSUM4SBS(PPUThread&, ppu_opcode_t);
-	static void VSUM4SHS(PPUThread&, ppu_opcode_t);
-	static void VSUM4UBS(PPUThread&, ppu_opcode_t);
-	static void VUPKHPX(PPUThread&, ppu_opcode_t);
-	static void VUPKHSB(PPUThread&, ppu_opcode_t);
-	static void VUPKHSH(PPUThread&, ppu_opcode_t);
-	static void VUPKLPX(PPUThread&, ppu_opcode_t);
-	static void VUPKLSB(PPUThread&, ppu_opcode_t);
-	static void VUPKLSH(PPUThread&, ppu_opcode_t);
-	static void VXOR(PPUThread&, ppu_opcode_t);
-	static void MULLI(PPUThread&, ppu_opcode_t);
-	static void SUBFIC(PPUThread&, ppu_opcode_t);
-	static void CMPLI(PPUThread&, ppu_opcode_t);
-	static void CMPI(PPUThread&, ppu_opcode_t);
-	static void ADDIC(PPUThread&, ppu_opcode_t);
-	static void ADDI(PPUThread&, ppu_opcode_t);
-	static void ADDIS(PPUThread&, ppu_opcode_t);
-	static void BC(PPUThread&, ppu_opcode_t);
-	static void HACK(PPUThread&, ppu_opcode_t);
-	static void SC(PPUThread&, ppu_opcode_t);
-	static void B(PPUThread&, ppu_opcode_t);
-	static void MCRF(PPUThread&, ppu_opcode_t);
-	static void BCLR(PPUThread&, ppu_opcode_t);
-	static void CRNOR(PPUThread&, ppu_opcode_t);
-	static void CRANDC(PPUThread&, ppu_opcode_t);
-	static void ISYNC(PPUThread&, ppu_opcode_t);
-	static void CRXOR(PPUThread&, ppu_opcode_t);
-	static void CRNAND(PPUThread&, ppu_opcode_t);
-	static void CRAND(PPUThread&, ppu_opcode_t);
-	static void CREQV(PPUThread&, ppu_opcode_t);
-	static void CRORC(PPUThread&, ppu_opcode_t);
-	static void CROR(PPUThread&, ppu_opcode_t);
-	static void BCCTR(PPUThread&, ppu_opcode_t);
-	static void RLWIMI(PPUThread&, ppu_opcode_t);
-	static void RLWINM(PPUThread&, ppu_opcode_t);
-	static void RLWNM(PPUThread&, ppu_opcode_t);
-	static void ORI(PPUThread&, ppu_opcode_t);
-	static void ORIS(PPUThread&, ppu_opcode_t);
-	static void XORI(PPUThread&, ppu_opcode_t);
-	static void XORIS(PPUThread&, ppu_opcode_t);
-	static void ANDI(PPUThread&, ppu_opcode_t);
-	static void ANDIS(PPUThread&, ppu_opcode_t);
-	static void RLDICL(PPUThread&, ppu_opcode_t);
-	static void RLDICR(PPUThread&, ppu_opcode_t);
-	static void RLDIC(PPUThread&, ppu_opcode_t);
-	static void RLDIMI(PPUThread&, ppu_opcode_t);
-	static void RLDCL(PPUThread&, ppu_opcode_t);
-	static void RLDCR(PPUThread&, ppu_opcode_t);
-	static void CMP(PPUThread&, ppu_opcode_t);
-	static void TW(PPUThread&, ppu_opcode_t);
-	static void LVSL(PPUThread&, ppu_opcode_t);
-	static void LVEBX(PPUThread&, ppu_opcode_t);
-	static void SUBFC(PPUThread&, ppu_opcode_t);
-	static void MULHDU(PPUThread&, ppu_opcode_t);
-	static void ADDC(PPUThread&, ppu_opcode_t);
-	static void MULHWU(PPUThread&, ppu_opcode_t);
-	static void MFOCRF(PPUThread&, ppu_opcode_t);
-	static void LWARX(PPUThread&, ppu_opcode_t);
-	static void LDX(PPUThread&, ppu_opcode_t);
-	static void LWZX(PPUThread&, ppu_opcode_t);
-	static void SLW(PPUThread&, ppu_opcode_t);
-	static void CNTLZW(PPUThread&, ppu_opcode_t);
-	static void SLD(PPUThread&, ppu_opcode_t);
-	static void AND(PPUThread&, ppu_opcode_t);
-	static void CMPL(PPUThread&, ppu_opcode_t);
-	static void LVSR(PPUThread&, ppu_opcode_t);
-	static void LVEHX(PPUThread&, ppu_opcode_t);
-	static void SUBF(PPUThread&, ppu_opcode_t);
-	static void LDUX(PPUThread&, ppu_opcode_t);
-	static void DCBST(PPUThread&, ppu_opcode_t);
-	static void LWZUX(PPUThread&, ppu_opcode_t);
-	static void CNTLZD(PPUThread&, ppu_opcode_t);
-	static void ANDC(PPUThread&, ppu_opcode_t);
-	static void TD(PPUThread&, ppu_opcode_t);
-	static void LVEWX(PPUThread&, ppu_opcode_t);
-	static void MULHD(PPUThread&, ppu_opcode_t);
-	static void MULHW(PPUThread&, ppu_opcode_t);
-	static void LDARX(PPUThread&, ppu_opcode_t);
-	static void DCBF(PPUThread&, ppu_opcode_t);
-	static void LBZX(PPUThread&, ppu_opcode_t);
-	static void LVX(PPUThread&, ppu_opcode_t);
-	static void NEG(PPUThread&, ppu_opcode_t);
-	static void LBZUX(PPUThread&, ppu_opcode_t);
-	static void NOR(PPUThread&, ppu_opcode_t);
-	static void STVEBX(PPUThread&, ppu_opcode_t);
-	static void SUBFE(PPUThread&, ppu_opcode_t);
-	static void ADDE(PPUThread&, ppu_opcode_t);
-	static void MTOCRF(PPUThread&, ppu_opcode_t);
-	static void STDX(PPUThread&, ppu_opcode_t);
-	static void STWCX(PPUThread&, ppu_opcode_t);
-	static void STWX(PPUThread&, ppu_opcode_t);
-	static void STVEHX(PPUThread&, ppu_opcode_t);
-	static void STDUX(PPUThread&, ppu_opcode_t);
-	static void STWUX(PPUThread&, ppu_opcode_t);
-	static void STVEWX(PPUThread&, ppu_opcode_t);
-	static void SUBFZE(PPUThread&, ppu_opcode_t);
-	static void ADDZE(PPUThread&, ppu_opcode_t);
-	static void STDCX(PPUThread&, ppu_opcode_t);
-	static void STBX(PPUThread&, ppu_opcode_t);
-	static void STVX(PPUThread&, ppu_opcode_t);
-	static void MULLD(PPUThread&, ppu_opcode_t);
-	static void SUBFME(PPUThread&, ppu_opcode_t);
-	static void ADDME(PPUThread&, ppu_opcode_t);
-	static void MULLW(PPUThread&, ppu_opcode_t);
-	static void DCBTST(PPUThread&, ppu_opcode_t);
-	static void STBUX(PPUThread&, ppu_opcode_t);
-	static void ADD(PPUThread&, ppu_opcode_t);
-	static void DCBT(PPUThread&, ppu_opcode_t);
-	static void LHZX(PPUThread&, ppu_opcode_t);
-	static void EQV(PPUThread&, ppu_opcode_t);
-	static void ECIWX(PPUThread&, ppu_opcode_t);
-	static void LHZUX(PPUThread&, ppu_opcode_t);
-	static void XOR(PPUThread&, ppu_opcode_t);
-	static void MFSPR(PPUThread&, ppu_opcode_t);
-	static void LWAX(PPUThread&, ppu_opcode_t);
-	static void DST(PPUThread&, ppu_opcode_t);
-	static void LHAX(PPUThread&, ppu_opcode_t);
-	static void LVXL(PPUThread&, ppu_opcode_t);
-	static void MFTB(PPUThread&, ppu_opcode_t);
-	static void LWAUX(PPUThread&, ppu_opcode_t);
-	static void DSTST(PPUThread&, ppu_opcode_t);
-	static void LHAUX(PPUThread&, ppu_opcode_t);
-	static void STHX(PPUThread&, ppu_opcode_t);
-	static void ORC(PPUThread&, ppu_opcode_t);
-	static void ECOWX(PPUThread&, ppu_opcode_t);
-	static void STHUX(PPUThread&, ppu_opcode_t);
-	static void OR(PPUThread&, ppu_opcode_t);
-	static void DIVDU(PPUThread&, ppu_opcode_t);
-	static void DIVWU(PPUThread&, ppu_opcode_t);
-	static void MTSPR(PPUThread&, ppu_opcode_t);
-	static void DCBI(PPUThread&, ppu_opcode_t);
-	static void NAND(PPUThread&, ppu_opcode_t);
-	static void STVXL(PPUThread&, ppu_opcode_t);
-	static void DIVD(PPUThread&, ppu_opcode_t);
-	static void DIVW(PPUThread&, ppu_opcode_t);
-	static void LVLX(PPUThread&, ppu_opcode_t);
-	static void LDBRX(PPUThread&, ppu_opcode_t);
-	static void LSWX(PPUThread&, ppu_opcode_t);
-	static void LWBRX(PPUThread&, ppu_opcode_t);
-	static void LFSX(PPUThread&, ppu_opcode_t);
-	static void SRW(PPUThread&, ppu_opcode_t);
-	static void SRD(PPUThread&, ppu_opcode_t);
-	static void LVRX(PPUThread&, ppu_opcode_t);
-	static void LSWI(PPUThread&, ppu_opcode_t);
-	static void LFSUX(PPUThread&, ppu_opcode_t);
-	static void SYNC(PPUThread&, ppu_opcode_t);
-	static void LFDX(PPUThread&, ppu_opcode_t);
-	static void LFDUX(PPUThread&, ppu_opcode_t);
-	static void STVLX(PPUThread&, ppu_opcode_t);
-	static void STDBRX(PPUThread&, ppu_opcode_t);
-	static void STSWX(PPUThread&, ppu_opcode_t);
-	static void STWBRX(PPUThread&, ppu_opcode_t);
-	static void STFSX(PPUThread&, ppu_opcode_t);
-	static void STVRX(PPUThread&, ppu_opcode_t);
-	static void STFSUX(PPUThread&, ppu_opcode_t);
-	static void STSWI(PPUThread&, ppu_opcode_t);
-	static void STFDX(PPUThread&, ppu_opcode_t);
-	static void STFDUX(PPUThread&, ppu_opcode_t);
-	static void LVLXL(PPUThread&, ppu_opcode_t);
-	static void LHBRX(PPUThread&, ppu_opcode_t);
-	static void SRAW(PPUThread&, ppu_opcode_t);
-	static void SRAD(PPUThread&, ppu_opcode_t);
-	static void LVRXL(PPUThread&, ppu_opcode_t);
-	static void DSS(PPUThread&, ppu_opcode_t);
-	static void SRAWI(PPUThread&, ppu_opcode_t);
-	static void SRADI(PPUThread&, ppu_opcode_t);
-	static void EIEIO(PPUThread&, ppu_opcode_t);
-	static void STVLXL(PPUThread&, ppu_opcode_t);
-	static void STHBRX(PPUThread&, ppu_opcode_t);
-	static void EXTSH(PPUThread&, ppu_opcode_t);
-	static void STVRXL(PPUThread&, ppu_opcode_t);
-	static void EXTSB(PPUThread&, ppu_opcode_t);
-	static void STFIWX(PPUThread&, ppu_opcode_t);
-	static void EXTSW(PPUThread&, ppu_opcode_t);
-	static void ICBI(PPUThread&, ppu_opcode_t);
-	static void DCBZ(PPUThread&, ppu_opcode_t);
-	static void LWZ(PPUThread&, ppu_opcode_t);
-	static void LWZU(PPUThread&, ppu_opcode_t);
-	static void LBZ(PPUThread&, ppu_opcode_t);
-	static void LBZU(PPUThread&, ppu_opcode_t);
-	static void STW(PPUThread&, ppu_opcode_t);
-	static void STWU(PPUThread&, ppu_opcode_t);
-	static void STB(PPUThread&, ppu_opcode_t);
-	static void STBU(PPUThread&, ppu_opcode_t);
-	static void LHZ(PPUThread&, ppu_opcode_t);
-	static void LHZU(PPUThread&, ppu_opcode_t);
-	static void LHA(PPUThread&, ppu_opcode_t);
-	static void LHAU(PPUThread&, ppu_opcode_t);
-	static void STH(PPUThread&, ppu_opcode_t);
-	static void STHU(PPUThread&, ppu_opcode_t);
-	static void LMW(PPUThread&, ppu_opcode_t);
-	static void STMW(PPUThread&, ppu_opcode_t);
-	static void LFS(PPUThread&, ppu_opcode_t);
-	static void LFSU(PPUThread&, ppu_opcode_t);
-	static void LFD(PPUThread&, ppu_opcode_t);
-	static void LFDU(PPUThread&, ppu_opcode_t);
-	static void STFS(PPUThread&, ppu_opcode_t);
-	static void STFSU(PPUThread&, ppu_opcode_t);
-	static void STFD(PPUThread&, ppu_opcode_t);
-	static void STFDU(PPUThread&, ppu_opcode_t);
-	static void LD(PPUThread&, ppu_opcode_t);
-	static void LDU(PPUThread&, ppu_opcode_t);
-	static void LWA(PPUThread&, ppu_opcode_t);
-	static void FDIVS(PPUThread&, ppu_opcode_t);
-	static void FSUBS(PPUThread&, ppu_opcode_t);
-	static void FADDS(PPUThread&, ppu_opcode_t);
-	static void FSQRTS(PPUThread&, ppu_opcode_t);
-	static void FRES(PPUThread&, ppu_opcode_t);
-	static void FMULS(PPUThread&, ppu_opcode_t);
-	static void FMADDS(PPUThread&, ppu_opcode_t);
-	static void FMSUBS(PPUThread&, ppu_opcode_t);
-	static void FNMSUBS(PPUThread&, ppu_opcode_t);
-	static void FNMADDS(PPUThread&, ppu_opcode_t);
-	static void STD(PPUThread&, ppu_opcode_t);
-	static void STDU(PPUThread&, ppu_opcode_t);
-	static void MTFSB1(PPUThread&, ppu_opcode_t);
-	static void MCRFS(PPUThread&, ppu_opcode_t);
-	static void MTFSB0(PPUThread&, ppu_opcode_t);
-	static void MTFSFI(PPUThread&, ppu_opcode_t);
-	static void MFFS(PPUThread&, ppu_opcode_t);
-	static void MTFSF(PPUThread&, ppu_opcode_t);
-	static void FCMPU(PPUThread&, ppu_opcode_t);
-	static void FRSP(PPUThread&, ppu_opcode_t);
-	static void FCTIW(PPUThread&, ppu_opcode_t);
-	static void FCTIWZ(PPUThread&, ppu_opcode_t);
-	static void FDIV(PPUThread&, ppu_opcode_t);
-	static void FSUB(PPUThread&, ppu_opcode_t);
-	static void FADD(PPUThread&, ppu_opcode_t);
-	static void FSQRT(PPUThread&, ppu_opcode_t);
-	static void FSEL(PPUThread&, ppu_opcode_t);
-	static void FMUL(PPUThread&, ppu_opcode_t);
-	static void FRSQRTE(PPUThread&, ppu_opcode_t);
-	static void FMSUB(PPUThread&, ppu_opcode_t);
-	static void FMADD(PPUThread&, ppu_opcode_t);
-	static void FNMSUB(PPUThread&, ppu_opcode_t);
-	static void FNMADD(PPUThread&, ppu_opcode_t);
-	static void FCMPO(PPUThread&, ppu_opcode_t);
-	static void FNEG(PPUThread&, ppu_opcode_t);
-	static void FMR(PPUThread&, ppu_opcode_t);
-	static void FNABS(PPUThread&, ppu_opcode_t);
-	static void FABS(PPUThread&, ppu_opcode_t);
-	static void FCTID(PPUThread&, ppu_opcode_t);
-	static void FCTIDZ(PPUThread&, ppu_opcode_t);
-	static void FCFID(PPUThread&, ppu_opcode_t);
+	static bool MFVSCR(PPUThread&, ppu_opcode_t);
+	static bool MTVSCR(PPUThread&, ppu_opcode_t);
+	static bool VADDCUW(PPUThread&, ppu_opcode_t);
+	static bool VADDFP(PPUThread&, ppu_opcode_t);
+	static bool VADDSBS(PPUThread&, ppu_opcode_t);
+	static bool VADDSHS(PPUThread&, ppu_opcode_t);
+	static bool VADDSWS(PPUThread&, ppu_opcode_t);
+	static bool VADDUBM(PPUThread&, ppu_opcode_t);
+	static bool VADDUBS(PPUThread&, ppu_opcode_t);
+	static bool VADDUHM(PPUThread&, ppu_opcode_t);
+	static bool VADDUHS(PPUThread&, ppu_opcode_t);
+	static bool VADDUWM(PPUThread&, ppu_opcode_t);
+	static bool VADDUWS(PPUThread&, ppu_opcode_t);
+	static bool VAND(PPUThread&, ppu_opcode_t);
+	static bool VANDC(PPUThread&, ppu_opcode_t);
+	static bool VAVGSB(PPUThread&, ppu_opcode_t);
+	static bool VAVGSH(PPUThread&, ppu_opcode_t);
+	static bool VAVGSW(PPUThread&, ppu_opcode_t);
+	static bool VAVGUB(PPUThread&, ppu_opcode_t);
+	static bool VAVGUH(PPUThread&, ppu_opcode_t);
+	static bool VAVGUW(PPUThread&, ppu_opcode_t);
+	static bool VCFSX(PPUThread&, ppu_opcode_t);
+	static bool VCFUX(PPUThread&, ppu_opcode_t);
+	static bool VCMPBFP(PPUThread&, ppu_opcode_t);
+	static bool VCMPEQFP(PPUThread&, ppu_opcode_t);
+	static bool VCMPEQUB(PPUThread&, ppu_opcode_t);
+	static bool VCMPEQUH(PPUThread&, ppu_opcode_t);
+	static bool VCMPEQUW(PPUThread&, ppu_opcode_t);
+	static bool VCMPGEFP(PPUThread&, ppu_opcode_t);
+	static bool VCMPGTFP(PPUThread&, ppu_opcode_t);
+	static bool VCMPGTSB(PPUThread&, ppu_opcode_t);
+	static bool VCMPGTSH(PPUThread&, ppu_opcode_t);
+	static bool VCMPGTSW(PPUThread&, ppu_opcode_t);
+	static bool VCMPGTUB(PPUThread&, ppu_opcode_t);
+	static bool VCMPGTUH(PPUThread&, ppu_opcode_t);
+	static bool VCMPGTUW(PPUThread&, ppu_opcode_t);
+	static bool VCTSXS(PPUThread&, ppu_opcode_t);
+	static bool VCTUXS(PPUThread&, ppu_opcode_t);
+	static bool VEXPTEFP(PPUThread&, ppu_opcode_t);
+	static bool VLOGEFP(PPUThread&, ppu_opcode_t);
+	static bool VMADDFP(PPUThread&, ppu_opcode_t);
+	static bool VMAXFP(PPUThread&, ppu_opcode_t);
+	static bool VMAXSB(PPUThread&, ppu_opcode_t);
+	static bool VMAXSH(PPUThread&, ppu_opcode_t);
+	static bool VMAXSW(PPUThread&, ppu_opcode_t);
+	static bool VMAXUB(PPUThread&, ppu_opcode_t);
+	static bool VMAXUH(PPUThread&, ppu_opcode_t);
+	static bool VMAXUW(PPUThread&, ppu_opcode_t);
+	static bool VMHADDSHS(PPUThread&, ppu_opcode_t);
+	static bool VMHRADDSHS(PPUThread&, ppu_opcode_t);
+	static bool VMINFP(PPUThread&, ppu_opcode_t);
+	static bool VMINSB(PPUThread&, ppu_opcode_t);
+	static bool VMINSH(PPUThread&, ppu_opcode_t);
+	static bool VMINSW(PPUThread&, ppu_opcode_t);
+	static bool VMINUB(PPUThread&, ppu_opcode_t);
+	static bool VMINUH(PPUThread&, ppu_opcode_t);
+	static bool VMINUW(PPUThread&, ppu_opcode_t);
+	static bool VMLADDUHM(PPUThread&, ppu_opcode_t);
+	static bool VMRGHB(PPUThread&, ppu_opcode_t);
+	static bool VMRGHH(PPUThread&, ppu_opcode_t);
+	static bool VMRGHW(PPUThread&, ppu_opcode_t);
+	static bool VMRGLB(PPUThread&, ppu_opcode_t);
+	static bool VMRGLH(PPUThread&, ppu_opcode_t);
+	static bool VMRGLW(PPUThread&, ppu_opcode_t);
+	static bool VMSUMMBM(PPUThread&, ppu_opcode_t);
+	static bool VMSUMSHM(PPUThread&, ppu_opcode_t);
+	static bool VMSUMSHS(PPUThread&, ppu_opcode_t);
+	static bool VMSUMUBM(PPUThread&, ppu_opcode_t);
+	static bool VMSUMUHM(PPUThread&, ppu_opcode_t);
+	static bool VMSUMUHS(PPUThread&, ppu_opcode_t);
+	static bool VMULESB(PPUThread&, ppu_opcode_t);
+	static bool VMULESH(PPUThread&, ppu_opcode_t);
+	static bool VMULEUB(PPUThread&, ppu_opcode_t);
+	static bool VMULEUH(PPUThread&, ppu_opcode_t);
+	static bool VMULOSB(PPUThread&, ppu_opcode_t);
+	static bool VMULOSH(PPUThread&, ppu_opcode_t);
+	static bool VMULOUB(PPUThread&, ppu_opcode_t);
+	static bool VMULOUH(PPUThread&, ppu_opcode_t);
+	static bool VNMSUBFP(PPUThread&, ppu_opcode_t);
+	static bool VNOR(PPUThread&, ppu_opcode_t);
+	static bool VOR(PPUThread&, ppu_opcode_t);
+	static bool VPERM(PPUThread&, ppu_opcode_t);
+	static bool VPKPX(PPUThread&, ppu_opcode_t);
+	static bool VPKSHSS(PPUThread&, ppu_opcode_t);
+	static bool VPKSHUS(PPUThread&, ppu_opcode_t);
+	static bool VPKSWSS(PPUThread&, ppu_opcode_t);
+	static bool VPKSWUS(PPUThread&, ppu_opcode_t);
+	static bool VPKUHUM(PPUThread&, ppu_opcode_t);
+	static bool VPKUHUS(PPUThread&, ppu_opcode_t);
+	static bool VPKUWUM(PPUThread&, ppu_opcode_t);
+	static bool VPKUWUS(PPUThread&, ppu_opcode_t);
+	static bool VREFP(PPUThread&, ppu_opcode_t);
+	static bool VRFIM(PPUThread&, ppu_opcode_t);
+	static bool VRFIN(PPUThread&, ppu_opcode_t);
+	static bool VRFIP(PPUThread&, ppu_opcode_t);
+	static bool VRFIZ(PPUThread&, ppu_opcode_t);
+	static bool VRLB(PPUThread&, ppu_opcode_t);
+	static bool VRLH(PPUThread&, ppu_opcode_t);
+	static bool VRLW(PPUThread&, ppu_opcode_t);
+	static bool VRSQRTEFP(PPUThread&, ppu_opcode_t);
+	static bool VSEL(PPUThread&, ppu_opcode_t);
+	static bool VSL(PPUThread&, ppu_opcode_t);
+	static bool VSLB(PPUThread&, ppu_opcode_t);
+	static bool VSLDOI(PPUThread&, ppu_opcode_t);
+	static bool VSLH(PPUThread&, ppu_opcode_t);
+	static bool VSLO(PPUThread&, ppu_opcode_t);
+	static bool VSLW(PPUThread&, ppu_opcode_t);
+	static bool VSPLTB(PPUThread&, ppu_opcode_t);
+	static bool VSPLTH(PPUThread&, ppu_opcode_t);
+	static bool VSPLTISB(PPUThread&, ppu_opcode_t);
+	static bool VSPLTISH(PPUThread&, ppu_opcode_t);
+	static bool VSPLTISW(PPUThread&, ppu_opcode_t);
+	static bool VSPLTW(PPUThread&, ppu_opcode_t);
+	static bool VSR(PPUThread&, ppu_opcode_t);
+	static bool VSRAB(PPUThread&, ppu_opcode_t);
+	static bool VSRAH(PPUThread&, ppu_opcode_t);
+	static bool VSRAW(PPUThread&, ppu_opcode_t);
+	static bool VSRB(PPUThread&, ppu_opcode_t);
+	static bool VSRH(PPUThread&, ppu_opcode_t);
+	static bool VSRO(PPUThread&, ppu_opcode_t);
+	static bool VSRW(PPUThread&, ppu_opcode_t);
+	static bool VSUBCUW(PPUThread&, ppu_opcode_t);
+	static bool VSUBFP(PPUThread&, ppu_opcode_t);
+	static bool VSUBSBS(PPUThread&, ppu_opcode_t);
+	static bool VSUBSHS(PPUThread&, ppu_opcode_t);
+	static bool VSUBSWS(PPUThread&, ppu_opcode_t);
+	static bool VSUBUBM(PPUThread&, ppu_opcode_t);
+	static bool VSUBUBS(PPUThread&, ppu_opcode_t);
+	static bool VSUBUHM(PPUThread&, ppu_opcode_t);
+	static bool VSUBUHS(PPUThread&, ppu_opcode_t);
+	static bool VSUBUWM(PPUThread&, ppu_opcode_t);
+	static bool VSUBUWS(PPUThread&, ppu_opcode_t);
+	static bool VSUMSWS(PPUThread&, ppu_opcode_t);
+	static bool VSUM2SWS(PPUThread&, ppu_opcode_t);
+	static bool VSUM4SBS(PPUThread&, ppu_opcode_t);
+	static bool VSUM4SHS(PPUThread&, ppu_opcode_t);
+	static bool VSUM4UBS(PPUThread&, ppu_opcode_t);
+	static bool VUPKHPX(PPUThread&, ppu_opcode_t);
+	static bool VUPKHSB(PPUThread&, ppu_opcode_t);
+	static bool VUPKHSH(PPUThread&, ppu_opcode_t);
+	static bool VUPKLPX(PPUThread&, ppu_opcode_t);
+	static bool VUPKLSB(PPUThread&, ppu_opcode_t);
+	static bool VUPKLSH(PPUThread&, ppu_opcode_t);
+	static bool VXOR(PPUThread&, ppu_opcode_t);
+	static bool TDI(PPUThread&, ppu_opcode_t);
+	static bool TWI(PPUThread&, ppu_opcode_t);
+	static bool MULLI(PPUThread&, ppu_opcode_t);
+	static bool SUBFIC(PPUThread&, ppu_opcode_t);
+	static bool CMPLI(PPUThread&, ppu_opcode_t);
+	static bool CMPI(PPUThread&, ppu_opcode_t);
+	static bool ADDIC(PPUThread&, ppu_opcode_t);
+	static bool ADDI(PPUThread&, ppu_opcode_t);
+	static bool ADDIS(PPUThread&, ppu_opcode_t);
+	static bool BC(PPUThread&, ppu_opcode_t);
+	static bool HACK(PPUThread&, ppu_opcode_t);
+	static bool SC(PPUThread&, ppu_opcode_t);
+	static bool B(PPUThread&, ppu_opcode_t);
+	static bool MCRF(PPUThread&, ppu_opcode_t);
+	static bool BCLR(PPUThread&, ppu_opcode_t);
+	static bool CRNOR(PPUThread&, ppu_opcode_t);
+	static bool CRANDC(PPUThread&, ppu_opcode_t);
+	static bool ISYNC(PPUThread&, ppu_opcode_t);
+	static bool CRXOR(PPUThread&, ppu_opcode_t);
+	static bool CRNAND(PPUThread&, ppu_opcode_t);
+	static bool CRAND(PPUThread&, ppu_opcode_t);
+	static bool CREQV(PPUThread&, ppu_opcode_t);
+	static bool CRORC(PPUThread&, ppu_opcode_t);
+	static bool CROR(PPUThread&, ppu_opcode_t);
+	static bool BCCTR(PPUThread&, ppu_opcode_t);
+	static bool RLWIMI(PPUThread&, ppu_opcode_t);
+	static bool RLWINM(PPUThread&, ppu_opcode_t);
+	static bool RLWNM(PPUThread&, ppu_opcode_t);
+	static bool ORI(PPUThread&, ppu_opcode_t);
+	static bool ORIS(PPUThread&, ppu_opcode_t);
+	static bool XORI(PPUThread&, ppu_opcode_t);
+	static bool XORIS(PPUThread&, ppu_opcode_t);
+	static bool ANDI(PPUThread&, ppu_opcode_t);
+	static bool ANDIS(PPUThread&, ppu_opcode_t);
+	static bool RLDICL(PPUThread&, ppu_opcode_t);
+	static bool RLDICR(PPUThread&, ppu_opcode_t);
+	static bool RLDIC(PPUThread&, ppu_opcode_t);
+	static bool RLDIMI(PPUThread&, ppu_opcode_t);
+	static bool RLDCL(PPUThread&, ppu_opcode_t);
+	static bool RLDCR(PPUThread&, ppu_opcode_t);
+	static bool CMP(PPUThread&, ppu_opcode_t);
+	static bool TW(PPUThread&, ppu_opcode_t);
+	static bool LVSL(PPUThread&, ppu_opcode_t);
+	static bool LVEBX(PPUThread&, ppu_opcode_t);
+	static bool SUBFC(PPUThread&, ppu_opcode_t);
+	static bool MULHDU(PPUThread&, ppu_opcode_t);
+	static bool ADDC(PPUThread&, ppu_opcode_t);
+	static bool MULHWU(PPUThread&, ppu_opcode_t);
+	static bool MFOCRF(PPUThread&, ppu_opcode_t);
+	static bool LWARX(PPUThread&, ppu_opcode_t);
+	static bool LDX(PPUThread&, ppu_opcode_t);
+	static bool LWZX(PPUThread&, ppu_opcode_t);
+	static bool SLW(PPUThread&, ppu_opcode_t);
+	static bool CNTLZW(PPUThread&, ppu_opcode_t);
+	static bool SLD(PPUThread&, ppu_opcode_t);
+	static bool AND(PPUThread&, ppu_opcode_t);
+	static bool CMPL(PPUThread&, ppu_opcode_t);
+	static bool LVSR(PPUThread&, ppu_opcode_t);
+	static bool LVEHX(PPUThread&, ppu_opcode_t);
+	static bool SUBF(PPUThread&, ppu_opcode_t);
+	static bool LDUX(PPUThread&, ppu_opcode_t);
+	static bool DCBST(PPUThread&, ppu_opcode_t);
+	static bool LWZUX(PPUThread&, ppu_opcode_t);
+	static bool CNTLZD(PPUThread&, ppu_opcode_t);
+	static bool ANDC(PPUThread&, ppu_opcode_t);
+	static bool TD(PPUThread&, ppu_opcode_t);
+	static bool LVEWX(PPUThread&, ppu_opcode_t);
+	static bool MULHD(PPUThread&, ppu_opcode_t);
+	static bool MULHW(PPUThread&, ppu_opcode_t);
+	static bool LDARX(PPUThread&, ppu_opcode_t);
+	static bool DCBF(PPUThread&, ppu_opcode_t);
+	static bool LBZX(PPUThread&, ppu_opcode_t);
+	static bool LVX(PPUThread&, ppu_opcode_t);
+	static bool NEG(PPUThread&, ppu_opcode_t);
+	static bool LBZUX(PPUThread&, ppu_opcode_t);
+	static bool NOR(PPUThread&, ppu_opcode_t);
+	static bool STVEBX(PPUThread&, ppu_opcode_t);
+	static bool SUBFE(PPUThread&, ppu_opcode_t);
+	static bool ADDE(PPUThread&, ppu_opcode_t);
+	static bool MTOCRF(PPUThread&, ppu_opcode_t);
+	static bool STDX(PPUThread&, ppu_opcode_t);
+	static bool STWCX(PPUThread&, ppu_opcode_t);
+	static bool STWX(PPUThread&, ppu_opcode_t);
+	static bool STVEHX(PPUThread&, ppu_opcode_t);
+	static bool STDUX(PPUThread&, ppu_opcode_t);
+	static bool STWUX(PPUThread&, ppu_opcode_t);
+	static bool STVEWX(PPUThread&, ppu_opcode_t);
+	static bool SUBFZE(PPUThread&, ppu_opcode_t);
+	static bool ADDZE(PPUThread&, ppu_opcode_t);
+	static bool STDCX(PPUThread&, ppu_opcode_t);
+	static bool STBX(PPUThread&, ppu_opcode_t);
+	static bool STVX(PPUThread&, ppu_opcode_t);
+	static bool MULLD(PPUThread&, ppu_opcode_t);
+	static bool SUBFME(PPUThread&, ppu_opcode_t);
+	static bool ADDME(PPUThread&, ppu_opcode_t);
+	static bool MULLW(PPUThread&, ppu_opcode_t);
+	static bool DCBTST(PPUThread&, ppu_opcode_t);
+	static bool STBUX(PPUThread&, ppu_opcode_t);
+	static bool ADD(PPUThread&, ppu_opcode_t);
+	static bool DCBT(PPUThread&, ppu_opcode_t);
+	static bool LHZX(PPUThread&, ppu_opcode_t);
+	static bool EQV(PPUThread&, ppu_opcode_t);
+	static bool ECIWX(PPUThread&, ppu_opcode_t);
+	static bool LHZUX(PPUThread&, ppu_opcode_t);
+	static bool XOR(PPUThread&, ppu_opcode_t);
+	static bool MFSPR(PPUThread&, ppu_opcode_t);
+	static bool LWAX(PPUThread&, ppu_opcode_t);
+	static bool DST(PPUThread&, ppu_opcode_t);
+	static bool LHAX(PPUThread&, ppu_opcode_t);
+	static bool LVXL(PPUThread&, ppu_opcode_t);
+	static bool MFTB(PPUThread&, ppu_opcode_t);
+	static bool LWAUX(PPUThread&, ppu_opcode_t);
+	static bool DSTST(PPUThread&, ppu_opcode_t);
+	static bool LHAUX(PPUThread&, ppu_opcode_t);
+	static bool STHX(PPUThread&, ppu_opcode_t);
+	static bool ORC(PPUThread&, ppu_opcode_t);
+	static bool ECOWX(PPUThread&, ppu_opcode_t);
+	static bool STHUX(PPUThread&, ppu_opcode_t);
+	static bool OR(PPUThread&, ppu_opcode_t);
+	static bool DIVDU(PPUThread&, ppu_opcode_t);
+	static bool DIVWU(PPUThread&, ppu_opcode_t);
+	static bool MTSPR(PPUThread&, ppu_opcode_t);
+	static bool DCBI(PPUThread&, ppu_opcode_t);
+	static bool NAND(PPUThread&, ppu_opcode_t);
+	static bool STVXL(PPUThread&, ppu_opcode_t);
+	static bool DIVD(PPUThread&, ppu_opcode_t);
+	static bool DIVW(PPUThread&, ppu_opcode_t);
+	static bool LVLX(PPUThread&, ppu_opcode_t);
+	static bool LDBRX(PPUThread&, ppu_opcode_t);
+	static bool LSWX(PPUThread&, ppu_opcode_t);
+	static bool LWBRX(PPUThread&, ppu_opcode_t);
+	static bool LFSX(PPUThread&, ppu_opcode_t);
+	static bool SRW(PPUThread&, ppu_opcode_t);
+	static bool SRD(PPUThread&, ppu_opcode_t);
+	static bool LVRX(PPUThread&, ppu_opcode_t);
+	static bool LSWI(PPUThread&, ppu_opcode_t);
+	static bool LFSUX(PPUThread&, ppu_opcode_t);
+	static bool SYNC(PPUThread&, ppu_opcode_t);
+	static bool LFDX(PPUThread&, ppu_opcode_t);
+	static bool LFDUX(PPUThread&, ppu_opcode_t);
+	static bool STVLX(PPUThread&, ppu_opcode_t);
+	static bool STDBRX(PPUThread&, ppu_opcode_t);
+	static bool STSWX(PPUThread&, ppu_opcode_t);
+	static bool STWBRX(PPUThread&, ppu_opcode_t);
+	static bool STFSX(PPUThread&, ppu_opcode_t);
+	static bool STVRX(PPUThread&, ppu_opcode_t);
+	static bool STFSUX(PPUThread&, ppu_opcode_t);
+	static bool STSWI(PPUThread&, ppu_opcode_t);
+	static bool STFDX(PPUThread&, ppu_opcode_t);
+	static bool STFDUX(PPUThread&, ppu_opcode_t);
+	static bool LVLXL(PPUThread&, ppu_opcode_t);
+	static bool LHBRX(PPUThread&, ppu_opcode_t);
+	static bool SRAW(PPUThread&, ppu_opcode_t);
+	static bool SRAD(PPUThread&, ppu_opcode_t);
+	static bool LVRXL(PPUThread&, ppu_opcode_t);
+	static bool DSS(PPUThread&, ppu_opcode_t);
+	static bool SRAWI(PPUThread&, ppu_opcode_t);
+	static bool SRADI(PPUThread&, ppu_opcode_t);
+	static bool EIEIO(PPUThread&, ppu_opcode_t);
+	static bool STVLXL(PPUThread&, ppu_opcode_t);
+	static bool STHBRX(PPUThread&, ppu_opcode_t);
+	static bool EXTSH(PPUThread&, ppu_opcode_t);
+	static bool STVRXL(PPUThread&, ppu_opcode_t);
+	static bool EXTSB(PPUThread&, ppu_opcode_t);
+	static bool STFIWX(PPUThread&, ppu_opcode_t);
+	static bool EXTSW(PPUThread&, ppu_opcode_t);
+	static bool ICBI(PPUThread&, ppu_opcode_t);
+	static bool DCBZ(PPUThread&, ppu_opcode_t);
+	static bool LWZ(PPUThread&, ppu_opcode_t);
+	static bool LWZU(PPUThread&, ppu_opcode_t);
+	static bool LBZ(PPUThread&, ppu_opcode_t);
+	static bool LBZU(PPUThread&, ppu_opcode_t);
+	static bool STW(PPUThread&, ppu_opcode_t);
+	static bool STWU(PPUThread&, ppu_opcode_t);
+	static bool STB(PPUThread&, ppu_opcode_t);
+	static bool STBU(PPUThread&, ppu_opcode_t);
+	static bool LHZ(PPUThread&, ppu_opcode_t);
+	static bool LHZU(PPUThread&, ppu_opcode_t);
+	static bool LHA(PPUThread&, ppu_opcode_t);
+	static bool LHAU(PPUThread&, ppu_opcode_t);
+	static bool STH(PPUThread&, ppu_opcode_t);
+	static bool STHU(PPUThread&, ppu_opcode_t);
+	static bool LMW(PPUThread&, ppu_opcode_t);
+	static bool STMW(PPUThread&, ppu_opcode_t);
+	static bool LFS(PPUThread&, ppu_opcode_t);
+	static bool LFSU(PPUThread&, ppu_opcode_t);
+	static bool LFD(PPUThread&, ppu_opcode_t);
+	static bool LFDU(PPUThread&, ppu_opcode_t);
+	static bool STFS(PPUThread&, ppu_opcode_t);
+	static bool STFSU(PPUThread&, ppu_opcode_t);
+	static bool STFD(PPUThread&, ppu_opcode_t);
+	static bool STFDU(PPUThread&, ppu_opcode_t);
+	static bool LD(PPUThread&, ppu_opcode_t);
+	static bool LDU(PPUThread&, ppu_opcode_t);
+	static bool LWA(PPUThread&, ppu_opcode_t);
+	static bool STD(PPUThread&, ppu_opcode_t);
+	static bool STDU(PPUThread&, ppu_opcode_t);
+	static bool FDIVS(PPUThread&, ppu_opcode_t);
+	static bool FSUBS(PPUThread&, ppu_opcode_t);
+	static bool FADDS(PPUThread&, ppu_opcode_t);
+	static bool FSQRTS(PPUThread&, ppu_opcode_t);
+	static bool FRES(PPUThread&, ppu_opcode_t);
+	static bool FMULS(PPUThread&, ppu_opcode_t);
+	static bool FMADDS(PPUThread&, ppu_opcode_t);
+	static bool FMSUBS(PPUThread&, ppu_opcode_t);
+	static bool FNMSUBS(PPUThread&, ppu_opcode_t);
+	static bool FNMADDS(PPUThread&, ppu_opcode_t);
+	static bool MTFSB1(PPUThread&, ppu_opcode_t);
+	static bool MCRFS(PPUThread&, ppu_opcode_t);
+	static bool MTFSB0(PPUThread&, ppu_opcode_t);
+	static bool MTFSFI(PPUThread&, ppu_opcode_t);
+	static bool MFFS(PPUThread&, ppu_opcode_t);
+	static bool MTFSF(PPUThread&, ppu_opcode_t);
+	static bool FCMPU(PPUThread&, ppu_opcode_t);
+	static bool FRSP(PPUThread&, ppu_opcode_t);
+	static bool FCTIW(PPUThread&, ppu_opcode_t);
+	static bool FCTIWZ(PPUThread&, ppu_opcode_t);
+	static bool FDIV(PPUThread&, ppu_opcode_t);
+	static bool FSUB(PPUThread&, ppu_opcode_t);
+	static bool FADD(PPUThread&, ppu_opcode_t);
+	static bool FSQRT(PPUThread&, ppu_opcode_t);
+	static bool FSEL(PPUThread&, ppu_opcode_t);
+	static bool FMUL(PPUThread&, ppu_opcode_t);
+	static bool FRSQRTE(PPUThread&, ppu_opcode_t);
+	static bool FMSUB(PPUThread&, ppu_opcode_t);
+	static bool FMADD(PPUThread&, ppu_opcode_t);
+	static bool FNMSUB(PPUThread&, ppu_opcode_t);
+	static bool FNMADD(PPUThread&, ppu_opcode_t);
+	static bool FCMPO(PPUThread&, ppu_opcode_t);
+	static bool FNEG(PPUThread&, ppu_opcode_t);
+	static bool FMR(PPUThread&, ppu_opcode_t);
+	static bool FNABS(PPUThread&, ppu_opcode_t);
+	static bool FABS(PPUThread&, ppu_opcode_t);
+	static bool FCTID(PPUThread&, ppu_opcode_t);
+	static bool FCTIDZ(PPUThread&, ppu_opcode_t);
+	static bool FCFID(PPUThread&, ppu_opcode_t);
 
-	static void UNK(PPUThread&, ppu_opcode_t);
+	static bool UNK(PPUThread&, ppu_opcode_t);
 };
 
 struct ppu_interpreter_precise final : ppu_interpreter
diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp
index 56de5d7234..8bb313482a 100644
--- a/rpcs3/Emu/Cell/PPUModule.cpp
+++ b/rpcs3/Emu/Cell/PPUModule.cpp
@@ -1,4 +1,5 @@
 #include "stdafx.h"
+#include "Utilities/Config.h"
 #include "Utilities/AutoPause.h"
 #include "Crypto/sha1.h"
 #include "Loader/ELF.h"
@@ -10,6 +11,99 @@
 
 #include "Emu/Cell/lv2/sys_prx.h"
 
+#include <unordered_set>
+
+LOG_CHANNEL(cellAdec);
+LOG_CHANNEL(cellAtrac);
+LOG_CHANNEL(cellAtracMulti);
+LOG_CHANNEL(cellAudio);
+LOG_CHANNEL(cellAvconfExt);
+LOG_CHANNEL(cellBGDL);
+LOG_CHANNEL(cellCamera);
+LOG_CHANNEL(cellCelp8Enc);
+LOG_CHANNEL(cellCelpEnc);
+LOG_CHANNEL(cellDaisy);
+LOG_CHANNEL(cellDmux);
+LOG_CHANNEL(cellFiber);
+LOG_CHANNEL(cellFont);
+LOG_CHANNEL(cellFontFT);
+LOG_CHANNEL(cellFs);
+LOG_CHANNEL(cellGame);
+LOG_CHANNEL(cellGameExec);
+LOG_CHANNEL(cellGcmSys);
+LOG_CHANNEL(cellGem);
+LOG_CHANNEL(cellGifDec);
+LOG_CHANNEL(cellHttp);
+LOG_CHANNEL(cellHttpUtil);
+LOG_CHANNEL(cellImeJp);
+LOG_CHANNEL(cellJpgDec);
+LOG_CHANNEL(cellJpgEnc);
+LOG_CHANNEL(cellKey2char);
+LOG_CHANNEL(cellL10n);
+LOG_CHANNEL(cellMic);
+LOG_CHANNEL(cellMusic);
+LOG_CHANNEL(cellMusicDecode);
+LOG_CHANNEL(cellMusicExport);
+LOG_CHANNEL(cellNetCtl);
+LOG_CHANNEL(cellOskDialog);
+LOG_CHANNEL(cellOvis);
+LOG_CHANNEL(cellPamf);
+LOG_CHANNEL(cellPhotoDecode);
+LOG_CHANNEL(cellPhotoExport);
+LOG_CHANNEL(cellPhotoImportUtil);
+LOG_CHANNEL(cellPngDec);
+LOG_CHANNEL(cellPngEnc);
+LOG_CHANNEL(cellPrint);
+LOG_CHANNEL(cellRec);
+LOG_CHANNEL(cellRemotePlay);
+LOG_CHANNEL(cellResc);
+LOG_CHANNEL(cellRtc);
+LOG_CHANNEL(cellRudp);
+LOG_CHANNEL(cellSail);
+LOG_CHANNEL(cellSailRec);
+LOG_CHANNEL(cellSaveData);
+LOG_CHANNEL(cellScreenshot);
+LOG_CHANNEL(cellSearch);
+LOG_CHANNEL(cellSheap);
+LOG_CHANNEL(cellSpudll);
+LOG_CHANNEL(cellSpurs);
+LOG_CHANNEL(cellSpursJq);
+LOG_CHANNEL(cellSsl);
+LOG_CHANNEL(cellSubdisplay);
+LOG_CHANNEL(cellSync);
+LOG_CHANNEL(cellSync2);
+LOG_CHANNEL(cellSysconf);
+LOG_CHANNEL(cellSysmodule);
+LOG_CHANNEL(cellSysutil);
+LOG_CHANNEL(cellSysutilAp);
+LOG_CHANNEL(cellSysutilAvc);
+LOG_CHANNEL(cellSysutilAvc2);
+LOG_CHANNEL(cellSysutilMisc);
+LOG_CHANNEL(cellUsbd);
+LOG_CHANNEL(cellUsbPspcm);
+LOG_CHANNEL(cellUserInfo);
+LOG_CHANNEL(cellVdec);
+LOG_CHANNEL(cellVideoExport);
+LOG_CHANNEL(cellVideoUpload);
+LOG_CHANNEL(cellVoice);
+LOG_CHANNEL(cellVpost);
+LOG_CHANNEL(libmixer);
+LOG_CHANNEL(libsnd3);
+LOG_CHANNEL(libsynth2);
+LOG_CHANNEL(sceNp);
+LOG_CHANNEL(sceNp2);
+LOG_CHANNEL(sceNpClans);
+LOG_CHANNEL(sceNpCommerce2);
+LOG_CHANNEL(sceNpSns);
+LOG_CHANNEL(sceNpTrophy);
+LOG_CHANNEL(sceNpTus);
+LOG_CHANNEL(sceNpUtil);
+LOG_CHANNEL(sys_io);
+LOG_CHANNEL(sys_libc);
+LOG_CHANNEL(sys_lv2dbg);
+LOG_CHANNEL(libnet);
+LOG_CHANNEL(sysPrxForUser);
+
 cfg::bool_entry g_cfg_hook_ppu_funcs(cfg::root.core, "Hook static functions");
 cfg::bool_entry g_cfg_load_liblv2(cfg::root.core, "Load liblv2.sprx only");
 
@@ -41,12 +135,18 @@ extern void ppu_execute_function(PPUThread& ppu, u32 index)
 			{
 				func(ppu);
 			}
-			catch (...)
+			catch (EmulationStopped)
 			{
 				LOG_WARNING(PPU, "Function '%s' aborted", ppu.last_function);
 				ppu.last_function = previous_function;
 				throw;
 			}
+			catch (...)
+			{
+				LOG_ERROR(PPU, "Function '%s' aborted", ppu.last_function);
+				ppu.last_function = previous_function;
+				throw;
+			}
 
 			LOG_TRACE(PPU, "Function '%s' finished, r3=0x%llx", ppu.last_function, ppu.GPR[3]);
 			ppu.last_function = previous_function;
@@ -917,7 +1017,7 @@ void ppu_exec_loader::load() const
 		}
 		else
 		{
-			throw fmt::exception("Failed to load liblv2.sprx: %s", bijective_find<elf_error>(loader, "???"));
+			throw fmt::exception("Failed to load liblv2.sprx: %s", loader.get_error());
 		}
 	}
 	else
@@ -939,7 +1039,7 @@ void ppu_exec_loader::load() const
 			}
 			else
 			{
-				LOG_FATAL(LOADER, "Failed to load %s: %s", name, bijective_find<elf_error>(loader, "???"));
+				LOG_FATAL(LOADER, "Failed to load %s: %s", name, loader.get_error());
 			}
 		}
 	}
@@ -1130,7 +1230,7 @@ void ppu_exec_loader::load() const
 
 	auto ppu = idm::make_ptr<PPUThread>("main_thread");
 
-	ppu->PC = entry.addr() & -0x1000;
+	ppu->pc = entry.addr() & -0x1000;
 	ppu->stack_size = Emu.GetPrimaryStackSize();
 	ppu->prio = Emu.GetPrimaryPrio();
 	ppu->cpu_init();
@@ -1166,6 +1266,8 @@ void ppu_exec_loader::load() const
 	ppu->GPR[9] = Emu.GetTLSFilesz();
 	ppu->GPR[10] = Emu.GetTLSMemsz();
 
+	//ppu->state += cpu_state::interrupt;
+
 	// Set memory protections
 	//for (const auto& prog : progs)
 	//{
@@ -1175,7 +1277,7 @@ void ppu_exec_loader::load() const
 	//	if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz && (prog.p_flags & 0x2) == 0 /* W */)
 	//	{
 	//		// Set memory protection to read-only where necessary
-	//		ASSERT(vm::page_protect(addr, ::align(size, 0x1000), 0, 0, vm::page_writable));
+	//		VERIFY(vm::page_protect(addr, ::align(size, 0x1000), 0, 0, vm::page_writable));
 	//	}
 	//}
 }
diff --git a/rpcs3/Emu/Cell/PPUModule.h b/rpcs3/Emu/Cell/PPUModule.h
index 5b1438968f..957f8b6a38 100644
--- a/rpcs3/Emu/Cell/PPUModule.h
+++ b/rpcs3/Emu/Cell/PPUModule.h
@@ -1,6 +1,5 @@
 #pragma once
 
-#include "Utilities/Config.h"
 #include "PPUFunction.h"
 #include "PPUCallback.h"
 #include "ErrorCodes.h"
@@ -207,15 +206,9 @@ inline RT ppu_execute_function_or_callback(const char* name, PPUThread& ppu, Arg
 	{
 		return Func(std::forward<Args>(args)...);
 	}
-	catch (const std::exception&)
-	{
-		LOG_ERROR(PPU, "Function '%s' aborted", ppu.last_function);
-		ppu.last_function = previous_function;
-		throw;
-	}
 	catch (...)
 	{
-		LOG_WARNING(PPU, "Function '%s' aborted", ppu.last_function);
+		LOG_ERROR(PPU, "Function call '%s' aborted", ppu.last_function);
 		ppu.last_function = previous_function;
 		throw;
 	}
diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp
index c3ddecefce..4f7b33ba06 100644
--- a/rpcs3/Emu/Cell/PPUThread.cpp
+++ b/rpcs3/Emu/Cell/PPUThread.cpp
@@ -1,4 +1,5 @@
 #include "stdafx.h"
+#include "Utilities/Config.h"
 #include "Emu/Memory/Memory.h"
 #include "Emu/System.h"
 #include "Emu/IdManager.h"
@@ -93,7 +94,7 @@ void PPUThread::cpu_task()
 	{
 		const auto cpu = static_cast<PPUThread*>(get_current_cpu_thread());
 
-		return fmt::format("%s [0x%08x]", cpu->get_name(), cpu->PC);
+		return fmt::format("%s [0x%08x]", cpu->get_name(), cpu->pc);
 	};
 
 	const auto base = vm::_ptr<const u8>(0);
@@ -104,45 +105,135 @@ void PPUThread::cpu_task()
 		g_cfg_ppu_decoder.get() == ppu_decoder_type::fast ? &s_ppu_interpreter_fast.get_table() :
 		throw std::logic_error("Invalid PPU decoder"));
 
-	u32 _pc{};
-	u32 op0, op1, op2;
-	ppu_inter_func_t func0, func1, func2;
+	v128 _op;
+	decltype(&ppu_interpreter::UNK) func0, func1, func2, func3;
 
 	while (true)
 	{
-		if (LIKELY(_pc == PC && !state.load()))
+		if (UNLIKELY(state.load()))
 		{
-			func0(*this, { op0 });
-
-			if (LIKELY((_pc += 4) == (PC += 4) && !state.load()))
-			{
-				func1(*this, { op1 });
-
-				if (LIKELY((_pc += 4) == (PC += 4)))
-				{
-					op0 = op2;
-					func0 = func2;
-					const auto ops = reinterpret_cast<const be_t<u32>*>(base + _pc);
-					func1 = table[ppu_decode(op1 = ops[1])];
-					func2 = table[ppu_decode(op2 = ops[2])];
-					continue;
-				}
-			}
+			if (check_status()) return;
 		}
 
 		// Reinitialize
-		_pc = PC;
-		const auto ops = reinterpret_cast<const be_t<u32>*>(base + _pc);
-		func0 = table[ppu_decode(op0 = ops[0])];
-		func1 = table[ppu_decode(op1 = ops[1])];
-		func2 = table[ppu_decode(op2 = ops[2])];
+		{
+			const auto _ops = _mm_shuffle_epi8(_mm_lddqu_si128(reinterpret_cast<const __m128i*>(base + pc)), _mm_set_epi8(12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3));
+			_op.vi = _ops;
+			const v128 _i = v128::fromV(_mm_and_si128(_mm_or_si128(_mm_slli_epi32(_op.vi, 6), _mm_srli_epi32(_op.vi, 26)), _mm_set1_epi32(0x1ffff)));
+			func0 = table[_i._u32[0]];
+			func1 = table[_i._u32[1]];
+			func2 = table[_i._u32[2]];
+			func3 = table[_i._u32[3]];
+		}
 
-		if (UNLIKELY(check_status())) return;
+		while (LIKELY(func0(*this, { _op._u32[0] })))
+		{
+			if (pc += 4, LIKELY(func1(*this, { _op._u32[1] })))
+			{
+				if (pc += 4, LIKELY(func2(*this, { _op._u32[2] })))
+				{
+					pc += 4;
+					func0 = func3;
+
+					const auto _ops = _mm_shuffle_epi8(_mm_lddqu_si128(reinterpret_cast<const __m128i*>(base + pc + 4)), _mm_set_epi8(12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3));
+					_op.vi = _mm_alignr_epi8(_ops, _op.vi, 12);
+					const v128 _i = v128::fromV(_mm_and_si128(_mm_or_si128(_mm_slli_epi32(_op.vi, 6), _mm_srli_epi32(_op.vi, 26)), _mm_set1_epi32(0x1ffff)));
+					func1 = table[_i._u32[1]];
+					func2 = table[_i._u32[2]];
+					func3 = table[_i._u32[3]];
+
+					if (UNLIKELY(state.load()))
+					{
+						break;
+					}
+					continue;
+				}
+				break;
+			}
+			break;
+		}
 	}
 }
 
+constexpr auto stop_state = make_bitset(cpu_state::stop, cpu_state::exit, cpu_state::suspend);
+
+atomic_t<u32> g_ppu_core[2]{};
+
 bool PPUThread::handle_interrupt()
 {
+	// Reschedule and wake up a new thread, possibly this one as well.
+	return false;
+
+	// Check virtual core allocation
+	if (g_ppu_core[0] != id && g_ppu_core[1] != id)
+	{
+		auto cpu0 = idm::get<PPUThread>(g_ppu_core[0]);
+		auto cpu1 = idm::get<PPUThread>(g_ppu_core[1]);
+
+		if (cpu0 && cpu1)
+		{
+			if (cpu1->prio > cpu0->prio)
+			{
+				cpu0 = std::move(cpu1);
+			}
+
+			// Preempt thread with the lowest priority
+			if (prio < cpu0->prio)
+			{
+				cpu0->state += cpu_state::interrupt;
+			}
+		}
+		else
+		{
+			// Try to obtain a virtual core in optimistic way
+			if (g_ppu_core[0].compare_and_swap_test(0, id) || g_ppu_core[1].compare_and_swap_test(0, id))
+			{
+				state -= cpu_state::interrupt;
+				return true;
+			}
+		}
+
+		return false;
+	}
+
+	// Select appropriate thread
+	u32 top_prio = -1;
+	u32 selected = -1;
+
+	idm::select<PPUThread>([&](u32 id, PPUThread& ppu)
+	{
+		// Exclude suspended and low-priority threads
+		if (!ppu.state.test(stop_state) && ppu.prio < top_prio /*&& (!ppu.is_sleep() || ppu.state & cpu_state::signal)*/)
+		{
+			top_prio = ppu.prio;
+			selected = id;
+		}
+	});
+
+	// If current thread selected
+	if (selected == id)
+	{
+		state -= cpu_state::interrupt;
+		VERIFY(g_ppu_core[0] == id || g_ppu_core[1] == id);
+		return true;
+	}
+
+	// If another thread selected
+	const auto thread = idm::get<PPUThread>(selected);
+
+	// Lend virtual core to another thread
+	if (thread && thread->state.test_and_reset(cpu_state::interrupt))
+	{
+		g_ppu_core[0].compare_and_swap(id, thread->id);
+		g_ppu_core[1].compare_and_swap(id, thread->id);
+		(*thread)->lock_notify();
+	}
+	else
+	{
+		g_ppu_core[0].compare_and_swap(id, 0);
+		g_ppu_core[1].compare_and_swap(id, 0);
+	}
+
 	return false;
 }
 
@@ -167,13 +258,13 @@ be_t<u64>* PPUThread::get_stack_arg(s32 i, u64 align)
 
 void PPUThread::fast_call(u32 addr, u32 rtoc)
 {
-	auto old_PC = PC;
+	auto old_PC = pc;
 	auto old_stack = GPR[1];
 	auto old_rtoc = GPR[2];
 	auto old_LR = LR;
 	auto old_task = std::move(custom_task);
 
-	PC = addr;
+	pc = addr;
 	GPR[2] = rtoc;
 	LR = Emu.GetCPUThreadStop();
 	custom_task = nullptr;
@@ -190,7 +281,7 @@ void PPUThread::fast_call(u32 addr, u32 rtoc)
 
 	state -= cpu_state::ret;
 
-	PC = old_PC;
+	pc = old_PC;
 
 	if (GPR[1] != old_stack) // GPR[1] shouldn't change
 	{
@@ -200,4 +291,10 @@ void PPUThread::fast_call(u32 addr, u32 rtoc)
 	GPR[2] = old_rtoc;
 	LR = old_LR;
 	custom_task = std::move(old_task);
+
+	//if (custom_task)
+	//{
+	//	state += cpu_state::interrupt;
+	//	handle_interrupt();
+	//}
 }
diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h
index 8507f54c44..8307245196 100644
--- a/rpcs3/Emu/Cell/PPUThread.h
+++ b/rpcs3/Emu/Cell/PPUThread.h
@@ -66,9 +66,9 @@ public:
 	u64 LR{}; // Link Register
 	u64 CTR{}; // Counter Register
 	u32 VRSAVE{};
-	u32 PC{};
 
-	s32 prio = 0; // Thread priority
+	u32 pc = 0;
+	u32 prio = -1; // Thread priority
 	u32 stack_addr = 0; // Stack address
 	u32 stack_size = 0; // Stack size
 	bool is_joinable = true;
@@ -191,7 +191,7 @@ struct ppu_gpr_cast_impl<vm::_ptr_base<T, AT>, void>
 
 	static inline vm::_ptr_base<T, AT> from(const u64 reg)
 	{
-		return{ ppu_gpr_cast_impl<AT>::from(reg), vm::addr };
+		return vm::cast(ppu_gpr_cast_impl<AT>::from(reg));
 	}
 };
 
@@ -205,7 +205,7 @@ struct ppu_gpr_cast_impl<vm::_ref_base<T, AT>, void>
 
 	static inline vm::_ref_base<T, AT> from(const u64 reg)
 	{
-		return{ ppu_gpr_cast_impl<AT>::from(reg), vm::addr };
+		return vm::cast(ppu_gpr_cast_impl<AT>::from(reg));
 	}
 };
 
diff --git a/rpcs3/Emu/Cell/RawSPUThread.cpp b/rpcs3/Emu/Cell/RawSPUThread.cpp
index 60033cfa2f..808c0a2900 100644
--- a/rpcs3/Emu/Cell/RawSPUThread.cpp
+++ b/rpcs3/Emu/Cell/RawSPUThread.cpp
@@ -31,7 +31,7 @@ void RawSPUThread::on_init()
 		// Install correct SPU index and LS address
 		const_cast<u32&>(index) = id;
 		const_cast<u32&>(offset) = vm::falloc(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index, 0x40000);
-		ASSERT(offset);
+		VERIFY(offset);
 
 		SPUThread::on_init();
 	}
@@ -101,7 +101,7 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value)
 		}))
 		{
 			state -= cpu_state::stop;
-			lock_notify();
+			(*this)->lock_notify();
 		}
 	};
 
diff --git a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp
index 8ac7256513..35dec7108a 100644
--- a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp
+++ b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp
@@ -7,6 +7,8 @@
 #include "SPUInterpreter.h"
 #include "SPUASMJITRecompiler.h"
 
+#include <cmath>
+
 #define ASMJIT_STATIC
 #define ASMJIT_DEBUG
 
@@ -1962,8 +1964,8 @@ void spu_recompiler::CFLTS(spu_opcode_t op)
 {
 	const XmmLink& va = XmmGet(op.ra, XmmType::Float);
 	const XmmLink& vi = XmmAlloc();
-	if (op.i8 != 173) c->mulps(va, XmmConst(_mm_set1_ps(exp2f(static_cast<s16>(173 - op.i8))))); // scale
-	c->movaps(vi, XmmConst(_mm_set1_ps(exp2f(31))));
+	if (op.i8 != 173) c->mulps(va, XmmConst(_mm_set1_ps(std::exp2(static_cast<float>(static_cast<s16>(173 - op.i8)))))); // scale
+	c->movaps(vi, XmmConst(_mm_set1_ps(std::exp2(31.f))));
 	c->cmpps(vi, va, 2);
 	c->cvttps2dq(va, va); // convert to ints with truncation
 	c->pxor(va, vi); // fix result saturation (0x80000000 -> 0x7fffffff)
@@ -1976,16 +1978,16 @@ void spu_recompiler::CFLTU(spu_opcode_t op)
 	const XmmLink& vs = XmmAlloc();
 	const XmmLink& vs2 = XmmAlloc();
 	const XmmLink& vs3 = XmmAlloc();
-	if (op.i8 != 173) c->mulps(va, XmmConst(_mm_set1_ps(exp2f(static_cast<s16>(173 - op.i8))))); // scale
+	if (op.i8 != 173) c->mulps(va, XmmConst(_mm_set1_ps(std::exp2(static_cast<float>(static_cast<s16>(173 - op.i8)))))); // scale
 	c->maxps(va, XmmConst(_mm_set1_ps(0.0f))); // saturate
 	c->movaps(vs, va); // copy scaled value
 	c->movaps(vs2, va);
-	c->movaps(vs3, XmmConst(_mm_set1_ps(exp2f(31))));
+	c->movaps(vs3, XmmConst(_mm_set1_ps(std::exp2(31.f))));
 	c->subps(vs2, vs3);
 	c->cmpps(vs3, vs, 2);
 	c->andps(vs2, vs3);
 	c->cvttps2dq(va, va);
-	c->cmpps(vs, XmmConst(_mm_set1_ps(exp2f(32))), 5);
+	c->cmpps(vs, XmmConst(_mm_set1_ps(std::exp2(32.f))), 5);
 	c->cvttps2dq(vs2, vs2);
 	c->por(va, vs);
 	c->por(va, vs2);
@@ -1996,7 +1998,7 @@ void spu_recompiler::CSFLT(spu_opcode_t op)
 {
 	const XmmLink& va = XmmGet(op.ra, XmmType::Int);
 	c->cvtdq2ps(va, va); // convert to floats
-	if (op.i8 != 155) c->mulps(va, XmmConst(_mm_set1_ps(exp2f(static_cast<s16>(op.i8 - 155))))); // scale
+	if (op.i8 != 155) c->mulps(va, XmmConst(_mm_set1_ps(std::exp2(static_cast<float>(static_cast<s16>(op.i8 - 155)))))); // scale
 	c->movaps(SPU_OFF_128(gpr[op.rt]), va);
 }
 
@@ -2008,9 +2010,9 @@ void spu_recompiler::CUFLT(spu_opcode_t op)
 	c->pand(va, XmmConst(_mm_set1_epi32(0x7fffffff)));
 	c->cvtdq2ps(va, va); // convert to floats
 	c->psrad(v1, 31); // generate mask from sign bit
-	c->andps(v1, XmmConst(_mm_set1_ps(exp2f(31)))); // generate correction component
+	c->andps(v1, XmmConst(_mm_set1_ps(std::exp2(31.f)))); // generate correction component
 	c->addps(va, v1); // add correction component
-	if (op.i8 != 155) c->mulps(va, XmmConst(_mm_set1_ps(exp2f(static_cast<s16>(op.i8 - 155))))); // scale
+	if (op.i8 != 155) c->mulps(va, XmmConst(_mm_set1_ps(std::exp2(static_cast<float>(static_cast<s16>(op.i8 - 155)))))); // scale
 	c->movaps(SPU_OFF_128(gpr[op.rt]), va);
 }
 
diff --git a/rpcs3/Emu/Cell/SPUInterpreter.cpp b/rpcs3/Emu/Cell/SPUInterpreter.cpp
index 217f35728c..139c91319f 100644
--- a/rpcs3/Emu/Cell/SPUInterpreter.cpp
+++ b/rpcs3/Emu/Cell/SPUInterpreter.cpp
@@ -5,7 +5,8 @@
 #include "SPUThread.h"
 #include "SPUInterpreter.h"
 
-#include <fenv.h>
+#include <cmath>
+#include <cfenv>
 
 // Compare 16 packed unsigned bytes (greater than)
 inline __m128i sse_cmpgt_epu8(__m128i A, __m128i B)
@@ -942,8 +943,8 @@ void spu_interpreter_fast::FI(SPUThread& spu, spu_opcode_t op)
 	const auto mask_sf = _mm_set1_epi32(0x000003ff); // step fraction mask
 	const auto mask_yf = _mm_set1_epi32(0x0007ffff); // Y fraction mask (bits 13..31)
 	const auto base = _mm_or_ps(_mm_and_ps(spu.gpr[op.rb].vf, mask_bf), _mm_castsi128_ps(_mm_set1_epi32(0x3f800000)));
-	const auto step = _mm_mul_ps(_mm_cvtepi32_ps(_mm_and_si128(spu.gpr[op.rb].vi, mask_sf)), _mm_set1_ps(exp2f(-13)));
-	const auto y = _mm_mul_ps(_mm_cvtepi32_ps(_mm_and_si128(spu.gpr[op.ra].vi, mask_yf)), _mm_set1_ps(exp2f(-19)));
+	const auto step = _mm_mul_ps(_mm_cvtepi32_ps(_mm_and_si128(spu.gpr[op.rb].vi, mask_sf)), _mm_set1_ps(std::exp2(-13.f)));
+	const auto y = _mm_mul_ps(_mm_cvtepi32_ps(_mm_and_si128(spu.gpr[op.ra].vi, mask_yf)), _mm_set1_ps(std::exp2(-19.f)));
 	spu.gpr[op.rt].vf = _mm_or_ps(_mm_and_ps(mask_se, spu.gpr[op.rb].vf), _mm_andnot_ps(mask_se, _mm_sub_ps(base, _mm_mul_ps(step, y))));
 }
 
@@ -1409,9 +1410,9 @@ void spu_interpreter_precise::FRSQEST(SPUThread& spu, spu_opcode_t op)
 			result = extended(0, 0x7FFFFF);
 		}
 		else if (isextended(a))
-			result = 0.5f / sqrtf(fabsf(ldexpf_extended(a, -2)));
+			result = 0.5f / std::sqrt(std::fabs(ldexpf_extended(a, -2)));
 		else
-			result = 1 / sqrtf(fabsf(a));
+			result = 1 / std::sqrt(std::fabs(a));
 		spu.gpr[op.rt]._f[i] = result;
 	}
 }
@@ -1502,9 +1503,9 @@ static void FA_FS(SPUThread& spu, spu_opcode_t op, bool sub)
 		else
 		{
 			result = a + b;
-			if (result == copysignf(FLOAT_MAX_NORMAL, result))
+			if (result == std::copysign(FLOAT_MAX_NORMAL, result))
 			{
-				result = ldexpf_extended(ldexpf(a, -1) + ldexpf(b, -1), 1);
+				result = ldexpf_extended(std::ldexp(a, -1) + std::ldexp(b, -1), 1);
 				if (isextended(result))
 					spu.fpscr.setSinglePrecisionExceptionFlags(w, FPSCR_SDIFF);
 			}
@@ -1515,7 +1516,7 @@ static void FA_FS(SPUThread& spu, spu_opcode_t op, bool sub)
 			}
 			else if (result == 0.0f)
 			{
-				if (fabsf(a) != fabsf(b))
+				if (std::fabs(a) != std::fabs(b))
 					spu.fpscr.setSinglePrecisionExceptionFlags(w, FPSCR_SUNF | FPSCR_SDIFF);
 				result = +0.0f;
 			}
@@ -1560,7 +1561,7 @@ void spu_interpreter_precise::FM(SPUThread& spu, spu_opcode_t op)
 					result = ldexpf_extended(a, -1) * b;
 				else
 					result = a * ldexpf_extended(b, -1);
-				if (result == copysignf(FLOAT_MAX_NORMAL, result))
+				if (result == std::copysign(FLOAT_MAX_NORMAL, result))
 				{
 					spu.fpscr.setSinglePrecisionExceptionFlags(w, FPSCR_SOVF);
 					result = extended(sign, 0x7FFFFF);
@@ -1572,13 +1573,13 @@ void spu_interpreter_precise::FM(SPUThread& spu, spu_opcode_t op)
 		else
 		{
 			result = a * b;
-			if (result == copysignf(FLOAT_MAX_NORMAL, result))
+			if (result == std::copysign(FLOAT_MAX_NORMAL, result))
 			{
 				feclearexcept(FE_ALL_EXCEPT);
 				if (fexpf(a) > fexpf(b))
-					result = ldexpf(a, -1) * b;
+					result = std::ldexp(a, -1) * b;
 				else
-					result = a * ldexpf(b, -1);
+					result = a * std::ldexp(b, -1);
 				result = ldexpf_extended(result, 1);
 				if (isextended(result))
 					spu.fpscr.setSinglePrecisionExceptionFlags(w, FPSCR_SDIFF);
@@ -1638,12 +1639,12 @@ static void DFASM(SPUThread& spu, spu_opcode_t op, DoubleOp operation)
 		if (isdenormal(a))
 		{
 			spu.fpscr.setDoublePrecisionExceptionFlags(i, FPSCR_DDENORM);
-			a = copysign(0.0, a);
+			a = std::copysign(0.0, a);
 		}
 		if (isdenormal(b))
 		{
 			spu.fpscr.setDoublePrecisionExceptionFlags(i, FPSCR_DDENORM);
-			b = copysign(0.0, b);
+			b = std::copysign(0.0, b);
 		}
 		double result;
 		if (std::isnan(a) || std::isnan(b))
@@ -1698,17 +1699,17 @@ static void DFMA(SPUThread& spu, spu_opcode_t op, bool neg, bool sub)
 		if (isdenormal(a))
 		{
 			spu.fpscr.setDoublePrecisionExceptionFlags(i, FPSCR_DDENORM);
-			a = copysign(0.0, a);
+			a = std::copysign(0.0, a);
 		}
 		if (isdenormal(b))
 		{
 			spu.fpscr.setDoublePrecisionExceptionFlags(i, FPSCR_DDENORM);
-			b = copysign(0.0, b);
+			b = std::copysign(0.0, b);
 		}
 		if (isdenormal(c))
 		{
 			spu.fpscr.setDoublePrecisionExceptionFlags(i, FPSCR_DDENORM);
-			c = copysign(0.0, c);
+			c = std::copysign(0.0, c);
 		}
 		double result;
 		if (std::isnan(a) || std::isnan(b) || std::isnan(c))
@@ -1857,9 +1858,9 @@ void spu_interpreter_precise::CFLTS(SPUThread& spu, spu_opcode_t op)
 		const float a = spu.gpr[op.ra]._f[i];
 		float scaled;
 		if ((fexpf(a) - 127) + scale >= 32)
-			scaled = copysignf(4294967296.0f, a);
+			scaled = std::copysign(4294967296.0f, a);
 		else
-			scaled = ldexpf(a, scale);
+			scaled = std::ldexp(a, scale);
 		s32 result;
 		if (scaled >= 2147483648.0f)
 			result = 0x7FFFFFFF;
@@ -1879,9 +1880,9 @@ void spu_interpreter_precise::CFLTU(SPUThread& spu, spu_opcode_t op)
 		const float a = spu.gpr[op.ra]._f[i];
 		float scaled;
 		if ((fexpf(a) - 127) + scale >= 32)
-			scaled = copysignf(4294967296.0f, a);
+			scaled = std::copysign(4294967296.0f, a);
 		else
-			scaled = ldexpf(a, scale);
+			scaled = std::ldexp(a, scale);
 		u32 result;
 		if (scaled >= 4294967296.0f)
 			result = 0xFFFFFFFF;
@@ -2002,9 +2003,9 @@ static void FMA(SPUThread& spu, spu_opcode_t op, bool neg, bool sub)
 				}
 				else
 				{
-					result = fmaf(new_a, new_b, ldexpf_extended(c, -2));
+					result = std::fma(new_a, new_b, ldexpf_extended(c, -2));
 				}
-				if (fabsf(result) >= ldexpf(1.0f, 127))
+				if (std::fabs(result) >= std::ldexp(1.0f, 127))
 				{
 					spu.fpscr.setSinglePrecisionExceptionFlags(w, FPSCR_SOVF);
 					result = extended(sign, 0x7FFFFF);
@@ -2033,8 +2034,8 @@ static void FMA(SPUThread& spu, spu_opcode_t op, bool neg, bool sub)
 			}
 			else
 			{
-				result = fmaf(ldexpf(a, -1), ldexpf(b, -1), ldexpf_extended(c, -2));
-				if (fabsf(result) >= ldexpf(1.0f, 127))
+				result = std::fma(std::ldexp(a, -1), std::ldexp(b, -1), ldexpf_extended(c, -2));
+				if (std::fabs(result) >= std::ldexp(1.0f, 127))
 				{
 					spu.fpscr.setSinglePrecisionExceptionFlags(w, FPSCR_SOVF);
 					result = extended(sign, 0x7FFFFF);
@@ -2048,15 +2049,15 @@ static void FMA(SPUThread& spu, spu_opcode_t op, bool neg, bool sub)
 		else
 		{
 			feclearexcept(FE_ALL_EXCEPT);
-			result = fmaf(a, b, c);
+			result = std::fma(a, b, c);
 			if (fetestexcept(FE_OVERFLOW))
 			{
 				spu.fpscr.setSinglePrecisionExceptionFlags(w, FPSCR_SDIFF);
 				if (fexpf(a) > fexpf(b))
-					result = fmaf(ldexpf(a, -2), b, ldexpf(c, -2));
+					result = std::fma(std::ldexp(a, -2), b, std::ldexp(c, -2));
 				else
-					result = fmaf(a, ldexpf(b, -2), ldexpf(c, -2));
-				if (fabsf(result) >= ldexpf(1.0f, 127))
+					result = std::fma(a, std::ldexp(b, -2), std::ldexp(c, -2));
+				if (fabsf(result) >= std::ldexp(1.0f, 127))
 				{
 					spu.fpscr.setSinglePrecisionExceptionFlags(w, FPSCR_SOVF);
 					result = extended(sign, 0x7FFFFF);
diff --git a/rpcs3/Emu/Cell/SPURecompiler.h b/rpcs3/Emu/Cell/SPURecompiler.h
index ed9b9aae64..355bde4bd5 100644
--- a/rpcs3/Emu/Cell/SPURecompiler.h
+++ b/rpcs3/Emu/Cell/SPURecompiler.h
@@ -2,6 +2,8 @@
 
 #include "SPUAnalyser.h"
 
+#include <mutex>
+
 // SPU Recompiler instance base (must be global or PS3 process-local)
 class spu_recompiler_base
 {
diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp
index 9ec1cd4643..b339abedf5 100644
--- a/rpcs3/Emu/Cell/SPUThread.cpp
+++ b/rpcs3/Emu/Cell/SPUThread.cpp
@@ -18,10 +18,14 @@
 
 #include "Emu/Memory/wait_engine.h"
 
+#include <cmath>
 #include <cfenv>
+#include <thread>
 
 extern u64 get_timebased_time();
 
+extern std::mutex& get_current_thread_mutex();
+
 enum class spu_decoder_type
 {
 	precise,
@@ -54,13 +58,72 @@ void spu_int_ctrl_t::set(u64 ints)
 		if (tag && tag->handler)
 		{
 			tag->handler->signal++;
-			tag->handler->thread->notify();
+			(*tag->handler->thread)->notify();
 		}
 	}
 }
 
 const spu_imm_table_t g_spu_imm;
 
+spu_imm_table_t::scale_table_t::scale_table_t()
+{
+	for (s32 i = -155; i < 174; i++)
+	{
+		m_data[i + 155] = _mm_set1_ps(static_cast<float>(std::exp2(i)));
+	}
+}
+
+spu_imm_table_t::spu_imm_table_t()
+{
+	for (u32 i = 0; i < sizeof(fsm) / sizeof(fsm[0]); i++)
+	{
+		for (u32 j = 0; j < 4; j++)
+		{
+			fsm[i]._u32[j] = (i & (1 << j)) ? 0xffffffff : 0;
+		}
+	}
+
+	for (u32 i = 0; i < sizeof(fsmh) / sizeof(fsmh[0]); i++)
+	{
+		for (u32 j = 0; j < 8; j++)
+		{
+			fsmh[i]._u16[j] = (i & (1 << j)) ? 0xffff : 0;
+		}
+	}
+
+	for (u32 i = 0; i < sizeof(fsmb) / sizeof(fsmb[0]); i++)
+	{
+		for (u32 j = 0; j < 16; j++)
+		{
+			fsmb[i]._u8[j] = (i & (1 << j)) ? 0xff : 0;
+		}
+	}
+
+	for (u32 i = 0; i < sizeof(sldq_pshufb) / sizeof(sldq_pshufb[0]); i++)
+	{
+		for (u32 j = 0; j < 16; j++)
+		{
+			sldq_pshufb[i]._u8[j] = static_cast<u8>(j - i);
+		}
+	}
+
+	for (u32 i = 0; i < sizeof(srdq_pshufb) / sizeof(srdq_pshufb[0]); i++)
+	{
+		for (u32 j = 0; j < 16; j++)
+		{
+			srdq_pshufb[i]._u8[j] = (j + i > 15) ? 0xff : static_cast<u8>(j + i);
+		}
+	}
+
+	for (u32 i = 0; i < sizeof(rldq_pshufb) / sizeof(rldq_pshufb[0]); i++)
+	{
+		for (u32 j = 0; j < 16; j++)
+		{
+			rldq_pshufb[i]._u8[j] = static_cast<u8>((j - i) & 0xf);
+		}
+	}
+}
+
 std::string SPUThread::get_name() const
 {
 	return fmt::format("%sSPU[0x%x] Thread (%s)", offset > RAW_SPU_BASE_ADDR ? "Raw" : "", id, name);
@@ -188,7 +251,7 @@ SPUThread::SPUThread(const std::string& name, u32 index)
 	, index(index)
 	, offset(vm::alloc(0x40000, vm::main))
 {
-	Ensures(offset);
+	ENSURES(offset);
 }
 
 void SPUThread::push_snr(u32 number, u32 value)
@@ -477,18 +540,13 @@ void SPUThread::set_events(u32 mask)
 		throw EXCEPTION("Unimplemented events (0x%x)", unimpl);
 	}
 
-	// set new events, get old event mask
+	// Set new events, get old event mask
 	const u32 old_stat = ch_event_stat.fetch_or(mask);
 
-	// notify if some events were set
-	if (~old_stat & mask && old_stat & SPU_EVENT_WAITING)
+	// Notify if some events were set
+	if (~old_stat & mask && old_stat & SPU_EVENT_WAITING && ch_event_stat & SPU_EVENT_WAITING)
 	{
-		std::lock_guard<std::mutex> lock(get_current_thread_mutex());
-
-		if (ch_event_stat & SPU_EVENT_WAITING)
-		{
-			notify();
-		}
+		(*this)->lock_notify();
 	}
 }
 
@@ -540,30 +598,14 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
 
 	auto read_channel = [&](spu_channel_t& channel)
 	{
-		std::unique_lock<std::mutex> lock(get_current_thread_mutex(), std::defer_lock);
-
-		while (true)
+		if (!channel.try_pop(out))
 		{
-			if (channel.try_pop(out))
-			{
-				return true;
-			}
+			cpu_thread_lock{*this}, thread_ctrl::wait(WRAP_EXPR(state & cpu_state::stop || channel.try_pop(out)));
 
-			CHECK_EMU_STATUS;
-
-			if (state & cpu_state::stop)
-			{
-				return false;
-			}
-
-			if (!lock)
-			{
-				lock.lock();
-				continue;
-			}
-
-			get_current_thread_cv().wait(lock);
+			return !state.test(cpu_state::stop);
 		}
+
+		return true;
 	};
 
 	switch (ch)
@@ -1103,7 +1145,7 @@ bool SPUThread::stop_and_signal(u32 code)
 	{
 	case 0x001:
 	{
-		std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
+		std::this_thread::sleep_for(1ms); // hack
 		return true;
 	}
 
@@ -1195,7 +1237,7 @@ bool SPUThread::stop_and_signal(u32 code)
 				return false;
 			}
 
-			group->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
+			group->cv.wait_for(lv2_lock, 1ms);
 		}
 
 		// change group status
@@ -1261,7 +1303,7 @@ bool SPUThread::stop_and_signal(u32 code)
 			if (thread && thread.get() != this)
 			{
 				thread->state -= cpu_state::suspend;
-				thread->lock_notify();
+				(*thread)->lock_notify();
 			}
 		}
 
@@ -1300,7 +1342,7 @@ bool SPUThread::stop_and_signal(u32 code)
 			if (thread && thread.get() != this)
 			{
 				thread->state += cpu_state::stop;
-				thread->lock_notify();
+				(*thread)->lock_notify();
 			}
 		}
 
@@ -1404,7 +1446,7 @@ void SPUThread::fast_call(u32 ls_addr)
 	custom_task = std::move(old_task);
 }
 
-void SPUThread::RegisterHleFunction(u32 addr, std::function<bool(SPUThread&SPU)> function)
+void SPUThread::RegisterHleFunction(u32 addr, std::function<bool(SPUThread&)> function)
 {
 	m_addr_to_hle_function_map[addr] = function;
 	_ref<u32>(addr) = 0x00000003; // STOP 3
diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h
index 38bb09e2b0..d75dd5e676 100644
--- a/rpcs3/Emu/Cell/SPUThread.h
+++ b/rpcs3/Emu/Cell/SPUThread.h
@@ -4,7 +4,6 @@
 #include "Emu/CPU/CPUThread.h"
 #include "Emu/Cell/SPUInterpreter.h"
 #include "MFC.h"
-#include <cmath>
 
 class lv2_event_queue_t;
 struct lv2_spu_group_t;
@@ -380,13 +379,7 @@ struct spu_imm_table_t
 		std::array<__m128, 155 + 174> m_data;
 
 	public:
-		scale_table_t()
-		{
-			for (s32 i = -155; i < 174; i++)
-			{
-				m_data[i + 155] = _mm_set1_ps(static_cast<float>(std::exp2(i)));
-			}
-		}
+		scale_table_t();
 
 		force_inline __m128 operator [] (s32 scale) const
 		{
@@ -395,56 +388,7 @@ struct spu_imm_table_t
 	}
 	const scale;
 
-	spu_imm_table_t()
-	{
-		for (u32 i = 0; i < sizeof(fsm) / sizeof(fsm[0]); i++)
-		{
-			for (u32 j = 0; j < 4; j++)
-			{
-				fsm[i]._u32[j] = (i & (1 << j)) ? 0xffffffff : 0;
-			}
-		}
-
-		for (u32 i = 0; i < sizeof(fsmh) / sizeof(fsmh[0]); i++)
-		{
-			for (u32 j = 0; j < 8; j++)
-			{
-				fsmh[i]._u16[j] = (i & (1 << j)) ? 0xffff : 0;
-			}
-		}
-
-		for (u32 i = 0; i < sizeof(fsmb) / sizeof(fsmb[0]); i++)
-		{
-			for (u32 j = 0; j < 16; j++)
-			{
-				fsmb[i]._u8[j] = (i & (1 << j)) ? 0xff : 0;
-			}
-		}
-
-		for (u32 i = 0; i < sizeof(sldq_pshufb) / sizeof(sldq_pshufb[0]); i++)
-		{
-			for (u32 j = 0; j < 16; j++)
-			{
-				sldq_pshufb[i]._u8[j] = static_cast<u8>(j - i);
-			}
-		}
-
-		for (u32 i = 0; i < sizeof(srdq_pshufb) / sizeof(srdq_pshufb[0]); i++)
-		{
-			for (u32 j = 0; j < 16; j++)
-			{
-				srdq_pshufb[i]._u8[j] = (j + i > 15) ? 0xff : static_cast<u8>(j + i);
-			}
-		}
-
-		for (u32 i = 0; i < sizeof(rldq_pshufb) / sizeof(rldq_pshufb[0]); i++)
-		{
-			for (u32 j = 0; j < 16; j++)
-			{
-				rldq_pshufb[i]._u8[j] = static_cast<u8>((j - i) & 0xf);
-			}
-		}
-	}
+	spu_imm_table_t();
 };
 
 extern const spu_imm_table_t g_spu_imm;
@@ -646,7 +590,7 @@ public:
 		return *_ptr<T>(lsa);
 	}
 
-	void RegisterHleFunction(u32 addr, std::function<bool(SPUThread & SPU)> function);
+	void RegisterHleFunction(u32 addr, std::function<bool(SPUThread&)> function);
 	void UnregisterHleFunction(u32 addr);
 	void UnregisterHleFunctions(u32 start_addr, u32 end_addr);
 };
diff --git a/rpcs3/Emu/Cell/lv2/IPC.h b/rpcs3/Emu/Cell/lv2/IPC.h
deleted file mode 100644
index 777409307a..0000000000
--- a/rpcs3/Emu/Cell/lv2/IPC.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#pragma once
-
-#include <memory>
-#include <unordered_map>
-
-#include "Utilities/SharedMutex.h"
-
-// IPC manager for lv2 objects of type T and 64-bit IPC keys.
-// External declaration of g_ipc is required.
-template<typename T>
-class ipc_manager final
-{
-	std::unordered_map<u64, std::weak_ptr<T>> m_map;
-
-	shared_mutex m_mutex;
-
-	static ipc_manager g_ipc;
-
-public:
-	// Add new object if specified ipc_key is not used
-	template<typename F>
-	static auto add(u64 ipc_key, F&& provider) -> decltype(static_cast<std::shared_ptr<T>>(provider()))
-	{
-		writer_lock lock(g_ipc.m_mutex);
-
-		// Get object location
-		std::weak_ptr<T>& wptr = g_ipc.m_map[ipc_key];
-
-		if (wptr.expired())
-		{
-			// Call a function which must return the object
-			std::shared_ptr<T> result = provider();
-			wptr = result;
-			return result;
-		}
-
-		return{};
-	}
-
-	// Get existing object with specified ipc_key
-	static std::shared_ptr<T> get(u64 ipc_key)
-	{
-		reader_lock lock(g_ipc.m_mutex);
-
-		const auto found = g_ipc.m_map.find(ipc_key);
-
-		if (found != g_ipc.m_map.end())
-		{
-			return found->second.lock();
-		}
-
-		return{};
-	}
-};
diff --git a/rpcs3/Emu/Cell/lv2/lv2.cpp b/rpcs3/Emu/Cell/lv2/lv2.cpp
index 771302c551..7a1788939b 100644
--- a/rpcs3/Emu/Cell/lv2/lv2.cpp
+++ b/rpcs3/Emu/Cell/lv2/lv2.cpp
@@ -1,4 +1,5 @@
 #include "stdafx.h"
+#include "Utilities/Config.h"
 #include "Utilities/AutoPause.h"
 #include "Emu/System.h"
 
@@ -29,6 +30,30 @@
 #include "sys_fs.h"
 #include "sys_dbg.h"
 
+LOG_CHANNEL(sys_cond);
+LOG_CHANNEL(sys_dbg);
+LOG_CHANNEL(sys_event);
+LOG_CHANNEL(sys_event_flag);
+LOG_CHANNEL(sys_fs);
+LOG_CHANNEL(sys_interrupt);
+LOG_CHANNEL(sys_lwcond);
+LOG_CHANNEL(sys_lwmutex);
+LOG_CHANNEL(sys_memory);
+LOG_CHANNEL(sys_mmapper);
+LOG_CHANNEL(sys_mutex);
+LOG_CHANNEL(sys_ppu_thread);
+LOG_CHANNEL(sys_process);
+LOG_CHANNEL(sys_prx);
+LOG_CHANNEL(sys_rsx);
+LOG_CHANNEL(sys_rwlock);
+LOG_CHANNEL(sys_semaphore);
+LOG_CHANNEL(sys_spu);
+LOG_CHANNEL(sys_time);
+LOG_CHANNEL(sys_timer);
+LOG_CHANNEL(sys_trace);
+LOG_CHANNEL(sys_tty);
+LOG_CHANNEL(sys_vm);
+
 extern std::string ppu_get_syscall_name(u64 code);
 
 static void null_func(PPUThread& ppu)
@@ -903,15 +928,21 @@ extern void ppu_execute_syscall(PPUThread& ppu, u64 code)
 	{
 		g_ppu_syscall_table[code](ppu);
 	}
-	catch (...)
+	catch (EmulationStopped)
 	{
 		LOG_WARNING(PPU, "Syscall '%s' (%llu) aborted", ppu_get_syscall_name(code), code);
 		ppu.last_function = previous_function;
 		throw;
 	}
+	catch (...)
+	{
+		LOG_ERROR(PPU, "Syscall '%s' (%llu) aborted", ppu_get_syscall_name(code), code);
+		ppu.last_function = previous_function;
+		throw;
+	}
 
 	LOG_TRACE(PPU, "Syscall '%s' (%llu) finished, r3=0x%llx", ppu_get_syscall_name(code), code, ppu.GPR[3]);
 	ppu.last_function = previous_function;
 }
 
-lv2_lock_t::type::mutex_type lv2_lock_t::mutex;
+DECLARE(lv2_lock_t::mutex);
diff --git a/rpcs3/Emu/Cell/lv2/sys_cond.cpp b/rpcs3/Emu/Cell/lv2/sys_cond.cpp
index 82853dac81..db5f2478fb 100644
--- a/rpcs3/Emu/Cell/lv2/sys_cond.cpp
+++ b/rpcs3/Emu/Cell/lv2/sys_cond.cpp
@@ -1,5 +1,4 @@
 #include "stdafx.h"
-#include "Utilities/Config.h"
 #include "Emu/Memory/Memory.h"
 #include "Emu/System.h"
 #include "Emu/IdManager.h"
@@ -9,7 +8,9 @@
 #include "sys_mutex.h"
 #include "sys_cond.h"
 
-LOG_CHANNEL(sys_cond);
+#include <algorithm>
+
+logs::channel sys_cond("sys_cond", logs::level::notice);
 
 extern u64 get_system_time();
 
@@ -24,8 +25,8 @@ void lv2_cond_t::notify(lv2_lock_t, cpu_thread* thread)
 	{
 		mutex->owner = std::static_pointer_cast<cpu_thread>(thread->shared_from_this());
 
-		ASSERT(!thread->state.test_and_set(cpu_state::signal));
-		thread->notify();
+		VERIFY(!thread->state.test_and_set(cpu_state::signal));
+		(*thread)->notify();
 	}
 }
 
diff --git a/rpcs3/Emu/Cell/lv2/sys_dbg.cpp b/rpcs3/Emu/Cell/lv2/sys_dbg.cpp
index 3890fc906f..7c73318b80 100644
--- a/rpcs3/Emu/Cell/lv2/sys_dbg.cpp
+++ b/rpcs3/Emu/Cell/lv2/sys_dbg.cpp
@@ -1,5 +1,4 @@
 #include "stdafx.h"
-#include "Utilities/Config.h"
 #include "Emu/Memory/Memory.h"
 #include "Emu/System.h"
 #include "Emu/IdManager.h"
@@ -7,4 +6,4 @@
 #include "Emu/Cell/ErrorCodes.h"
 #include "sys_dbg.h"
 
-LOG_CHANNEL(sys_dbg);
+logs::channel sys_dbg("sys_dbg", logs::level::notice);
diff --git a/rpcs3/Emu/Cell/lv2/sys_event.cpp b/rpcs3/Emu/Cell/lv2/sys_event.cpp
index ac105aabb5..2c1994419b 100644
--- a/rpcs3/Emu/Cell/lv2/sys_event.cpp
+++ b/rpcs3/Emu/Cell/lv2/sys_event.cpp
@@ -1,25 +1,26 @@
 #include "stdafx.h"
-#include "Utilities/Config.h"
 #include "Emu/Memory/Memory.h"
 #include "Emu/System.h"
 #include "Emu/IdManager.h"
+#include "Emu/IPC.h"
 
 #include "Emu/Cell/ErrorCodes.h"
 #include "Emu/Cell/PPUThread.h"
 #include "Emu/Cell/SPUThread.h"
 #include "sys_process.h"
 #include "sys_event.h"
-#include "IPC.h"
 
-LOG_CHANNEL(sys_event);
+logs::channel sys_event("sys_event", logs::level::notice);
 
-template<> DECLARE(ipc_manager<lv2_event_queue_t>::g_ipc) {};
+template<> DECLARE(ipc_manager<lv2_event_queue_t, u64>::g_ipc) {};
 
 extern u64 get_system_time();
 
 std::shared_ptr<lv2_event_queue_t> lv2_event_queue_t::make(u32 protocol, s32 type, u64 name, u64 ipc_key, s32 size)
 {
-	auto make_expr = WRAP_EXPR(idm::import<lv2_event_queue_t>(WRAP_EXPR(std::make_shared<lv2_event_queue_t>(protocol, type, name, ipc_key, size))));
+	auto queue = std::make_shared<lv2_event_queue_t>(protocol, type, name, ipc_key, size);
+
+	auto make_expr = WRAP_EXPR(idm::import<lv2_event_queue_t>(WRAP_EXPR(queue)));
 
 	if (ipc_key == SYS_EVENT_QUEUE_LOCAL)
 	{
@@ -28,7 +29,12 @@ std::shared_ptr<lv2_event_queue_t> lv2_event_queue_t::make(u32 protocol, s32 typ
 	}
 
 	// IPC queue
-	return ipc_manager<lv2_event_queue_t>::add(ipc_key, make_expr);
+	if (ipc_manager<lv2_event_queue_t, u64>::add(ipc_key, make_expr))
+	{
+		return queue;
+	}
+
+	return nullptr;
 }
 
 std::shared_ptr<lv2_event_queue_t> lv2_event_queue_t::find(u64 ipc_key)
@@ -39,12 +45,12 @@ std::shared_ptr<lv2_event_queue_t> lv2_event_queue_t::find(u64 ipc_key)
 		return{};
 	}
 
-	return ipc_manager<lv2_event_queue_t>::get(ipc_key);
+	return ipc_manager<lv2_event_queue_t, u64>::get(ipc_key);
 }
 
 void lv2_event_queue_t::push(lv2_lock_t, u64 source, u64 data1, u64 data2, u64 data3)
 {
-	Expects(m_sq.empty() || m_events.empty());
+	EXPECTS(m_sq.empty() || m_events.empty());
 
 	// save event if no waiters
 	if (m_sq.empty())
@@ -77,15 +83,15 @@ void lv2_event_queue_t::push(lv2_lock_t, u64 source, u64 data1, u64 data2, u64 d
 		throw fmt::exception("Unexpected (queue.type=%d, thread.type=%d)" HERE, type, thread->type);
 	}
 
-	ASSERT(!thread->state.test_and_set(cpu_state::signal));
-	thread->notify();
+	VERIFY(!thread->state.test_and_set(cpu_state::signal));
+	(*thread)->notify();
 
 	return m_sq.pop_front();
 }
 
 lv2_event_queue_t::event_type lv2_event_queue_t::pop(lv2_lock_t)
 {
-	Expects(m_events.size());
+	EXPECTS(m_events.size());
 	auto result = m_events.front();
 	m_events.pop_front();
 	return result;
@@ -171,7 +177,7 @@ s32 sys_event_queue_destroy(u32 equeue_id, s32 mode)
 		}
 
 		thread->state += cpu_state::signal;
-		thread->notify();
+		(*thread)->notify();
 	}
 
 	return CELL_OK;
@@ -270,7 +276,7 @@ s32 sys_event_queue_receive(PPUThread& ppu, u32 equeue_id, vm::ptr<sys_event_t>
 
 	if (ppu.GPR[3])
 	{
-		Ensures(!idm::check<lv2_event_queue_t>(equeue_id));
+		ENSURES(!idm::check<lv2_event_queue_t>(equeue_id));
 		return CELL_ECANCELED;
 	}
 
diff --git a/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp b/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp
index 87814cf8e4..d39ba434d0 100644
--- a/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp
+++ b/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp
@@ -1,5 +1,4 @@
 #include "stdafx.h"
-#include "Utilities/Config.h"
 #include "Emu/Memory/Memory.h"
 #include "Emu/System.h"
 #include "Emu/IdManager.h"
@@ -8,7 +7,9 @@
 #include "Emu/Cell/PPUThread.h"
 #include "sys_event_flag.h"
 
-LOG_CHANNEL(sys_event_flag);
+#include <algorithm>
+
+logs::channel sys_event_flag("sys_event_flag", logs::level::notice);
 
 extern u64 get_system_time();
 
@@ -28,8 +29,8 @@ void lv2_event_flag_t::notify_all(lv2_lock_t)
 			// save pattern
 			ppu.GPR[4] = clear_pattern(bitptn, mode);
 
-			ASSERT(!thread->state.test_and_set(cpu_state::signal));
-			thread->notify();
+			VERIFY(!thread->state.test_and_set(cpu_state::signal));
+			(*thread)->notify();
 
 			return true;
 		}
@@ -291,8 +292,8 @@ s32 sys_event_flag_cancel(u32 id, vm::ptr<u32> num)
 		// clear "mode" as a sign of cancellation
 		ppu.GPR[5] = 0;
 
-		ASSERT(!thread->state.test_and_set(cpu_state::signal));
-		thread->notify();
+		VERIFY(!thread->state.test_and_set(cpu_state::signal));
+		(*thread)->notify();
 	}
 
 	eflag->sq.clear();
diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.cpp b/rpcs3/Emu/Cell/lv2/sys_fs.cpp
index a2e2899cb6..de95dfebdd 100644
--- a/rpcs3/Emu/Cell/lv2/sys_fs.cpp
+++ b/rpcs3/Emu/Cell/lv2/sys_fs.cpp
@@ -1,5 +1,4 @@
 #include "stdafx.h"
-#include "Utilities/Config.h"
 #include "Emu/Memory/Memory.h"
 #include "Emu/System.h"
 #include "Emu/IdManager.h"
@@ -10,7 +9,7 @@
 #include "Utilities/StrUtil.h"
 #include <cerrno>
 
-LOG_CHANNEL(sys_fs);
+logs::channel sys_fs("sys_fs", logs::level::notice);
 
 s32 sys_fs_test(u32 arg1, u32 arg2, vm::ptr<u32> arg3, u32 arg4, vm::ptr<char> arg5, u32 arg6)
 {
@@ -352,9 +351,9 @@ s32 sys_fs_rmdir(vm::cptr<char> path)
 
 	if (!fs::remove_dir(vfs::get(path.get_ptr())))
 	{
-		switch (auto error = fs::error)
+		switch (auto error = fs::g_tls_error)
 		{
-		case ENOENT: return CELL_FS_ENOENT;
+		case fs::error::noent: return CELL_FS_ENOENT;
 		default: sys_fs.error("sys_fs_rmdir(): unknown error %d", error);
 		}
 
@@ -372,9 +371,9 @@ s32 sys_fs_unlink(vm::cptr<char> path)
 
 	if (!fs::remove_file(vfs::get(path.get_ptr())))
 	{
-		switch (auto error = fs::error)
+		switch (auto error = fs::g_tls_error)
 		{
-		case ENOENT: return CELL_FS_ENOENT;
+		case fs::error::noent: return CELL_FS_ENOENT;
 		default: sys_fs.error("sys_fs_unlink(): unknown error %d", error);
 		}
 
@@ -451,9 +450,9 @@ s32 sys_fs_truncate(vm::cptr<char> path, u64 size)
 
 	if (!fs::truncate_file(vfs::get(path.get_ptr()), size))
 	{
-		switch (auto error = fs::error)
+		switch (auto error = fs::g_tls_error)
 		{
-		case ENOENT: return CELL_FS_ENOENT;
+		case fs::error::noent: return CELL_FS_ENOENT;
 		default: sys_fs.error("sys_fs_truncate(): unknown error %d", error);
 		}
 
@@ -478,9 +477,9 @@ s32 sys_fs_ftruncate(u32 fd, u64 size)
 
 	if (!file->file.trunc(size))
 	{
-		switch (auto error = fs::error)
+		switch (auto error = fs::g_tls_error)
 		{
-		case 0:
+		case fs::error::ok:
 		default: sys_fs.error("sys_fs_ftruncate(): unknown error %d", error);
 		}
 
diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.h b/rpcs3/Emu/Cell/lv2/sys_fs.h
index fd63e6df52..ad044f23a3 100644
--- a/rpcs3/Emu/Cell/lv2/sys_fs.h
+++ b/rpcs3/Emu/Cell/lv2/sys_fs.h
@@ -2,6 +2,9 @@
 
 #include "Utilities/Thread.h"
 
+#include <mutex>
+#include <condition_variable>
+
 namespace vm { using namespace ps3; }
 
 #pragma pack(push, 4)
diff --git a/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp b/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp
index ca2fe1f9d9..ec831f61e4 100644
--- a/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp
+++ b/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp
@@ -1,5 +1,4 @@
 #include "stdafx.h"
-#include "Utilities/Config.h"
 #include "Emu/Memory/Memory.h"
 #include "Emu/System.h"
 #include "Emu/IdManager.h"
@@ -8,20 +7,20 @@
 #include "Emu/Cell/PPUThread.h"
 #include "sys_interrupt.h"
 
-LOG_CHANNEL(sys_interrupt);
+logs::channel sys_interrupt("sys_interrupt", logs::level::notice);
 
 void lv2_int_serv_t::join(PPUThread& ppu, lv2_lock_t lv2_lock)
 {
 	// Use is_joining to stop interrupt thread and signal
 	thread->is_joining = true;
-	thread->notify();
+	(*thread)->notify();
 
 	// Start joining
 	while (!(thread->state & cpu_state::exit))
 	{
 		CHECK_EMU_STATUS;
 
-		get_current_thread_cv().wait_for(lv2_lock, std::chrono::milliseconds(1));
+		get_current_thread_cv().wait_for(lv2_lock, 1ms);
 	}
 
 	// Cleanup
@@ -93,7 +92,7 @@ s32 _sys_interrupt_thread_establish(vm::ptr<u32> ih, u32 intrtag, u32 intrthread
 
 	it->custom_task = [handler, arg1, arg2](PPUThread& ppu)
 	{
-		const u32 pc   = ppu.PC;
+		const u32 pc   = ppu.pc;
 		const u32 rtoc = ppu.GPR[2];
 
 		LV2_LOCK;
@@ -128,7 +127,7 @@ s32 _sys_interrupt_thread_establish(vm::ptr<u32> ih, u32 intrtag, u32 intrthread
 	};
 
 	it->state -= cpu_state::stop;
-	it->lock_notify();
+	(*it)->lock_notify();
 
 	*ih = handler->id;
 
diff --git a/rpcs3/Emu/Cell/lv2/sys_lwcond.cpp b/rpcs3/Emu/Cell/lv2/sys_lwcond.cpp
index e56a69f78d..eaea8482bc 100644
--- a/rpcs3/Emu/Cell/lv2/sys_lwcond.cpp
+++ b/rpcs3/Emu/Cell/lv2/sys_lwcond.cpp
@@ -1,5 +1,4 @@
 #include "stdafx.h"
-#include "Utilities/Config.h"
 #include "Emu/Memory/Memory.h"
 #include "Emu/System.h"
 #include "Emu/IdManager.h"
@@ -9,7 +8,9 @@
 #include "sys_lwmutex.h"
 #include "sys_lwcond.h"
 
-LOG_CHANNEL(sys_lwcond);
+#include <algorithm>
+
+logs::channel sys_lwcond("sys_lwcond", logs::level::notice);
 
 extern u64 get_system_time();
 
@@ -29,8 +30,8 @@ void lv2_lwcond_t::notify(lv2_lock_t, cpu_thread* thread, const std::shared_ptr<
 		mutex->signaled--;
 	}
 
-	ASSERT(!thread->state.test_and_set(cpu_state::signal));
-	thread->notify();
+	VERIFY(!thread->state.test_and_set(cpu_state::signal));
+	(*thread)->notify();
 }
 
 s32 _sys_lwcond_create(vm::ptr<u32> lwcond_id, u32 lwmutex_id, vm::ptr<sys_lwcond_t> control, u64 name, u32 arg5)
diff --git a/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp b/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp
index 479030acf5..9178bda26d 100644
--- a/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp
+++ b/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp
@@ -1,5 +1,4 @@
 #include "stdafx.h"
-#include "Utilities/Config.h"
 #include "Emu/Memory/Memory.h"
 #include "Emu/System.h"
 #include "Emu/IdManager.h"
@@ -8,7 +7,7 @@
 #include "Emu/Cell/PPUThread.h"
 #include "sys_lwmutex.h"
 
-LOG_CHANNEL(sys_lwmutex);
+logs::channel sys_lwmutex("sys_lwmutex", logs::level::notice);
 
 extern u64 get_system_time();
 
@@ -22,8 +21,8 @@ void lv2_lwmutex_t::unlock(lv2_lock_t)
 	if (sq.size())
 	{
 		auto& thread = sq.front();
-		ASSERT(!thread->state.test_and_set(cpu_state::signal));
-		thread->notify();
+		VERIFY(!thread->state.test_and_set(cpu_state::signal));
+		(*thread)->notify();
 
 		sq.pop_front();
 	}
diff --git a/rpcs3/Emu/Cell/lv2/sys_memory.cpp b/rpcs3/Emu/Cell/lv2/sys_memory.cpp
index 47a7fc79cc..ac850638f4 100644
--- a/rpcs3/Emu/Cell/lv2/sys_memory.cpp
+++ b/rpcs3/Emu/Cell/lv2/sys_memory.cpp
@@ -1,5 +1,4 @@
 #include "stdafx.h"
-#include "Utilities/Config.h"
 #include "Emu/Memory/Memory.h"
 #include "Emu/System.h"
 #include "Emu/IdManager.h"
@@ -7,7 +6,7 @@
 #include "Emu/Cell/ErrorCodes.h"
 #include "sys_memory.h"
 
-LOG_CHANNEL(sys_memory);
+logs::channel sys_memory("sys_memory", logs::level::notice);
 
 s32 sys_memory_allocate(u32 size, u64 flags, vm::ptr<u32> alloc_addr)
 {
@@ -150,28 +149,27 @@ s32 sys_memory_free(u32 addr)
 	const auto area = vm::get(vm::user_space);
 
 	// Check all memory containers
-	for (auto& ct : idm::get_all<lv2_memory_container_t>())
+	const auto ct = idm::select<lv2_memory_container_t>([&](u32, lv2_memory_container_t& ct)
 	{
-		auto found = ct->allocs.find(addr);
+		return ct.allocs.count(addr) != 0;
+	});
 
-		if (found != ct->allocs.end())
+	if (ct)
+	{
+		const u32 size = ct->allocs.at(addr);
+
+		if (!area->dealloc(addr))
 		{
-			const u32 size = found->second;
-
-			if (!area->dealloc(addr))
-			{
-				throw EXCEPTION("Memory not deallocated (cid=0x%x, addr=0x%x, size=0x%x)", ct->id, addr, size);
-			}
-
-			// Return memory
-			ct->used -= size;
-			ct->allocs.erase(found);
-
-			// Fix "physical" memory
-			area->used += size;
-
-			return CELL_OK;
+			throw EXCEPTION("Memory not deallocated (cid=0x%x, addr=0x%x, size=0x%x)", ct->id, addr, size);
 		}
+
+		ct->allocs.erase(addr);
+
+		// Return "memory"
+		ct->used -= size;
+		area->used += size;
+
+		return CELL_OK;
 	}
 
 	if (!area->dealloc(addr))
@@ -205,10 +203,10 @@ s32 sys_memory_get_user_memory_size(vm::ptr<sys_memory_info_t> mem_info)
 	u32 reserved = 0;
 
 	// Check all memory containers
-	for (auto& ct : idm::get_all<lv2_memory_container_t>())
+	idm::select<lv2_memory_container_t>([&](u32, lv2_memory_container_t& ct)
 	{
-		reserved += ct->size;
-	}
+		reserved += ct.size;
+	});
 
 	const auto area = vm::get(vm::user_space);
 	
@@ -236,10 +234,10 @@ s32 sys_memory_container_create(vm::ptr<u32> cid, u32 size)
 	u32 reserved = 0;
 
 	// Check all memory containers
-	for (auto& ct : idm::get_all<lv2_memory_container_t>())
+	idm::select<lv2_memory_container_t>([&](u32, lv2_memory_container_t& ct)
 	{
-		reserved += ct->size;
-	}
+		reserved += ct.size;
+	});
 
 	const auto area = vm::get(vm::user_space);
 
diff --git a/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp b/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp
index c8e70246cd..12d9218ccd 100644
--- a/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp
+++ b/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp
@@ -1,5 +1,4 @@
 #include "stdafx.h"
-#include "Utilities/Config.h"
 #include "Emu/Memory/Memory.h"
 #include "Emu/System.h"
 #include "Emu/IdManager.h"
@@ -7,7 +6,7 @@
 #include "Emu/Cell/ErrorCodes.h"
 #include "sys_mmapper.h"
 
-LOG_CHANNEL(sys_mmapper);
+logs::channel sys_mmapper("sys_mmapper", logs::level::notice);
 
 s32 sys_mmapper_allocate_address(u64 size, u64 flags, u64 alignment, vm::ptr<u32> alloc_addr)
 {
@@ -334,24 +333,26 @@ s32 sys_mmapper_unmap_memory(u32 addr, vm::ptr<u32> mem_id)
 		return CELL_EINVAL;
 	}
 
-	for (auto& mem : idm::get_all<lv2_memory_t>())
+	const auto mem = idm::select<lv2_memory_t>([&](u32, lv2_memory_t& mem)
 	{
-		if (mem->addr == addr)
-		{
-			if (!area->dealloc(addr))
-			{
-				throw EXCEPTION("Deallocation failed (mem_id=0x%x, addr=0x%x)", mem->id, addr);
-			}
+		return mem.addr == addr;
+	});
 
-			mem->addr = 0;
-
-			*mem_id = mem->id;
-
-			return CELL_OK;
-		}
+	if (!mem)
+	{
+		return CELL_EINVAL;
 	}
 
-	return CELL_EINVAL;
+	if (!area->dealloc(addr))
+	{
+		throw EXCEPTION("Deallocation failed (mem_id=0x%x, addr=0x%x)", mem->id, addr);
+	}
+
+	mem->addr = 0;
+
+	*mem_id = mem->id;
+
+	return CELL_OK;
 }
 
 s32 sys_mmapper_enable_page_fault_notification(u32 addr, u32 eq)
diff --git a/rpcs3/Emu/Cell/lv2/sys_mutex.cpp b/rpcs3/Emu/Cell/lv2/sys_mutex.cpp
index 8e32dfb99e..fe0687cf67 100644
--- a/rpcs3/Emu/Cell/lv2/sys_mutex.cpp
+++ b/rpcs3/Emu/Cell/lv2/sys_mutex.cpp
@@ -1,5 +1,4 @@
 #include "stdafx.h"
-#include "Utilities/Config.h"
 #include "Emu/Memory/Memory.h"
 #include "Emu/System.h"
 #include "Emu/IdManager.h"
@@ -8,7 +7,7 @@
 #include "Emu/Cell/PPUThread.h"
 #include "sys_mutex.h"
 
-LOG_CHANNEL(sys_mutex);
+logs::channel sys_mutex("sys_mutex", logs::level::notice);
 
 extern u64 get_system_time();
 
@@ -21,8 +20,8 @@ void lv2_mutex_t::unlock(lv2_lock_t)
 		// pick new owner; protocol is ignored in current implementation
 		owner = std::static_pointer_cast<cpu_thread>(sq.front()->shared_from_this());
 
-		ASSERT(!owner->state.test_and_set(cpu_state::signal));
-		owner->notify();
+		VERIFY(!owner->state.test_and_set(cpu_state::signal));
+		(*owner)->notify();
 	}
 }
 
diff --git a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp
index a77a242c23..d269c71245 100644
--- a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp
+++ b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp
@@ -1,5 +1,4 @@
 #include "stdafx.h"
-#include "Utilities/Config.h"
 #include "Emu/Memory/Memory.h"
 #include "Emu/System.h"
 #include "Emu/IdManager.h"
@@ -8,7 +7,9 @@
 #include "Emu/Cell/PPUThread.h"
 #include "sys_ppu_thread.h"
 
-LOG_CHANNEL(sys_ppu_thread);
+#include <thread>
+
+logs::channel sys_ppu_thread("sys_ppu_thread", logs::level::notice);
 
 void _sys_ppu_thread_exit(PPUThread& ppu, u64 errorcode)
 {
@@ -29,6 +30,7 @@ void _sys_ppu_thread_exit(PPUThread& ppu, u64 errorcode)
 	//}
 
 	ppu.state += cpu_state::exit;
+	//ppu.handle_interrupt();
 
 	// Delete detached thread
 	if (!ppu.is_joinable)
@@ -73,6 +75,8 @@ s32 sys_ppu_thread_join(PPUThread& ppu, u32 thread_id, vm::ptr<u64> vptr)
 		return CELL_EDEADLK;
 	}
 
+	ppu.sleep();
+
 	// mark joining
 	thread->is_joining = true;
 
@@ -81,9 +85,11 @@ s32 sys_ppu_thread_join(PPUThread& ppu, u32 thread_id, vm::ptr<u64> vptr)
 	{
 		CHECK_EMU_STATUS;
 
-		get_current_thread_cv().wait_for(lv2_lock, std::chrono::milliseconds(1));
+		get_current_thread_cv().wait_for(lv2_lock, 1ms);
 	}
 
+	ppu.awake();
+
 	// get exit status from the register
 	if (vptr) *vptr = thread->GPR[3];
 
@@ -219,28 +225,6 @@ s32 sys_ppu_thread_restart(u32 thread_id)
 	return CELL_OK;
 }
 
-u32 ppu_thread_create(u32 entry, u64 arg, s32 prio, u32 stacksize, const std::string& name, std::function<void(PPUThread&)> task)
-{
-	const auto ppu = idm::make_ptr<PPUThread>(name);
-
-	ppu->prio = prio;
-	ppu->stack_size = stacksize;
-	ppu->custom_task = std::move(task);
-	ppu->cpu_init();
-
-	if (entry)
-	{
-		ppu->PC = vm::read32(entry);
-		ppu->GPR[2] = vm::read32(entry + 4); // rtoc
-	}
-
-	ppu->GPR[3] = arg;
-	ppu->state -= cpu_state::stop;
-	ppu->lock_notify();
-
-	return ppu->id;
-}
-
 s32 _sys_ppu_thread_create(vm::ptr<u64> thread_id, vm::ptr<ppu_thread_param_t> param, u64 arg, u64 unk, s32 prio, u32 stacksize, u64 flags, vm::cptr<char> threadname)
 {
 	sys_ppu_thread.warning("_sys_ppu_thread_create(thread_id=*0x%x, param=*0x%x, arg=0x%llx, unk=0x%llx, prio=%d, stacksize=0x%x, flags=0x%llx, threadname=*0x%x)",
@@ -267,13 +251,14 @@ s32 _sys_ppu_thread_create(vm::ptr<u64> thread_id, vm::ptr<ppu_thread_param_t> p
 	ppu->stack_size = std::max<u32>(stacksize, 0x4000);
 	ppu->cpu_init();
 
-	ppu->PC = vm::read32(param->entry);
+	ppu->pc = vm::read32(param->entry);
 	ppu->GPR[2] = vm::read32(param->entry + 4); // rtoc
 	ppu->GPR[3] = arg;
 	ppu->GPR[4] = unk; // actually unknown
 	ppu->GPR[13] = param->tls;
 
 	ppu->is_joinable = is_joinable;
+	//ppu->state += cpu_state::interrupt;
 
 	*thread_id = ppu->id;
 
@@ -294,7 +279,7 @@ s32 sys_ppu_thread_start(u32 thread_id)
 	}
 
 	thread->state -= cpu_state::stop;
-	thread->lock_notify();
+	(*thread)->lock_notify();
 
 	return CELL_OK;
 }
diff --git a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.h b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.h
index 8a103ae7bf..eefd4d047b 100644
--- a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.h
+++ b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.h
@@ -41,9 +41,6 @@ enum : u32
 	PPU_THREAD_STATUS_UNKNOWN,
 };
 
-// Aux
-u32 ppu_thread_create(u32 entry, u64 arg, s32 prio, u32 stacksize, const std::string& name, std::function<void(PPUThread&)> task = nullptr);
-
 // SysCalls
 void _sys_ppu_thread_exit(PPUThread& ppu, u64 errorcode);
 void sys_ppu_thread_yield();
diff --git a/rpcs3/Emu/Cell/lv2/sys_process.cpp b/rpcs3/Emu/Cell/lv2/sys_process.cpp
index 8291849120..f1dcde9162 100644
--- a/rpcs3/Emu/Cell/lv2/sys_process.cpp
+++ b/rpcs3/Emu/Cell/lv2/sys_process.cpp
@@ -1,5 +1,4 @@
 #include "stdafx.h"
-#include "Utilities/Config.h"
 #include "Emu/Memory/Memory.h"
 #include "Emu/System.h"
 #include "Emu/IdManager.h"
@@ -22,7 +21,9 @@
 #include "sys_fs.h"
 #include "sys_process.h"
 
-LOG_CHANNEL(sys_process);
+#include <thread>
+
+logs::channel sys_process("sys_process", logs::level::notice);
 
 s32 process_getpid()
 {
@@ -61,7 +62,7 @@ s32 sys_process_exit(s32 status)
 	{
 		CHECK_EMU_STATUS;
 
-		std::this_thread::sleep_for(std::chrono::milliseconds(1));
+		std::this_thread::sleep_for(1ms);
 	}
 
 	return CELL_OK;
@@ -88,7 +89,7 @@ s32 sys_process_get_number_of_object(u32 object, vm::ptr<u32> nump)
 	case SYS_LWMUTEX_OBJECT: *nump = idm::get_count<lv2_lwmutex_t>(); break;
 	case SYS_TIMER_OBJECT: *nump = idm::get_count<lv2_timer_t>(); break;
 	case SYS_SEMAPHORE_OBJECT: *nump = idm::get_count<lv2_sema_t>(); break;
-	case SYS_FS_FD_OBJECT: throw EXCEPTION("SYS_FS_FD_OBJECT");
+	case SYS_FS_FD_OBJECT: *nump = idm::get_count<lv2_fs_object_t>(); break;
 	case SYS_LWCOND_OBJECT: *nump = idm::get_count<lv2_lwcond_t>(); break;
 	case SYS_EVENT_FLAG_OBJECT: *nump = idm::get_count<lv2_event_flag_t>(); break;
 
@@ -101,6 +102,17 @@ s32 sys_process_get_number_of_object(u32 object, vm::ptr<u32> nump)
 	return CELL_OK;
 }
 
+#include <set>
+
+template<typename T>
+void idm_get_set(std::set<u32>& out)
+{
+	idm::select<T>([&](u32 id, T&)
+	{
+		out.emplace(id);
+	});
+}
+
 s32 sys_process_get_id(u32 object, vm::ptr<u32> buffer, u32 size, vm::ptr<u32> set_size)
 {
 	sys_process.error("sys_process_get_id(object=0x%x, buffer=*0x%x, size=%d, set_size=*0x%x)", object, buffer, size, set_size);
@@ -109,24 +121,24 @@ s32 sys_process_get_id(u32 object, vm::ptr<u32> buffer, u32 size, vm::ptr<u32> s
 
 	switch (object)
 	{
-	case SYS_MEM_OBJECT: objects = idm::get_set<lv2_memory_t>(); break;
-	case SYS_MUTEX_OBJECT: objects = idm::get_set<lv2_mutex_t>(); break;
-	case SYS_COND_OBJECT: objects = idm::get_set<lv2_cond_t>(); break;
-	case SYS_RWLOCK_OBJECT: objects = idm::get_set<lv2_rwlock_t>(); break;
-	case SYS_INTR_TAG_OBJECT: objects = idm::get_set<lv2_int_tag_t>(); break;
-	case SYS_INTR_SERVICE_HANDLE_OBJECT: objects = idm::get_set<lv2_int_serv_t>(); break;
-	case SYS_EVENT_QUEUE_OBJECT: objects = idm::get_set<lv2_event_queue_t>(); break;
-	case SYS_EVENT_PORT_OBJECT: objects = idm::get_set<lv2_event_port_t>(); break;
+	case SYS_MEM_OBJECT: idm_get_set<lv2_memory_t>(objects); break;
+	case SYS_MUTEX_OBJECT: idm_get_set<lv2_mutex_t>(objects); break;
+	case SYS_COND_OBJECT: idm_get_set<lv2_cond_t>(objects); break;
+	case SYS_RWLOCK_OBJECT: idm_get_set<lv2_rwlock_t>(objects); break;
+	case SYS_INTR_TAG_OBJECT: idm_get_set<lv2_int_tag_t>(objects); break;
+	case SYS_INTR_SERVICE_HANDLE_OBJECT: idm_get_set<lv2_int_serv_t>(objects); break;
+	case SYS_EVENT_QUEUE_OBJECT: idm_get_set<lv2_event_queue_t>(objects); break;
+	case SYS_EVENT_PORT_OBJECT: idm_get_set<lv2_event_port_t>(objects); break;
 	case SYS_TRACE_OBJECT: throw EXCEPTION("SYS_TRACE_OBJECT");
 	case SYS_SPUIMAGE_OBJECT: throw EXCEPTION("SYS_SPUIMAGE_OBJECT");
-	case SYS_PRX_OBJECT: objects = idm::get_set<lv2_prx_t>(); break;
+	case SYS_PRX_OBJECT: idm_get_set<lv2_prx_t>(objects); break;
 	case SYS_SPUPORT_OBJECT: throw EXCEPTION("SYS_SPUPORT_OBJECT");
-	case SYS_LWMUTEX_OBJECT: objects = idm::get_set<lv2_lwmutex_t>(); break;
-	case SYS_TIMER_OBJECT: objects = idm::get_set<lv2_timer_t>(); break;
-	case SYS_SEMAPHORE_OBJECT: objects = idm::get_set<lv2_sema_t>(); break;
-	case SYS_FS_FD_OBJECT: throw EXCEPTION("SYS_FS_FD_OBJECT");
-	case SYS_LWCOND_OBJECT: objects = idm::get_set<lv2_lwcond_t>(); break;
-	case SYS_EVENT_FLAG_OBJECT: objects = idm::get_set<lv2_event_flag_t>(); break;
+	case SYS_LWMUTEX_OBJECT: idm_get_set<lv2_lwmutex_t>(objects); break;
+	case SYS_TIMER_OBJECT: idm_get_set<lv2_timer_t>(objects); break;
+	case SYS_SEMAPHORE_OBJECT: idm_get_set<lv2_sema_t>(objects); break;
+	case SYS_FS_FD_OBJECT: idm_get_set<lv2_fs_object_t>(objects); break;
+	case SYS_LWCOND_OBJECT: idm_get_set<lv2_lwcond_t>(objects); break;
+	case SYS_EVENT_FLAG_OBJECT: idm_get_set<lv2_event_flag_t>(objects); break;
 
 	default:
 	{
diff --git a/rpcs3/Emu/Cell/lv2/sys_prx.cpp b/rpcs3/Emu/Cell/lv2/sys_prx.cpp
index 99ec5b9ac5..a7cf11a62c 100644
--- a/rpcs3/Emu/Cell/lv2/sys_prx.cpp
+++ b/rpcs3/Emu/Cell/lv2/sys_prx.cpp
@@ -1,5 +1,4 @@
 #include "stdafx.h"
-#include "Utilities/Config.h"
 #include "Emu/Memory/Memory.h"
 #include "Emu/System.h"
 #include "Emu/IdManager.h"
@@ -9,7 +8,7 @@
 #include "Emu/Cell/ErrorCodes.h"
 #include "sys_prx.h"
 
-LOG_CHANNEL(sys_prx);
+logs::channel sys_prx("sys_prx", logs::level::notice);
 
 s32 prx_load_module(std::string path, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt)
 {
diff --git a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp
index 5d4d8ee83d..df512caf7a 100644
--- a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp
+++ b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp
@@ -1,12 +1,11 @@
 #include "stdafx.h"
-#include "Utilities/Config.h"
 #include "Emu/Memory/Memory.h"
 #include "Emu/System.h"
 
 #include "Emu/Cell/ErrorCodes.h"
 #include "sys_rsx.h"
 
-LOG_CHANNEL(sys_rsx);
+logs::channel sys_rsx("sys_rsx", logs::level::notice);
 
 s32 sys_rsx_device_open()
 {
diff --git a/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp b/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp
index 351d9ca7bb..89c43c48f5 100644
--- a/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp
+++ b/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp
@@ -1,5 +1,4 @@
 #include "stdafx.h"
-#include "Utilities/Config.h"
 #include "Emu/Memory/Memory.h"
 #include "Emu/System.h"
 #include "Emu/IdManager.h"
@@ -8,7 +7,7 @@
 #include "Emu/Cell/PPUThread.h"
 #include "sys_rwlock.h"
 
-LOG_CHANNEL(sys_rwlock);
+logs::channel sys_rwlock("sys_rwlock", logs::level::notice);
 
 extern u64 get_system_time();
 
@@ -19,8 +18,8 @@ void lv2_rwlock_t::notify_all(lv2_lock_t)
 	{
 		writer = std::static_pointer_cast<cpu_thread>(wsq.front()->shared_from_this());
 
-		ASSERT(!writer->state.test_and_set(cpu_state::signal));
-		writer->notify();
+		VERIFY(!writer->state.test_and_set(cpu_state::signal));
+		(*writer)->notify();
 
 		return wsq.pop_front();
 	}
@@ -32,8 +31,8 @@ void lv2_rwlock_t::notify_all(lv2_lock_t)
 
 		for (auto& thread : rsq)
 		{
-			ASSERT(!thread->state.test_and_set(cpu_state::signal));
-			thread->notify();
+			VERIFY(!thread->state.test_and_set(cpu_state::signal));
+			(*thread)->notify();
 		}
 
 		return rsq.clear();
diff --git a/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp b/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp
index ec49e8c24d..c22bfa8a17 100644
--- a/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp
+++ b/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp
@@ -1,5 +1,4 @@
 #include "stdafx.h"
-#include "Utilities/Config.h"
 #include "Emu/Memory/Memory.h"
 #include "Emu/System.h"
 #include "Emu/IdManager.h"
@@ -8,7 +7,7 @@
 #include "Emu/Cell/PPUThread.h"
 #include "sys_semaphore.h"
 
-LOG_CHANNEL(sys_semaphore);
+logs::channel sys_semaphore("sys_semaphore", logs::level::notice);
 
 extern u64 get_system_time();
 
@@ -174,8 +173,8 @@ s32 sys_semaphore_post(u32 sem_id, s32 count)
 		count--;
 
 		auto& thread = sem->sq.front();
-		ASSERT(!thread->state.test_and_set(cpu_state::signal));
-		thread->notify();
+		VERIFY(!thread->state.test_and_set(cpu_state::signal));
+		(*thread)->notify();
 
 		sem->sq.pop_front();
 	}
diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.cpp b/rpcs3/Emu/Cell/lv2/sys_spu.cpp
index cdccda8e14..5ffa71ca81 100644
--- a/rpcs3/Emu/Cell/lv2/sys_spu.cpp
+++ b/rpcs3/Emu/Cell/lv2/sys_spu.cpp
@@ -1,5 +1,4 @@
 #include "stdafx.h"
-#include "Utilities/Config.h"
 #include "Emu/Memory/Memory.h"
 #include "Emu/System.h"
 #include "Emu/IdManager.h"
@@ -12,7 +11,7 @@
 #include "sys_event.h"
 #include "sys_spu.h"
 
-LOG_CHANNEL(sys_spu);
+logs::channel sys_spu("sys_spu", logs::level::notice);
 
 void LoadSpuImage(const fs::file& stream, u32& spu_ep, u32 addr)
 {
@@ -20,7 +19,7 @@ void LoadSpuImage(const fs::file& stream, u32& spu_ep, u32 addr)
 
 	if (loader != elf_error::ok)
 	{
-		throw fmt::exception("Failed to load SPU image: %s" HERE, bijective_find<elf_error>(loader, "???"));
+		throw fmt::exception("Failed to load SPU image: %s" HERE, loader.get_error());
 	}
 
 	for (const auto& prog : loader.progs)
@@ -323,7 +322,7 @@ s32 sys_spu_thread_group_start(u32 id)
 		if (thread)
 		{
 			thread->state -= cpu_state::stop;
-			thread->lock_notify();
+			(*thread)->lock_notify();
 		}
 	}
 
@@ -421,7 +420,7 @@ s32 sys_spu_thread_group_resume(u32 id)
 		if (thread)
 		{
 			thread->state -= cpu_state::suspend;
-			thread->lock_notify();
+			(*thread)->lock_notify();
 		}
 	}
 
@@ -504,7 +503,7 @@ s32 sys_spu_thread_group_terminate(u32 id, s32 value)
 		if (thread)
 		{
 			thread->state += cpu_state::stop;
-			thread->lock_notify();
+			(*thread)->lock_notify();
 		}
 	}
 
@@ -563,7 +562,7 @@ s32 sys_spu_thread_group_join(u32 id, vm::ptr<u32> cause, vm::ptr<u32> status)
 
 		CHECK_EMU_STATUS;
 
-		group->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
+		group->cv.wait_for(lv2_lock, 1ms);
 	}
 
 	switch (group->join_state & ~SPU_TGJSF_IS_JOINING)
diff --git a/rpcs3/Emu/Cell/lv2/sys_sync.h b/rpcs3/Emu/Cell/lv2/sys_sync.h
index e96c05f9f8..dbe76cf817 100644
--- a/rpcs3/Emu/Cell/lv2/sys_sync.h
+++ b/rpcs3/Emu/Cell/lv2/sys_sync.h
@@ -1,6 +1,8 @@
 #pragma once
 
 #include "Utilities/SleepQueue.h"
+#include <mutex>
+#include <condition_variable>
 
 namespace vm { using namespace ps3; }
 
@@ -43,7 +45,6 @@ enum
 	SYS_SYNC_NOT_ADAPTIVE = 0x2000,
 };
 
-extern std::mutex& get_current_thread_mutex();
 extern std::condition_variable& get_current_thread_cv();
 
 // Simple class for global mutex to pass unique_lock and check it
@@ -56,8 +57,8 @@ struct lv2_lock_t
 	lv2_lock_t(type& lv2_lock)
 		: ref(lv2_lock)
 	{
-		Expects(ref.owns_lock());
-		Expects(ref.mutex() == &mutex);
+		EXPECTS(ref.owns_lock());
+		EXPECTS(ref.mutex() == &mutex);
 	}
 
 	operator type&() const
diff --git a/rpcs3/Emu/Cell/lv2/sys_time.cpp b/rpcs3/Emu/Cell/lv2/sys_time.cpp
index 39f4b1a156..e9a60295de 100644
--- a/rpcs3/Emu/Cell/lv2/sys_time.cpp
+++ b/rpcs3/Emu/Cell/lv2/sys_time.cpp
@@ -1,5 +1,4 @@
 #include "stdafx.h"
-#include "Utilities/Config.h"
 #include "Emu/Memory/Memory.h"
 #include "Emu/System.h"
 
@@ -45,7 +44,7 @@ const g_time_aux_info = []() -> time_aux_info_t // initialize time-related value
 
 #endif
 
-LOG_CHANNEL(sys_time);
+logs::channel sys_time("sys_time", logs::level::notice);
 
 static const u64 g_timebase_freq = /*79800000*/ 80000000; // 80 Mhz
 
diff --git a/rpcs3/Emu/Cell/lv2/sys_timer.cpp b/rpcs3/Emu/Cell/lv2/sys_timer.cpp
index 5944157ad2..d4edeea141 100644
--- a/rpcs3/Emu/Cell/lv2/sys_timer.cpp
+++ b/rpcs3/Emu/Cell/lv2/sys_timer.cpp
@@ -1,5 +1,4 @@
 #include "stdafx.h"
-#include "Utilities/Config.h"
 #include "Emu/Memory/Memory.h"
 #include "Emu/System.h"
 #include "Emu/IdManager.h"
@@ -9,10 +8,14 @@
 #include "sys_process.h"
 #include "sys_timer.h"
 
-LOG_CHANNEL(sys_timer);
+#include <thread>
+
+logs::channel sys_timer("sys_timer", logs::level::notice);
 
 extern u64 get_system_time();
 
+extern std::mutex& get_current_thread_mutex();
+
 void lv2_timer_t::on_task()
 {
 	std::unique_lock<std::mutex> lock(get_current_thread_mutex());
@@ -51,7 +54,7 @@ void lv2_timer_t::on_task()
 			continue;
 		}
 
-		get_current_thread_cv().wait_for(lock, std::chrono::milliseconds(1));
+		get_current_thread_cv().wait_for(lock, 1ms);
 	}
 }
 
@@ -64,7 +67,7 @@ void lv2_timer_t::on_stop()
 {
 	// Signal thread using invalid state and join
 	state = -1;
-	lock_notify();
+	(*this)->lock_notify();
 	named_thread::on_stop();
 }
 
@@ -170,7 +173,7 @@ s32 _sys_timer_start(u32 timer_id, u64 base_time, u64 period)
 	timer->period = period;
 	timer->state  = SYS_TIMER_STATE_RUN;
 
-	timer->lock_notify();
+	(*timer)->lock_notify();
 
 	return CELL_OK;
 }
@@ -244,6 +247,8 @@ s32 sys_timer_disconnect_event_queue(u32 timer_id)
 	return CELL_OK;
 }
 
+#include <thread>
+
 s32 sys_timer_sleep(u32 sleep_time)
 {
 	sys_timer.trace("sys_timer_sleep(sleep_time=%d)", sleep_time);
@@ -258,7 +263,7 @@ s32 sys_timer_sleep(u32 sleep_time)
 	{
 		CHECK_EMU_STATUS;
 
-		std::this_thread::sleep_for(std::chrono::milliseconds(1));
+		std::this_thread::sleep_for(1ms);
 	}
 	
 	if (useconds > passed)
@@ -281,7 +286,7 @@ s32 sys_timer_usleep(const u64 sleep_time)
 	{
 		CHECK_EMU_STATUS;
 
-		std::this_thread::sleep_for(std::chrono::milliseconds(1));
+		std::this_thread::sleep_for(1ms);
 	}
 
 	if (sleep_time > passed)
diff --git a/rpcs3/Emu/Cell/lv2/sys_trace.cpp b/rpcs3/Emu/Cell/lv2/sys_trace.cpp
index 78a10eb063..bf5fc20c61 100644
--- a/rpcs3/Emu/Cell/lv2/sys_trace.cpp
+++ b/rpcs3/Emu/Cell/lv2/sys_trace.cpp
@@ -1,12 +1,11 @@
 #include "stdafx.h"
-#include "Utilities/Config.h"
 #include "Emu/Memory/Memory.h"
 #include "Emu/System.h"
 
 #include "Emu/Cell/ErrorCodes.h"
 #include "sys_trace.h"
 
-LOG_CHANNEL(sys_trace);
+logs::channel sys_trace("sys_trace", logs::level::notice);
 
 s32 sys_trace_create()
 {
diff --git a/rpcs3/Emu/Cell/lv2/sys_tty.cpp b/rpcs3/Emu/Cell/lv2/sys_tty.cpp
index c91ded14f4..4a9b62ca72 100644
--- a/rpcs3/Emu/Cell/lv2/sys_tty.cpp
+++ b/rpcs3/Emu/Cell/lv2/sys_tty.cpp
@@ -1,12 +1,11 @@
 #include "stdafx.h"
-#include "Utilities/Config.h"
 #include "Emu/Memory/Memory.h"
 #include "Emu/System.h"
 
 #include "Emu/Cell/ErrorCodes.h"
 #include "sys_tty.h"
 
-LOG_CHANNEL(sys_tty);
+logs::channel sys_tty("sys_tty", logs::level::notice);
 
 extern fs::file g_tty;
 
diff --git a/rpcs3/Emu/Cell/lv2/sys_vm.cpp b/rpcs3/Emu/Cell/lv2/sys_vm.cpp
index 22492efb6e..8c5ec0613c 100644
--- a/rpcs3/Emu/Cell/lv2/sys_vm.cpp
+++ b/rpcs3/Emu/Cell/lv2/sys_vm.cpp
@@ -1,5 +1,4 @@
 #include "stdafx.h"
-#include "Utilities/Config.h"
 #include "Emu/Memory/Memory.h"
 #include "Emu/System.h"
 #include "Emu/IdManager.h"
@@ -8,7 +7,7 @@
 #include "sys_memory.h"
 #include "sys_vm.h"
 
-LOG_CHANNEL(sys_vm);
+logs::channel sys_vm("sys_vm", logs::level::notice);
 
 s32 sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr<u32> addr)
 {