From a33575b1152b77b0ce9d31acc411812ea436d311 Mon Sep 17 00:00:00 2001
From: Nekotekina <fbx@3mf.ru>
Date: Mon, 10 Mar 2014 03:07:53 +0400
Subject: [PATCH 1/5] Compilation fix

---
 rpcs3/Emu/Cell/PPUThread.h             |  2 +-
 rpcs3/Emu/SysCalls/Modules/cellSpurs.h | 21 ++++++++++++++-------
 2 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h
index fbb53bf1ae..0302180399 100644
--- a/rpcs3/Emu/Cell/PPUThread.h
+++ b/rpcs3/Emu/Cell/PPUThread.h
@@ -526,7 +526,7 @@ static const s32 MAX_INT_VALUE = 0x7fffffff;
 class PPUThread : public PPCThread
 {
 public:
-	std::atomic<u32> owned_mutexes;
+	u32 owned_mutexes;
 
 public:
 	PPCdouble FPR[32]; //Floating Point Register
diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.h b/rpcs3/Emu/SysCalls/Modules/cellSpurs.h
index af9f4c4e6c..bc9f70b848 100644
--- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.h
+++ b/rpcs3/Emu/SysCalls/Modules/cellSpurs.h
@@ -87,7 +87,8 @@ struct CellSpursTraceInfo
 	//u8 padding[]; 
 };
 
-__declspec(align(8)) struct CellTraceHeader 
+//__declspec(align(8))
+struct CellTraceHeader 
 { 
 	u8 tag; 
 	u8 length; 
@@ -135,17 +136,20 @@ struct CellSpursTracePacket
 	} data;
 };
 
-__declspec(align(128)) struct CellSpurs
+//__declspec(align(128))
+struct CellSpurs
 { 
 	u8 skip[CELL_SPURS_SIZE];  
 };
 
-__declspec(align(128)) struct CellSpurs2
+//__declspec(align(128))
+struct CellSpurs2
 { 
 	u8 skip[CELL_SPURS_SIZE2 - CELL_SPURS_SIZE];
 };
 
-__declspec(align(8)) struct CellSpursAttribute
+//__declspec(align(8))
+struct CellSpursAttribute
 { 
 	u8 skip[CELL_SPURS_ATTRIBUTE_SIZE];  
 };
@@ -184,7 +188,8 @@ enum
 };
 
 
-__declspec(align(128)) struct CellSpursTaskset 
+//__declspec(align(128))
+struct CellSpursTaskset 
 {
 	u8 skip[6400];
 };
@@ -217,7 +222,8 @@ struct CellSpursTasksetInfo
 #define CELL_SPURS_TASKSET_SIZE                   CELL_SPURS_TASKSET_CLASS0_SIZE
 */
 
-__declspec(align(128)) struct CellSpursTaskset2 
+//__declspec(align(128))
+struct CellSpursTaskset2 
 {
 	be_t<u8> skip[10496];
 };
@@ -267,7 +273,8 @@ struct CellSpursTaskAttribute2
 	//be_t<u32> __reserved__[]; 
 };
 
-__declspec(align(128)) struct CellSpursTaskExitCode 
+//__declspec(align(128))
+struct CellSpursTaskExitCode 
 {
 	unsigned char skip[128];
 };

From 7f7d5a57c80a1308ae206890267359c9a7d2242f Mon Sep 17 00:00:00 2001
From: Nekotekina <fbx@3mf.ru>
Date: Tue, 11 Mar 2014 20:20:01 +0400
Subject: [PATCH 2/5] rldcr, rldcl instructions

Some intructions fixed
---
 rpcs3/Emu/CPU/CPUThread.cpp     |  2 +-
 rpcs3/Emu/Cell/PPUDisAsm.h      |  7 +++++
 rpcs3/Emu/Cell/PPUInstrTable.h  |  3 ++-
 rpcs3/Emu/Cell/PPUInterpreter.h | 48 ++++++++++++++++++++++++++-------
 rpcs3/Emu/Cell/PPUOpcodes.h     |  2 ++
 5 files changed, 50 insertions(+), 12 deletions(-)

diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp
index 1ec31434b2..ec21cc80a1 100644
--- a/rpcs3/Emu/CPU/CPUThread.cpp
+++ b/rpcs3/Emu/CPU/CPUThread.cpp
@@ -393,7 +393,7 @@ s64 CPUThread::ExecAsCallback(u64 pc, bool wait, u64 a1, u64 a2, u64 a3, u64 a4)
 	{
 		if (Emu.IsStopped())
 		{
-			ConLog.Warning("ExecAsCallback() aborted");
+			ConLog.Warning("ExecAsCallback(wait=%s) aborted", wxString(wait ? "true" : false).wx_str());
 			return CELL_EABORT; // doesn't mean anything
 		}
 		Sleep(1);
diff --git a/rpcs3/Emu/Cell/PPUDisAsm.h b/rpcs3/Emu/Cell/PPUDisAsm.h
index a5cbf1775b..c904350589 100644
--- a/rpcs3/Emu/Cell/PPUDisAsm.h
+++ b/rpcs3/Emu/Cell/PPUDisAsm.h
@@ -1206,6 +1206,13 @@ private:
 	{
 		DisAsm_R2_INT2_RC("rldimi", ra, rs, sh, mb, rc);
 	}
+	void RLDC_LR(u32 ra, u32 rs, u32 rb, u32 m_eb, bool is_r, bool rc)
+	{
+		if (is_r)
+			DisAsm_R3_INT2_RC("rldcr", ra, rs, rb, m_eb, 0, rc);
+		else
+			DisAsm_R3_INT2_RC("rldcl", ra, rs, rb, m_eb, 0, rc);
+	}
 	void CMP(u32 crfd, u32 l, u32 ra, u32 rb)
 	{
 		DisAsm_CR1_R2(wxString::Format("cmp%s", wxString(l ? "d" : "w").wx_str()), crfd, ra, rb);
diff --git a/rpcs3/Emu/Cell/PPUInstrTable.h b/rpcs3/Emu/Cell/PPUInstrTable.h
index e82c02abdb..a65c9224a0 100644
--- a/rpcs3/Emu/Cell/PPUInstrTable.h
+++ b/rpcs3/Emu/Cell/PPUInstrTable.h
@@ -193,7 +193,7 @@ namespace PPU_instr
 	static CodeField<26, 31> GD_04; //0x3f
 	static CodeField<21, 31> GD_04_0;//0x7ff
 	static CodeField<21, 30> GD_13; //0x3ff
-	static CodeField<28, 29> GD_1e; //0x3
+	static CodeField<27, 29> GD_1e; //0x7
 	static CodeField<21, 30> GD_1f; //0x3ff
 	static CodeField<30, 31> GD_3a; //0x3
 	static CodeField<26, 30> GD_3b; //0x1f
@@ -441,6 +441,7 @@ namespace PPU_instr
 	bind_instr(g1e_list, RLDICR, RA, RS, sh, me, RC);
 	bind_instr(g1e_list, RLDIC, RA, RS, sh, mb, RC);
 	bind_instr(g1e_list, RLDIMI, RA, RS, sh, mb, RC);
+	bind_instr(g1e_list, RLDC_LR, RA, RS, RB, mb, AA, RC);
 
 	/*0x000*/bind_instr(g1f_list, CMP, CRFD, L_10, RA, RB);
 	/*0x004*/bind_instr(g1f_list, TW, TO, RA, RB);
diff --git a/rpcs3/Emu/Cell/PPUInterpreter.h b/rpcs3/Emu/Cell/PPUInterpreter.h
index ea916d43b1..474cc75f25 100644
--- a/rpcs3/Emu/Cell/PPUInterpreter.h
+++ b/rpcs3/Emu/Cell/PPUInterpreter.h
@@ -2238,6 +2238,17 @@ private:
 		CPU.GPR[ra] = (CPU.GPR[ra] & ~mask) | (rotl64(CPU.GPR[rs], sh) & mask);
 		if(rc) CPU.UpdateCR0<s64>(CPU.GPR[ra]);
 	}
+	void RLDC_LR(u32 ra, u32 rs, u32 rb, u32 m_eb, bool is_r, bool rc)
+	{
+		if (is_r) // rldcr
+		{
+			RLDICR(ra, rs, CPU.GPR[rb], m_eb, rc);
+		}
+		else // rldcl
+		{
+			RLDICL(ra, rs, CPU.GPR[rb], m_eb, rc);
+		}
+	}
 	void CMP(u32 crfd, u32 l, u32 ra, u32 rb)
 	{
 		CPU.UpdateCRnS(l, crfd, CPU.GPR[ra], CPU.GPR[rb]);
@@ -2766,7 +2777,7 @@ private:
 	}
 	void MULLW(u32 rd, u32 ra, u32 rb, u32 oe, bool rc)
 	{
-		CPU.GPR[rd] = (s64)(s32)((s32)CPU.GPR[ra] * (s32)CPU.GPR[rb]);
+		CPU.GPR[rd] = (s64)((s64)(s32)CPU.GPR[ra] * (s64)(s32)CPU.GPR[rb]);
 		if(rc) CPU.UpdateCR0<s32>(CPU.GPR[rd]);
 		if(oe) UNK("mullwo");
 	}
@@ -2949,7 +2960,7 @@ private:
 		if (RB == 0 || ((u64)RA == (1ULL << 63) && RB == -1))
 		{
 			if(oe) UNK("divdo");
-			CPU.GPR[rd] = (((u64)RA & (1ULL << 63)) && RB == 0) ? -1 : 0;
+			CPU.GPR[rd] = /*(((u64)RA & (1ULL << 63)) && RB == 0) ? -1 :*/ 0;
 		}
 		else
 		{
@@ -2966,11 +2977,11 @@ private:
 		if (RB == 0 || ((u32)RA == (1 << 31) && RB == -1))
 		{
 			if(oe) UNK("divwo");
-			CPU.GPR[rd] = (((u32)RA & (1 << 31)) && RB == 0) ? -1 : 0;
+			CPU.GPR[rd] = /*(((u32)RA & (1 << 31)) && RB == 0) ? -1 :*/ 0;
 		}
 		else
 		{
-			CPU.GPR[rd] = (s64)(RA / RB);
+			CPU.GPR[rd] = (u32)(RA / RB);
 		}
 
 		if(rc) CPU.UpdateCR0<s32>(CPU.GPR[rd]);
@@ -3077,18 +3088,34 @@ private:
 	void SRAW(u32 ra, u32 rs, u32 rb, bool rc)
 	{
 		s32 RS = CPU.GPR[rs];
-		s32 RB = CPU.GPR[rb];
-		CPU.GPR[ra] = RS >> RB;
-		CPU.XER.CA = (RS < 0) & ((CPU.GPR[ra] << RB) != RS);
+		u8 shift = CPU.GPR[rb] & 63;
+		if (shift > 31)
+		{
+			CPU.GPR[ra] = 0 - (RS < 0);
+			CPU.XER.CA = (RS < 0);
+		}
+		else
+		{
+			CPU.GPR[ra] = RS >> shift;
+			CPU.XER.CA = (RS < 0) & ((CPU.GPR[ra] << shift) != RS);
+		}
 
 		if(rc) CPU.UpdateCR0<s64>(CPU.GPR[ra]);
 	}
 	void SRAD(u32 ra, u32 rs, u32 rb, bool rc)
 	{
 		s64 RS = CPU.GPR[rs];
-		s64 RB = CPU.GPR[rb];
-		CPU.GPR[ra] = RS >> RB;
-		CPU.XER.CA = (RS < 0) & ((CPU.GPR[ra] << RB) != RS);
+		u8 shift = CPU.GPR[rb] & 127;
+		if (shift > 63)
+		{
+			CPU.GPR[ra] = 0 - (RS < 0);
+			CPU.XER.CA = (RS < 0);
+		}
+		else
+		{
+			CPU.GPR[ra] = RS >> shift;
+			CPU.XER.CA = (RS < 0) & ((CPU.GPR[ra] << shift) != RS);
+		}
 
 		if(rc) CPU.UpdateCR0<s64>(CPU.GPR[ra]);
 	}
@@ -3162,6 +3189,7 @@ private:
 	void EXTSW(u32 ra, u32 rs, bool rc)
 	{
 		CPU.GPR[ra] = (s64)(s32)CPU.GPR[rs];
+		//CPU.XER.CA = ((s64)CPU.GPR[ra] < 0); // ???
 		if(rc) CPU.UpdateCR0<s32>(CPU.GPR[ra]);
 	}
 	/*0x3d6*///ICBI
diff --git a/rpcs3/Emu/Cell/PPUOpcodes.h b/rpcs3/Emu/Cell/PPUOpcodes.h
index 71a8d3b2f1..2d18686ecf 100644
--- a/rpcs3/Emu/Cell/PPUOpcodes.h
+++ b/rpcs3/Emu/Cell/PPUOpcodes.h
@@ -250,6 +250,7 @@ namespace PPU_opcodes
 		RLDICR 	= 0x1,
 		RLDIC 	= 0x2,
 		RLDIMI 	= 0x3,
+		RLDC_LR	= 0x4,
 	};
 
 	enum G_1fOpcodes //Field 21 - 30
@@ -644,6 +645,7 @@ public:
 	virtual void RLDICR(u32 ra, u32 rs, u32 sh, u32 me, bool rc) = 0;
 	virtual void RLDIC(u32 ra, u32 rs, u32 sh, u32 mb, bool rc) = 0;
 	virtual void RLDIMI(u32 ra, u32 rs, u32 sh, u32 mb, bool rc) = 0;
+	virtual void RLDC_LR(u32 ra, u32 rs, u32 rb, u32 m_eb, bool is_r, bool rc) = 0;
 	virtual void CMP(u32 crfd, u32 l, u32 ra, u32 rb) = 0;
 	virtual void TW(u32 to, u32 ra, u32 rb) = 0;
 	virtual void LVSL(u32 vd, u32 ra, u32 rb) = 0;

From 8cc6a287a7a599df34581fbd937e45ef2ccc8685 Mon Sep 17 00:00:00 2001
From: Nekotekina <fbx@3mf.ru>
Date: Thu, 13 Mar 2014 13:17:45 +0400
Subject: [PATCH 3/5] Update

---
 rpcs3/Emu/CPU/CPUThread.cpp             |   2 +-
 rpcs3/Emu/SysCalls/Modules/cellAdec.cpp | 117 +++++++++++++++++++-----
 rpcs3/Emu/SysCalls/Modules/cellAdec.h   |   3 +
 rpcs3/Emu/SysCalls/Modules/cellDmux.cpp |  81 +++++++++-------
 rpcs3/Emu/SysCalls/Modules/cellDmux.h   |  83 +++++++----------
 rpcs3/Emu/SysCalls/Modules/cellVdec.cpp |  30 +++---
 rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp   |   1 +
 7 files changed, 198 insertions(+), 119 deletions(-)

diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp
index ec21cc80a1..9df0cc6a9e 100644
--- a/rpcs3/Emu/CPU/CPUThread.cpp
+++ b/rpcs3/Emu/CPU/CPUThread.cpp
@@ -393,7 +393,7 @@ s64 CPUThread::ExecAsCallback(u64 pc, bool wait, u64 a1, u64 a2, u64 a3, u64 a4)
 	{
 		if (Emu.IsStopped())
 		{
-			ConLog.Warning("ExecAsCallback(wait=%s) aborted", wxString(wait ? "true" : false).wx_str());
+			ConLog.Warning("ExecAsCallback(wait=%s) aborted", wxString(wait ? "true" : "false").wx_str());
 			return CELL_EABORT; // doesn't mean anything
 		}
 		Sleep(1);
diff --git a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp
index 94a754d8e4..4147d21aaa 100644
--- a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp
+++ b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp
@@ -20,14 +20,66 @@ int adecRead(void* opaque, u8* buf, int buf_size)
 {
 	AudioDecoder& adec = *(AudioDecoder*)opaque;
 
-	if (adec.reader.size < (u32)buf_size)
+	int res = 0;
+
+next:
+	if (adec.reader.size < (u32)buf_size /*&& !vdec.just_started*/)
+	{
+		while (adec.job.IsEmpty())
+		{
+			if (Emu.IsStopped())
+			{
+				ConLog.Warning("vdecRead() aborted");
+				return 0;
+			}
+			Sleep(1);
+		}
+
+		switch (adec.job.Peek().type)
+		{
+		case adecEndSeq:
+			{
+				buf_size = adec.reader.size;
+			}
+			break;
+		case adecDecodeAu:
+			{
+				if (!Memory.CopyToReal(buf, adec.reader.addr, adec.reader.size))
+				{
+					ConLog.Error("adecRead: data reading failed (reader.size=0x%x)", adec.reader.size);
+					Emu.Pause();
+					return 0;
+				}
+
+				buf += adec.reader.size;
+				buf_size -= adec.reader.size;
+				res += adec.reader.size;
+
+				adec.adecCb->ExecAsCallback(adec.cbFunc, false, adec.id, CELL_ADEC_MSG_TYPE_AUDONE, adec.task.au.auInfo_addr, adec.cbArg);
+
+				adec.job.Pop(adec.task);
+
+				adec.reader.addr = adec.task.au.addr;
+				adec.reader.size = adec.task.au.size;
+
+				adec.last_pts = adec.task.au.pts;
+			}
+			break;
+		default:
+			ConLog.Error("adecRead(): sequence error (task %d)", adec.job.Peek().type);
+			return 0;
+		}
+
+		goto next;
+	}
+	else if (adec.reader.size < (u32)buf_size)
 	{
 		buf_size = adec.reader.size;
 	}
 
 	if (!buf_size)
 	{
-		return 0;
+		return res;
 	}
 	else if (!Memory.CopyToReal(buf, adec.reader.addr, buf_size))
 	{
@@ -39,7 +91,7 @@ int adecRead(void* opaque, u8* buf, int buf_size)
 	{
 		adec.reader.addr += buf_size;
 		adec.reader.size -= buf_size;
-		return 0 + buf_size;
+		return res + buf_size;
 	}
 }
 
@@ -59,7 +111,7 @@ u32 adecOpen(AudioDecoder* data)
 	{
 		ConLog.Write("Audio Decoder enter()");
 
-		AdecTask task;
+		AdecTask& task = adec.task;
 
 		while (true)
 		{
@@ -119,12 +171,12 @@ u32 adecOpen(AudioDecoder* data)
 
 			case adecDecodeAu:
 				{
-					int err;
+					int err = 0;
 
 					adec.reader.addr = task.au.addr;
 					adec.reader.size = task.au.size;
 
-					u64 last_pts = task.au.pts;
+					adec.last_pts = task.au.pts;
 
 					struct AVPacketHolder : AVPacket
 					{
@@ -160,7 +212,7 @@ u32 adecOpen(AudioDecoder* data)
 						if (Memory.CopyToReal(buf, task.au.addr, task.au.size)) dump.Write(buf, task.au.size);
 						free(buf);
 						dump.Close();
-					}
+					}*/
 
 					if (adec.just_started) // deferred initialization
 					{
@@ -171,6 +223,13 @@ u32 adecOpen(AudioDecoder* data)
 							Emu.Pause();
 							break;
 						}
+						AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_ATRAC3P); // ???
+						if (!codec)
+						{
+							ConLog.Error("adecDecodeAu: avcodec_find_decoder() failed");
+							Emu.Pause();
+							break;
+						}
 						err = avformat_find_stream_info(adec.fmt, NULL);
 						if (err)
 						{
@@ -185,16 +244,8 @@ u32 adecOpen(AudioDecoder* data)
 							break;
 						}
 						adec.ctx = adec.fmt->streams[0]->codec; // TODO: check data
-						
-						AVCodec* codec = avcodec_find_decoder(adec.ctx->codec_id); // ???
-						if (!codec)
-						{
-							ConLog.Error("adecDecodeAu: avcodec_find_decoder() failed");
-							Emu.Pause();
-							break;
-						}
 
-						AVDictionary* opts;
+						AVDictionary* opts = nullptr;
 						av_dict_set(&opts, "refcounted_frames", "1", 0);
 						{
 							SMutexGeneralLocker lock(g_mutex_avcodec_open2);
@@ -210,9 +261,17 @@ u32 adecOpen(AudioDecoder* data)
 						adec.just_started = false;
 					}
 
-					while (av_read_frame(adec.fmt, &au) >= 0)*/ while (true)
+					bool last_frame = false;
+
+					while (true)
 					{
-						if (!adec.ctx) // fake
+						if (Emu.IsStopped())
+						{
+							ConLog.Warning("adecDecodeAu aborted");
+							return;
+						}
+
+						/*if (!adec.ctx) // fake
 						{
 							AdecFrame frame;
 							frame.pts = task.au.pts;
@@ -223,13 +282,18 @@ u32 adecOpen(AudioDecoder* data)
 							frame.data = nullptr;
 							adec.frames.Push(frame);
 
-							/*Callback cb;
-							cb.SetAddr(adec.cbFunc);
-							cb.Handle(adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg);
-							cb.Branch(false);*/
 							adec.adecCb->ExecAsCallback(adec.cbFunc, false, adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg);
 
 							break;
+						}*/
+
+						last_frame = av_read_frame(adec.fmt, &au) < 0;
+						if (last_frame)
+						{
+							//break;
+							av_free(au.data);
+							au.data = NULL;
+							au.size = 0;
 						}
 
 						struct VdecFrameHolder : AdecFrame
@@ -261,10 +325,13 @@ u32 adecOpen(AudioDecoder* data)
 
 						int decode = avcodec_decode_audio4(adec.ctx, frame.data, &got_frame, &au);
 
-						if (decode < 0)
+						if (decode <= 0)
 						{
-							ConLog.Error("adecDecodeAu: AU decoding error(0x%x)", decode);
-							break;
+							if (!last_frame && decode < 0)
+							{
+								ConLog.Error("adecDecodeAu: AU decoding error(0x%x)", decode);
+							}
+							if (!got_frame && adec.reader.size == 0) break;
 						}
 
 						if (got_frame)
diff --git a/rpcs3/Emu/SysCalls/Modules/cellAdec.h b/rpcs3/Emu/SysCalls/Modules/cellAdec.h
index bab8ccd6c9..793a78905a 100644
--- a/rpcs3/Emu/SysCalls/Modules/cellAdec.h
+++ b/rpcs3/Emu/SysCalls/Modules/cellAdec.h
@@ -1064,6 +1064,9 @@ public:
 	const u32 cbArg;
 	u32 memBias;
 
+	AdecTask task;
+	u64 last_pts;
+
 	CPUThread* adecCb;
 
 	AudioDecoder(AudioCodecType type, u32 addr, u32 size, u32 func, u32 arg)
diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp
index 36b8ffef44..bc09f6777b 100644
--- a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp
+++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp
@@ -18,7 +18,7 @@ void dmuxQueryEsAttr(u32 info_addr /* may be 0 */, const mem_ptr_t<CellCodecEsFi
 					 const u32 esSpecificInfo_addr, mem_ptr_t<CellDmuxEsAttr> attr)
 {
 	if (esFilterId->filterIdMajor >= 0xe0)
-		attr->memSize = 0x1000000; // 0x45fa49 from ps3
+		attr->memSize = 0x3000000; // 0x45fa49 from ps3
 	else
 		attr->memSize = 0x200000; // 0x73d9 from ps3
 
@@ -156,6 +156,16 @@ u32 dmuxOpen(Demuxer* data)
 
 							//ConLog.Write("*** AT3+ AU sent (pts=0x%llx, dts=0x%llx)", pes.pts, pes.dts);
 
+							stream.skip(4);
+							len -= 4;
+							u32 abc;
+							stream.peek(abc);
+							if (abc == 0x5548D00F)
+							{
+								stream.skip(8);
+								len -= 8;
+							}
+
 							es.push(stream, len - pes.size - 3, pes);
 							es.finish(stream);
 							
@@ -231,7 +241,7 @@ u32 dmuxOpen(Demuxer* data)
 								continue;
 							}
 
-							//hack: reconstruction of MPEG2-PS stream for vdec module (seems it works without it too)
+							//reconstruction of MPEG2-PS stream for vdec module
 							stream = backup;
 							es.push(stream, len + 6 /*- pes.size - 3*/, pes);
 						}
@@ -288,18 +298,32 @@ u32 dmuxOpen(Demuxer* data)
 			{
 			case dmuxSetStream:
 				{
+					if (stream.discontinuity)
+					{
+						for (u32 i = 0; i < 192; i++)
+						{
+							if (esALL[i])
+							{
+								esALL[i]->reset();
+							}
+						}
+						updates_count = 0;
+						updates_signaled = 0;
+					}
+
+					if (updates_count != updates_signaled)
+					{
+						ConLog.Error("dmuxSetStream: stream update inconsistency (input=%d, signaled=%d)", updates_count, updates_signaled);
+						return;
+					}
+
+					updates_count++;
 					stream = task.stream;
 					ConLog.Write("*** stream updated(addr=0x%x, size=0x%x, discont=%d, userdata=0x%llx)",
 						stream.addr, stream.size, stream.discontinuity, stream.userdata);
-					if (stream.discontinuity) for (u32 i = 0; i < 192; i++)
-					{
-						if (esALL[i])
-						{
-							esALL[i]->reset();
-						}
-					}
-					updates_count++;
+
 					dmux.is_running = true;
+					dmux.fbSetStream.Push(task.stream.addr); // feedback
 				}
 				break;
 
@@ -592,12 +616,12 @@ int cellDmuxSetStream(u32 demuxerHandle, const u32 streamAddress, u32 streamSize
 		return CELL_DMUX_ERROR_FATAL;
 	}
 
-	while (dmux->is_running) // !!!
+	if (dmux->is_running)
 	{
 		if (Emu.IsStopped())
 		{
 			ConLog.Warning("cellDmuxSetStream(%d) aborted (waiting)", demuxerHandle);
-			break;
+			return CELL_OK;
 		}
 		Sleep(1);
 		return CELL_DMUX_ERROR_BUSY;
@@ -612,14 +636,16 @@ int cellDmuxSetStream(u32 demuxerHandle, const u32 streamAddress, u32 streamSize
 
 	dmux->job.Push(task);
 
-	while (!dmux->is_running)
+	u32 addr;
+	if (!dmux->fbSetStream.Pop(addr))
 	{
-		if (Emu.IsStopped())
-		{
-			ConLog.Warning("cellDmuxSetStream(%d) aborted", demuxerHandle);
-			break;
-		}
-		Sleep(1);
+		ConLog.Warning("cellDmuxSetStream(%d) aborted (fbSetStream.Pop())", demuxerHandle);
+		return CELL_OK;
+	}
+	if (addr != info.addr)
+	{
+		ConLog.Error("cellDmuxSetStream(%d): wrong stream queued (right=0x%x, queued=0x%x)", demuxerHandle, info.addr, addr);
+		Emu.Pause();
 	}
 	return CELL_OK;
 }
@@ -921,7 +947,7 @@ int cellDmuxPeekAuEx(u32 esHandle, mem32_t auInfoEx_ptr, mem32_t auSpecificInfo_
 
 int cellDmuxReleaseAu(u32 esHandle)
 {
-	cellDmux.Log("cellDmuxReleaseAu(esHandle=0x%x)", esHandle);
+	cellDmux.Log("(disabled) cellDmuxReleaseAu(esHandle=0x%x)", esHandle);
 
 	return CELL_OK;
 
@@ -931,21 +957,8 @@ int cellDmuxReleaseAu(u32 esHandle)
 		return CELL_DMUX_ERROR_ARG;
 	}
 
-	if (!es->canrelease())
-	{
-		cellDmux.Error("cellDmuxReleaseAu: no AU");
-		return CELL_DMUX_ERROR_SEQ;
-	}
-
-	/*DemuxerTask task(dmuxReleaseAu);
-	task.es.es = esHandle;
-	task.es.es_ptr = es;
-
-	es->dmux->job.Push(task);*/
-
 	if (!es->release())
 	{
-		cellDmux.Error("cellDmuxReleaseAu failed");
 		return CELL_DMUX_ERROR_SEQ;
 	}
 	return CELL_OK;
@@ -953,7 +966,7 @@ int cellDmuxReleaseAu(u32 esHandle)
 
 int cellDmuxFlushEs(u32 esHandle)
 {
-	cellDmux.Log("cellDmuxFlushEs(esHandle=0x%x)", esHandle);
+	cellDmux.Warning("cellDmuxFlushEs(esHandle=0x%x)", esHandle);
 
 	ElementaryStream* es;
 	if (!Emu.GetIdManager().GetIDData(esHandle, es))
diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.h b/rpcs3/Emu/SysCalls/Modules/cellDmux.h
index cc504fe2f0..ce55c27eb5 100644
--- a/rpcs3/Emu/SysCalls/Modules/cellDmux.h
+++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.h
@@ -304,11 +304,6 @@ enum
 	PRIVATE_STREAM_2         = 0x000001bf,
 };
 
-enum
-{
-	MAX_AU = 640 * 1024 + 128, // 640 KB
-};
-
 struct DemuxerStream
 {
 	u32 addr;
@@ -385,7 +380,7 @@ struct PesHeader
 				stream.get(v);
 				if (v != 0xFF) break; // skip padding bytes
 				empty++;
-				if (empty = size) return;
+				if (empty == size) return;
 			};
 
 			if ((v & 0xF0) == 0x20 && (size - empty) >= 5) // pts only
@@ -460,7 +455,8 @@ struct DemuxerTask
 class Demuxer
 {
 public:
-	SQueue<DemuxerTask> job;
+	SQueue<DemuxerTask, 32> job;
+	SQueue<u32, 16> fbSetStream;
 	const u32 memAddr;
 	const u32 memSize;
 	const u32 cbFunc;
@@ -491,6 +487,26 @@ class ElementaryStream
 	u32 last_addr; // AU that is being written now
 	u32 last_size; // number of bytes written (after 128b header)
 	u32 peek_addr; // AU that will be obtained by GetAu(Ex)/PeekAu(Ex)
+
+	bool is_full()
+	{
+		if (first_addr)
+		{
+			if (first_addr >= last_addr)
+			{
+				return (first_addr - last_addr) <= GetMaxAU();
+			}
+			else
+			{
+				// probably, always false
+				return (last_addr + GetMaxAU()) > (memAddr + memSize);
+			}
+		}
+		else
+		{
+			return false;
+		}
+	}
 	
 public:
 	Demuxer* dmux;
@@ -523,6 +539,11 @@ public:
 	{
 	}
 
+	const u32 GetMaxAU() const
+	{
+		return 640 * 1024 + 128;
+	}
+
 	volatile bool hasunseen()
 	{
 		return peek_addr;
@@ -536,21 +557,7 @@ public:
 	bool isfull()
 	{
 		SMutexLocker lock(mutex);
-		if (first_addr)
-		{
-			if (first_addr > last_addr)
-			{
-				return (first_addr - last_addr) < MAX_AU;
-			}
-			else
-			{
-				return (first_addr + MAX_AU) > (memAddr + memSize);
-			}
-		}
-		else
-		{
-			return false;
-		}
+		return is_full();
 	}
 
 	void finish(DemuxerStream& stream) // not multithread-safe
@@ -565,8 +572,9 @@ public:
 		{
 			peek_addr = last_addr;
 		}
+
 		u32 new_addr = a128(last_addr + 128 + last_size);
-		if ((new_addr + MAX_AU) > (memAddr + memSize))
+		if ((new_addr + GetMaxAU()) > (memAddr + memSize))
 		{
 			last_addr = memAddr;
 		}
@@ -581,24 +589,8 @@ public:
 	{
 		SMutexLocker lock(mutex);
 		//ConLog.Write("es::push(): peek=0x%x, first=0x%x, last=0x%x, size=0x%x", peek_addr, first_addr, last_addr, last_size);
-		bool is_full;
-		if (first_addr)
-		{
-			if (first_addr > last_addr)
-			{
-				is_full = (first_addr - last_addr) < MAX_AU;
-			}
-			else
-			{
-				is_full = (first_addr + MAX_AU) > (memAddr + memSize);
-			}
-		}
-		else
-		{
-			is_full = false;
-		}
 
-		if (is_full)
+		if (is_full())
 		{
 			ConLog.Error("ElementaryStream::push(): buffer is full");
 			Emu.Pause();
@@ -646,16 +638,11 @@ public:
 		}
 	}
 
-	volatile bool canrelease()
-	{
-		return first_addr;
-	}
-
 	bool release()
 	{
 		SMutexLocker lock(mutex);
 		//ConLog.Write("es::release(): peek=0x%x, first=0x%x, last=0x%x, size=0x%x", peek_addr, first_addr, last_addr, last_size);
-		if (!canrelease())
+		if (!first_addr)
 		{
 			ConLog.Error("ElementaryStream::release(): buffer is empty");
 			return false;
@@ -675,7 +662,7 @@ public:
 		{
 			first_addr = 0;
 		}
-		else if ((new_addr + MAX_AU) > (memAddr + memSize))
+		else if ((new_addr + GetMaxAU()) > (memAddr + memSize))
 		{
 			first_addr = memAddr;
 		}
@@ -706,7 +693,7 @@ public:
 			{
 				peek_addr = 0;
 			}
-			else if ((new_addr + MAX_AU) > (memAddr + memSize))
+			else if ((new_addr + GetMaxAU()) > (memAddr + memSize))
 			{
 				peek_addr = memAddr;
 			}
diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp
index 31fab366d6..5ea762662f 100644
--- a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp
+++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp
@@ -23,7 +23,8 @@ int vdecRead(void* opaque, u8* buf, int buf_size)
 
 	int res = 0;
 
-	if (vdec.reader.size < (u32)buf_size && !vdec.just_started)
+next:
+	if (vdec.reader.size < (u32)buf_size /*&& !vdec.just_started*/)
 	{
 		while (vdec.job.IsEmpty())
 		{
@@ -74,6 +75,8 @@ int vdecRead(void* opaque, u8* buf, int buf_size)
 			ConLog.Error("vdecRead(): sequence error (task %d)", vdec.job.Peek().type);
 			return 0;
 		}
+		
+		goto next;
 	}
 	else if (vdec.reader.size < (u32)buf_size)
 	{
@@ -235,14 +238,21 @@ u32 vdecOpen(VideoDecoder* data)
 
 					if (vdec.just_started) // deferred initialization
 					{
-						err = avformat_open_input(&vdec.fmt, NULL, NULL, NULL);
+						err = avformat_open_input(&vdec.fmt, NULL, av_find_input_format("mpeg"), NULL);
 						if (err)
 						{
 							ConLog.Error("vdecDecodeAu: avformat_open_input() failed");
 							Emu.Pause();
 							break;
 						}
-						err = avformat_find_stream_info(vdec.fmt, NULL);
+						AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_H264); // ???
+						if (!codec)
+						{
+							ConLog.Error("vdecDecodeAu: avcodec_find_decoder() failed");
+							Emu.Pause();
+							break;
+						}
+						/*err = avformat_find_stream_info(vdec.fmt, NULL);
 						if (err)
 						{
 							ConLog.Error("vdecDecodeAu: avformat_find_stream_info() failed");
@@ -254,17 +264,15 @@ u32 vdecOpen(VideoDecoder* data)
 							ConLog.Error("vdecDecodeAu: no stream found");
 							Emu.Pause();
 							break;
-						}
-						vdec.ctx = vdec.fmt->streams[0]->codec; // TODO: check data
-						
-						AVCodec* codec = avcodec_find_decoder(vdec.ctx->codec_id); // ???
-						if (!codec)
+						}*/
+						if (!avformat_new_stream(vdec.fmt, codec))
 						{
-							ConLog.Error("vdecDecodeAu: avcodec_find_decoder() failed");
+							ConLog.Error("vdecDecodeAu: avformat_new_stream() failed");
 							Emu.Pause();
 							break;
 						}
-
+						vdec.ctx = vdec.fmt->streams[0]->codec; // TODO: check data
+						
 						AVDictionary* opts = nullptr;
 						av_dict_set(&opts, "refcounted_frames", "1", 0);
 						{
@@ -292,6 +300,7 @@ u32 vdecOpen(VideoDecoder* data)
 							ConLog.Warning("vdecDecodeAu aborted");
 							return;
 						}
+
 						last_frame = av_read_frame(vdec.fmt, &au) < 0;
 						if (last_frame)
 						{
@@ -335,7 +344,6 @@ u32 vdecOpen(VideoDecoder* data)
 							if (!last_frame && decode < 0)
 							{
 								ConLog.Error("vdecDecodeAu: AU decoding error(0x%x)", decode);
-								break;
 							}
 							if (!got_picture && vdec.reader.size == 0) break; // video end?
 						}
diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp
index 10cd0af5ff..ab987cb8cd 100644
--- a/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp
+++ b/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp
@@ -198,6 +198,7 @@ bool SleepQueue::finalize()
 		}
 	}
 
+	m_mutex.unlock();
 	return true;
 }
 

From 2c447f686dc575d3264b8b7a26eb2e829a9fc2bb Mon Sep 17 00:00:00 2001
From: Nekotekina <fbx@3mf.ru>
Date: Thu, 13 Mar 2014 20:11:16 +0400
Subject: [PATCH 4/5] sys_spinlock implemented

---
 rpcs3/Emu/SysCalls/Modules/cellAdec.cpp      | 20 ++++----
 rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp     | 44 ++++++++---------
 rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp |  5 ++
 rpcs3/Emu/SysCalls/SysCalls.h                |  7 +++
 rpcs3/Emu/SysCalls/lv2/SC_Spinlock.cpp       | 51 ++++++++++++++++++++
 rpcs3/Emu/SysCalls/lv2/SC_Spinlock.h         |  6 +++
 rpcs3/rpcs3.vcxproj                          |  1 +
 rpcs3/rpcs3.vcxproj.filters                  |  3 ++
 8 files changed, 105 insertions(+), 32 deletions(-)
 create mode 100644 rpcs3/Emu/SysCalls/lv2/SC_Spinlock.cpp
 create mode 100644 rpcs3/Emu/SysCalls/lv2/SC_Spinlock.h

diff --git a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp
index 4147d21aaa..a2805567c4 100644
--- a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp
+++ b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp
@@ -23,13 +23,13 @@ int adecRead(void* opaque, u8* buf, int buf_size)
 	int res = 0;
 
 next:
-	if (adec.reader.size < (u32)buf_size /*&& !vdec.just_started*/)
+	if (adec.reader.size < (u32)buf_size /*&& !adec.just_started*/)
 	{
 		while (adec.job.IsEmpty())
 		{
 			if (Emu.IsStopped())
 			{
-				ConLog.Warning("vdecRead() aborted");
+				ConLog.Warning("adecRead() aborted");
 				return 0;
 			}
 			Sleep(1);
@@ -212,7 +212,7 @@ u32 adecOpen(AudioDecoder* data)
 						if (Memory.CopyToReal(buf, task.au.addr, task.au.size)) dump.Write(buf, task.au.size);
 						free(buf);
 						dump.Close();
-					}*/
+					}
 
 					if (adec.just_started) // deferred initialization
 					{
@@ -259,7 +259,7 @@ u32 adecOpen(AudioDecoder* data)
 							break;
 						}
 						adec.just_started = false;
-					}
+					}*/
 
 					bool last_frame = false;
 
@@ -271,7 +271,7 @@ u32 adecOpen(AudioDecoder* data)
 							return;
 						}
 
-						/*if (!adec.ctx) // fake
+						if (!adec.ctx) // fake
 						{
 							AdecFrame frame;
 							frame.pts = task.au.pts;
@@ -285,7 +285,7 @@ u32 adecOpen(AudioDecoder* data)
 							adec.adecCb->ExecAsCallback(adec.cbFunc, false, adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg);
 
 							break;
-						}*/
+						}
 
 						last_frame = av_read_frame(adec.fmt, &au) < 0;
 						if (last_frame)
@@ -296,14 +296,14 @@ u32 adecOpen(AudioDecoder* data)
 							au.size = 0;
 						}
 
-						struct VdecFrameHolder : AdecFrame
+						struct AdecFrameHolder : AdecFrame
 						{
-							VdecFrameHolder()
+							AdecFrameHolder()
 							{
 								data = av_frame_alloc();
 							}
 
-							~VdecFrameHolder()
+							~AdecFrameHolder()
 							{
 								if (data)
 								{
@@ -336,7 +336,7 @@ u32 adecOpen(AudioDecoder* data)
 
 						if (got_frame)
 						{
-							ConLog.Write("got_frame (%d, vdec: pts=0x%llx, dts=0x%llx)", got_frame, au.pts, au.dts);					
+							ConLog.Write("got_frame (%d, pts=0x%llx, dts=0x%llx)", got_frame, au.pts, au.dts);					
 
 							frame.pts = task.au.pts; // ???
 							frame.auAddr = task.au.addr;
diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp
index aca92144af..c211fa07d3 100644
--- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp
+++ b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp
@@ -9,7 +9,7 @@ Module cellSpurs(0x000a, cellSpurs_init);
 int _cellSpursAttributeInitialize(mem_ptr_t<CellSpursAttribute> attr, int nSpus, int spuPriority, 
 									int ppuPriority, bool exitIfNoWork)
 {
-	cellSpurs.Warning("cellSpursAttributeInitialize(attr_addr=0x%x, nSpus=%u, spuPriority=%u, ppuPriority=%u, exitIfNoWork=%u)",
+	cellSpurs.Error("_cellSpursAttributeInitialize(attr_addr=0x%x, nSpus=%u, spuPriority=%u, ppuPriority=%u, exitIfNoWork=%u)",
 						attr.GetAddr(), nSpus, spuPriority, ppuPriority, exitIfNoWork);
 	if(!attr.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
 
@@ -18,7 +18,7 @@ int _cellSpursAttributeInitialize(mem_ptr_t<CellSpursAttribute> attr, int nSpus,
 
 int cellSpursAttributeSetMemoryContainerForSpuThread(mem_ptr_t<CellSpursAttribute> attr, u32 container)
 {
-	cellSpurs.Warning("cellSpursAttributeSetMemoryContainerForSpuThread(attr_addr=0x%x, container=0x%x)",
+	cellSpurs.Error("cellSpursAttributeSetMemoryContainerForSpuThread(attr_addr=0x%x, container=0x%x)",
 						attr.GetAddr(), container);
 	if(!attr.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
 
@@ -27,7 +27,7 @@ int cellSpursAttributeSetMemoryContainerForSpuThread(mem_ptr_t<CellSpursAttribut
 
 int cellSpursAttributeSetNamePrefix(mem_ptr_t<CellSpursAttribute> attr, const mem8_t prefix, u32 size)
 {
-	cellSpurs.Warning("cellSpursAttributeSetNamePrefix(attr_addr=0x%x, prefix_addr=0x%x, size=0x%x)",
+	cellSpurs.Error("cellSpursAttributeSetNamePrefix(attr_addr=0x%x, prefix_addr=0x%x, size=0x%x)",
 						attr.GetAddr(), prefix.GetAddr(), size);
 	if(!attr.IsGood() || !prefix.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
 	if(size > 15) return CELL_SPURS_CORE_ERROR_INVAL;
@@ -37,7 +37,7 @@ int cellSpursAttributeSetNamePrefix(mem_ptr_t<CellSpursAttribute> attr, const me
 
 int cellSpursAttributeEnableSpuPrintfIfAvailable(mem_ptr_t<CellSpursAttribute> attr)
 {
-	cellSpurs.Warning("cellSpursAttributeEnableSpuPrintfIfAvailable(attr_addr=0x%x)", attr.GetAddr());
+	cellSpurs.Error("cellSpursAttributeEnableSpuPrintfIfAvailable(attr_addr=0x%x)", attr.GetAddr());
 	if(!attr.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
 
 	return CELL_OK;
@@ -45,7 +45,7 @@ int cellSpursAttributeEnableSpuPrintfIfAvailable(mem_ptr_t<CellSpursAttribute> a
 
 int cellSpursAttributeSetSpuThreadGroupType(mem_ptr_t<CellSpursAttribute> attr, int type)
 {
-	cellSpurs.Warning("cellSpursAttributeSetSpuThreadGroupType(attr_addr=0x%x, type=%u)", attr.GetAddr(), type);
+	cellSpurs.Error("cellSpursAttributeSetSpuThreadGroupType(attr_addr=0x%x, type=%u)", attr.GetAddr(), type);
 	if(!attr.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
 
 	return CELL_OK;
@@ -54,7 +54,7 @@ int cellSpursAttributeSetSpuThreadGroupType(mem_ptr_t<CellSpursAttribute> attr,
 int cellSpursAttributeEnableSystemWorkload(mem_ptr_t<CellSpursAttribute> attr, const u8 priority[8], 
 										   uint maxSpu, const bool isPreemptible[8])
 {
-	cellSpurs.Warning("cellSpursAttributeEnableSystemWorkload(attr_addr=0x%x, priority[%u], maxSpu=%u, isPreemptible[%u])",
+	cellSpurs.Error("cellSpursAttributeEnableSystemWorkload(attr_addr=0x%x, priority[%u], maxSpu=%u, isPreemptible[%u])",
 						attr.GetAddr(), priority, maxSpu, isPreemptible);
 	if(!attr.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
 	for (int i=0; i<8; i++)
@@ -65,7 +65,7 @@ int cellSpursAttributeEnableSystemWorkload(mem_ptr_t<CellSpursAttribute> attr, c
 
 int cellSpursInitializeWithAttribute2(mem_ptr_t<CellSpurs2> spurs, const mem_ptr_t<CellSpursAttribute> attr)
 {
-	cellSpurs.Warning("cellSpursInitializeWithAttribute2(spurs_addr=0x%x, spurs_addr=0x%x)",
+	cellSpurs.Error("cellSpursInitializeWithAttribute2(spurs_addr=0x%x, spurs_addr=0x%x)",
 						spurs.GetAddr(), attr.GetAddr());
 	if(!attr.IsGood() || !spurs.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
 
@@ -74,7 +74,7 @@ int cellSpursInitializeWithAttribute2(mem_ptr_t<CellSpurs2> spurs, const mem_ptr
 
 int cellSpursFinalize(mem_ptr_t<CellSpurs> spurs)
 {
-	cellSpurs.Warning("cellSpursFinalize(spurs_addr=0x%x)", spurs.GetAddr());
+	cellSpurs.Error("cellSpursFinalize(spurs_addr=0x%x)", spurs.GetAddr());
 	if(!spurs.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
 
 	return CELL_OK;
@@ -82,7 +82,7 @@ int cellSpursFinalize(mem_ptr_t<CellSpurs> spurs)
 
 int cellSpursGetSpuThreadGroupId(mem_ptr_t<CellSpurs> spurs, mem32_t group)
 {
-	cellSpurs.Warning("cellSpursGetSpuThreadGroupId(spurs_addr=0x%x, group_addr=0x%x)", 
+	cellSpurs.Error("cellSpursGetSpuThreadGroupId(spurs_addr=0x%x, group_addr=0x%x)", 
 		spurs.GetAddr(), group.GetAddr());
 	if(!spurs.IsGood() || group.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
 
@@ -91,7 +91,7 @@ int cellSpursGetSpuThreadGroupId(mem_ptr_t<CellSpurs> spurs, mem32_t group)
 
 int cellSpursGetNumSpuThread(mem_ptr_t<CellSpurs> spurs, mem32_t nThreads)
 {
-	cellSpurs.Warning("cellSpursGetNumSpuThread(spurs_addr=0x%x, nThreads_addr=0x%x)", 
+	cellSpurs.Error("cellSpursGetNumSpuThread(spurs_addr=0x%x, nThreads_addr=0x%x)", 
 		spurs.GetAddr(), nThreads.GetAddr());
 	if(!spurs.IsGood() || nThreads.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
 
@@ -100,7 +100,7 @@ int cellSpursGetNumSpuThread(mem_ptr_t<CellSpurs> spurs, mem32_t nThreads)
 
 int cellSpursGetSpuThreadId(mem_ptr_t<CellSpurs> spurs, mem32_t thread, mem32_t nThreads)
 {
-	cellSpurs.Warning("cellSpursGetSpuThreadId(spurs_addr=0x%x, thread_addr=0x%x, nThreads_addr=0x%x)", 
+	cellSpurs.Error("cellSpursGetSpuThreadId(spurs_addr=0x%x, thread_addr=0x%x, nThreads_addr=0x%x)", 
 		spurs.GetAddr(), thread.GetAddr(), nThreads.GetAddr());
 	if(!spurs.IsGood() || !thread.IsGood() || nThreads.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
 
@@ -109,7 +109,7 @@ int cellSpursGetSpuThreadId(mem_ptr_t<CellSpurs> spurs, mem32_t thread, mem32_t
 
 int cellSpursSetMaxContention(mem_ptr_t<CellSpurs> spurs, uint workloadId, uint maxContention)
 {
-	cellSpurs.Warning("cellSpursSetMaxContention(spurs_addr=0x%x, workloadId=%u, maxContention=%u)", 
+	cellSpurs.Error("cellSpursSetMaxContention(spurs_addr=0x%x, workloadId=%u, maxContention=%u)", 
 		spurs.GetAddr(), workloadId, maxContention);
 	if(!spurs.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
 
@@ -118,7 +118,7 @@ int cellSpursSetMaxContention(mem_ptr_t<CellSpurs> spurs, uint workloadId, uint
 
 int cellSpursSetPriorities(mem_ptr_t<CellSpurs> spurs, uint workloadId, const u8 priorities[CELL_SPURS_MAX_SPU])
 {
-	cellSpurs.Warning("cellSpursSetPriorities(spurs_addr=0x%x, workloadId=%u, priorities[%u])", 
+	cellSpurs.Error("cellSpursSetPriorities(spurs_addr=0x%x, workloadId=%u, priorities[%u])", 
 		spurs.GetAddr(), workloadId, priorities);
 	if(!spurs.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
 
@@ -127,7 +127,7 @@ int cellSpursSetPriorities(mem_ptr_t<CellSpurs> spurs, uint workloadId, const u8
 
 int cellSpursSetPriority(mem_ptr_t<CellSpurs> spurs, uint workloadId, uint spuId, uint priority)
 {
-	cellSpurs.Warning("cellSpursSetPriority(spurs_addr=0x%x, workloadId=%u, spuId=%u, priority=%u)", 
+	cellSpurs.Error("cellSpursSetPriority(spurs_addr=0x%x, workloadId=%u, spuId=%u, priority=%u)", 
 		spurs.GetAddr(), workloadId, spuId, priority);
 	if(!spurs.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
 
@@ -136,7 +136,7 @@ int cellSpursSetPriority(mem_ptr_t<CellSpurs> spurs, uint workloadId, uint spuId
 
 int cellSpursSetPreemptionVictimHints(mem_ptr_t<CellSpurs> spurs, const bool isPreemptible[8])
 {
-	cellSpurs.Warning("cellSpursSetPreemptionVictimHints(spurs_addr=0x%x, isPreemptible[%u])", 
+	cellSpurs.Error("cellSpursSetPreemptionVictimHints(spurs_addr=0x%x, isPreemptible[%u])", 
 						spurs.GetAddr(), isPreemptible);
 	if(!spurs.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
 
@@ -145,7 +145,7 @@ int cellSpursSetPreemptionVictimHints(mem_ptr_t<CellSpurs> spurs, const bool isP
 
 int cellSpursAttachLv2EventQueue(mem_ptr_t<CellSpurs> spurs, u32 queue, mem8_t port, int isDynamic)
 {
-	cellSpurs.Warning("cellSpursAttachLv2EventQueue(spurs_addr=0x%x, queue=0x%x, port_addr=0x%x, isDynamic=%u)", 
+	cellSpurs.Error("cellSpursAttachLv2EventQueue(spurs_addr=0x%x, queue=0x%x, port_addr=0x%x, isDynamic=%u)", 
 						spurs.GetAddr(), queue, port.GetAddr(), isDynamic);
 	if(!spurs.IsGood() || !port.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
 
@@ -154,7 +154,7 @@ int cellSpursAttachLv2EventQueue(mem_ptr_t<CellSpurs> spurs, u32 queue, mem8_t p
 
 int cellSpursDetachLv2EventQueue(mem_ptr_t<CellSpurs> spurs, u8 port)
 {
-	cellSpurs.Warning("cellSpursDetachLv2EventQueue(spurs_addr=0x%x, port=0x%x)", spurs.GetAddr(), port);
+	cellSpurs.Error("cellSpursDetachLv2EventQueue(spurs_addr=0x%x, port=0x%x)", spurs.GetAddr(), port);
 	if(!spurs.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
 
 	return CELL_OK;
@@ -162,7 +162,7 @@ int cellSpursDetachLv2EventQueue(mem_ptr_t<CellSpurs> spurs, u8 port)
 
 int cellSpursEnableExceptionEventHandler(mem_ptr_t<CellSpurs> spurs, bool flag)
 {
-	cellSpurs.Warning("cellSpursEnableExceptionEventHandler(spurs_addr=0x%x, flag=%u)", spurs.GetAddr(), flag);
+	cellSpurs.Error("cellSpursEnableExceptionEventHandler(spurs_addr=0x%x, flag=%u)", spurs.GetAddr(), flag);
 	if(!spurs.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
 
 	return CELL_OK;
@@ -171,7 +171,7 @@ int cellSpursEnableExceptionEventHandler(mem_ptr_t<CellSpurs> spurs, bool flag)
 int cellSpursSetGlobalExceptionEventHandler(mem_ptr_t<CellSpurs> spurs, 
 											mem_func_ptr_t<CellSpursGlobalExceptionEventHandler> eaHandler, mem_ptr_t<void> arg)
 {
-	cellSpurs.Warning("cellSpursEnableExceptionEventHandler(spurs_addr=0x%x, eaHandler_addr=0x%x, arg_addr=0x%x,)", 
+	cellSpurs.Error("cellSpursEnableExceptionEventHandler(spurs_addr=0x%x, eaHandler_addr=0x%x, arg_addr=0x%x,)", 
 		spurs.GetAddr(), eaHandler.GetAddr(), arg.GetAddr());
 	if(!spurs.IsGood() || eaHandler.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
 
@@ -180,7 +180,7 @@ int cellSpursSetGlobalExceptionEventHandler(mem_ptr_t<CellSpurs> spurs,
 
 int cellSpursUnsetGlobalExceptionEventHandler(mem_ptr_t<CellSpurs> spurs)
 {
-	cellSpurs.Warning("cellSpursUnsetGlobalExceptionEventHandler(spurs_addr=0x%x)", spurs.GetAddr());
+	cellSpurs.Error("cellSpursUnsetGlobalExceptionEventHandler(spurs_addr=0x%x)", spurs.GetAddr());
 	if(!spurs.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
 
 	return CELL_OK;
@@ -188,7 +188,7 @@ int cellSpursUnsetGlobalExceptionEventHandler(mem_ptr_t<CellSpurs> spurs)
 
 int cellSpursGetInfo(mem_ptr_t<CellSpurs> spurs, mem_ptr_t<CellSpursInfo> info)
 {
-	cellSpurs.Warning("cellSpursGetInfo(spurs_addr=0x%x, info_addr=0x%x)", spurs.GetAddr(), info.GetAddr());
+	cellSpurs.Error("cellSpursGetInfo(spurs_addr=0x%x, info_addr=0x%x)", spurs.GetAddr(), info.GetAddr());
 	if(!spurs.IsGood() || !info.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
 
 	return CELL_OK;
@@ -197,7 +197,7 @@ int cellSpursGetInfo(mem_ptr_t<CellSpurs> spurs, mem_ptr_t<CellSpursInfo> info)
 // Task functions
 int cellSpursGetTasksetId(mem_ptr_t<CellSpursTaskset> taskset, mem32_t workloadId)
 {
-	cellSpurs.Warning("cellSpursGetTasksetId(taskset_addr=0x%x, workloadId_addr=0x%x)", taskset.GetAddr(), workloadId.GetAddr());
+	cellSpurs.Error("cellSpursGetTasksetId(taskset_addr=0x%x, workloadId_addr=0x%x)", taskset.GetAddr(), workloadId.GetAddr());
 	if(!taskset.IsGood() || !taskset.IsGood()) return CELL_SPURS_TASK_ERROR_NULL_POINTER;
 
 	return CELL_OK;
diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp
index 175ea47fb5..945e925063 100644
--- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp
+++ b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp
@@ -185,6 +185,11 @@ void sysPrxForUser_init()
 	sysPrxForUser.AddFunc(0x52aadadf, sys_lwcond_signal_to);
 	sysPrxForUser.AddFunc(0x2a6d9d51, sys_lwcond_wait);
 
+	sysPrxForUser.AddFunc(0x8c2bb498, sys_spinlock_initialize);
+	sysPrxForUser.AddFunc(0xa285139d, sys_spinlock_lock);
+	sysPrxForUser.AddFunc(0x722a0254, sys_spinlock_trylock);
+	sysPrxForUser.AddFunc(0x5267cb35, sys_spinlock_unlock);
+
 	sysPrxForUser.AddFunc(0x67f9fedb, sys_game_process_exitspawn2);
 	sysPrxForUser.AddFunc(0xfc52a7a9, sys_game_process_exitspawn);
 
diff --git a/rpcs3/Emu/SysCalls/SysCalls.h b/rpcs3/Emu/SysCalls/SysCalls.h
index 9d75580371..0b06490c51 100644
--- a/rpcs3/Emu/SysCalls/SysCalls.h
+++ b/rpcs3/Emu/SysCalls/SysCalls.h
@@ -9,6 +9,7 @@
 #include "lv2/SC_Lwcond.h"
 #include "lv2/SC_Event_flag.h"
 #include "lv2/SC_Condition.h"
+#include "lv2/SC_Spinlock.h"
 #include "Emu/event.h"
 //#define SYSCALLS_DEBUG
 
@@ -200,6 +201,12 @@ extern int sys_rwlock_wlock(u32 rw_lock_id, u64 timeout);
 extern int sys_rwlock_trywlock(u32 rw_lock_id);
 extern int sys_rwlock_wunlock(u32 rw_lock_id);
 
+//sys_spinlock
+extern void sys_spinlock_initialize(mem_ptr_t<spinlock> lock);
+extern void sys_spinlock_lock(mem_ptr_t<spinlock> lock);
+extern int sys_spinlock_trylock(mem_ptr_t<spinlock> lock);
+extern void sys_spinlock_unlock(mem_ptr_t<spinlock> lock);
+
 //ppu_thread
 extern void sys_ppu_thread_exit(u64 errorcode);
 extern int sys_ppu_thread_yield();
diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Spinlock.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Spinlock.cpp
new file mode 100644
index 0000000000..90d9a35a3a
--- /dev/null
+++ b/rpcs3/Emu/SysCalls/lv2/SC_Spinlock.cpp
@@ -0,0 +1,51 @@
+#include "stdafx.h"
+#include "Emu/SysCalls/SysCalls.h"
+#include "Emu/SysCalls/lv2/SC_Spinlock.h"
+
+SysCallBase sys_spinlock("sys_spinlock");
+
+void sys_spinlock_initialize(mem_ptr_t<spinlock> lock)
+{
+	sys_spinlock.Log("sys_spinlock_initialize(lock_addr=0x%x)", lock.GetAddr());
+
+	lock->mutex.initialize();
+}
+
+void sys_spinlock_lock(mem_ptr_t<spinlock> lock)
+{
+	sys_spinlock.Log("sys_spinlock_lock(lock_addr=0x%x)", lock.GetAddr());
+
+	be_t<u32> tid = GetCurrentPPUThread().GetId();
+	switch (lock->mutex.lock(tid))
+	{
+	case SMR_ABORT: ConLog.Warning("sys_spinlock_lock(0x%x) aborted", lock.GetAddr()); break;
+	case SMR_DEADLOCK: ConLog.Error("sys_spinlock_lock(0x%x) reached deadlock", lock.GetAddr()); break; // ???
+	default: break;
+	}
+}
+
+int sys_spinlock_trylock(mem_ptr_t<spinlock> lock)
+{
+	sys_spinlock.Log("sys_spinlock_trylock(lock_addr=0x%x)", lock.GetAddr());
+
+	be_t<u32> tid = GetCurrentPPUThread().GetId();
+	switch (lock->mutex.trylock(tid))
+	{
+	case SMR_FAILED: return CELL_EBUSY;
+	case SMR_ABORT: ConLog.Warning("sys_spinlock_trylock(0x%x) aborted", lock.GetAddr()); break;
+	case SMR_DEADLOCK: ConLog.Error("sys_spinlock_trylock(0x%x) reached deadlock", lock.GetAddr()); break;
+	default: break;
+	}
+
+	return CELL_OK;
+}
+
+void sys_spinlock_unlock(mem_ptr_t<spinlock> lock)
+{
+	sys_spinlock.Log("sys_spinlock_unlock(lock_addr=0x%x)", lock.GetAddr());
+
+	switch (lock->mutex.unlock(lock->mutex.GetOwner()))
+	{
+	default: break;
+	}
+}
\ No newline at end of file
diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Spinlock.h b/rpcs3/Emu/SysCalls/lv2/SC_Spinlock.h
new file mode 100644
index 0000000000..0ff4af4029
--- /dev/null
+++ b/rpcs3/Emu/SysCalls/lv2/SC_Spinlock.h
@@ -0,0 +1,6 @@
+#pragma once
+
+struct spinlock
+{
+	SMutexBE mutex;
+};
\ No newline at end of file
diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj
index 1dfb346159..a02f6bf916 100644
--- a/rpcs3/rpcs3.vcxproj
+++ b/rpcs3/rpcs3.vcxproj
@@ -277,6 +277,7 @@
     <ClCompile Include="Emu\SysCalls\lv2\SC_RSX.cpp" />
     <ClCompile Include="Emu\SysCalls\lv2\SC_Rwlock.cpp" />
     <ClCompile Include="Emu\SysCalls\lv2\SC_Semaphore.cpp" />
+    <ClCompile Include="Emu\SysCalls\lv2\SC_Spinlock.cpp" />
     <ClCompile Include="Emu\SysCalls\lv2\SC_SPU_Thread.cpp" />
     <ClCompile Include="Emu\SysCalls\lv2\SC_Time.cpp" />
     <ClCompile Include="Emu\SysCalls\lv2\SC_Timer.cpp" />
diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters
index b10d1cb470..7e4015ba55 100644
--- a/rpcs3/rpcs3.vcxproj.filters
+++ b/rpcs3/rpcs3.vcxproj.filters
@@ -466,6 +466,9 @@
     <ClCompile Include="Emu\SysCalls\Modules\cellUserInfo.cpp">
       <Filter>Emu\SysCalls\Modules</Filter>
     </ClCompile>
+    <ClCompile Include="Emu\SysCalls\lv2\SC_Spinlock.cpp">
+      <Filter>Emu\SysCalls\lv2</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="rpcs3.rc" />

From 60d922da110d71d3ab701fb8f4312687583670d2 Mon Sep 17 00:00:00 2001
From: Nekotekina <fbx@3mf.ru>
Date: Sat, 15 Mar 2014 19:43:14 +0400
Subject: [PATCH 5/5] DMA List commands

cellAudio: multiple queue support
sys_cond simplified
cellFsMkdir (?)
---
 rpcs3/Emu/Audio/cellAudio.h              |   4 +-
 rpcs3/Emu/Cell/MFC.h                     |   5 +-
 rpcs3/Emu/Cell/SPUThread.h               | 117 ++++++++++++++++++++++-
 rpcs3/Emu/SysCalls/Modules/cellAudio.cpp |  56 ++++++++---
 rpcs3/Emu/SysCalls/lv2/SC_Condition.cpp  | 112 ++--------------------
 rpcs3/Emu/SysCalls/lv2/SC_Condition.h    |   1 +
 rpcs3/Emu/SysCalls/lv2/SC_Event.cpp      |   2 +-
 rpcs3/Emu/SysCalls/lv2/SC_FileSystem.cpp |   7 +-
 rpcs3/Emu/SysCalls/lv2/SC_Mutex.cpp      |  31 +-----
 rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp |  30 +-----
 rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.h   |  25 +++++
 11 files changed, 215 insertions(+), 175 deletions(-)

diff --git a/rpcs3/Emu/Audio/cellAudio.h b/rpcs3/Emu/Audio/cellAudio.h
index 7d492b0ba9..dc371c9c67 100644
--- a/rpcs3/Emu/Audio/cellAudio.h
+++ b/rpcs3/Emu/Audio/cellAudio.h
@@ -121,6 +121,7 @@ struct AudioPortConfig
 
 struct AudioConfig  //custom structure
 {
+	std::mutex m_mutex;
 	enum
 	{
 		AUDIO_PORT_COUNT = 8,
@@ -131,15 +132,14 @@ struct AudioConfig  //custom structure
 	bool m_is_audio_initialized;
 	bool m_is_audio_finalized;
 	u32 m_port_in_use;
-	u64 event_key;
 	u64 counter;
 	u64 start_time;
+	Array<u64> m_keys;
 
 	AudioConfig()
 		: m_is_audio_initialized(false)
 		, m_is_audio_finalized(false)
 		, m_port_in_use(0)
-		, event_key(0x80004d494f323221)
 		, counter(0)
 	{
 		memset(&m_ports, 0, sizeof(AudioPortConfig) * AUDIO_PORT_COUNT);
diff --git a/rpcs3/Emu/Cell/MFC.h b/rpcs3/Emu/Cell/MFC.h
index 6016924ae5..bef241c7b8 100644
--- a/rpcs3/Emu/Cell/MFC.h
+++ b/rpcs3/Emu/Cell/MFC.h
@@ -18,6 +18,7 @@ enum
 
 	MFC_BARRIER_MASK = 0x01,
 	MFC_FENCE_MASK   = 0x02,
+	MFC_LIST_MASK    = 0x04,
 	MFC_MASK_CMD     = 0xffff,
 };
 
@@ -165,7 +166,7 @@ struct DMAC
 		//returns true if the command should be deleted from the queue
 		if (cmd & (MFC_BARRIER_MASK | MFC_FENCE_MASK)) _mm_mfence();
 
-		switch(cmd & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK))
+		switch(cmd & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK | MFC_LIST_MASK))
 		{
 		case MFC_PUT_CMD:
 			Memory.Copy(ea, ls_offset + lsa, size);
@@ -176,7 +177,7 @@ struct DMAC
 		return true;
 
 		default:
-			ConLog.Error("Unknown DMA cmd.");
+			ConLog.Error("DMAC::ProcessCmd(): Unknown DMA cmd.");
 		return true;
 		}
 	}
diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h
index fcaccd72c9..cfed36752e 100644
--- a/rpcs3/Emu/Cell/SPUThread.h
+++ b/rpcs3/Emu/Cell/SPUThread.h
@@ -1,6 +1,7 @@
 #pragma once
 #include "PPCThread.h"
 #include "Emu/event.h"
+#include "Emu/SysCalls/lv2/SC_SPU_Thread.h"
 #include "MFC.h"
 #include <mutex>
 
@@ -484,6 +485,22 @@ public:
 		Channel<1> AtomicStat;
 	} Prxy;
 
+	struct StalledList
+	{
+		u32 lsa;
+		u64 ea;
+		u16 tag;
+		u16 size;
+		u32 cmd;
+		MFCReg* MFCArgs;
+
+		StalledList()
+			: MFCArgs(nullptr)
+		{
+		}
+	} StallList[32];
+	Channel<1> StallStat;
+
 	struct
 	{
 		Channel<1> Out_MBox;
@@ -505,6 +522,66 @@ public:
 
 	DMAC dmac;
 
+	void ListCmd(u32 lsa, u64 ea, u16 tag, u16 size, u32 cmd, MFCReg& MFCArgs)
+	{
+		u32 list_addr = ea & 0x3ffff;
+		u32 list_size = size / 8;
+		lsa &= 0x3fff0;
+
+		struct list_element
+		{
+			be_t<u16> s; // Stall-and-Notify bit (0x8000)
+			be_t<u16> ts; // List Transfer Size
+			be_t<u32> ea; // External Address Low
+		};
+
+		u32 result = MFC_PPU_DMA_CMD_SEQUENCE_ERROR;
+
+		for (u32 i = 0; i < list_size; i++)
+		{
+			mem_ptr_t<list_element> rec(dmac.ls_offset + list_addr + i * 8);
+
+			u32 size = rec->ts;
+			if (size < 16 && size != 1 && size != 2 && size != 4 && size != 8)
+			{
+				ConLog.Error("DMA List: invalid transfer size(%d)", size);
+				return;
+			}
+
+			u32 addr = rec->ea;
+			result = dmac.Cmd(cmd, tag, lsa | (addr & 0xf), addr, size);
+			if (result == MFC_PPU_DMA_CMD_SEQUENCE_ERROR)
+			{
+				break;
+			}
+
+			if (Ini.HLELogging.GetValue() || rec->s)
+				ConLog.Write("*** list element(%d/%d): s = 0x%x, ts = 0x%x, low ea = 0x%x (lsa = 0x%x)",
+					i, list_size, (u16)rec->s, (u16)rec->ts, (u32)rec->ea, lsa | (addr & 0xf));
+
+			lsa += max(size, (u32)16);
+
+			if (rec->s & se16(0x8000))
+			{
+				StallStat.PushUncond_OR(1 << tag);
+
+				if (StallList[tag].MFCArgs)
+				{
+					ConLog.Error("DMA List: existing stalled list found (tag=%d)", tag);
+				}
+				StallList[tag].MFCArgs = &MFCArgs;
+				StallList[tag].cmd = cmd;
+				StallList[tag].ea = (ea & ~0xffffffff) | (list_addr + (i + 1) * 8);
+				StallList[tag].lsa = lsa;
+				StallList[tag].size = (list_size - i - 1) * 8;
+
+				return;
+			}
+		}
+
+		MFCArgs.CMDStatus.SetValue(result);
+	}
+
 	void EnqMfcCmd(MFCReg& MFCArgs)
 	{
 		u32 cmd = MFCArgs.CMDStatus.GetValue();
@@ -528,7 +605,7 @@ public:
 				lsa, ea, tag, size, cmd);
 			if (op & MFC_PUT_CMD)
 			{
-				SMutexLocker lock(reservation.mutex);
+				SMutexLocker lock(reservation.mutex); // should be removed
 				MFCArgs.CMDStatus.SetValue(dmac.Cmd(cmd, tag, lsa, ea, size));
 				if ((reservation.addr + reservation.size > ea && reservation.addr <= ea + size) || 
 					(ea + size > reservation.addr && ea <= reservation.addr + reservation.size))
@@ -543,6 +620,19 @@ public:
 		}
 		break;
 
+		case MFC_PUTL_CMD:
+		case MFC_GETL_CMD:
+		{
+			if (Ini.HLELogging.GetValue()) ConLog.Write("DMA %s%s%s: lsa = 0x%x, list = 0x%llx, tag = 0x%x, size = 0x%x, cmd = 0x%x",
+				wxString(op & MFC_PUT_CMD ? "PUTL" : "GETL").wx_str(),
+				wxString(op & MFC_BARRIER_MASK ? "B" : "").wx_str(),
+				wxString(op & MFC_FENCE_MASK ? "F" : "").wx_str(),
+				lsa, ea, tag, size, cmd);
+
+			ListCmd(lsa, ea, tag, size, cmd, MFCArgs);
+		}
+		break;
+
 		case MFC_GETLLAR_CMD:
 		case MFC_PUTLLC_CMD:
 		case MFC_PUTLLUC_CMD:
@@ -628,6 +718,9 @@ public:
 		case MFC_RdTagStat:
 			return Prxy.TagStatus.GetCount();
 
+		case MFC_RdListStallStat:
+			return StallStat.GetCount();
+
 		case MFC_WrTagUpdate:
 			return Prxy.TagStatus.GetCount(); // hack
 
@@ -751,6 +844,24 @@ public:
 			EnqMfcCmd(MFC1);
 		break;
 
+		case MFC_WrListStallAck:
+		{
+			if (v >= 32)
+			{
+				ConLog.Error("MFC_WrListStallAck error: invalid tag(%d)", v);
+				return;
+			}
+			StalledList temp = StallList[v];
+			if (!temp.MFCArgs)
+			{
+				ConLog.Error("MFC_WrListStallAck error: empty tag(%d)", v);
+				return;
+			}
+			StallList[v].MFCArgs = nullptr;
+			ListCmd(temp.lsa, temp.ea, temp.tag, temp.size, temp.cmd, *temp.MFCArgs);
+		}
+		break;
+
 		default:
 			ConLog.Error("%s error: unknown/illegal channel (%d [%s]).", wxString(__FUNCTION__).wx_str(), ch, wxString(spu_ch_name[ch]).wx_str());
 		break;
@@ -790,6 +901,10 @@ public:
 			while (!Prxy.AtomicStat.Pop(v) && !Emu.IsStopped()) Sleep(1);
 		break;
 
+		case MFC_RdListStallStat:
+			while (!StallStat.Pop(v) && !Emu.IsStopped()) Sleep(1);
+		break;
+
 		default:
 			ConLog.Error("%s error: unknown/illegal channel (%d [%s]).", wxString(__FUNCTION__).wx_str(), ch, wxString(spu_ch_name[ch]).wx_str());
 		break;
diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp
index 1fb6dc72ff..f6ff6404b2 100644
--- a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp
+++ b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp
@@ -60,6 +60,8 @@ int cellAudioInit()
 			memset(buffer2, 0, sizeof(buffer2));
 			memset(oal_buffer.get(), 0, oal_buffer_size * sizeof(u16));
 
+			Array<u64> keys;
+
 			if(m_audio_out)
 			{
 				m_audio_out->Init();
@@ -144,8 +146,16 @@ int cellAudioInit()
 				}
 
 				// send aftermix event (normal audio event)
-				// TODO: check event source
-				Emu.GetEventManager().SendEvent(m_config.event_key, 0x10103000e010e07, 0, 0, 0);
+				{
+					std::lock_guard<std::mutex> lock(m_config.m_mutex);
+					keys.SetCount(m_config.m_keys.GetCount());
+					memcpy(keys.GetPtr(), m_config.m_keys.GetPtr(), sizeof(u64) * keys.GetCount());
+				}
+				for (u32 i = 0; i < keys.GetCount(); i++)
+				{
+					// TODO: check event source
+					Emu.GetEventManager().SendEvent(keys[i], 0x10103000e010e07, 0, 0, 0);
+				}
 
 				oal_buffer_offset += sizeof(buffer) / sizeof(float);
 
@@ -441,22 +451,27 @@ int cellAudioCreateNotifyEventQueue(mem32_t id, mem64_t key)
 {
 	cellAudio.Warning("cellAudioCreateNotifyEventQueue(id_addr=0x%x, key_addr=0x%x)", id.GetAddr(), key.GetAddr());
 
-	while (Emu.GetEventManager().CheckKey(m_config.event_key))
+	std::lock_guard<std::mutex> lock(m_config.m_mutex);
+
+	u64 event_key = 0;
+	while (Emu.GetEventManager().CheckKey((event_key << 48) | 0x80004d494f323221))
 	{
-		m_config.event_key++; // experimental
+		event_key++; // experimental
 		//return CELL_AUDIO_ERROR_EVENT_QUEUE;
 	}
+	event_key = (event_key << 48) | 0x80004d494f323221; // left part: 0x8000, 0x8001, 0x8002 ...
 
-	EventQueue* eq = new EventQueue(SYS_SYNC_FIFO, SYS_PPU_QUEUE, m_config.event_key, m_config.event_key, 32);
+	EventQueue* eq = new EventQueue(SYS_SYNC_FIFO, SYS_PPU_QUEUE, event_key, event_key, 32);
 
-	if (!Emu.GetEventManager().RegisterKey(eq, m_config.event_key))
+	if (!Emu.GetEventManager().RegisterKey(eq, event_key))
 	{
 		delete eq;
 		return CELL_AUDIO_ERROR_EVENT_QUEUE;
 	}
 
+	m_config.m_keys.AddCpy(event_key);
 	id = cellAudio.GetNewId(eq);
-	key = m_config.event_key;
+	key = event_key;
 
 	return CELL_OK;
 }
@@ -471,7 +486,9 @@ int cellAudioSetNotifyEventQueue(u64 key)
 {
 	cellAudio.Warning("cellAudioSetNotifyEventQueue(key=0x%llx)", key);
 
-	//m_config.event_key = key;
+	std::lock_guard<std::mutex> lock(m_config.m_mutex);
+
+	m_config.m_keys.AddCpy(key);
 
 	/*EventQueue* eq;
 	if (!Emu.GetEventManager().GetEventQueue(key, eq))
@@ -494,13 +511,30 @@ int cellAudioRemoveNotifyEventQueue(u64 key)
 {
 	cellAudio.Warning("cellAudioRemoveNotifyEventQueue(key=0x%llx)", key);
 
-	EventQueue* eq;
-	if (!Emu.GetEventManager().GetEventQueue(key, eq))
+	std::lock_guard<std::mutex> lock(m_config.m_mutex);
+
+	bool found = false;
+	for (u32 i = 0; i < m_config.m_keys.GetCount(); i++)
 	{
+		if (m_config.m_keys[i] == key)
+		{
+			m_config.m_keys.RemoveAt(i);
+			found = true;
+			break;
+		}
+	}
+
+	if (!found)
+	{
+		// ???
 		return CELL_AUDIO_ERROR_PARAM;
 	}
 
-	m_config.event_key = 0x80004d494f323221;
+	/*EventQueue* eq;
+	if (!Emu.GetEventManager().GetEventQueue(key, eq))
+	{
+		return CELL_AUDIO_ERROR_PARAM;
+	}*/
 
 	// TODO: disconnect port
 
diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Condition.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Condition.cpp
index 8f0785ab96..cc6a1d7c9d 100644
--- a/rpcs3/Emu/SysCalls/lv2/SC_Condition.cpp
+++ b/rpcs3/Emu/SysCalls/lv2/SC_Condition.cpp
@@ -71,48 +71,15 @@ int sys_cond_signal(u32 cond_id)
 	}
 
 	Mutex* mutex = cond->mutex;
-	u32 tid = GetCurrentPPUThread().GetId();
-
-	bool was_locked = (mutex->m_mutex.GetOwner() == tid);
 
 	if (u32 target = (mutex->protocol == SYS_SYNC_PRIORITY ? cond->m_queue.pop_prio() : cond->m_queue.pop()))
 	{
-		CPUThread* tt = Emu.GetCPU().GetThread(target);
-		bool valid = tt && tt->IsAlive();
-		if (!valid)
-		{
-			sys_cond.Error("sys_cond_signal(%d): signal to invalid thread(%d)", cond_id, target);
-			return CELL_OK;
-		}
+		cond->cond.lock(target);
 
-		if (!was_locked) // mutex hasn't been locked (don't care about mutex state)
+		if (Emu.IsStopped())
 		{
-			if (u32 owner = mutex->m_mutex.GetOwner())
-			{
-				tt = Emu.GetCPU().GetThread(owner);
-				valid = tt && tt->IsAlive();
-				if (!valid)
-				{
-					sys_cond.Error("sys_cond_signal(%d): deadlock on invalid thread(%d)", cond_id, owner);
-					return CELL_OK;
-				}
-			}
-			mutex->m_mutex.lock(tid);
-			mutex->recursive = 1;
-			mutex->m_mutex.unlock(tid, target);
+			ConLog.Warning("sys_cond_signal(id=%d) aborted", cond_id);
 		}
-		else // mutex has been locked (should preserve original mutex state)
-		{
-			mutex->recursive = 1;
-			mutex->m_mutex.unlock(tid, target);
-			mutex->m_mutex.lock(tid);
-			mutex->recursive = 1;
-		}
-	}
-
-	if (Emu.IsStopped())
-	{
-		ConLog.Warning("sys_cond_signal(id=%d) aborted", cond_id);
 	}
 
 	return CELL_OK;
@@ -129,43 +96,10 @@ int sys_cond_signal_all(u32 cond_id)
 	}
 
 	Mutex* mutex = cond->mutex;
-	u32 tid = GetCurrentPPUThread().GetId();
-
-	bool was_locked = (mutex->m_mutex.GetOwner() == tid);
 
 	while (u32 target = (mutex->protocol == SYS_SYNC_PRIORITY ? cond->m_queue.pop_prio() : cond->m_queue.pop()))
 	{
-		CPUThread* tt = Emu.GetCPU().GetThread(target);
-		bool valid = tt && tt->IsAlive();
-		if (!valid)
-		{
-			sys_cond.Error("sys_cond_signal_all(%d): signal to invalid thread(%d)", cond_id, target);
-			return CELL_OK;
-		}
-
-		if (!was_locked)
-		{
-			if (u32 owner = mutex->m_mutex.GetOwner())
-			{
-				tt = Emu.GetCPU().GetThread(owner);
-				valid = tt && tt->IsAlive();
-				if (!valid)
-				{
-					sys_cond.Error("sys_cond_signal_all(%d): deadlock on invalid thread(%d)", cond_id, owner);
-					return CELL_OK;
-				}
-			}
-			mutex->m_mutex.lock(tid);
-			mutex->recursive = 1;
-			mutex->m_mutex.unlock(tid, target);
-		}
-		else
-		{
-			mutex->recursive = 1;
-			mutex->m_mutex.unlock(tid, target);
-			mutex->m_mutex.lock(tid);
-			mutex->recursive = 1;
-		}
+		cond->cond.lock(target);
 
 		if (Emu.IsStopped())
 		{
@@ -197,35 +131,10 @@ int sys_cond_signal_to(u32 cond_id, u32 thread_id)
 	}
 
 	Mutex* mutex = cond->mutex;
-	u32 tid = GetCurrentPPUThread().GetId();
-
-	bool was_locked = (mutex->m_mutex.GetOwner() == tid);
 
 	u32 target = thread_id;
 	{
-		if (!was_locked)
-		{
-			if (u32 owner = mutex->m_mutex.GetOwner())
-			{
-				CPUThread* tt = Emu.GetCPU().GetThread(owner);
-				bool valid = tt && tt->IsAlive();
-				if (!valid)
-				{
-					sys_cond.Error("sys_cond_signal_to(%d): deadlock on invalid thread(%d)", cond_id, owner);
-					return CELL_OK;
-				}
-			}
-			mutex->m_mutex.lock(tid);
-			mutex->recursive = 1;
-			mutex->m_mutex.unlock(tid, target);
-		}
-		else
-		{
-			mutex->recursive = 1;
-			mutex->m_mutex.unlock(tid, target);
-			mutex->m_mutex.lock(tid);
-			mutex->recursive = 1;
-		}
+		cond->cond.lock(target);
 	}
 
 	if (Emu.IsStopped())
@@ -264,15 +173,11 @@ int sys_cond_wait(u32 cond_id, u64 timeout)
 
 	while (true)
 	{
-		/* switch (mutex->m_mutex.trylock(tid))
+		if (cond->cond.GetOwner() == tid)
 		{
-		case SMR_OK: mutex->m_mutex.unlock(tid); break;
-		case SMR_SIGNAL: mutex->recursive = 1; return CELL_OK;
-		} */
-		if (mutex->m_mutex.GetOwner() == tid)
-		{
-			_mm_mfence();
+			mutex->m_mutex.lock(tid);
 			mutex->recursive = 1;
+			cond->cond.unlock(tid);
 			return CELL_OK;
 		}
 
@@ -281,6 +186,7 @@ int sys_cond_wait(u32 cond_id, u64 timeout)
 		if (counter++ > max_counter)
 		{
 			cond->m_queue.invalidate(tid);
+			GetCurrentPPUThread().owned_mutexes--;
 			return CELL_ETIMEDOUT;
 		}
 		if (Emu.IsStopped())
diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Condition.h b/rpcs3/Emu/SysCalls/lv2/SC_Condition.h
index dc849948b4..460923a504 100644
--- a/rpcs3/Emu/SysCalls/lv2/SC_Condition.h
+++ b/rpcs3/Emu/SysCalls/lv2/SC_Condition.h
@@ -16,6 +16,7 @@ struct sys_cond_attribute
 struct Cond
 {
 	Mutex* mutex; // associated with mutex
+	SMutex cond;
 	SleepQueue m_queue;
 
 	Cond(Mutex* mutex, u64 name)
diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Event.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Event.cpp
index b662ee10c5..d6ea1a26a3 100644
--- a/rpcs3/Emu/SysCalls/lv2/SC_Event.cpp
+++ b/rpcs3/Emu/SysCalls/lv2/SC_Event.cpp
@@ -203,7 +203,7 @@ int sys_event_queue_receive(u32 equeue_id, mem_ptr_t<sys_event_data> event, u64
 				eq->owner.unlock(tid);
 				sys_event.Log(" *** event received: source=0x%llx, d1=0x%llx, d2=0x%llx, d3=0x%llx", 
 					(u64)event->source, (u64)event->data1, (u64)event->data2, (u64)event->data3);
-				/* HACK: passing event data in registers */
+				/* passing event data in registers */
 				PPUThread& t = GetCurrentPPUThread();
 				t.GPR[4] = event->source;
 				t.GPR[5] = event->data1;
diff --git a/rpcs3/Emu/SysCalls/lv2/SC_FileSystem.cpp b/rpcs3/Emu/SysCalls/lv2/SC_FileSystem.cpp
index dfbe386ca0..c006439d1e 100644
--- a/rpcs3/Emu/SysCalls/lv2/SC_FileSystem.cpp
+++ b/rpcs3/Emu/SysCalls/lv2/SC_FileSystem.cpp
@@ -324,10 +324,15 @@ int cellFsMkdir(u32 path_addr, u32 mode)
 	const wxString& ps3_path = Memory.ReadString(path_addr);
 	sys_fs.Log("cellFsMkdir(path=\"%s\", mode=0x%x)", ps3_path.wx_str(), mode);
 	
-	vfsDir dir;
+	/*vfsDir dir;
 	if(dir.IsExists(ps3_path))
 		return CELL_EEXIST;
 	if(!dir.Create(ps3_path))
+		return CELL_EBUSY;*/
+
+	if(Emu.GetVFS().ExistsDir(ps3_path))
+		return CELL_EEXIST;
+	if(!Emu.GetVFS().CreateDir(ps3_path))
 		return CELL_EBUSY;
 
 	return CELL_OK;
diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Mutex.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Mutex.cpp
index ce1b3f51d3..d0d2b3f962 100644
--- a/rpcs3/Emu/SysCalls/lv2/SC_Mutex.cpp
+++ b/rpcs3/Emu/SysCalls/lv2/SC_Mutex.cpp
@@ -98,8 +98,9 @@ int sys_mutex_lock(u32 mutex_id, u64 timeout)
 
 	PPUThread& t = GetCurrentPPUThread();
 	u32 tid = t.GetId();
-	u32 owner = mutex->m_mutex.GetOwner();
 
+	_mm_mfence();
+	u32 owner = mutex->m_mutex.GetOwner();
 	if (owner == tid)
 	{
 		if (mutex->is_recursive)
@@ -119,22 +120,10 @@ int sys_mutex_lock(u32 mutex_id, u64 timeout)
 	{
 		if (CPUThread* tt = Emu.GetCPU().GetThread(owner))
 		{
-			if (!tt->IsAlive())
-			{
-				if (owner == mutex->m_mutex.GetOwner()) sys_mtx.Error("sys_mutex_lock(%d): deadlock on invalid thread(%d)", mutex_id, owner);
-				/*mutex->m_mutex.unlock(owner, tid);
-				mutex->recursive = 1;
-				t.owned_mutexes++; 
-				return CELL_OK;*/
-			}
 		}
 		else
 		{
 			sys_mtx.Error("sys_mutex_lock(%d): deadlock on invalid thread(%d)", mutex_id, owner);
-			/*mutex->m_mutex.unlock(owner, tid);
-			mutex->recursive = 1;
-			t.owned_mutexes++; 
-			return CELL_OK;*/
 		}
 	}
 
@@ -180,8 +169,9 @@ int sys_mutex_trylock(u32 mutex_id)
 
 	PPUThread& t = GetCurrentPPUThread();
 	u32 tid = t.GetId();
-	u32 owner = mutex->m_mutex.GetOwner();
 
+	_mm_mfence();
+	u32 owner = mutex->m_mutex.GetOwner();
 	if (owner == tid)
 	{
 		if (mutex->is_recursive)
@@ -201,22 +191,10 @@ int sys_mutex_trylock(u32 mutex_id)
 	{
 		if (CPUThread* tt = Emu.GetCPU().GetThread(owner))
 		{
-			if (!tt->IsAlive())
-			{
-				if (owner == mutex->m_mutex.GetOwner()) sys_mtx.Error("sys_mutex_trylock(%d): deadlock on invalid thread(%d)", mutex_id, owner);
-				/*mutex->m_mutex.unlock(owner, tid);
-				mutex->recursive = 1;
-				t.owned_mutexes++; 
-				return CELL_OK;*/
-			}
 		}
 		else
 		{
 			sys_mtx.Error("sys_mutex_trylock(%d): deadlock on invalid thread(%d)", mutex_id, owner);
-			/*mutex->m_mutex.unlock(owner, tid);
-			mutex->recursive = 1;
-			t.owned_mutexes++; 
-			return CELL_OK;*/
 		}
 	}
 
@@ -241,6 +219,7 @@ int sys_mutex_unlock(u32 mutex_id)
 	PPUThread& t = GetCurrentPPUThread();
 	u32 tid = t.GetId();
 
+	_mm_mfence();
 	if (mutex->m_mutex.GetOwner() == tid)
 	{
 		if (!mutex->recursive || (mutex->recursive != 1 && !mutex->is_recursive))
diff --git a/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp b/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp
index 02b898207e..170343883c 100644
--- a/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp
+++ b/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp
@@ -9,32 +9,6 @@
 static SysCallBase sc_spu("sys_spu");
 extern SysCallBase sys_event;
 
-static const u32 g_spu_group_thr_max = 255;
-
-struct SpuGroupInfo
-{
-	Array<u32> list;
-	std::atomic<u32> lock;
-	wxString m_name;
-	int m_prio;
-	int m_type;
-	int m_ct;
-
-	SpuGroupInfo(wxString name, u32 num, int prio, int type, u32 ct) 
-		: m_name(name)
-		, m_prio(prio)
-		, m_type(type)
-		, m_ct(ct)
-		, lock(0)
-	{
-		list.SetCount(num);
-		for (u32 i = 0; i < num; i++)
-		{
-			list[i] = 0;
-		}
-	}
-};
-
 u32 LoadSpuImage(vfsStream& stream, u32& spu_ep)
 {
 	ELFLoader l(stream);
@@ -114,7 +88,7 @@ int sys_spu_thread_initialize(mem32_t thread, u32 group, u32 spu_num, mem_ptr_t<
 		return CELL_EFAULT;
 	}
 
-	if(spu_num >= g_spu_group_thr_max)
+	if(spu_num >= group_info->list.GetCount())
 	{
 		return CELL_EINVAL;
 	}
@@ -287,7 +261,7 @@ int sys_spu_thread_group_create(mem32_t id, u32 num, int prio, mem_ptr_t<sys_spu
 
 	if (!Memory.IsGoodAddr(attr->name_addr, attr->name_len)) return CELL_EFAULT;
 
-	if (num > g_spu_group_thr_max) return CELL_EINVAL;
+	if (num > 256) return CELL_EINVAL;
 
 	if (prio < 16 || prio > 255) return CELL_EINVAL;
 
diff --git a/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.h b/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.h
index 7d674155e4..1721b9c232 100644
--- a/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.h
+++ b/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.h
@@ -55,3 +55,28 @@ struct sys_spu_segment
 	be_t<int> size;
 	be_t<u64> src;
 };
+
+struct SpuGroupInfo
+{
+	Array<u32> list;
+	std::atomic<u32> lock;
+	wxString m_name;
+	int m_prio;
+	int m_type;
+	int m_ct;
+
+	SpuGroupInfo(wxString name, u32 num, int prio, int type, u32 ct) 
+		: m_name(name)
+		, m_prio(prio)
+		, m_type(type)
+		, m_ct(ct)
+		, lock(0)
+	{
+		num = 256;
+		list.SetCount(num);
+		for (u32 i = 0; i < num; i++)
+		{
+			list[i] = 0;
+		}
+	}
+};
\ No newline at end of file