/****************************************************************************
*                                                                           *
* Project 64 - A Nintendo 64 emulator.                                      *
* http://www.pj64-emu.com/                                                  *
* Copyright (C) 2012 Project64. All rights reserved.                        *
*                                                                           *
* License:                                                                  *
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html                        *
*                                                                           *
****************************************************************************/
#include "stdafx.h"

CCodeSection * CRecompilerOps::m_Section = NULL;
CRegInfo	   CRecompilerOps::m_RegWorkingSet;
STEP_TYPE      CRecompilerOps::m_NextInstruction;
DWORD          CRecompilerOps::m_CompilePC;
OPCODE         CRecompilerOps::m_Opcode;
DWORD          CRecompilerOps::m_BranchCompare = 0;

void CRecompilerOps::CompileReadTLBMiss (DWORD VirtualAddress, x86Reg LookUpReg ) 
{
	MoveConstToVariable(VirtualAddress,g_TLBLoadAddress,"TLBLoadAddress");
	TestX86RegToX86Reg(LookUpReg,LookUpReg);
	m_Section->CompileExit(m_CompilePC, m_CompilePC,m_RegWorkingSet,CExitInfo::TLBReadMiss,FALSE,JeLabel32);
}

void CRecompilerOps::CompileReadTLBMiss (x86Reg AddressReg, x86Reg LookUpReg ) 
{
	MoveX86regToVariable(AddressReg,g_TLBLoadAddress,"TLBLoadAddress");
	TestX86RegToX86Reg(LookUpReg,LookUpReg);
	m_Section->CompileExit(m_CompilePC, m_CompilePC,m_RegWorkingSet,CExitInfo::TLBReadMiss,FALSE,JeLabel32);
}

void CRecompilerOps::CompileWriteTLBMiss (x86Reg AddressReg, x86Reg LookUpReg ) 
{
	MoveX86regToVariable(AddressReg,&g_TLBStoreAddress,"g_TLBStoreAddress");
	TestX86RegToX86Reg(LookUpReg,LookUpReg);
	m_Section->CompileExit(m_CompilePC, m_CompilePC,m_RegWorkingSet,CExitInfo::TLBWriteMiss,FALSE,JeLabel32);
}

bool DelaySlotEffectsCompare ( DWORD PC, DWORD Reg1, DWORD Reg2 );

/************************** Branch functions  ************************/
void CRecompilerOps::Compile_Branch (CRecompilerOps::BranchFunction CompareFunc, BRANCH_TYPE BranchType, BOOL Link)
{
	static CRegInfo RegBeforeDelay;
	static bool EffectDelaySlot;

	if ( m_NextInstruction == NORMAL ) {
		CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
		
		if (m_CompilePC + ((short)m_Opcode.offset << 2) + 4 == m_CompilePC + 8)
		{
			return; 
		}

		if ((m_CompilePC & 0xFFC) != 0xFFC) 
		{
			switch (BranchType) {
			case BranchTypeRs: EffectDelaySlot = DelaySlotEffectsCompare(m_CompilePC,m_Opcode.rs,0); break;
			case BranchTypeRsRt: EffectDelaySlot = DelaySlotEffectsCompare(m_CompilePC,m_Opcode.rs,m_Opcode.rt); break;
			case BranchTypeCop1: 
				{
					OPCODE Command;

					if (!g_MMU->LW_VAddr(m_CompilePC + 4, Command.Hex)) {
						g_Notify->DisplayError(GS(MSG_FAIL_LOAD_WORD));
						ExitThread(0);
					}
					
					EffectDelaySlot = FALSE;
					if (Command.op == R4300i_CP1) {
						if (Command.fmt == R4300i_COP1_S && (Command.funct & 0x30) == 0x30 ) {
							EffectDelaySlot = TRUE;
						} 
						if (Command.fmt == R4300i_COP1_D && (Command.funct & 0x30) == 0x30 ) {
							EffectDelaySlot = TRUE;
						} 
					}
				}
				break;
			default:
				if (bHaveDebugger()) { g_Notify->DisplayError(L"Unknown branch type"); }
			}
		} else {
			EffectDelaySlot = true;
		}
		m_Section->m_Jump.JumpPC         = m_CompilePC;
		m_Section->m_Jump.TargetPC       = m_CompilePC + ((short)m_Opcode.offset << 2) + 4;
		if (m_Section->m_JumpSection != NULL) {
			m_Section->m_Jump.BranchLabel.Format("Section_%d",m_Section->m_JumpSection->m_SectionID);
		} else {
			m_Section->m_Jump.BranchLabel.Format("Exit_%X_jump_%X",m_Section->m_EnterPC,m_Section->m_Jump.TargetPC);
		}
		m_Section->m_Jump.LinkLocation    = NULL;
		m_Section->m_Jump.LinkLocation2   = NULL;
		m_Section->m_Jump.DoneDelaySlot   = FALSE;
		m_Section->m_Cont.JumpPC          = m_CompilePC;
		m_Section->m_Cont.TargetPC        = m_CompilePC + 8;
		if (m_Section->m_ContinueSection != NULL) {
			m_Section->m_Cont.BranchLabel.Format("Section_%d",m_Section->m_ContinueSection->m_SectionID);
		} else {
			m_Section->m_Cont.BranchLabel.Format("Exit_%X_continue_%X",m_Section->m_EnterPC,m_Section->m_Cont.TargetPC);
		}
		m_Section->m_Cont.LinkLocation    = NULL;
		m_Section->m_Cont.LinkLocation2   = NULL;
		m_Section->m_Cont.DoneDelaySlot   = FALSE;
		if (m_Section->m_Jump.TargetPC < m_Section->m_Cont.TargetPC) {
			m_Section->m_Cont.FallThrough = FALSE;
			m_Section->m_Jump.FallThrough = TRUE;
		} else {
			m_Section->m_Cont.FallThrough = TRUE;
			m_Section->m_Jump.FallThrough = FALSE;
		}

		if (Link) {
			UnMap_GPR( 31, FALSE);
			m_RegWorkingSet.SetMipsRegLo(31,m_CompilePC + 8);
			m_RegWorkingSet.SetMipsRegState(31,CRegInfo::STATE_CONST_32_SIGN);
		}
		if (EffectDelaySlot) {
			if ((m_CompilePC & 0xFFC) != 0xFFC) 
			{
				m_Section->m_Cont.BranchLabel = m_Section->m_ContinueSection != NULL ? "Continue" : "ExitBlock";
				m_Section->m_Jump.BranchLabel = m_Section->m_JumpSection != NULL ? "Jump" : "ExitBlock";
			} else {
				m_Section->m_Cont.BranchLabel = "Continue";
				m_Section->m_Jump.BranchLabel = "Jump";
			}			
			if (m_Section->m_Jump.TargetPC != m_Section->m_Cont.TargetPC) 
			{
				CompareFunc(); 
			}
			if (!m_Section->m_Jump.FallThrough && !m_Section->m_Cont.FallThrough) {
				if (m_Section->m_Jump.LinkLocation != NULL) {
					CPU_Message("");
					CPU_Message("      %s:",m_Section->m_Jump.BranchLabel.c_str());
					SetJump32((DWORD *)m_Section->m_Jump.LinkLocation,(DWORD *)m_RecompPos);
					m_Section->m_Jump.LinkLocation = NULL;
					if (m_Section->m_Jump.LinkLocation2 != NULL) {
						SetJump32((DWORD *)m_Section->m_Jump.LinkLocation2,(DWORD *)m_RecompPos);
						m_Section->m_Jump.LinkLocation2 = NULL;
					}
					m_Section->m_Jump.FallThrough = TRUE;
				} else if (m_Section->m_Cont.LinkLocation != NULL){
					CPU_Message("");
					CPU_Message("      %s:",m_Section->m_Cont.BranchLabel.c_str());
					SetJump32((DWORD *)m_Section->m_Cont.LinkLocation,(DWORD *)m_RecompPos);
					m_Section->m_Cont.LinkLocation = NULL;
					if (m_Section->m_Cont.LinkLocation2 != NULL) {
						SetJump32((DWORD *)m_Section->m_Cont.LinkLocation2,(DWORD *)m_RecompPos);
						m_Section->m_Cont.LinkLocation2 = NULL;
					}
					m_Section->m_Cont.FallThrough = TRUE;
				}
			}
			if ((m_CompilePC & 0xFFC) == 0xFFC) 
			{
				BYTE * DelayLinkLocation = NULL;
				if (m_Section->m_Jump.FallThrough)
				{
					if (m_Section->m_Jump.LinkLocation != NULL || m_Section->m_Jump.LinkLocation2 != NULL)
					{
						g_Notify->BreakPoint(__FILEW__,__LINE__);
					}
					MoveConstToVariable(m_Section->m_Jump.TargetPC,&R4300iOp::m_JumpToLocation,"R4300iOp::m_JumpToLocation");
				}
				else if (m_Section->m_Cont.FallThrough)
				{
					if (m_Section->m_Cont.LinkLocation != NULL || m_Section->m_Cont.LinkLocation2 != NULL)
					{
						g_Notify->BreakPoint(__FILEW__,__LINE__);
					}
					MoveConstToVariable(m_Section->m_Cont.TargetPC,&R4300iOp::m_JumpToLocation,"R4300iOp::m_JumpToLocation");
				}
				
				if (m_Section->m_Jump.LinkLocation != NULL || m_Section->m_Jump.LinkLocation2 != NULL)
				{
					JmpLabel8("DoDelaySlot",0);
					if (DelayLinkLocation != NULL) { g_Notify->BreakPoint(__FILEW__,__LINE__); }
					DelayLinkLocation = (BYTE *)(m_RecompPos - 1);

					CPU_Message("      ");
					CPU_Message("      %s:",m_Section->m_Jump.BranchLabel.c_str());
					SetJump32(m_Section->m_Jump.LinkLocation,(DWORD *)m_RecompPos);
					m_Section->m_Jump.LinkLocation = NULL;
					if (m_Section->m_Jump.LinkLocation2 != NULL) {
						SetJump32(m_Section->m_Jump.LinkLocation2,(DWORD *)m_RecompPos);
						m_Section->m_Jump.LinkLocation2 = NULL;
					}
					MoveConstToVariable(m_Section->m_Jump.TargetPC,&R4300iOp::m_JumpToLocation,"R4300iOp::m_JumpToLocation");
				}
				if (m_Section->m_Cont.LinkLocation != NULL || m_Section->m_Cont.LinkLocation2 != NULL)
				{
					JmpLabel8("DoDelaySlot",0);
					if (DelayLinkLocation != NULL) { g_Notify->BreakPoint(__FILEW__,__LINE__); }
					DelayLinkLocation = (BYTE *)(m_RecompPos - 1);

					CPU_Message("      ");
					CPU_Message("      %s:",m_Section->m_Cont.BranchLabel.c_str());
					SetJump32(m_Section->m_Cont.LinkLocation,(DWORD *)m_RecompPos);
					m_Section->m_Cont.LinkLocation = NULL;
					if (m_Section->m_Cont.LinkLocation2 != NULL) {
						SetJump32(m_Section->m_Cont.LinkLocation2,(DWORD *)m_RecompPos);
						m_Section->m_Cont.LinkLocation2 = NULL;
					}
					MoveConstToVariable(m_Section->m_Cont.TargetPC,&R4300iOp::m_JumpToLocation,"R4300iOp::m_JumpToLocation");
				}
				if (DelayLinkLocation)
				{
					CPU_Message("");
					CPU_Message("      DoDelaySlot:");
					SetJump8(DelayLinkLocation,m_RecompPos);
				}
				OverflowDelaySlot(false);
				return;
			}
			ResetX86Protection();
			RegBeforeDelay = m_RegWorkingSet;
		}
		m_NextInstruction = DO_DELAY_SLOT;
	} else if (m_NextInstruction == DELAY_SLOT_DONE ) {		
		if (EffectDelaySlot) { 
			CJumpInfo * FallInfo = m_Section->m_Jump.FallThrough?&m_Section->m_Jump:&m_Section->m_Cont;
			CJumpInfo * JumpInfo = m_Section->m_Jump.FallThrough?&m_Section->m_Cont:&m_Section->m_Jump;

			if (FallInfo->FallThrough && !FallInfo->DoneDelaySlot) {
				ResetX86Protection();
				FallInfo->RegSet = m_RegWorkingSet;
				if (FallInfo == &m_Section->m_Jump) {
					if (m_Section->m_JumpSection != NULL) {
						m_Section->m_Jump.BranchLabel.Format("Section_%d",m_Section->m_JumpSection->m_SectionID);
					} else {
						m_Section->m_Jump.BranchLabel = "ExitBlock";
					}
					if (FallInfo->TargetPC <= m_CompilePC) 
					{
						UpdateCounters(m_Section->m_Jump.RegSet,true,true);
						CPU_Message("CompileSystemCheck 12");
						CompileSystemCheck(FallInfo->TargetPC,m_Section->m_Jump.RegSet);
						ResetX86Protection();
						FallInfo->ExitReason = CExitInfo::Normal_NoSysCheck;
						FallInfo->JumpPC = (DWORD)-1;
					}
				} else {
					if (m_Section->m_ContinueSection != NULL) {
						m_Section->m_Cont.BranchLabel.Format("Section_%d",m_Section->m_ContinueSection->m_SectionID);
					} else {
						m_Section->m_Cont.BranchLabel = "ExitBlock";
					}
				}		
				FallInfo->DoneDelaySlot = TRUE;
				if (!JumpInfo->DoneDelaySlot) {
					FallInfo->FallThrough = FALSE;				
					JmpLabel32(FallInfo->BranchLabel.c_str(),0);
					FallInfo->LinkLocation = (DWORD *)(m_RecompPos - 4);
					
					if (JumpInfo->LinkLocation != NULL) {
						CPU_Message("      %s:",JumpInfo->BranchLabel.c_str());
						SetJump32((DWORD *)JumpInfo->LinkLocation,(DWORD *)m_RecompPos);
						JumpInfo->LinkLocation = NULL;
						if (JumpInfo->LinkLocation2 != NULL) {
							SetJump32((DWORD *)JumpInfo->LinkLocation2,(DWORD *)m_RecompPos);
							JumpInfo->LinkLocation2 = NULL;
						}
						JumpInfo->FallThrough = TRUE;
						m_NextInstruction = DO_DELAY_SLOT;
						m_RegWorkingSet = RegBeforeDelay;
						return; 
					}
				}
			}
		} else {
			if (m_Section->m_Jump.TargetPC != m_Section->m_Cont.TargetPC) 
			{
				CompareFunc();
				ResetX86Protection();
				m_Section->m_Cont.RegSet = m_RegWorkingSet;
				m_Section->m_Jump.RegSet = m_RegWorkingSet;
			} else {
				m_Section->m_Jump.FallThrough = false;
				m_Section->m_Cont.FallThrough = true;
				m_Section->m_Cont.RegSet = m_RegWorkingSet;
				if (m_Section->m_ContinueSection == NULL && m_Section->m_JumpSection != NULL)
				{
					m_Section->m_ContinueSection = m_Section->m_JumpSection;
					m_Section->m_JumpSection = NULL;
				}
				if (m_Section->m_ContinueSection != NULL) {
					m_Section->m_Cont.BranchLabel.Format("Section_%d",m_Section->m_ContinueSection->m_SectionID);
				} else {
					m_Section->m_Cont.BranchLabel = "ExitBlock";
				}
			}
		}
		m_Section->GenerateSectionLinkage();
		m_NextInstruction = END_BLOCK;
	} else {
		if (bHaveDebugger())
		{
			g_Notify->DisplayError(L"WTF\n\nBranch\nNextInstruction = %X", m_NextInstruction);
		}
	}
}

void CRecompilerOps::Compile_BranchLikely (BranchFunction CompareFunc, BOOL Link)
{
	if ( m_NextInstruction == NORMAL ) {		
		CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
		
		if (!g_System->bLinkBlocks() || (m_CompilePC & 0xFFC) == 0xFFC)
		{
			m_Section->m_Jump.JumpPC   = m_CompilePC;
			m_Section->m_Jump.TargetPC = m_CompilePC + ((short)m_Opcode.offset << 2) + 4;
			m_Section->m_Cont.JumpPC   = m_CompilePC;
			m_Section->m_Cont.TargetPC = m_CompilePC + 8;
		} else {
			if (m_Section->m_Jump.JumpPC != m_CompilePC)
			{
				g_Notify->BreakPoint(__FILEW__,__LINE__);
			}
			if (m_Section->m_Cont.JumpPC != m_CompilePC)
			{
				g_Notify->BreakPoint(__FILEW__,__LINE__);
			}
			if (m_Section->m_Cont.TargetPC != m_CompilePC + 8)
			{
				g_Notify->BreakPoint(__FILEW__,__LINE__);
			}
		}
		if (m_Section->m_JumpSection != NULL) {
			m_Section->m_Jump.BranchLabel.Format("Section_%d",((CCodeSection *)m_Section->m_JumpSection)->m_SectionID);
		} else {
			m_Section->m_Jump.BranchLabel = "ExitBlock";
		}
		if (m_Section->m_ContinueSection != NULL) {
			m_Section->m_Cont.BranchLabel.Format("Section_%d",((CCodeSection *)m_Section->m_ContinueSection)->m_SectionID);
		} else {
			m_Section->m_Cont.BranchLabel = "ExitBlock";
		}
		m_Section->m_Jump.FallThrough   = TRUE;
		m_Section->m_Jump.LinkLocation  = NULL;
		m_Section->m_Jump.LinkLocation2 = NULL;
		m_Section->m_Cont.FallThrough   = FALSE;
		m_Section->m_Cont.LinkLocation  = NULL;
		m_Section->m_Cont.LinkLocation2 = NULL;
		if (Link)
		{
			UnMap_GPR( 31, FALSE);
			m_RegWorkingSet.SetMipsRegLo(31, m_CompilePC + 8);
			m_RegWorkingSet.SetMipsRegState(31,CRegInfo::STATE_CONST_32_SIGN);
		}
		CompareFunc(); 
		ResetX86Protection();

		m_Section->m_Cont.RegSet = m_RegWorkingSet;
		if ((m_CompilePC & 0xFFC) == 0xFFC) 
		{
			if (m_Section->m_Cont.FallThrough) 
			{
				if (m_Section->m_Jump.LinkLocation != NULL)
				{
					g_Notify->BreakPoint(__FILEW__,__LINE__); 
				}
			}

			if (m_Section->m_Jump.LinkLocation != NULL || m_Section->m_Jump.FallThrough) 
			{
				if (m_Section->m_Jump.LinkLocation != NULL) {
					SetJump32(m_Section->m_Jump.LinkLocation,(DWORD *)m_RecompPos);
					m_Section->m_Jump.LinkLocation = NULL;
					if (m_Section->m_Jump.LinkLocation2 != NULL) { 
						SetJump32(m_Section->m_Jump.LinkLocation2,(DWORD *)m_RecompPos);
						m_Section->m_Jump.LinkLocation2 = NULL;
					}
				}
				
				MoveConstToVariable(m_Section->m_Jump.TargetPC,&R4300iOp::m_JumpToLocation,"R4300iOp::m_JumpToLocation");
				OverflowDelaySlot(false);
				CPU_Message("      ");
				CPU_Message("      %s:",m_Section->m_Cont.BranchLabel.c_str());
			} else if (!m_Section->m_Cont.FallThrough) {
				g_Notify->BreakPoint(__FILEW__,__LINE__);
			}

			if (m_Section->m_Cont.LinkLocation != NULL) {
				SetJump32(m_Section->m_Cont.LinkLocation,(DWORD *)m_RecompPos);
				m_Section->m_Cont.LinkLocation = NULL;
				if (m_Section->m_Cont.LinkLocation2 != NULL) { 
					SetJump32(m_Section->m_Cont.LinkLocation2,(DWORD *)m_RecompPos);
					m_Section->m_Cont.LinkLocation2 = NULL;
				}
			}
			m_Section->CompileExit(m_CompilePC, m_CompilePC + 8,m_Section->m_Cont.RegSet,CExitInfo::Normal,TRUE,NULL);
			return;
		} else {
			m_NextInstruction = DO_DELAY_SLOT;
		}

		if (g_System->bLinkBlocks())
		{
			m_Section->m_Jump.RegSet = m_RegWorkingSet;
			m_Section->GenerateSectionLinkage();
			m_NextInstruction = END_BLOCK;
		} else {
			if (m_Section->m_Cont.FallThrough)
			{
				if (m_Section->m_Jump.LinkLocation != NULL)
				{
					g_Notify->BreakPoint(__FILEW__,__LINE__);
				}
				m_Section->GenerateSectionLinkage();
				m_NextInstruction = END_BLOCK;
			}
		}
	} else if (m_NextInstruction == DELAY_SLOT_DONE ) {
		ResetX86Protection();
		m_Section->m_Jump.RegSet = m_RegWorkingSet;
		m_Section->GenerateSectionLinkage();
		m_NextInstruction = END_BLOCK;
	} else if (bHaveDebugger()) {
		g_Notify->DisplayError(L"WTF\n\nBranchLikely\nNextInstruction = %X", m_NextInstruction);
	}
}

void CRecompilerOps::BNE_Compare (void) 
{
	BYTE *Jump = NULL;

	if (IsKnown(m_Opcode.rs) && IsKnown(m_Opcode.rt)) {
		if (IsConst(m_Opcode.rs) && IsConst(m_Opcode.rt)) {
			if (Is64Bit(m_Opcode.rs) || Is64Bit(m_Opcode.rt)) {
				CRecompilerOps::UnknownOpcode();
			} else if (GetMipsRegLo(m_Opcode.rs) != GetMipsRegLo(m_Opcode.rt)) {
				m_Section->m_Jump.FallThrough = TRUE;
				m_Section->m_Cont.FallThrough = FALSE;
			} else {
				m_Section->m_Jump.FallThrough = FALSE;
				m_Section->m_Cont.FallThrough = TRUE;
			}
		} else if (IsMapped(m_Opcode.rs) && IsMapped(m_Opcode.rt)) {
			ProtectGPR(m_Opcode.rs);
			ProtectGPR(m_Opcode.rt);
			if (Is64Bit(m_Opcode.rs) || Is64Bit(m_Opcode.rt)) 
			{
				CompX86RegToX86Reg(
					Is32Bit(m_Opcode.rs)?Map_TempReg(x86_Any,m_Opcode.rs,TRUE):GetMipsRegMapHi(m_Opcode.rs),
					Is32Bit(m_Opcode.rt)?Map_TempReg(x86_Any,m_Opcode.rt,TRUE):GetMipsRegMapHi(m_Opcode.rt)
				);
					
				if (m_Section->m_Jump.FallThrough) {
					JneLabel8("continue",0);
					Jump = m_RecompPos - 1;
				} else {
					JneLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
					m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
				}
				CompX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rs),GetMipsRegMapLo(m_Opcode.rt));
				if (m_Section->m_Cont.FallThrough) {
					JneLabel32 ( m_Section->m_Jump.BranchLabel.c_str(), 0 );
					m_Section->m_Jump.LinkLocation2 = (DWORD *)(m_RecompPos - 4);
				} else if (m_Section->m_Jump.FallThrough) {
					JeLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
					m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
					CPU_Message("      ");
					CPU_Message("      continue:");
					SetJump8(Jump,m_RecompPos);
				} else {
					JeLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
					m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
					JmpLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
					m_Section->m_Jump.LinkLocation2 = (DWORD *)(m_RecompPos - 4);
				}
			} else {
				CompX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rs),GetMipsRegMapLo(m_Opcode.rt));
				if (m_Section->m_Cont.FallThrough) {
					JneLabel32 ( m_Section->m_Jump.BranchLabel.c_str(), 0 );
					m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
				} else if (m_Section->m_Jump.FallThrough) {
					JeLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
					m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
				} else {
					JeLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
					m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
					JmpLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
					m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
				}
			}
		} else {
			DWORD ConstReg = IsConst(m_Opcode.rt)?m_Opcode.rt:m_Opcode.rs;
			DWORD MappedReg = IsConst(m_Opcode.rt)?m_Opcode.rs:m_Opcode.rt;

			if (Is64Bit(ConstReg) || Is64Bit(MappedReg)) {
				if (Is32Bit(ConstReg) || Is32Bit(MappedReg)) {
					ProtectGPR(MappedReg);
					if (Is32Bit(MappedReg)) {
						CompConstToX86reg(Map_TempReg(x86_Any,MappedReg,TRUE),GetMipsRegHi(ConstReg));
					} else {
						CompConstToX86reg(GetMipsRegMapHi(MappedReg),GetMipsRegLo_S(ConstReg) >> 31);
					}
				} else {
					CompConstToX86reg(GetMipsRegMapHi(MappedReg),GetMipsRegHi(ConstReg));
				}
				if (m_Section->m_Jump.FallThrough) {
					JneLabel8("continue",0);
					Jump = m_RecompPos - 1;
				} else {
					JneLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
					m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
				}
				CompConstToX86reg(GetMipsRegMapLo(MappedReg),GetMipsRegLo(ConstReg));
				if (m_Section->m_Cont.FallThrough) {
					JneLabel32 ( m_Section->m_Jump.BranchLabel.c_str(), 0 );
					m_Section->m_Jump.LinkLocation2 = (DWORD *)(m_RecompPos - 4);
				} else if (m_Section->m_Jump.FallThrough) {
					JeLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
					m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
					CPU_Message("      ");
					CPU_Message("      continue:");
					SetJump8(Jump,m_RecompPos);
				} else {
					JeLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
					m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
					JmpLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
					m_Section->m_Jump.LinkLocation2 = (DWORD *)(m_RecompPos - 4);
				}
			} else {
				CompConstToX86reg(GetMipsRegMapLo(MappedReg),GetMipsRegLo(ConstReg));
				if (m_Section->m_Cont.FallThrough) {
					JneLabel32 ( m_Section->m_Jump.BranchLabel.c_str(), 0 );
					m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
				} else if (m_Section->m_Jump.FallThrough) {
					JeLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
					m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
				} else {
					JeLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
					m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
					JmpLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
					m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
				}
			}
		}
	} else if (IsKnown(m_Opcode.rs) || IsKnown(m_Opcode.rt)) {
		DWORD KnownReg = IsKnown(m_Opcode.rt)?m_Opcode.rt:m_Opcode.rs;
		DWORD UnknownReg = IsKnown(m_Opcode.rt)?m_Opcode.rs:m_Opcode.rt;

		if (!g_System->b32BitCore())
		{
			if (IsConst(KnownReg)) {
				if (Is64Bit(KnownReg)) {
					CompConstToVariable(GetMipsRegHi(KnownReg),&_GPR[UnknownReg].W[1],CRegName::GPR_Hi[UnknownReg]);
				} else if (IsSigned(KnownReg)) {
					CompConstToVariable((GetMipsRegLo_S(KnownReg) >> 31),&_GPR[UnknownReg].W[1],CRegName::GPR_Hi[UnknownReg]);
				} else {
					CompConstToVariable(0,&_GPR[UnknownReg].W[1],CRegName::GPR_Hi[UnknownReg]);
				}
			} else {
				if (Is64Bit(KnownReg)) {
					CompX86regToVariable(GetMipsRegMapHi(KnownReg),&_GPR[UnknownReg].W[1],CRegName::GPR_Hi[UnknownReg]);
				} else if (IsSigned(KnownReg)) {
					ProtectGPR(KnownReg);
					CompX86regToVariable(Map_TempReg(x86_Any,KnownReg,TRUE),&_GPR[UnknownReg].W[1],CRegName::GPR_Hi[UnknownReg]);
				} else {
					CompConstToVariable(0,&_GPR[UnknownReg].W[1],CRegName::GPR_Hi[UnknownReg]);
				}
			}
			if (m_Section->m_Jump.FallThrough) {
				JneLabel8("continue",0);
				Jump = m_RecompPos - 1;
			} else {
				JneLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
				m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
			}
		}
		if (IsConst(KnownReg)) {
			CompConstToVariable(GetMipsRegLo(KnownReg),&_GPR[UnknownReg].W[0],CRegName::GPR_Lo[UnknownReg]);
		} else {
			CompX86regToVariable(GetMipsRegMapLo(KnownReg),&_GPR[UnknownReg].W[0],CRegName::GPR_Lo[UnknownReg]);
		}
		if (m_Section->m_Cont.FallThrough) {
			JneLabel32 ( m_Section->m_Jump.BranchLabel.c_str(), 0 );
			if (g_System->b32BitCore())
			{
				m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
			} else {
				m_Section->m_Jump.LinkLocation2 = (DWORD *)(m_RecompPos - 4);
			}
		} else if (m_Section->m_Jump.FallThrough) {
			JeLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
			m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
			
			if (Jump)
			{
				CPU_Message("      ");
				CPU_Message("      continue:");

				SetJump8(Jump,m_RecompPos);
			}
		} else {
			JeLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
			m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
			JmpLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
			if (g_System->b32BitCore())
			{
				m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
			} else {
				m_Section->m_Jump.LinkLocation2 = (DWORD *)(m_RecompPos - 4);
			}
		}
	} else {
		x86Reg Reg = x86_Any;

		if (!g_System->b32BitCore())
		{
			Reg = Map_TempReg(x86_Any,m_Opcode.rt,TRUE);		
			CompX86regToVariable(Reg,&_GPR[m_Opcode.rs].W[1],CRegName::GPR_Hi[m_Opcode.rs]);
			if (m_Section->m_Jump.FallThrough) {
				JneLabel8("continue",0);
				Jump = m_RecompPos - 1;
			} else {
				JneLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
				m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
			}
		}

		Reg = Map_TempReg(Reg,m_Opcode.rt,FALSE);
		CompX86regToVariable(Reg,&_GPR[m_Opcode.rs].W[0],CRegName::GPR_Lo[m_Opcode.rs]);
		if (m_Section->m_Cont.FallThrough) {
			JneLabel32 ( m_Section->m_Jump.BranchLabel.c_str(), 0 );
			if (g_System->b32BitCore())
			{
				m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
			} else {
				m_Section->m_Jump.LinkLocation2 = (DWORD *)(m_RecompPos - 4);
			}
		} else if (m_Section->m_Jump.FallThrough) {
			JeLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
			m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
			if (Jump)
			{
				CPU_Message("      ");
				CPU_Message("      continue:");
				SetJump8(Jump,m_RecompPos);
			}
		} else {
			JeLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
			m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
			JmpLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
			if (g_System->b32BitCore())
			{
				m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
			} else {
				m_Section->m_Jump.LinkLocation2 = (DWORD *)(m_RecompPos - 4);
			}
		}
	}
}

void CRecompilerOps::BEQ_Compare (void) {
	BYTE *Jump = NULL;

	if (IsKnown(m_Opcode.rs) && IsKnown(m_Opcode.rt)) {
		if (IsConst(m_Opcode.rs) && IsConst(m_Opcode.rt)) { 
			if (Is64Bit(m_Opcode.rs) || Is64Bit(m_Opcode.rt)) {
				CRecompilerOps::UnknownOpcode();
			} else if (GetMipsRegLo(m_Opcode.rs) == GetMipsRegLo(m_Opcode.rt)) {
				m_Section->m_Jump.FallThrough = TRUE;
				m_Section->m_Cont.FallThrough = FALSE;
			} else {
				m_Section->m_Jump.FallThrough = FALSE;
				m_Section->m_Cont.FallThrough = TRUE;
			}
		}
		else if (IsMapped(m_Opcode.rs) && IsMapped(m_Opcode.rt)) 
		{
			if ((Is64Bit(m_Opcode.rs) || Is64Bit(m_Opcode.rt)) && !g_System->b32BitCore()) 
			{
				ProtectGPR(m_Opcode.rs);
				ProtectGPR(m_Opcode.rt);

				CompX86RegToX86Reg(
					Is32Bit(m_Opcode.rs)?Map_TempReg(x86_Any,m_Opcode.rs,TRUE):GetMipsRegMapHi(m_Opcode.rs),
					Is32Bit(m_Opcode.rt)?Map_TempReg(x86_Any,m_Opcode.rt,TRUE):GetMipsRegMapHi(m_Opcode.rt)
				);
				if (m_Section->m_Cont.FallThrough) {
					JneLabel8("continue",0);
					Jump = m_RecompPos - 1;
				} else {
					JneLabel32(m_Section->m_Cont.BranchLabel.c_str(),0);
					m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
				}
				CompX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rs),GetMipsRegMapLo(m_Opcode.rt));
				if (m_Section->m_Cont.FallThrough) {
					JeLabel32 ( m_Section->m_Jump.BranchLabel.c_str(), 0 );
					m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
					CPU_Message("      ");
					CPU_Message("      continue:");
					SetJump8(Jump,m_RecompPos);
				} else if (m_Section->m_Jump.FallThrough) {
					JneLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
					m_Section->m_Cont.LinkLocation2 = (DWORD *)(m_RecompPos - 4);
				} else {
					JneLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
					m_Section->m_Cont.LinkLocation2 = (DWORD *)(m_RecompPos - 4);
					JmpLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
					m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
				}
			} else {
				CompX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rs),GetMipsRegMapLo(m_Opcode.rt));
				if (m_Section->m_Cont.FallThrough) {
					JeLabel32 ( m_Section->m_Jump.BranchLabel.c_str(), 0 );
					m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
				} else if (m_Section->m_Jump.FallThrough) {
					JneLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
					m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
				} else {
					JneLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
					m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
					JmpLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
					m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
				}
			}
		} else {
			DWORD ConstReg = IsConst(m_Opcode.rt)?m_Opcode.rt:m_Opcode.rs;
			DWORD MappedReg = IsConst(m_Opcode.rt)?m_Opcode.rs:m_Opcode.rt;

			if (Is64Bit(ConstReg) || Is64Bit(MappedReg)) {
				if (Is32Bit(ConstReg) || Is32Bit(MappedReg)) {
					if (Is32Bit(MappedReg)) {
						ProtectGPR(MappedReg);
						CompConstToX86reg(Map_TempReg(x86_Any,MappedReg,TRUE),GetMipsRegHi(ConstReg));
					} else {
						CompConstToX86reg(GetMipsRegMapHi(MappedReg),GetMipsRegLo_S(ConstReg) >> 31);
					}
				} else {
					CompConstToX86reg(GetMipsRegMapHi(MappedReg),GetMipsRegHi(ConstReg));
				}			
				if (m_Section->m_Cont.FallThrough) {
					JneLabel8("continue",0);
					Jump = m_RecompPos - 1;
				} else {
					JneLabel32(m_Section->m_Cont.BranchLabel.c_str(),0);
					m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
				}
				CompConstToX86reg(GetMipsRegMapLo(MappedReg),GetMipsRegLo(ConstReg));
				if (m_Section->m_Cont.FallThrough) {
					JeLabel32 ( m_Section->m_Jump.BranchLabel.c_str(), 0 );
					m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
					CPU_Message("      ");
					CPU_Message("      continue:");
					SetJump8(Jump,m_RecompPos);
				} else if (m_Section->m_Jump.FallThrough) {
					JneLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
					m_Section->m_Cont.LinkLocation2 = (DWORD *)(m_RecompPos - 4);
				} else {
					JneLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
					m_Section->m_Cont.LinkLocation2 = (DWORD *)(m_RecompPos - 4);
					JmpLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
					m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
				}
			} else {
				CompConstToX86reg(GetMipsRegMapLo(MappedReg),GetMipsRegLo(ConstReg));
				if (m_Section->m_Cont.FallThrough) {
					JeLabel32 ( m_Section->m_Jump.BranchLabel.c_str(), 0 );
					m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
				} else if (m_Section->m_Jump.FallThrough) {
					JneLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
					m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
				} else {
					JneLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
					m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
					JmpLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
					m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
				}
			}
		}
	} else if (IsKnown(m_Opcode.rs) || IsKnown(m_Opcode.rt)) {
		DWORD KnownReg = IsKnown(m_Opcode.rt)?m_Opcode.rt:m_Opcode.rs;
		DWORD UnknownReg = IsKnown(m_Opcode.rt)?m_Opcode.rs:m_Opcode.rt;

		if (!g_System->b32BitCore())
		{
			if (IsConst(KnownReg)) {
				if (Is64Bit(KnownReg)) {
					CompConstToVariable(GetMipsRegHi(KnownReg),&_GPR[UnknownReg].W[1],CRegName::GPR_Hi[UnknownReg]);
				} else if (IsSigned(KnownReg)) {
					CompConstToVariable(GetMipsRegLo_S(KnownReg) >> 31,&_GPR[UnknownReg].W[1],CRegName::GPR_Hi[UnknownReg]);
				} else {
					CompConstToVariable(0,&_GPR[UnknownReg].W[1],CRegName::GPR_Hi[UnknownReg]);
				}
			} else {
				ProtectGPR(KnownReg);
				if (Is64Bit(KnownReg)) {
					CompX86regToVariable(GetMipsRegMapHi(KnownReg),&_GPR[UnknownReg].W[1],CRegName::GPR_Hi[UnknownReg]);
				} else if (IsSigned(KnownReg)) {
					CompX86regToVariable(Map_TempReg(x86_Any,KnownReg,TRUE),&_GPR[UnknownReg].W[1],CRegName::GPR_Hi[UnknownReg]);
				} else {
					CompConstToVariable(0,&_GPR[UnknownReg].W[1],CRegName::GPR_Hi[UnknownReg]);
				}
			}
			if (m_Section->m_Cont.FallThrough) {
				JneLabel8("continue",0);
				Jump = m_RecompPos - 1;
			} else {
				JneLabel32(m_Section->m_Cont.BranchLabel.c_str(),0);
				m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
			}
		}
		if (IsConst(KnownReg)) {
			CompConstToVariable(GetMipsRegLo(KnownReg),&_GPR[UnknownReg].W[0],CRegName::GPR_Lo[UnknownReg]);
		} else {
			CompX86regToVariable(GetMipsRegMapLo(KnownReg),&_GPR[UnknownReg].W[0],CRegName::GPR_Lo[UnknownReg]);
		}
		if (m_Section->m_Cont.FallThrough) {
			JeLabel32 ( m_Section->m_Jump.BranchLabel.c_str(), 0 );
			m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
			if (Jump)
			{
				CPU_Message("      ");
				CPU_Message("      continue:");
				SetJump8(Jump,m_RecompPos);
			}
		} else if (m_Section->m_Jump.FallThrough) {
			JneLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
			if (g_System->b32BitCore())
			{
				m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
			} else { 
				m_Section->m_Cont.LinkLocation2 = (DWORD *)(m_RecompPos - 4);
			}
		} else {
			JneLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
			m_Section->m_Cont.LinkLocation2 = (DWORD *)(m_RecompPos - 4);
			JmpLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
			m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
		}
	} else {
		x86Reg Reg = x86_Any;
		if (!g_System->b32BitCore())
		{
			Reg = Map_TempReg(x86_Any,m_Opcode.rs,TRUE);
			CompX86regToVariable(Reg,&_GPR[m_Opcode.rt].W[1],CRegName::GPR_Hi[m_Opcode.rt]);
			if (m_Section->m_Cont.FallThrough) {
				JneLabel8("continue",0);
				Jump = m_RecompPos - 1;
			} else {
				JneLabel32(m_Section->m_Cont.BranchLabel.c_str(),0);
				m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
			}
		}
		CompX86regToVariable(Map_TempReg(Reg,m_Opcode.rs,FALSE),&_GPR[m_Opcode.rt].W[0],CRegName::GPR_Lo[m_Opcode.rt]);
		if (m_Section->m_Cont.FallThrough) {
			JeLabel32 ( m_Section->m_Jump.BranchLabel.c_str(), 0 );
			m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
			if (Jump)
			{
				CPU_Message("      ");
				CPU_Message("      continue:");
				SetJump8(Jump,m_RecompPos);
			}
		} else if (m_Section->m_Jump.FallThrough) {
			JneLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
			if (g_System->b32BitCore())
			{
				m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
			} else {
				m_Section->m_Cont.LinkLocation2 = (DWORD *)(m_RecompPos - 4);
			}
		} else {
			JneLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
			if (g_System->b32BitCore())
			{
				m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
			} else {
				m_Section->m_Cont.LinkLocation2 = (DWORD *)(m_RecompPos - 4);
			}
			JmpLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
			m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
		}
	}
}

void CRecompilerOps::BGTZ_Compare (void) {
	if (IsConst(m_Opcode.rs)) {
		if (Is64Bit(m_Opcode.rs)) {
			if (GetMipsReg_S(m_Opcode.rs) > 0) {
				m_Section->m_Jump.FallThrough = TRUE;
				m_Section->m_Cont.FallThrough = FALSE;
			} else {
				m_Section->m_Jump.FallThrough = FALSE;
				m_Section->m_Cont.FallThrough = TRUE;
			}
		} else {
			if (GetMipsRegLo_S(m_Opcode.rs) > 0) {
				m_Section->m_Jump.FallThrough = TRUE;
				m_Section->m_Cont.FallThrough = FALSE;
			} else {
				m_Section->m_Jump.FallThrough = FALSE;
				m_Section->m_Cont.FallThrough = TRUE;
			}
		}
	} else if (IsMapped(m_Opcode.rs) && Is32Bit(m_Opcode.rs)) {
		CompConstToX86reg(GetMipsRegMapLo(m_Opcode.rs),0);
		if (m_Section->m_Jump.FallThrough) {
			JleLabel32 (m_Section->m_Cont.BranchLabel.c_str(), 0 );
			m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
		} else if (m_Section->m_Cont.FallThrough) {
			JgLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
			m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
		} else {
			JleLabel32 (m_Section->m_Cont.BranchLabel.c_str(), 0 );
			m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
			JmpLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
			m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
		}
	} else if (IsUnknown(m_Opcode.rs) && g_System->b32BitCore()) {
		CompConstToVariable(0,&_GPR[m_Opcode.rs].W[0],CRegName::GPR_Lo[m_Opcode.rs]);
		if (m_Section->m_Jump.FallThrough) {
			JleLabel32 (m_Section->m_Cont.BranchLabel.c_str(), 0 );
			m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
		} else if (m_Section->m_Cont.FallThrough) {
			JgLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
			m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
		} else {
			JleLabel32 (m_Section->m_Cont.BranchLabel.c_str(), 0 );
			m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
			JmpLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
			m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
		}
	} else {
		BYTE *Jump = NULL;

		if (IsMapped(m_Opcode.rs)) {
			CompConstToX86reg(GetMipsRegMapHi(m_Opcode.rs),0);
		} else {
			CompConstToVariable(0,&_GPR[m_Opcode.rs].W[1],CRegName::GPR_Hi[m_Opcode.rs]);
		}
		if (m_Section->m_Jump.FallThrough) {
			JlLabel32 (m_Section->m_Cont.BranchLabel.c_str(), 0 );
			m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
			JgLabel8("continue",0);
			Jump = m_RecompPos - 1;
		} else if (m_Section->m_Cont.FallThrough) {
			JlLabel8("continue",0);
			Jump = m_RecompPos - 1;
			JgLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
			m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
		} else {
			JlLabel32 (m_Section->m_Cont.BranchLabel.c_str(), 0 );
			m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
			JgLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
			m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
		}

		if (IsMapped(m_Opcode.rs)) {
			CompConstToX86reg(GetMipsRegMapLo(m_Opcode.rs),0);
		} else {
			CompConstToVariable(0,&_GPR[m_Opcode.rs].W[0],CRegName::GPR_Lo[m_Opcode.rs]);
		}
		if (m_Section->m_Jump.FallThrough) {
			JeLabel32 (m_Section->m_Cont.BranchLabel.c_str(), 0 );
			m_Section->m_Cont.LinkLocation2 = (DWORD *)(m_RecompPos - 4);
			CPU_Message("      continue:");
			SetJump8(Jump,m_RecompPos);
		} else if (m_Section->m_Cont.FallThrough) {
			JneLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
			m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
			CPU_Message("      continue:");
			SetJump8(Jump,m_RecompPos);
		} else {
			JneLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
			m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
			JmpLabel32 (m_Section->m_Cont.BranchLabel.c_str(), 0 );
			m_Section->m_Cont.LinkLocation2 = (DWORD *)(m_RecompPos - 4);
		}
	}
}

void CRecompilerOps::BLEZ_Compare (void) {
	if (IsConst(m_Opcode.rs)) {
		if (Is64Bit(m_Opcode.rs)) {
			if (GetMipsReg_S(m_Opcode.rs) <= 0) {
				m_Section->m_Jump.FallThrough = TRUE;
				m_Section->m_Cont.FallThrough = FALSE;
			} else {
				m_Section->m_Jump.FallThrough = FALSE;
				m_Section->m_Cont.FallThrough = TRUE;
			}
		} else if (IsSigned(m_Opcode.rs)) {
			if (GetMipsRegLo_S(m_Opcode.rs) <= 0) {
				m_Section->m_Jump.FallThrough = TRUE;
				m_Section->m_Cont.FallThrough = FALSE;
			} else {
				m_Section->m_Jump.FallThrough = FALSE;
				m_Section->m_Cont.FallThrough = TRUE;
			}
		} else {
			if (GetMipsRegLo(m_Opcode.rs) == 0) {
				m_Section->m_Jump.FallThrough = TRUE;
				m_Section->m_Cont.FallThrough = FALSE;
			} else {
				m_Section->m_Jump.FallThrough = FALSE;
				m_Section->m_Cont.FallThrough = TRUE;
			}
		}
	} else if (IsMapped(m_Opcode.rs)) {
		if (Is32Bit(m_Opcode.rs))
		{
			CompConstToX86reg(GetMipsRegMapLo(m_Opcode.rs),0);
			if (m_Section->m_Jump.FallThrough) {
				JgLabel32 (m_Section->m_Cont.BranchLabel.c_str(), 0 );
				m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
			} else if (m_Section->m_Cont.FallThrough) {
				JleLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
				m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
			} else {
				JgLabel32 (m_Section->m_Cont.BranchLabel.c_str(), 0 );
				m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
				JmpLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
				m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
			}
		} else {
			BYTE *Jump = NULL;

			if (IsMapped(m_Opcode.rs)) {
				CompConstToX86reg(GetMipsRegMapHi(m_Opcode.rs),0);
			} else {
				CompConstToVariable(0,&_GPR[m_Opcode.rs].W[1],CRegName::GPR_Hi[m_Opcode.rs]);
			}
			if (m_Section->m_Jump.FallThrough) {
				JgLabel32 (m_Section->m_Cont.BranchLabel.c_str(), 0 );
				m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
				JlLabel8("Continue",0);
				Jump = m_RecompPos - 1;
			} else if (m_Section->m_Cont.FallThrough) {
				JgLabel8("Continue",0);
				Jump = m_RecompPos - 1;
				JlLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
				m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
			} else {
				JgLabel32 (m_Section->m_Cont.BranchLabel.c_str(), 0 );
				m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
				JlLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
				m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
			}

			if (IsMapped(m_Opcode.rs)) {
				CompConstToX86reg(GetMipsRegMapLo(m_Opcode.rs),0);
			} else {
				CompConstToVariable(0,&_GPR[m_Opcode.rs].W[0],CRegName::GPR_Lo[m_Opcode.rs]);
			}
			if (m_Section->m_Jump.FallThrough) {
				JneLabel32 (m_Section->m_Cont.BranchLabel.c_str(), 0 );
				m_Section->m_Cont.LinkLocation2 = (DWORD *)(m_RecompPos - 4);
				CPU_Message("      continue:");
				SetJump8(Jump,m_RecompPos);
			} else if (m_Section->m_Cont.FallThrough) {
				JeLabel32 (m_Section->m_Jump.BranchLabel.c_str(), 0 );
				m_Section->m_Jump.LinkLocation2 = (DWORD *)(m_RecompPos - 4);
				CPU_Message("      continue:");
				SetJump8(Jump,m_RecompPos);
			} else {
				JneLabel32 (m_Section->m_Cont.BranchLabel.c_str(), 0 );
				m_Section->m_Cont.LinkLocation2 = (DWORD *)(m_RecompPos - 4);
				JmpLabel32("BranchToJump",0);
				m_Section->m_Jump.LinkLocation2 = (DWORD *)(m_RecompPos - 4);
			}
		}
	} else {
		BYTE *Jump = NULL;

		if (!g_System->b32BitCore())
		{
			CompConstToVariable(0,&_GPR[m_Opcode.rs].W[1],CRegName::GPR_Hi[m_Opcode.rs]);
			if (m_Section->m_Jump.FallThrough) {
				JgLabel32 (m_Section->m_Cont.BranchLabel.c_str(), 0 );
				m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
				JlLabel8("Continue",0);
				Jump = m_RecompPos - 1;
			} else if (m_Section->m_Cont.FallThrough) {
				JgLabel8("Continue",0);
				Jump = m_RecompPos - 1;
				JlLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
				m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
			} else {
				JgLabel32 (m_Section->m_Cont.BranchLabel.c_str(), 0 );
				m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
				JlLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
				m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
			}
			CompConstToVariable(0,&_GPR[m_Opcode.rs].W[0],CRegName::GPR_Lo[m_Opcode.rs]);
			if (m_Section->m_Jump.FallThrough) {
				JneLabel32 (m_Section->m_Cont.BranchLabel.c_str(), 0 );
				if (g_System->b32BitCore())
				{
					m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
				} else {
					m_Section->m_Cont.LinkLocation2 = (DWORD *)(m_RecompPos - 4);
				}
				if (Jump)
				{
					CPU_Message("      continue:");
					SetJump8(Jump,m_RecompPos);
				}
			} else if (m_Section->m_Cont.FallThrough) {
				JeLabel32 (m_Section->m_Jump.BranchLabel.c_str(), 0 );
				m_Section->m_Jump.LinkLocation2 = (DWORD *)(m_RecompPos - 4);
				if (Jump)
				{
					CPU_Message("      continue:");
					SetJump8(Jump,m_RecompPos);
				}
			} else {
				JneLabel32 (m_Section->m_Cont.BranchLabel.c_str(), 0 );
				m_Section->m_Cont.LinkLocation2 = (DWORD *)(m_RecompPos - 4);
				JmpLabel32("BranchToJump",0);
				m_Section->m_Jump.LinkLocation2 = (DWORD *)(m_RecompPos - 4);
			}
		} else {
			CompConstToVariable(0,&_GPR[m_Opcode.rs].W[0],CRegName::GPR_Lo[m_Opcode.rs]);
			if (m_Section->m_Jump.FallThrough) {
				JgLabel32 (m_Section->m_Cont.BranchLabel.c_str(), 0 );
				m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
			} else if (m_Section->m_Cont.FallThrough) {
				JleLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
				m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
			} else {
				JgLabel32 (m_Section->m_Cont.BranchLabel.c_str(), 0 );
				m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
				JmpLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
				m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
			}
		}		
	}
}

void CRecompilerOps::BLTZ_Compare (void) {
	if (IsConst(m_Opcode.rs)) {
		if (Is64Bit(m_Opcode.rs)) {
			if (GetMipsReg_S(m_Opcode.rs) < 0) {
				m_Section->m_Jump.FallThrough = TRUE;
				m_Section->m_Cont.FallThrough = FALSE;
			} else {
				m_Section->m_Jump.FallThrough = FALSE;
				m_Section->m_Cont.FallThrough = TRUE;
			}
		} else if (IsSigned(m_Opcode.rs)) {
			if (GetMipsRegLo_S(m_Opcode.rs) < 0) {
				m_Section->m_Jump.FallThrough = TRUE;
				m_Section->m_Cont.FallThrough = FALSE;
			} else {
				m_Section->m_Jump.FallThrough = FALSE;
				m_Section->m_Cont.FallThrough = TRUE;
			}
		} else {
			m_Section->m_Jump.FallThrough = FALSE;
			m_Section->m_Cont.FallThrough = TRUE;
		}
	} else if (IsMapped(m_Opcode.rs)) {
		if (Is64Bit(m_Opcode.rs)) {
			CompConstToX86reg(GetMipsRegMapHi(m_Opcode.rs),0);
			if (m_Section->m_Jump.FallThrough) {
				JgeLabel32 (m_Section->m_Cont.BranchLabel.c_str(), 0 );
				m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
			} else if (m_Section->m_Cont.FallThrough) {
				JlLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
				m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
			} else {
				JgeLabel32 (m_Section->m_Cont.BranchLabel.c_str(), 0 );
				m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
				JmpLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
				m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
			}
		} else if (IsSigned(m_Opcode.rs)) {
			CompConstToX86reg(GetMipsRegMapLo(m_Opcode.rs),0);
			if (m_Section->m_Jump.FallThrough) {
				JgeLabel32 (m_Section->m_Cont.BranchLabel.c_str(), 0 );
				m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
			} else if (m_Section->m_Cont.FallThrough) {
				JlLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
				m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
			} else {
				JgeLabel32 (m_Section->m_Cont.BranchLabel.c_str(), 0 );
				m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
				JmpLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
				m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
			}
		} else {
			m_Section->m_Jump.FallThrough = FALSE;
			m_Section->m_Cont.FallThrough = TRUE;
		}
	} else if (IsUnknown(m_Opcode.rs)) {
		if (g_System->b32BitCore())
		{
			CompConstToVariable(0,&_GPR[m_Opcode.rs].W[0],CRegName::GPR_Lo[m_Opcode.rs]);
		} else {
			CompConstToVariable(0,&_GPR[m_Opcode.rs].W[1],CRegName::GPR_Hi[m_Opcode.rs]);
		}
		if (m_Section->m_Jump.FallThrough) {
			JgeLabel32 (m_Section->m_Cont.BranchLabel.c_str(), 0 );
			m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
		} else if (m_Section->m_Cont.FallThrough) {
			JlLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
			m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
		} else {
			JlLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
			m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
			JmpLabel32 (m_Section->m_Cont.BranchLabel.c_str(), 0 );
			m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
		}
	}
}

void CRecompilerOps::BGEZ_Compare (void) {
	if (IsConst(m_Opcode.rs)) {
		if (Is64Bit(m_Opcode.rs)) {
			g_Notify->BreakPoint(__FILEW__,__LINE__);
			CRecompilerOps::UnknownOpcode();
		} else if (IsSigned(m_Opcode.rs)) {
			if (GetMipsRegLo_S(m_Opcode.rs) >= 0) {
				m_Section->m_Jump.FallThrough = TRUE;
				m_Section->m_Cont.FallThrough = FALSE;
			} else {
				m_Section->m_Jump.FallThrough = FALSE;
				m_Section->m_Cont.FallThrough = TRUE;
			}
		} else {
			m_Section->m_Jump.FallThrough = TRUE;
			m_Section->m_Cont.FallThrough = FALSE;
		}
	} else if (IsMapped(m_Opcode.rs)) {
		if (Is64Bit(m_Opcode.rs)) { 
			CompConstToX86reg(GetMipsRegMapHi(m_Opcode.rs),0);
			if (m_Section->m_Cont.FallThrough) {
				JgeLabel32 ( m_Section->m_Jump.BranchLabel.c_str(), 0 );
				m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
			} else if (m_Section->m_Jump.FallThrough) {
				JlLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
				m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
			} else {
				JlLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
				m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
				JmpLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
				m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
			}
		} else if (IsSigned(m_Opcode.rs)) {
			CompConstToX86reg(GetMipsRegMapLo(m_Opcode.rs),0);
			if (m_Section->m_Cont.FallThrough) {
				JgeLabel32 ( m_Section->m_Jump.BranchLabel.c_str(), 0 );
				m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
			} else if (m_Section->m_Jump.FallThrough) {
				JlLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
				m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
			} else {
				JlLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
				m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
				JmpLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
				m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
			}
		} else { 
			m_Section->m_Jump.FallThrough = TRUE;
			m_Section->m_Cont.FallThrough = FALSE;
		}
	} else {
		if (g_System->b32BitCore())
		{
			CompConstToVariable(0,&_GPR[m_Opcode.rs].W[0],CRegName::GPR_Lo[m_Opcode.rs]);		
		} else {
			CompConstToVariable(0,&_GPR[m_Opcode.rs].W[1],CRegName::GPR_Hi[m_Opcode.rs]);		
		}
		if (m_Section->m_Cont.FallThrough) {
			JgeLabel32 ( m_Section->m_Jump.BranchLabel.c_str(), 0 );
			m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
		} else if (m_Section->m_Jump.FallThrough) {
			JlLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
			m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
		} else {
			JlLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
			m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
			JmpLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
			m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
		}
	}
}

void CRecompilerOps::COP1_BCF_Compare (void) {
	TestVariable(FPCSR_C,&_FPCR[31],"_FPCR[31]");
	if (m_Section->m_Cont.FallThrough) {
		JeLabel32 ( m_Section->m_Jump.BranchLabel.c_str(), 0 );
		m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
	} else if (m_Section->m_Jump.FallThrough) {
		JneLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
		m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
	} else {
		JneLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
		m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
		JmpLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
		m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
	}
}

void CRecompilerOps::COP1_BCT_Compare (void) {
	TestVariable(FPCSR_C,&_FPCR[31],"_FPCR[31]");
	if (m_Section->m_Cont.FallThrough) {
		JneLabel32 ( m_Section->m_Jump.BranchLabel.c_str(), 0 );
		m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
	} else if (m_Section->m_Jump.FallThrough) {
		JeLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
		m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
	} else {
		JeLabel32 ( m_Section->m_Cont.BranchLabel.c_str(), 0 );
		m_Section->m_Cont.LinkLocation = (DWORD *)(m_RecompPos - 4);
		JmpLabel32(m_Section->m_Jump.BranchLabel.c_str(),0);
		m_Section->m_Jump.LinkLocation = (DWORD *)(m_RecompPos - 4);
	}
}

/*************************  OpCode functions *************************/
void CRecompilerOps::J (void) {
	if ( m_NextInstruction == NORMAL ) {
		CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
		if ((m_CompilePC & 0xFFC) == 0xFFC) 
		{
			MoveConstToVariable((m_CompilePC & 0xF0000000) + (m_Opcode.target << 2),&R4300iOp::m_JumpToLocation,"R4300iOp::m_JumpToLocation");
			OverflowDelaySlot(false);
			return;
		}

		m_Section->m_Jump.TargetPC      = (m_CompilePC & 0xF0000000) + (m_Opcode.target << 2);;
		m_Section->m_Jump.JumpPC        = m_CompilePC;
		if (m_Section->m_JumpSection != NULL) {
			m_Section->m_Jump.BranchLabel.Format("Section_%d",((CCodeSection *)m_Section->m_JumpSection)->m_SectionID);
		} else {
			m_Section->m_Jump.BranchLabel = "ExitBlock";
		}
		m_Section->m_Jump.FallThrough   = TRUE;
		m_Section->m_Jump.LinkLocation  = NULL;
		m_Section->m_Jump.LinkLocation2 = NULL;
		m_NextInstruction = DO_DELAY_SLOT;
	} else if (m_NextInstruction == DELAY_SLOT_DONE ) {		
		m_Section->m_Jump.RegSet = m_RegWorkingSet;
		m_Section->GenerateSectionLinkage();
		m_NextInstruction = END_BLOCK;
	} else if (bHaveDebugger()) {
		g_Notify->DisplayError(L"WTF\n\nJ\nNextInstruction = %X", m_NextInstruction);
	}
}

void CRecompilerOps::JAL (void) {
	if ( m_NextInstruction == NORMAL ) 
	{
		CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
		Map_GPR_32bit(31,true,-1);
		MoveVariableToX86reg(_PROGRAM_COUNTER,"_PROGRAM_COUNTER",GetMipsRegMapLo(31));
		AndConstToX86Reg(GetMipsRegMapLo(31), 0xF0000000);
		AddConstToX86Reg(GetMipsRegMapLo(31),(m_CompilePC + 8) & ~0xF0000000);
		if ((m_CompilePC & 0xFFC) == 0xFFC) 
		{
			MoveConstToVariable((m_CompilePC & 0xF0000000) + (m_Opcode.target << 2),&R4300iOp::m_JumpToLocation,"R4300iOp::m_JumpToLocation");
			OverflowDelaySlot(false);
			return;
		}
		m_Section->m_Jump.TargetPC = (m_CompilePC & 0xF0000000) + (m_Opcode.target << 2);
		m_Section->m_Jump.JumpPC = m_CompilePC;
		if (m_Section->m_JumpSection != NULL) {
			m_Section->m_Jump.BranchLabel.Format("Section_%d",((CCodeSection *)m_Section->m_JumpSection)->m_SectionID);
		} else {
			m_Section->m_Jump.BranchLabel = "ExitBlock";
		}
		m_Section->m_Jump.FallThrough   = TRUE;
		m_Section->m_Jump.LinkLocation  = NULL;
		m_Section->m_Jump.LinkLocation2 = NULL;
		m_NextInstruction = DO_DELAY_SLOT;
	} else if (m_NextInstruction == DELAY_SLOT_DONE ) {		
		if (m_Section->m_JumpSection)
		{
			m_Section->m_Jump.RegSet = m_RegWorkingSet;
			m_Section->GenerateSectionLinkage();
		} else {
			m_RegWorkingSet.WriteBackRegisters();

			x86Reg pc_reg = Map_TempReg(x86_Any,-1,false);
			MoveVariableToX86reg(_PROGRAM_COUNTER,"_PROGRAM_COUNTER",pc_reg);
			AndConstToX86Reg(pc_reg, 0xF0000000);
			AddConstToX86Reg(pc_reg,(m_Opcode.target << 2));
			MoveX86regToVariable(pc_reg,_PROGRAM_COUNTER,"_PROGRAM_COUNTER");

			DWORD TargetPC = (m_CompilePC & 0xF0000000) + (m_Opcode.target << 2);
			bool bCheck = TargetPC <= m_CompilePC;
			UpdateCounters(m_RegWorkingSet,bCheck, true);

			m_Section->CompileExit((DWORD)-1, (DWORD)-1,m_RegWorkingSet,bCheck ? CExitInfo::Normal : CExitInfo::Normal_NoSysCheck,TRUE,NULL);
		}
		m_NextInstruction = END_BLOCK;
	} else {
		g_Notify->BreakPoint(__FILEW__,__LINE__);
	}
	return;
}

void CRecompilerOps::ADDI (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	if (m_Opcode.rt == 0) { return; }

	if (g_System->bFastSP() && m_Opcode.rs == 29 && m_Opcode.rt == 29) {
		AddConstToX86Reg(Map_MemoryStack(x86_Any, true),(short)m_Opcode.immediate);
	}

	if (IsConst(m_Opcode.rs)) { 
		if (IsMapped(m_Opcode.rt)) { UnMap_GPR(m_Opcode.rt, FALSE); }
		m_RegWorkingSet.SetMipsRegLo(m_Opcode.rt, GetMipsRegLo(m_Opcode.rs) + (short)m_Opcode.immediate);
		m_RegWorkingSet.SetMipsRegState(m_Opcode.rt,CRegInfo::STATE_CONST_32_SIGN);
	} else {
		Map_GPR_32bit(m_Opcode.rt,TRUE,m_Opcode.rs);
		AddConstToX86Reg(GetMipsRegMapLo(m_Opcode.rt),(short)m_Opcode.immediate);
	}
	if (g_System->bFastSP() && m_Opcode.rt == 29 && m_Opcode.rs != 29) { 
		ResetX86Protection();
		g_MMU->ResetMemoryStack(); 
	}
}

void CRecompilerOps::ADDIU (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	if (m_Opcode.rt == 0 || (m_Opcode.immediate == 0 && m_Opcode.rs == m_Opcode.rt)) { return; }

	if (g_System->bFastSP())
	{
		if (m_Opcode.rs == 29 && m_Opcode.rt == 29) 
		{
			AddConstToX86Reg(Map_MemoryStack(x86_Any, TRUE),(short)m_Opcode.immediate);
		}
	}

	if (IsConst(m_Opcode.rs)) { 
		if (IsMapped(m_Opcode.rt)) { UnMap_GPR(m_Opcode.rt, FALSE); }
		m_RegWorkingSet.SetMipsRegLo(m_Opcode.rt, GetMipsRegLo(m_Opcode.rs) + (short)m_Opcode.immediate);
		m_RegWorkingSet.SetMipsRegState(m_Opcode.rt,CRegInfo::STATE_CONST_32_SIGN);
	} else {
		Map_GPR_32bit(m_Opcode.rt,TRUE,m_Opcode.rs);
		AddConstToX86Reg(GetMipsRegMapLo(m_Opcode.rt),(short)m_Opcode.immediate);
	}

	if (g_System->bFastSP() && m_Opcode.rt == 29 && m_Opcode.rs != 29) { 
		ResetX86Protection();
		g_MMU->ResetMemoryStack(); 
	}
}

void CRecompilerOps::SLTIU (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (m_Opcode.rt == 0) { return; }

	if (IsConst(m_Opcode.rs)) 
	{ 
		DWORD Result = Is64Bit(m_Opcode.rs) ? GetMipsReg(m_Opcode.rs) < ((unsigned)((__int64)((short)m_Opcode.immediate)))?1:0 : 
						GetMipsRegLo(m_Opcode.rs) < ((unsigned)((short)m_Opcode.immediate))?1:0;
		UnMap_GPR(m_Opcode.rt, FALSE);
		m_RegWorkingSet.SetMipsRegState(m_Opcode.rt,CRegInfo::STATE_CONST_32_SIGN);
		m_RegWorkingSet.SetMipsRegLo(m_Opcode.rt,Result);
	} else if (IsMapped(m_Opcode.rs)) { 
		if (Is64Bit(m_Opcode.rs)) {
			BYTE * Jump[2];

			CompConstToX86reg(GetMipsRegMapHi(m_Opcode.rs),((short)m_Opcode.immediate >> 31));
			JeLabel8("Low Compare",0);
			Jump[0] = m_RecompPos - 1;
			SetbVariable(&m_BranchCompare,"m_BranchCompare");
			JmpLabel8("Continue",0);
			Jump[1] = m_RecompPos - 1;
			CPU_Message("");
			CPU_Message("      Low Compare:");
			SetJump8(Jump[0],m_RecompPos);
			CompConstToX86reg(GetMipsRegMapLo(m_Opcode.rs),(short)m_Opcode.immediate);
			SetbVariable(&m_BranchCompare,"m_BranchCompare");
			CPU_Message("");
			CPU_Message("      Continue:");
			SetJump8(Jump[1],m_RecompPos);
			Map_GPR_32bit(m_Opcode.rt,FALSE, -1);
			MoveVariableToX86reg(&m_BranchCompare,"m_BranchCompare",GetMipsRegMapLo(m_Opcode.rt));
		} else {
			CompConstToX86reg(GetMipsRegMapLo(m_Opcode.rs),(short)m_Opcode.immediate);
			SetbVariable(&m_BranchCompare,"m_BranchCompare");
			Map_GPR_32bit(m_Opcode.rt,FALSE, -1);
			MoveVariableToX86reg(&m_BranchCompare,"m_BranchCompare",GetMipsRegMapLo(m_Opcode.rt));
		}
	} else if (g_System->b32BitCore()) {
		CompConstToVariable((short)m_Opcode.immediate,&_GPR[m_Opcode.rs].W[0],CRegName::GPR_Lo[m_Opcode.rs]);
		SetbVariable(&m_BranchCompare,"m_BranchCompare");
		Map_GPR_32bit(m_Opcode.rt,FALSE, -1);
		MoveVariableToX86reg(&m_BranchCompare,"m_BranchCompare",GetMipsRegMapLo(m_Opcode.rt));
	} else {
		BYTE * Jump = NULL;

		CompConstToVariable(((short)m_Opcode.immediate >> 31),&_GPR[m_Opcode.rs].W[1],CRegName::GPR_Hi[m_Opcode.rs]);
		JneLabel8("CompareSet",0);
		Jump = m_RecompPos - 1;
		CompConstToVariable((short)m_Opcode.immediate,&_GPR[m_Opcode.rs].W[0],CRegName::GPR_Lo[m_Opcode.rs]);
		CPU_Message("");
		CPU_Message("      CompareSet:");
		SetJump8(Jump,m_RecompPos);
		SetbVariable(&m_BranchCompare,"m_BranchCompare");
		Map_GPR_32bit(m_Opcode.rt,FALSE, -1);
		MoveVariableToX86reg(&m_BranchCompare,"m_BranchCompare",GetMipsRegMapLo(m_Opcode.rt));	
	}
}

void CRecompilerOps::SLTI (void) 
{
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (m_Opcode.rt == 0) { return; }

	if (IsConst(m_Opcode.rs)) { 
		DWORD Result = Is64Bit(m_Opcode.rs) ? 
			((__int64)GetMipsReg(m_Opcode.rs) < (__int64)((short)m_Opcode.immediate) ? 1:0) :
			( GetMipsRegLo_S(m_Opcode.rs) < (short)m_Opcode.immediate?1:0);

		UnMap_GPR(m_Opcode.rt, FALSE);
		m_RegWorkingSet.SetMipsRegState(m_Opcode.rt,CRegInfo::STATE_CONST_32_SIGN);
		m_RegWorkingSet.SetMipsRegLo(m_Opcode.rt,Result);
	} else if (IsMapped(m_Opcode.rs)) { 
		if (Is64Bit(m_Opcode.rs)) {
			BYTE * Jump[2];

			CompConstToX86reg(GetMipsRegMapHi(m_Opcode.rs),((short)m_Opcode.immediate >> 31));
			JeLabel8("Low Compare",0);
			Jump[0] = m_RecompPos - 1;
			SetlVariable(&m_BranchCompare,"m_BranchCompare");
			JmpLabel8("Continue",0);
			Jump[1] = m_RecompPos - 1;
			CPU_Message("");
			CPU_Message("      Low Compare:");
			SetJump8(Jump[0],m_RecompPos);
			CompConstToX86reg(GetMipsRegMapLo(m_Opcode.rs),(short)m_Opcode.immediate);
			SetbVariable(&m_BranchCompare,"m_BranchCompare");
			CPU_Message("");
			CPU_Message("      Continue:");
			SetJump8(Jump[1],m_RecompPos);
			Map_GPR_32bit(m_Opcode.rt,FALSE, -1);
			MoveVariableToX86reg(&m_BranchCompare,"m_BranchCompare",GetMipsRegMapLo(m_Opcode.rt));
		} else {
		/*	CompConstToX86reg(GetMipsRegMapLo(m_Opcode.rs),(short)m_Opcode.immediate);
			SetlVariable(&m_BranchCompare,"m_BranchCompare");
			Map_GPR_32bit(m_Opcode.rt,FALSE, -1);
			MoveVariableToX86reg(&m_BranchCompare,"m_BranchCompare",GetMipsRegMapLo(m_Opcode.rt));
			*/
			ProtectGPR( m_Opcode.rs);
			Map_GPR_32bit(m_Opcode.rt,FALSE, -1);
			CompConstToX86reg(GetMipsRegMapLo(m_Opcode.rs),(short)m_Opcode.immediate);
			
			if (GetMipsRegMapLo(m_Opcode.rt) > x86_EBX) {
				SetlVariable(&m_BranchCompare,"m_BranchCompare");
				MoveVariableToX86reg(&m_BranchCompare,"m_BranchCompare",GetMipsRegMapLo(m_Opcode.rt));
			} else {
				Setl(GetMipsRegMapLo(m_Opcode.rt));
				AndConstToX86Reg(GetMipsRegMapLo(m_Opcode.rt), 1);
			}
		}
	} else if (g_System->b32BitCore()) {
		Map_GPR_32bit(m_Opcode.rt,FALSE, -1);
		CompConstToVariable((short)m_Opcode.immediate,&_GPR[m_Opcode.rs].W[0],CRegName::GPR_Lo[m_Opcode.rs]);

		if (GetMipsRegMapLo(m_Opcode.rt) > x86_EBX) {
			SetlVariable(&m_BranchCompare,"m_BranchCompare");
			MoveVariableToX86reg(&m_BranchCompare,"m_BranchCompare",GetMipsRegMapLo(m_Opcode.rt));
		} else {
			Setl(GetMipsRegMapLo(m_Opcode.rt));
			AndConstToX86Reg(GetMipsRegMapLo(m_Opcode.rt), 1);
		}
	} else {
		BYTE * Jump[2] = { NULL, NULL };
		CompConstToVariable(((short)m_Opcode.immediate >> 31),&_GPR[m_Opcode.rs].W[1],CRegName::GPR_Hi[m_Opcode.rs]);
		JeLabel8("Low Compare",0);
		Jump[0] = m_RecompPos - 1;
		SetlVariable(&m_BranchCompare,"m_BranchCompare");
		JmpLabel8("Continue",0);
		Jump[1] = m_RecompPos - 1;
		CPU_Message("");
		CPU_Message("      Low Compare:");
		SetJump8(Jump[0], m_RecompPos);
		CompConstToVariable((short)m_Opcode.immediate,&_GPR[m_Opcode.rs].W[0],CRegName::GPR_Lo[m_Opcode.rs]);
		SetbVariable(&m_BranchCompare,"m_BranchCompare");
		if (Jump[1])
		{
			CPU_Message("");
			CPU_Message("      Continue:");
			SetJump8(Jump[1],m_RecompPos);
		}
		Map_GPR_32bit(m_Opcode.rt,FALSE, -1);
		MoveVariableToX86reg(&m_BranchCompare,"m_BranchCompare",GetMipsRegMapLo(m_Opcode.rt));
	}
}

void CRecompilerOps::ANDI (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	if (m_Opcode.rt == 0) { return;}

	if (IsConst(m_Opcode.rs)) {
		if (IsMapped(m_Opcode.rt)) { UnMap_GPR(m_Opcode.rt, FALSE); }
		m_RegWorkingSet.SetMipsRegState(m_Opcode.rt,CRegInfo::STATE_CONST_32_SIGN);
		m_RegWorkingSet.SetMipsRegLo(m_Opcode.rt, GetMipsRegLo(m_Opcode.rs) & m_Opcode.immediate);
	} else if (m_Opcode.immediate != 0) { 
		Map_GPR_32bit(m_Opcode.rt,FALSE,m_Opcode.rs);
		AndConstToX86Reg(GetMipsRegMapLo(m_Opcode.rt),m_Opcode.immediate);
	} else {
		Map_GPR_32bit(m_Opcode.rt,FALSE,0);
	}
}

void CRecompilerOps::ORI (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (m_Opcode.rt == 0) { return;}

	if (g_System->bFastSP() && m_Opcode.rs == 29 && m_Opcode.rt == 29) {
		OrConstToX86Reg(m_Opcode.immediate,Map_MemoryStack(x86_Any, true));
	}

	if (IsConst(m_Opcode.rs)) {
		if (IsMapped(m_Opcode.rt)) { UnMap_GPR(m_Opcode.rt, FALSE); }
		m_RegWorkingSet.SetMipsRegState(m_Opcode.rt,GetMipsRegState(m_Opcode.rs));
		m_RegWorkingSet.SetMipsRegHi(m_Opcode.rt,GetMipsRegHi(m_Opcode.rs));
		m_RegWorkingSet.SetMipsRegLo(m_Opcode.rt,GetMipsRegLo(m_Opcode.rs) | m_Opcode.immediate);
	} else if (IsMapped(m_Opcode.rs)) {
		if (g_System->b32BitCore())
		{
			Map_GPR_32bit(m_Opcode.rt,true,m_Opcode.rs);
		} else {
			if (Is64Bit(m_Opcode.rs)) {
				Map_GPR_64bit(m_Opcode.rt,m_Opcode.rs);
			} else {
				Map_GPR_32bit(m_Opcode.rt,IsSigned(m_Opcode.rs),m_Opcode.rs);
			}
		}
		OrConstToX86Reg(m_Opcode.immediate,GetMipsRegMapLo(m_Opcode.rt));
	} else {
		if (g_System->b32BitCore())
		{
			Map_GPR_32bit(m_Opcode.rt,true,m_Opcode.rs);
		} else {
			Map_GPR_64bit(m_Opcode.rt,m_Opcode.rs);
		}
		OrConstToX86Reg(m_Opcode.immediate,GetMipsRegMapLo(m_Opcode.rt));
	}

	if (g_System->bFastSP() && m_Opcode.rt == 29 && m_Opcode.rs != 29) { 
		ResetX86Protection();
		g_MMU->ResetMemoryStack(); 
	}
}

void CRecompilerOps::XORI (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (m_Opcode.rt == 0) { return;}

	if (IsConst(m_Opcode.rs)) {
		if (m_Opcode.rs != m_Opcode.rt) { UnMap_GPR(m_Opcode.rt, FALSE); }
		m_RegWorkingSet.SetMipsRegState(m_Opcode.rt,GetMipsRegState(m_Opcode.rs));
		m_RegWorkingSet.SetMipsRegHi(m_Opcode.rt,GetMipsRegHi(m_Opcode.rs));
		m_RegWorkingSet.SetMipsRegLo(m_Opcode.rt,GetMipsRegLo(m_Opcode.rs) ^ m_Opcode.immediate);
	} else {
		if (IsMapped(m_Opcode.rs) && Is32Bit(m_Opcode.rs)) {
			Map_GPR_32bit(m_Opcode.rt,IsSigned(m_Opcode.rs),m_Opcode.rs);
		} else if (g_System->b32BitCore()) {
			Map_GPR_32bit(m_Opcode.rt,true,m_Opcode.rs);
		} else {
			Map_GPR_64bit(m_Opcode.rt,m_Opcode.rs);
		}
		if (m_Opcode.immediate != 0) { XorConstToX86Reg(GetMipsRegMapLo(m_Opcode.rt),m_Opcode.immediate); }
	}
}

void CRecompilerOps::LUI (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (m_Opcode.rt == 0) { return;}

	if (g_System->bFastSP() && m_Opcode.rt == 29) {
		x86Reg Reg = Map_MemoryStack(x86_Any, true, false);
		DWORD Address;

		g_TransVaddr->TranslateVaddr(((short)m_Opcode.offset << 16), Address);
		if (Reg < 0) {
			MoveConstToVariable((DWORD)(Address + g_MMU->Rdram()), &(g_Recompiler->MemoryStackPos()), "MemoryStack");
		} else {
			MoveConstToX86reg((DWORD)(Address + g_MMU->Rdram()), Reg);
		}
	}

	UnMap_GPR(m_Opcode.rt, FALSE);
	m_RegWorkingSet.SetMipsRegLo(m_Opcode.rt, ((short)m_Opcode.offset << 16));
	m_RegWorkingSet.SetMipsRegState(m_Opcode.rt,CRegInfo::STATE_CONST_32_SIGN);
}

void CRecompilerOps::DADDIU (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	if (m_Opcode.rs != 0) { UnMap_GPR(m_Opcode.rs,TRUE); }
	if (m_Opcode.rs != 0) { UnMap_GPR(m_Opcode.rt,TRUE); }
	BeforeCallDirect(m_RegWorkingSet);
	MoveConstToVariable(m_Opcode.Hex, &R4300iOp::m_Opcode.Hex, "R4300iOp::m_Opcode.Hex");
	Call_Direct(R4300iOp::DADDIU, "R4300iOp::DADDIU");
	AfterCallDirect(m_RegWorkingSet);
}

void CRecompilerOps::CACHE (void){
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	if (g_Settings->LoadDword(Game_SMM_Cache) == 0)
	{
		return;
	}

	switch(m_Opcode.rt) {
	case 0:
	case 16:
		BeforeCallDirect(m_RegWorkingSet);
		PushImm32("CRecompiler::Remove_Cache",CRecompiler::Remove_Cache);
		PushImm32("0x20",0x20);
		if (IsConst(m_Opcode.base)) { 
			DWORD Address = GetMipsRegLo(m_Opcode.base) + (short)m_Opcode.offset;
			PushImm32("Address",Address);
		} else if (IsMapped(m_Opcode.base)) { 
			AddConstToX86Reg(GetMipsRegMapLo(m_Opcode.base),(short)m_Opcode.offset);
			Push(GetMipsRegMapLo(m_Opcode.base));
		} else {
			MoveVariableToX86reg(&_GPR[m_Opcode.base].UW[0],CRegName::GPR_Lo[m_Opcode.base],x86_EAX);
			AddConstToX86Reg(x86_EAX,(short)m_Opcode.offset);
			Push(x86_EAX);
		}
		MoveConstToX86reg((DWORD)g_Recompiler,x86_ECX);		
		Call_Direct(AddressOf(&CRecompiler::ClearRecompCode_Virt), "CRecompiler::ClearRecompCode_Virt");
		AfterCallDirect(m_RegWorkingSet);
		break;
	case 1:
	case 3:
	case 13:
	case 5:
	case 8:
	case 9:
	case 17:
	case 21:
	case 25:
		break;
	default:
		if (bHaveDebugger())
		{
			g_Notify->DisplayError(L"cache: %d",m_Opcode.rt);
		}
	}
}

/********************** R4300i OpCodes: Special **********************/
void CRecompilerOps::SPECIAL_SLL (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	if (m_Opcode.rd == 0) { return; }

	if (IsConst(m_Opcode.rt)) {
		if (IsMapped(m_Opcode.rd)) { UnMap_GPR(m_Opcode.rd, FALSE); }
		m_RegWorkingSet.SetMipsRegLo(m_Opcode.rd, GetMipsRegLo(m_Opcode.rt) << m_Opcode.sa);
		m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
		return;
	}
	if (m_Opcode.rd != m_Opcode.rt && IsMapped(m_Opcode.rt)) {
		switch (m_Opcode.sa) {
		case 0: 
			Map_GPR_32bit(m_Opcode.rd,TRUE,m_Opcode.rt);
			break;
		case 1:
			ProtectGPR(m_Opcode.rt);
			Map_GPR_32bit(m_Opcode.rd,TRUE,-1);
			LeaRegReg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapLo(m_Opcode.rt), 0, Multip_x2);
			break;			
		case 2:
			ProtectGPR(m_Opcode.rt);
			Map_GPR_32bit(m_Opcode.rd,TRUE,-1);
			LeaRegReg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapLo(m_Opcode.rt), 0, Multip_x4);
			break;			
		case 3:
			ProtectGPR(m_Opcode.rt);
			Map_GPR_32bit(m_Opcode.rd,TRUE,-1);
			LeaRegReg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapLo(m_Opcode.rt), 0, Multip_x8);
			break;
		default:
			Map_GPR_32bit(m_Opcode.rd,TRUE,m_Opcode.rt);
			ShiftLeftSignImmed(GetMipsRegMapLo(m_Opcode.rd),(BYTE)m_Opcode.sa);
		}
	} else {
		Map_GPR_32bit(m_Opcode.rd,TRUE,m_Opcode.rt);
		ShiftLeftSignImmed(GetMipsRegMapLo(m_Opcode.rd),(BYTE)m_Opcode.sa);
	}
}

void CRecompilerOps::SPECIAL_SRL (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (m_Opcode.rd == 0) { return; }
	
	if (IsConst(m_Opcode.rt)) {
		if (IsMapped(m_Opcode.rd)) { UnMap_GPR(m_Opcode.rd, FALSE); }
		m_RegWorkingSet.SetMipsRegLo(m_Opcode.rd, GetMipsRegLo(m_Opcode.rt) >> m_Opcode.sa);
		m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
		return;
	}
	Map_GPR_32bit(m_Opcode.rd,TRUE,m_Opcode.rt);
	ShiftRightUnsignImmed(GetMipsRegMapLo(m_Opcode.rd),(BYTE)m_Opcode.sa);
}

void CRecompilerOps::SPECIAL_SRA (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (m_Opcode.rd == 0) { return; }
	
	if (IsConst(m_Opcode.rt)) {
		if (IsMapped(m_Opcode.rd)) { UnMap_GPR(m_Opcode.rd, FALSE); }
		m_RegWorkingSet.SetMipsRegLo(m_Opcode.rd, GetMipsRegLo_S(m_Opcode.rt) >> m_Opcode.sa);
		m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
		return;
	}
	Map_GPR_32bit(m_Opcode.rd,TRUE,m_Opcode.rt);
	ShiftRightSignImmed(GetMipsRegMapLo(m_Opcode.rd),(BYTE)m_Opcode.sa);
}

void CRecompilerOps::SPECIAL_SLLV (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (m_Opcode.rd == 0) { return; }
	
	if (IsConst(m_Opcode.rs)) {
		DWORD Shift = (GetMipsRegLo(m_Opcode.rs) & 0x1F);
		if (IsConst(m_Opcode.rt)) {
			if (IsMapped(m_Opcode.rd)) { UnMap_GPR(m_Opcode.rd, FALSE); }
			m_RegWorkingSet.SetMipsRegLo(m_Opcode.rd, GetMipsRegLo(m_Opcode.rt) << Shift);
			m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
		} else {
			Map_GPR_32bit(m_Opcode.rd,TRUE,m_Opcode.rt);
			ShiftLeftSignImmed(GetMipsRegMapLo(m_Opcode.rd),(BYTE)Shift);
		}
		return;
	}
	Map_TempReg(x86_ECX,m_Opcode.rs,FALSE);
	AndConstToX86Reg(x86_ECX,0x1F);
	Map_GPR_32bit(m_Opcode.rd,TRUE,m_Opcode.rt);
	ShiftLeftSign(GetMipsRegMapLo(m_Opcode.rd));
}

void CRecompilerOps::SPECIAL_SRLV (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (m_Opcode.rd == 0) { return; }
	
	if (IsKnown(m_Opcode.rs) && IsConst(m_Opcode.rs)) {
		DWORD Shift = (GetMipsRegLo(m_Opcode.rs) & 0x1F);
		if (IsConst(m_Opcode.rt)) {
			if (IsMapped(m_Opcode.rd)) { UnMap_GPR(m_Opcode.rd, FALSE); }
			m_RegWorkingSet.SetMipsRegLo(m_Opcode.rd, GetMipsRegLo(m_Opcode.rt) >> Shift);
			m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
			return;
		}
		Map_GPR_32bit(m_Opcode.rd,TRUE,m_Opcode.rt);
		ShiftRightUnsignImmed(GetMipsRegMapLo(m_Opcode.rd),(BYTE)Shift);
		return;
	}
	Map_TempReg(x86_ECX,m_Opcode.rs,FALSE);
	AndConstToX86Reg(x86_ECX,0x1F);
	Map_GPR_32bit(m_Opcode.rd,TRUE,m_Opcode.rt);
	ShiftRightUnsign(GetMipsRegMapLo(m_Opcode.rd));
}

void CRecompilerOps::SPECIAL_SRAV (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (m_Opcode.rd == 0) { return; }
	
	if (IsKnown(m_Opcode.rs) && IsConst(m_Opcode.rs)) {
		DWORD Shift = (GetMipsRegLo(m_Opcode.rs) & 0x1F);
		if (IsConst(m_Opcode.rt)) {
			if (IsMapped(m_Opcode.rd)) { UnMap_GPR(m_Opcode.rd, FALSE); }
			m_RegWorkingSet.SetMipsRegLo(m_Opcode.rd, GetMipsRegLo_S(m_Opcode.rt) >> Shift);
			m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
			return;
		}
		Map_GPR_32bit(m_Opcode.rd,TRUE,m_Opcode.rt);
		ShiftRightSignImmed(GetMipsRegMapLo(m_Opcode.rd),(BYTE)Shift);
		return;
	}
	Map_TempReg(x86_ECX,m_Opcode.rs,FALSE);
	AndConstToX86Reg(x86_ECX,0x1F);
	Map_GPR_32bit(m_Opcode.rd,TRUE,m_Opcode.rt);
	ShiftRightSign(GetMipsRegMapLo(m_Opcode.rd));
}

void CRecompilerOps::SPECIAL_JR (void) {
	if ( m_NextInstruction == NORMAL ) 
	{
		CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
		if ((m_CompilePC & 0xFFC) == 0xFFC) 
		{
			if (IsMapped(m_Opcode.rs)) {
				MoveX86regToVariable(GetMipsRegMapLo(m_Opcode.rs),&R4300iOp::m_JumpToLocation,"R4300iOp::m_JumpToLocation");
				m_RegWorkingSet.WriteBackRegisters();
			} else {
				m_RegWorkingSet.WriteBackRegisters();
				MoveX86regToVariable(Map_TempReg(x86_Any,m_Opcode.rs,FALSE),&R4300iOp::m_JumpToLocation,"R4300iOp::m_JumpToLocation");
			}
			OverflowDelaySlot(true);
			return;
		}

		m_Section->m_Jump.FallThrough   = false;
		m_Section->m_Jump.LinkLocation  = NULL;
		m_Section->m_Jump.LinkLocation2 = NULL;
		m_Section->m_Cont.FallThrough   = FALSE;
		m_Section->m_Cont.LinkLocation  = NULL;
		m_Section->m_Cont.LinkLocation2 = NULL;

		if (DelaySlotEffectsCompare(m_CompilePC,m_Opcode.rs,0)) {
			if (IsConst(m_Opcode.rs)) { 
				MoveConstToVariable(GetMipsRegLo(m_Opcode.rs),_PROGRAM_COUNTER, "PROGRAM_COUNTER");
			} else 	if (IsMapped(m_Opcode.rs)) { 
				MoveX86regToVariable(GetMipsRegMapLo(m_Opcode.rs),_PROGRAM_COUNTER, "PROGRAM_COUNTER");
			} else {
				MoveX86regToVariable(Map_TempReg(x86_Any,m_Opcode.rs,FALSE),_PROGRAM_COUNTER, "PROGRAM_COUNTER");
			}
		}
		m_NextInstruction = DO_DELAY_SLOT;
	} else if (m_NextInstruction == DELAY_SLOT_DONE ) {		
		if (DelaySlotEffectsCompare(m_CompilePC,m_Opcode.rs,0)) {
			m_Section->CompileExit(m_CompilePC,(DWORD)-1,m_RegWorkingSet,CExitInfo::Normal,TRUE,NULL);
		} else {
			UpdateCounters(m_RegWorkingSet,true,true);
			if (IsConst(m_Opcode.rs)) { 
				MoveConstToVariable(GetMipsRegLo(m_Opcode.rs),_PROGRAM_COUNTER, "PROGRAM_COUNTER");
			} else if (IsMapped(m_Opcode.rs)) { 
				MoveX86regToVariable(GetMipsRegMapLo(m_Opcode.rs),_PROGRAM_COUNTER, "PROGRAM_COUNTER");
			} else {
				MoveX86regToVariable(Map_TempReg(x86_Any,m_Opcode.rs,FALSE),_PROGRAM_COUNTER, "PROGRAM_COUNTER");
			}
			m_Section->CompileExit((DWORD)-1, (DWORD)-1,m_RegWorkingSet,CExitInfo::Normal,TRUE,NULL);
			if (m_Section->m_JumpSection)
			{
				m_Section->GenerateSectionLinkage();
			}
		}
		m_NextInstruction = END_BLOCK;
	} else if (bHaveDebugger()) {
		g_Notify->DisplayError(L"WTF\n\nBranch\nNextInstruction = %X", m_NextInstruction);
	}
}

void CRecompilerOps::SPECIAL_JALR (void) 
{
	if ( m_NextInstruction == NORMAL ) 
	{
		CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
		if (DelaySlotEffectsCompare(m_CompilePC,m_Opcode.rs,0) && (m_CompilePC & 0xFFC) != 0xFFC)
		{
			if (IsConst(m_Opcode.rs)) { 
				MoveConstToVariable(GetMipsRegLo(m_Opcode.rs),_PROGRAM_COUNTER, "PROGRAM_COUNTER");
			} else 	if (IsMapped(m_Opcode.rs)) { 
				MoveX86regToVariable(GetMipsRegMapLo(m_Opcode.rs),_PROGRAM_COUNTER, "PROGRAM_COUNTER");
			} else {
				MoveX86regToVariable(Map_TempReg(x86_Any,m_Opcode.rs,FALSE),_PROGRAM_COUNTER, "PROGRAM_COUNTER");
			}
		}
		UnMap_GPR( m_Opcode.rd, FALSE);
		m_RegWorkingSet.SetMipsRegLo(m_Opcode.rd,m_CompilePC + 8);
		m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
		if ((m_CompilePC & 0xFFC) == 0xFFC) 
		{
			if (IsMapped(m_Opcode.rs)) {
				MoveX86regToVariable(GetMipsRegMapLo(m_Opcode.rs),&R4300iOp::m_JumpToLocation,"R4300iOp::m_JumpToLocation");
				m_RegWorkingSet.WriteBackRegisters();
			} else {
				m_RegWorkingSet.WriteBackRegisters();
				MoveX86regToVariable(Map_TempReg(x86_Any,m_Opcode.rs,FALSE),&R4300iOp::m_JumpToLocation,"R4300iOp::m_JumpToLocation");
			}
			OverflowDelaySlot(true);
			return;
		}

		m_Section->m_Jump.FallThrough   = false;
		m_Section->m_Jump.LinkLocation  = NULL;
		m_Section->m_Jump.LinkLocation2 = NULL;
		m_Section->m_Cont.FallThrough   = FALSE;
		m_Section->m_Cont.LinkLocation  = NULL;
		m_Section->m_Cont.LinkLocation2 = NULL;

		m_NextInstruction = DO_DELAY_SLOT;
	} else if (m_NextInstruction == DELAY_SLOT_DONE ) {		
		if (DelaySlotEffectsCompare(m_CompilePC,m_Opcode.rs,0)) {
			m_Section->CompileExit(m_CompilePC,(DWORD)-1,m_RegWorkingSet,CExitInfo::Normal,TRUE,NULL);
		} else {
			UpdateCounters(m_RegWorkingSet,true,true);
			if (IsConst(m_Opcode.rs)) { 
				MoveConstToVariable(GetMipsRegLo(m_Opcode.rs),_PROGRAM_COUNTER, "PROGRAM_COUNTER");
			} else if (IsMapped(m_Opcode.rs)) { 
				MoveX86regToVariable(GetMipsRegMapLo(m_Opcode.rs),_PROGRAM_COUNTER, "PROGRAM_COUNTER");
			} else {
				MoveX86regToVariable(Map_TempReg(x86_Any,m_Opcode.rs,FALSE),_PROGRAM_COUNTER, "PROGRAM_COUNTER");
			}
			m_Section->CompileExit((DWORD)-1, (DWORD)-1,m_RegWorkingSet,CExitInfo::Normal,TRUE,NULL);
			if (m_Section->m_JumpSection)
			{
				m_Section->GenerateSectionLinkage();
			}
		}
		m_NextInstruction = END_BLOCK;
	} else if (bHaveDebugger()) {
		g_Notify->DisplayError(L"WTF\n\nBranch\nNextInstruction = %X", m_NextInstruction);
	}
}

void CRecompilerOps::SPECIAL_SYSCALL (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	m_Section->CompileExit(m_CompilePC,(DWORD)-1,m_RegWorkingSet,CExitInfo::DoSysCall,TRUE,NULL);
	m_NextInstruction = END_BLOCK;
}

void CRecompilerOps::SPECIAL_MFLO (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (m_Opcode.rd == 0) { return; }

	Map_GPR_64bit(m_Opcode.rd,-1);
	MoveVariableToX86reg(&_RegLO->UW[0],"_RegLO->UW[0]",GetMipsRegMapLo(m_Opcode.rd));
	MoveVariableToX86reg(&_RegLO->UW[1],"_RegLO->UW[1]",GetMipsRegMapHi(m_Opcode.rd));
}

void CRecompilerOps::SPECIAL_MTLO (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	if (IsKnown(m_Opcode.rs) && IsConst(m_Opcode.rs)) {
		if (Is64Bit(m_Opcode.rs)) {
			MoveConstToVariable(GetMipsRegHi(m_Opcode.rs),&_RegLO->UW[1],"_RegLO->UW[1]");
		} else if (IsSigned(m_Opcode.rs) && ((GetMipsRegLo(m_Opcode.rs) & 0x80000000) != 0)) {
			MoveConstToVariable(0xFFFFFFFF,&_RegLO->UW[1],"_RegLO->UW[1]");
		} else {
			MoveConstToVariable(0,&_RegLO->UW[1],"_RegLO->UW[1]");
		}
		MoveConstToVariable(GetMipsRegLo(m_Opcode.rs), &_RegLO->UW[0],"_RegLO->UW[0]");
	} else if (IsKnown(m_Opcode.rs) && IsMapped(m_Opcode.rs)) {
		if (Is64Bit(m_Opcode.rs)) {
			MoveX86regToVariable(GetMipsRegMapHi(m_Opcode.rs),&_RegLO->UW[1],"_RegLO->UW[1]");
		} else if (IsSigned(m_Opcode.rs)) {
			MoveX86regToVariable(Map_TempReg(x86_Any,m_Opcode.rs,TRUE),&_RegLO->UW[1],"_RegLO->UW[1]");
		} else {
			MoveConstToVariable(0,&_RegLO->UW[1],"_RegLO->UW[1]");
		}
		MoveX86regToVariable(GetMipsRegMapLo(m_Opcode.rs), &_RegLO->UW[0],"_RegLO->UW[0]");
	} else {
		x86Reg reg = Map_TempReg(x86_Any,m_Opcode.rs,TRUE);
		MoveX86regToVariable(reg,&_RegLO->UW[1],"_RegLO->UW[1]");
		MoveX86regToVariable(Map_TempReg(reg,m_Opcode.rs,FALSE), &_RegLO->UW[0],"_RegLO->UW[0]");
	}
}

void CRecompilerOps::SPECIAL_MFHI (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (m_Opcode.rd == 0) { return; }

	Map_GPR_64bit(m_Opcode.rd,-1);
	MoveVariableToX86reg(&_RegHI->UW[0],"_RegHI->UW[0]",GetMipsRegMapLo(m_Opcode.rd));
	MoveVariableToX86reg(&_RegHI->UW[1],"_RegHI->UW[1]",GetMipsRegMapHi(m_Opcode.rd));
}

void CRecompilerOps::SPECIAL_MTHI (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	if (IsKnown(m_Opcode.rs) && IsConst(m_Opcode.rs)) {
		if (Is64Bit(m_Opcode.rs)) {
			MoveConstToVariable(GetMipsRegHi(m_Opcode.rs),&_RegHI->UW[1],"_RegHI->UW[1]");
		} else if (IsSigned(m_Opcode.rs) && ((GetMipsRegLo(m_Opcode.rs) & 0x80000000) != 0)) {
			MoveConstToVariable(0xFFFFFFFF,&_RegHI->UW[1],"_RegHI->UW[1]");
		} else {
			MoveConstToVariable(0,&_RegHI->UW[1],"_RegHI->UW[1]");
		}
		MoveConstToVariable(GetMipsRegLo(m_Opcode.rs), &_RegHI->UW[0],"_RegHI->UW[0]");
	} else if (IsKnown(m_Opcode.rs) && IsMapped(m_Opcode.rs)) {
		if (Is64Bit(m_Opcode.rs)) {
			MoveX86regToVariable(GetMipsRegMapHi(m_Opcode.rs),&_RegHI->UW[1],"_RegHI->UW[1]");
		} else if (IsSigned(m_Opcode.rs)) {
			MoveX86regToVariable(Map_TempReg(x86_Any,m_Opcode.rs,TRUE),&_RegHI->UW[1],"_RegHI->UW[1]");
		} else {
			MoveConstToVariable(0,&_RegHI->UW[1],"_RegHI->UW[1]");
		}
		MoveX86regToVariable(GetMipsRegMapLo(m_Opcode.rs), &_RegHI->UW[0],"_RegHI->UW[0]");
	} else {
		x86Reg reg = Map_TempReg(x86_Any,m_Opcode.rs,TRUE);
		MoveX86regToVariable(reg,&_RegHI->UW[1],"_RegHI->UW[1]");
		MoveX86regToVariable(Map_TempReg(reg,m_Opcode.rs,FALSE), &_RegHI->UW[0],"_RegHI->UW[0]");
	}
}

void CRecompilerOps::SPECIAL_DSLLV (void) {
	BYTE * Jump[2];

	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (m_Opcode.rd == 0) { return; }
	
	if (IsConst(m_Opcode.rs)) 
	{
		//DWORD Shift = (GetMipsRegLo(m_Opcode.rs) & 0x3F);
		CRecompilerOps::UnknownOpcode();
		return;
	}
	Map_TempReg(x86_ECX,m_Opcode.rs,FALSE);
	AndConstToX86Reg(x86_ECX,0x3F);
	Map_GPR_64bit(m_Opcode.rd,m_Opcode.rt);
	CompConstToX86reg(x86_ECX,0x20);
	JaeLabel8("MORE32", 0);
	Jump[0] = m_RecompPos - 1;
	ShiftLeftDouble(GetMipsRegMapHi(m_Opcode.rd),GetMipsRegMapLo(m_Opcode.rd));
	ShiftLeftSign(GetMipsRegMapLo(m_Opcode.rd));
	JmpLabel8("continue", 0);
	Jump[1] = m_RecompPos - 1;
	
	//MORE32:
	CPU_Message("");
	CPU_Message("      MORE32:");
	SetJump8(Jump[0],m_RecompPos);
	MoveX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapHi(m_Opcode.rd));
	XorX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapLo(m_Opcode.rd));
	AndConstToX86Reg(x86_ECX,0x1F);
	ShiftLeftSign(GetMipsRegMapHi(m_Opcode.rd));

	//continue:
	CPU_Message("");
	CPU_Message("      continue:");
	SetJump8(Jump[1],m_RecompPos);
}

void CRecompilerOps::SPECIAL_DSRLV (void) {
	BYTE * Jump[2];

	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (m_Opcode.rd == 0) { return; }
	
	if (IsConst(m_Opcode.rs)) {
		DWORD Shift = (GetMipsRegLo(m_Opcode.rs) & 0x3F);
		if (IsConst(m_Opcode.rt)) {
			if (IsMapped(m_Opcode.rd)) { UnMap_GPR(m_Opcode.rd, FALSE); }
			m_RegWorkingSet.SetMipsReg(m_Opcode.rd, Is64Bit(m_Opcode.rt)?GetMipsReg(m_Opcode.rt):(__int64)GetMipsRegLo_S(m_Opcode.rt));
			m_RegWorkingSet.SetMipsReg(m_Opcode.rd, GetMipsReg(m_Opcode.rd) >> Shift);
			if ((GetMipsRegHi(m_Opcode.rd) == 0) && (GetMipsRegLo(m_Opcode.rd) & 0x80000000) == 0) {
				m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
			} else if ((GetMipsRegHi(m_Opcode.rd) == 0xFFFFFFFF) && (GetMipsRegLo(m_Opcode.rd) & 0x80000000) != 0) {
				m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
			} else {
				m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_64);
			}
			return;
		}
		if (m_Opcode.rd == m_Opcode.rt)
		{
			CRecompilerOps::UnknownOpcode();
			return;
		}

		Map_TempReg(x86_ECX,-1,FALSE);
		MoveConstToX86reg(Shift, x86_ECX);
		Map_GPR_64bit(m_Opcode.rd,m_Opcode.rt);
		if ((Shift & 0x20) == 0x20)
		{
			MoveX86RegToX86Reg(GetMipsRegMapHi(m_Opcode.rd),GetMipsRegMapLo(m_Opcode.rd));
			XorX86RegToX86Reg(GetMipsRegMapHi(m_Opcode.rd),GetMipsRegMapHi(m_Opcode.rd));
			AndConstToX86Reg(x86_ECX,0x1F);
			ShiftRightUnsign(GetMipsRegMapLo(m_Opcode.rd));
		} else {
			ShiftRightDouble(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapHi(m_Opcode.rd));
			ShiftRightUnsign(GetMipsRegMapHi(m_Opcode.rd));
		}
	} else {
		Map_TempReg(x86_ECX,m_Opcode.rs,FALSE);
		AndConstToX86Reg(x86_ECX,0x3F);
		Map_GPR_64bit(m_Opcode.rd,m_Opcode.rt);
		CompConstToX86reg(x86_ECX,0x20);
		JaeLabel8("MORE32", 0);
		Jump[0] = m_RecompPos - 1;
		ShiftRightDouble(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapHi(m_Opcode.rd));
		ShiftRightUnsign(GetMipsRegMapHi(m_Opcode.rd));
		JmpLabel8("continue", 0);
		Jump[1] = m_RecompPos - 1;
		
		//MORE32:
		CPU_Message("");
		CPU_Message("      MORE32:");
		SetJump8(Jump[0],m_RecompPos);
		MoveX86RegToX86Reg(GetMipsRegMapHi(m_Opcode.rd),GetMipsRegMapLo(m_Opcode.rd));
		XorX86RegToX86Reg(GetMipsRegMapHi(m_Opcode.rd),GetMipsRegMapHi(m_Opcode.rd));
		AndConstToX86Reg(x86_ECX,0x1F);
		ShiftRightUnsign(GetMipsRegMapLo(m_Opcode.rd));

		//continue:
		CPU_Message("");
		CPU_Message("      continue:");
		SetJump8(Jump[1],m_RecompPos);
	}
}

void CRecompilerOps::SPECIAL_DSRAV (void) 
{
	BYTE * Jump[2];

	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (m_Opcode.rd == 0) { return; }
	
	if (IsConst(m_Opcode.rs)) 
	{
		//DWORD Shift = (GetMipsRegLo(m_Opcode.rs) & 0x3F);
		CRecompilerOps::UnknownOpcode();
		return;
	}
	Map_TempReg(x86_ECX,m_Opcode.rs,FALSE);
	AndConstToX86Reg(x86_ECX,0x3F);
	Map_GPR_64bit(m_Opcode.rd,m_Opcode.rt);
	CompConstToX86reg(x86_ECX,0x20);
	JaeLabel8("MORE32", 0);
	Jump[0] = m_RecompPos - 1;
	ShiftRightDouble(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapHi(m_Opcode.rd));
	ShiftRightSign(GetMipsRegMapHi(m_Opcode.rd));
	JmpLabel8("continue", 0);
	Jump[1] = m_RecompPos - 1;
	
	//MORE32:
	CPU_Message("");
	CPU_Message("      MORE32:");
	SetJump8(Jump[0],m_RecompPos);
	MoveX86RegToX86Reg(GetMipsRegMapHi(m_Opcode.rd),GetMipsRegMapLo(m_Opcode.rd));
	ShiftRightSignImmed(GetMipsRegMapHi(m_Opcode.rd),0x1F);
	AndConstToX86Reg(x86_ECX,0x1F);
	ShiftRightSign(GetMipsRegMapLo(m_Opcode.rd));

	//continue:
	CPU_Message("");
	CPU_Message("      continue:");
	SetJump8(Jump[1],m_RecompPos);
}

void CRecompilerOps::SPECIAL_MULT ( void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	m_RegWorkingSet.SetX86Protected(x86_EDX,TRUE);
	Map_TempReg(x86_EAX,m_Opcode.rs,FALSE);
	m_RegWorkingSet.SetX86Protected(x86_EDX,FALSE);
	Map_TempReg(x86_EDX,m_Opcode.rt,FALSE);

	imulX86reg(x86_EDX);

	MoveX86regToVariable(x86_EAX,&_RegLO->UW[0],"_RegLO->UW[0]");
	MoveX86regToVariable(x86_EDX,&_RegHI->UW[0],"_RegHI->UW[0]");
	ShiftRightSignImmed(x86_EAX,31);	/* paired */
	ShiftRightSignImmed(x86_EDX,31);
	MoveX86regToVariable(x86_EAX,&_RegLO->UW[1],"_RegLO->UW[1]");
	MoveX86regToVariable(x86_EDX,&_RegHI->UW[1],"_RegHI->UW[1]");
}

void CRecompilerOps::SPECIAL_MULTU (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	m_RegWorkingSet.SetX86Protected(x86_EDX, TRUE);
	Map_TempReg(x86_EAX,m_Opcode.rs,FALSE);
	m_RegWorkingSet.SetX86Protected(x86_EDX,FALSE);
	Map_TempReg(x86_EDX,m_Opcode.rt,FALSE);

	MulX86reg(x86_EDX);

	MoveX86regToVariable(x86_EAX,&_RegLO->UW[0],"_RegLO->UW[0]");
	MoveX86regToVariable(x86_EDX,&_RegHI->UW[0],"_RegHI->UW[0]");
	ShiftRightSignImmed(x86_EAX,31);	/* paired */
	ShiftRightSignImmed(x86_EDX,31);
	MoveX86regToVariable(x86_EAX,&_RegLO->UW[1],"_RegLO->UW[1]");
	MoveX86regToVariable(x86_EDX,&_RegHI->UW[1],"_RegHI->UW[1]");
}

void CRecompilerOps::SPECIAL_DIV (void) 
{
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	if (IsConst(m_Opcode.rt)) {
		if (GetMipsRegLo(m_Opcode.rt) == 0) {
			MoveConstToVariable(0, &_RegLO->UW[0], "_RegLO->UW[0]");
			MoveConstToVariable(0, &_RegLO->UW[1], "_RegLO->UW[1]");
			MoveConstToVariable(0, &_RegHI->UW[0], "_RegHI->UW[0]");
			MoveConstToVariable(0, &_RegHI->UW[1], "_RegHI->UW[1]");
			return;
		}
	} else {
		if (IsMapped(m_Opcode.rt)) {
			CompConstToX86reg(GetMipsRegMapLo(m_Opcode.rt),0);
		} else {
			CompConstToVariable(0, &_GPR[m_Opcode.rt].W[0], CRegName::GPR_Lo[m_Opcode.rt]);
		}
		m_Section->CompileExit(m_CompilePC, m_CompilePC,m_RegWorkingSet,CExitInfo::DivByZero,FALSE,JeLabel32);
	}
	/*	lo = (SD)rs / (SD)rt;
		hi = (SD)rs % (SD)rt; */

	m_RegWorkingSet.SetX86Protected(x86_EDX,TRUE);
	Map_TempReg(x86_EAX,m_Opcode.rs,FALSE);

	/* edx is the signed portion to eax */
	m_RegWorkingSet.SetX86Protected(x86_EDX, FALSE);
	Map_TempReg(x86_EDX, -1, FALSE);

	MoveX86RegToX86Reg(x86_EAX, x86_EDX);
	ShiftRightSignImmed(x86_EDX,31);

	if (IsMapped(m_Opcode.rt)) {
		idivX86reg(GetMipsRegMapLo(m_Opcode.rt));
	} else {
		idivX86reg(Map_TempReg(x86_Any,m_Opcode.rt,FALSE));
	}
		

	MoveX86regToVariable(x86_EAX,&_RegLO->UW[0],"_RegLO->UW[0]");
	MoveX86regToVariable(x86_EDX,&_RegHI->UW[0],"_RegHI->UW[0]");
	ShiftRightSignImmed(x86_EAX,31);	/* paired */
	ShiftRightSignImmed(x86_EDX,31);
	MoveX86regToVariable(x86_EAX,&_RegLO->UW[1],"_RegLO->UW[1]");
	MoveX86regToVariable(x86_EDX,&_RegHI->UW[1],"_RegHI->UW[1]");
}

void CRecompilerOps::SPECIAL_DIVU ( void) {
	BYTE *Jump[2];
	x86Reg Reg;

	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	if (IsConst(m_Opcode.rt)) {
		if (GetMipsRegLo(m_Opcode.rt) == 0) {
			MoveConstToVariable(0, &_RegLO->UW[0], "_RegLO->UW[0]");
			MoveConstToVariable(0, &_RegLO->UW[1], "_RegLO->UW[1]");
			MoveConstToVariable(0, &_RegHI->UW[0], "_RegHI->UW[0]");
			MoveConstToVariable(0, &_RegHI->UW[1], "_RegHI->UW[1]");
			return;
		}
		Jump[1] = NULL;
	} else {
		if (IsMapped(m_Opcode.rt)) {
			CompConstToX86reg(GetMipsRegMapLo(m_Opcode.rt),0);
		} else {
			CompConstToVariable(0, &_GPR[m_Opcode.rt].W[0], CRegName::GPR_Lo[m_Opcode.rt]);
		}
		JneLabel8("NoExcept", 0);
		Jump[0] = m_RecompPos - 1;

		MoveConstToVariable(0, &_RegLO->UW[0], "_RegLO->UW[0]");
		MoveConstToVariable(0, &_RegLO->UW[1], "_RegLO->UW[1]");
		MoveConstToVariable(0, &_RegHI->UW[0], "_RegHI->UW[0]");
		MoveConstToVariable(0, &_RegHI->UW[1], "_RegHI->UW[1]");

		JmpLabel8("EndDivu", 0);
		Jump[1] = m_RecompPos - 1;
		
		CPU_Message("");
		CPU_Message("      NoExcept:");
		SetJump8(Jump[0],m_RecompPos);
	}


	/*	lo = (UD)rs / (UD)rt;
		hi = (UD)rs % (UD)rt; */

	m_RegWorkingSet.SetX86Protected(x86_EAX,TRUE);
	Map_TempReg(x86_EDX, 0, FALSE);
	m_RegWorkingSet.SetX86Protected(x86_EAX,FALSE);

	Map_TempReg(x86_EAX,m_Opcode.rs,FALSE);
	Reg = Map_TempReg(x86_Any,m_Opcode.rt,FALSE);

	DivX86reg(Reg);

	MoveX86regToVariable(x86_EAX,&_RegLO->UW[0],"_RegLO->UW[0]");
	MoveX86regToVariable(x86_EDX,&_RegHI->UW[0],"_RegHI->UW[0]");

	/* wouldnt these be zero (???) */

	ShiftRightSignImmed(x86_EAX,31);	/* paired */
	ShiftRightSignImmed(x86_EDX,31);
	MoveX86regToVariable(x86_EAX,&_RegLO->UW[1],"_RegLO->UW[1]");
	MoveX86regToVariable(x86_EDX,&_RegHI->UW[1],"_RegHI->UW[1]");

	if( Jump[1] != NULL ) {
		CPU_Message("");
		CPU_Message("      EndDivu:");
		SetJump8(Jump[1],m_RecompPos);
	}
}

void CRecompilerOps::SPECIAL_DMULT (void) 
{
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	if (m_Opcode.rs != 0) { UnMap_GPR(m_Opcode.rs,TRUE); }
	if (m_Opcode.rs != 0) { UnMap_GPR(m_Opcode.rt,TRUE); }
	BeforeCallDirect(m_RegWorkingSet);
	MoveConstToVariable(m_Opcode.Hex, &R4300iOp::m_Opcode.Hex, "R4300iOp::m_Opcode.Hex");
	Call_Direct(R4300iOp::SPECIAL_DMULT, "R4300iOp::SPECIAL_DMULT");
	AfterCallDirect(m_RegWorkingSet);
}

void CRecompilerOps::SPECIAL_DMULTU (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	UnMap_GPR(m_Opcode.rs,TRUE);
	UnMap_GPR(m_Opcode.rt,TRUE);
	BeforeCallDirect(m_RegWorkingSet);
	MoveConstToVariable(m_Opcode.Hex, &R4300iOp::m_Opcode.Hex, "R4300iOp::m_Opcode.Hex");
	Call_Direct(R4300iOp::SPECIAL_DMULTU, "R4300iOp::SPECIAL_DMULTU");
	AfterCallDirect(m_RegWorkingSet);

#ifdef toremove
	/* _RegLO->UDW = (uint64)_GPR[m_Opcode.rs].UW[0] * (uint64)_GPR[m_Opcode.rt].UW[0]; */
	X86Protected(x86_EDX) = TRUE;
	Map_TempReg(x86_EAX,m_Opcode.rs,FALSE);
	X86Protected(x86_EDX) = FALSE;
	Map_TempReg(x86_EDX,m_Opcode.rt,FALSE);

	MulX86reg(x86_EDX);
	MoveX86regToVariable(x86_EAX, &_RegLO->UW[0], "_RegLO->UW[0]");
	MoveX86regToVariable(x86_EDX, &_RegLO->UW[1], "_RegLO->UW[1]");

	/* _RegHI->UDW = (uint64)_GPR[m_Opcode.rs].UW[1] * (uint64)_GPR[m_Opcode.rt].UW[1]; */
	Map_TempReg(x86_EAX,m_Opcode.rs,TRUE);
	Map_TempReg(x86_EDX,m_Opcode.rt,TRUE);

	MulX86reg(x86_EDX);
	MoveX86regToVariable(x86_EAX, &_RegHI->UW[0], "_RegHI->UW[0]");
	MoveX86regToVariable(x86_EDX, &_RegHI->UW[1], "_RegHI->UW[1]");

	/* Tmp[0].UDW = (uint64)_GPR[m_Opcode.rs].UW[1] * (uint64)_GPR[m_Opcode.rt].UW[0]; */
	Map_TempReg(x86_EAX,m_Opcode.rs,TRUE);
	Map_TempReg(x86_EDX,m_Opcode.rt,FALSE);

	Map_TempReg(x86_EBX,-1,FALSE);
	Map_TempReg(x86_ECX,-1,FALSE);

	MulX86reg(x86_EDX);
	MoveX86RegToX86Reg(x86_EAX, x86_EBX); /* EDX:EAX -> ECX:EBX */
	MoveX86RegToX86Reg(x86_EDX, x86_ECX);

	/* Tmp[1].UDW = (uint64)_GPR[m_Opcode.rs].UW[0] * (uint64)_GPR[m_Opcode.rt].UW[1]; */
	Map_TempReg(x86_EAX,m_Opcode.rs,FALSE);
	Map_TempReg(x86_EDX,m_Opcode.rt,TRUE);

	MulX86reg(x86_EDX);
	Map_TempReg(x86_ESI,-1,FALSE);
	Map_TempReg(x86_EDI,-1,FALSE);
	MoveX86RegToX86Reg(x86_EAX, x86_ESI); /* EDX:EAX -> EDI:ESI */
	MoveX86RegToX86Reg(x86_EDX, x86_EDI);

	/* Tmp[2].UDW = (uint64)_RegLO->UW[1] + (uint64)Tmp[0].UW[0] + (uint64)Tmp[1].UW[0]; */
	XorX86RegToX86Reg(x86_EDX, x86_EDX);
	MoveVariableToX86reg(&_RegLO->UW[1], "_RegLO->UW[1]", x86_EAX);
	AddX86RegToX86Reg(x86_EAX, x86_EBX);
	AddConstToX86Reg(x86_EDX, 0);
	AddX86RegToX86Reg(x86_EAX, x86_ESI);
	AddConstToX86Reg(x86_EDX, 0);			/* EDX:EAX */

	/* _RegLO->UDW += ((uint64)Tmp[0].UW[0] + (uint64)Tmp[1].UW[0]) << 32; */
	/* [low+4] += ebx + esi */

	AddX86regToVariable(x86_EBX, &_RegLO->UW[1], "_RegLO->UW[1]");
	AddX86regToVariable(x86_ESI, &_RegLO->UW[1], "_RegLO->UW[1]");

	/* _RegHI->UDW += (uint64)Tmp[0].UW[1] + (uint64)Tmp[1].UW[1] + Tmp[2].UW[1]; */
	/* [hi] += ecx + edi + edx */
	
	AddX86regToVariable(x86_ECX, &_RegHI->UW[0], "_RegHI->UW[0]");
	AdcConstToVariable(&_RegHI->UW[1], "_RegHI->UW[1]", 0);

	AddX86regToVariable(x86_EDI, &_RegHI->UW[0], "_RegHI->UW[0]");
	AdcConstToVariable(&_RegHI->UW[1], "_RegHI->UW[1]", 0);

	AddX86regToVariable(x86_EDX, &_RegHI->UW[0], "_RegHI->UW[0]");
	AdcConstToVariable(&_RegHI->UW[1], "_RegHI->UW[1]", 0);
#endif
}

void CRecompilerOps::SPECIAL_DDIV (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	UnMap_GPR(m_Opcode.rs,TRUE);
	UnMap_GPR(m_Opcode.rt,TRUE);
	BeforeCallDirect(m_RegWorkingSet);
	MoveConstToVariable(m_Opcode.Hex, &R4300iOp::m_Opcode.Hex, "R4300iOp::m_Opcode.Hex");
	Call_Direct(R4300iOp::SPECIAL_DDIV, "R4300iOp::SPECIAL_DDIV");
	AfterCallDirect(m_RegWorkingSet);
}

void CRecompilerOps::SPECIAL_DDIVU (void) 
{
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	UnMap_GPR(m_Opcode.rs,TRUE);
	UnMap_GPR(m_Opcode.rt,TRUE);
	BeforeCallDirect(m_RegWorkingSet);
	MoveConstToVariable(m_Opcode.Hex, &R4300iOp::m_Opcode.Hex, "R4300iOp::m_Opcode.Hex");
	Call_Direct(R4300iOp::SPECIAL_DDIVU, "R4300iOp::SPECIAL_DDIVU");
	AfterCallDirect(m_RegWorkingSet);
}

void CRecompilerOps::SPECIAL_ADD (void) {
	int source1 = m_Opcode.rd == m_Opcode.rt?m_Opcode.rt:m_Opcode.rs;
	int source2 = m_Opcode.rd == m_Opcode.rt?m_Opcode.rs:m_Opcode.rt;

	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (m_Opcode.rd == 0) { return; }

	if (IsConst(source1) && IsConst(source2)) {
		DWORD temp = GetMipsRegLo(source1) + GetMipsRegLo(source2);
		if (IsMapped(m_Opcode.rd)) { UnMap_GPR(m_Opcode.rd, FALSE); }
		m_RegWorkingSet.SetMipsRegLo(m_Opcode.rd,temp);
		m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
		return;
	}

	Map_GPR_32bit(m_Opcode.rd,TRUE, source1);
	if (IsConst(source2)) {
		AddConstToX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegLo(source2));
	} else if (IsKnown(source2) && IsMapped(source2)) {
		AddX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapLo(source2));
	} else {
		AddVariableToX86reg(GetMipsRegMapLo(m_Opcode.rd),&_GPR[source2].W[0],CRegName::GPR_Lo[source2]);
	}
	if (g_System->bFastSP() && m_Opcode.rd == 29)
	{ 
		g_MMU->ResetMemoryStack(); 
	}
}

void CRecompilerOps::SPECIAL_ADDU (void) {
	int source1 = m_Opcode.rd == m_Opcode.rt?m_Opcode.rt:m_Opcode.rs;
	int source2 = m_Opcode.rd == m_Opcode.rt?m_Opcode.rs:m_Opcode.rt;

	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (m_Opcode.rd == 0) { return; }

	if (IsConst(source1) && IsConst(source2)) {
		DWORD temp = GetMipsRegLo(source1) + GetMipsRegLo(source2);
		if (IsMapped(m_Opcode.rd)) { UnMap_GPR(m_Opcode.rd, FALSE); }
		m_RegWorkingSet.SetMipsRegLo(m_Opcode.rd,temp);
		m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
		return;
	}

	Map_GPR_32bit(m_Opcode.rd,TRUE, source1);
	if (IsConst(source2)) {
		AddConstToX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegLo(source2));
	} else if (IsKnown(source2) && IsMapped(source2)) {
		AddX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapLo(source2));
	} else {
		AddVariableToX86reg(GetMipsRegMapLo(m_Opcode.rd),&_GPR[source2].W[0],CRegName::GPR_Lo[source2]);
	}
	if (g_System->bFastSP() && m_Opcode.rd == 29)
	{ 
		g_MMU->ResetMemoryStack(); 
	}
}

void CRecompilerOps::SPECIAL_SUB (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (m_Opcode.rd == 0) { return; }

	if (IsConst(m_Opcode.rt)  && IsConst(m_Opcode.rs)) {
		DWORD temp = GetMipsRegLo(m_Opcode.rs) - GetMipsRegLo(m_Opcode.rt);
		if (IsMapped(m_Opcode.rd)) { UnMap_GPR(m_Opcode.rd, FALSE); }
		m_RegWorkingSet.SetMipsRegLo(m_Opcode.rd,temp);
		m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
	} else {
		if (m_Opcode.rd == m_Opcode.rt) {
			x86Reg Reg = Map_TempReg(x86_Any,m_Opcode.rt,FALSE);
			Map_GPR_32bit(m_Opcode.rd,TRUE, m_Opcode.rs);
			SubX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd),Reg);
			return;
		}
		Map_GPR_32bit(m_Opcode.rd,TRUE, m_Opcode.rs);
		if (IsConst(m_Opcode.rt)) {
			SubConstFromX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegLo(m_Opcode.rt));
		} else if (IsMapped(m_Opcode.rt)) {
			SubX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapLo(m_Opcode.rt));
		} else {
			SubVariableFromX86reg(GetMipsRegMapLo(m_Opcode.rd),&_GPR[m_Opcode.rt].W[0],CRegName::GPR_Lo[m_Opcode.rt]);
		}
	}
	if (g_System->bFastSP() && m_Opcode.rd == 29)
	{ 
		g_MMU->ResetMemoryStack(); 
	}
}

void CRecompilerOps::SPECIAL_SUBU (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (m_Opcode.rd == 0) { return; }

	if (IsConst(m_Opcode.rt)  && IsConst(m_Opcode.rs)) {
		DWORD temp = GetMipsRegLo(m_Opcode.rs) - GetMipsRegLo(m_Opcode.rt);
		if (IsMapped(m_Opcode.rd)) { UnMap_GPR(m_Opcode.rd, FALSE); }
		m_RegWorkingSet.SetMipsRegLo(m_Opcode.rd,temp);
		m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
	} else {
		if (m_Opcode.rd == m_Opcode.rt) {
			x86Reg Reg = Map_TempReg(x86_Any,m_Opcode.rt,FALSE);
			Map_GPR_32bit(m_Opcode.rd,TRUE, m_Opcode.rs);
			SubX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd),Reg);
			return;
		}
		Map_GPR_32bit(m_Opcode.rd,TRUE, m_Opcode.rs);
		if (IsConst(m_Opcode.rt)) {
			SubConstFromX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegLo(m_Opcode.rt));
		} else if (IsMapped(m_Opcode.rt)) {
			SubX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapLo(m_Opcode.rt));
		} else {
			SubVariableFromX86reg(GetMipsRegMapLo(m_Opcode.rd),&_GPR[m_Opcode.rt].W[0],CRegName::GPR_Lo[m_Opcode.rt]);
		}
	}

	if (g_System->bFastSP() && m_Opcode.rd == 29)
	{ 
		g_MMU->ResetMemoryStack(); 
	}
}

void CRecompilerOps::SPECIAL_AND (void) 
{
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	if (IsKnown(m_Opcode.rt) && IsKnown(m_Opcode.rs)) {
		if (IsConst(m_Opcode.rt) && IsConst(m_Opcode.rs)) {
			if (Is64Bit(m_Opcode.rt) || Is64Bit(m_Opcode.rs)) {
				m_RegWorkingSet.SetMipsReg(m_Opcode.rd,
					(Is64Bit(m_Opcode.rt)?GetMipsReg(m_Opcode.rt):(__int64)GetMipsRegLo_S(m_Opcode.rt)) &
					(Is64Bit(m_Opcode.rs)?GetMipsReg(m_Opcode.rs):(__int64)GetMipsRegLo_S(m_Opcode.rs))
				);
				
				if (GetMipsRegLo_S(m_Opcode.rd) < 0 && GetMipsRegHi_S(m_Opcode.rd) == -1){ 
					m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
				} else if (GetMipsRegLo_S(m_Opcode.rd) >= 0 && GetMipsRegHi_S(m_Opcode.rd) == 0){ 
					m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
				} else {
					m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_64);
				}
			} else {
				m_RegWorkingSet.SetMipsReg(m_Opcode.rd, GetMipsRegLo(m_Opcode.rt) & GetMipsReg(m_Opcode.rs));
				m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
			}			
		} else if (IsMapped(m_Opcode.rt) && IsMapped(m_Opcode.rs)) {
			int source1 = m_Opcode.rd == m_Opcode.rt?m_Opcode.rt:m_Opcode.rs;
			int source2 = m_Opcode.rd == m_Opcode.rt?m_Opcode.rs:m_Opcode.rt;
		
			ProtectGPR(source1);
			ProtectGPR(source2);
			if (Is32Bit(source1) && Is32Bit(source2)) {
				bool Sign = (IsSigned(m_Opcode.rt) && IsSigned(m_Opcode.rs))?true:false;
				Map_GPR_32bit(m_Opcode.rd,Sign,source1);				
				AndX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapLo(source2));
			} else if (Is32Bit(source1) || Is32Bit(source2)) {
				if (IsUnsigned(Is32Bit(source1)?source1:source2)) {
					Map_GPR_32bit(m_Opcode.rd,FALSE,source1);
					AndX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapLo(source2));
				} else {
					Map_GPR_64bit(m_Opcode.rd,source1);
					if (Is32Bit(source2)) {
						AndX86RegToX86Reg(GetMipsRegMapHi(m_Opcode.rd),Map_TempReg(x86_Any,source2,TRUE));
					} else {
						AndX86RegToX86Reg(GetMipsRegMapHi(m_Opcode.rd),GetMipsRegMapHi(source2));
					}
					AndX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapLo(source2));
				}
			} else {
				Map_GPR_64bit(m_Opcode.rd,source1);
				AndX86RegToX86Reg(GetMipsRegMapHi(m_Opcode.rd),GetMipsRegMapHi(source2));
				AndX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapLo(source2));
			}
		} else {
			int ConstReg = IsConst(m_Opcode.rt)?m_Opcode.rt:m_Opcode.rs;
			int MappedReg = IsConst(m_Opcode.rt)?m_Opcode.rs:m_Opcode.rt;

			if (Is64Bit(ConstReg)) {
				if (Is32Bit(MappedReg) && IsUnsigned(MappedReg)) {
					if (GetMipsRegLo(ConstReg) == 0) {
						Map_GPR_32bit(m_Opcode.rd,FALSE, 0);
					} else {
						DWORD Value = GetMipsRegLo(ConstReg);
						Map_GPR_32bit(m_Opcode.rd,FALSE, MappedReg);
						AndConstToX86Reg(GetMipsRegMapLo(m_Opcode.rd),Value);
					}
				} else {
					__int64 Value = GetMipsReg(ConstReg);
					Map_GPR_64bit(m_Opcode.rd,MappedReg);
					AndConstToX86Reg(GetMipsRegMapHi(m_Opcode.rd),(DWORD)(Value >> 32));
					AndConstToX86Reg(GetMipsRegMapLo(m_Opcode.rd),(DWORD)(Value & 0xFFFFFFFF));
				}
			} else if (Is64Bit(MappedReg)) {
				DWORD Value = GetMipsRegLo(ConstReg); 
				if (Value != 0) {
					Map_GPR_32bit(m_Opcode.rd,IsSigned(ConstReg)?TRUE:FALSE,MappedReg);					
					AndConstToX86Reg(GetMipsRegMapLo(m_Opcode.rd),Value);
				} else {
					Map_GPR_32bit(m_Opcode.rd,IsSigned(ConstReg)?TRUE:FALSE, 0);
				}
			} else {
				DWORD Value = GetMipsRegLo(ConstReg); 
				bool Sign = false;
				if (IsSigned(ConstReg) && IsSigned(MappedReg)) { Sign = true; }				
				if (Value != 0) {
					Map_GPR_32bit(m_Opcode.rd,Sign,MappedReg);
					AndConstToX86Reg(GetMipsRegMapLo(m_Opcode.rd),Value);
				} else {
					Map_GPR_32bit(m_Opcode.rd,false, 0);
				}
			}
		}
	} else if (IsKnown(m_Opcode.rt) || IsKnown(m_Opcode.rs)) {
		DWORD KnownReg = IsKnown(m_Opcode.rt)?m_Opcode.rt:m_Opcode.rs;
		DWORD UnknownReg = IsKnown(m_Opcode.rt)?m_Opcode.rs:m_Opcode.rt;

		if (IsConst(KnownReg)) {
			if (Is64Bit(KnownReg)) {
				unsigned __int64 Value = GetMipsReg(KnownReg);
				Map_GPR_64bit(m_Opcode.rd,UnknownReg);
				AndConstToX86Reg(GetMipsRegMapHi(m_Opcode.rd),(DWORD)(Value >> 32));
				AndConstToX86Reg(GetMipsRegMapLo(m_Opcode.rd),(DWORD)(Value & 0xFFFFFFFF));
			} else {
				DWORD Value = GetMipsRegLo(KnownReg);
				Map_GPR_32bit(m_Opcode.rd,IsSigned(KnownReg),UnknownReg);
				AndConstToX86Reg(GetMipsRegMapLo(m_Opcode.rd),Value);
			}
		} else {
			ProtectGPR(KnownReg);
			if (KnownReg == m_Opcode.rd) {
				if (Is64Bit(KnownReg) || !g_System->b32BitCore()) {
					Map_GPR_64bit(m_Opcode.rd,KnownReg);
					AndVariableToX86Reg(&_GPR[UnknownReg].W[1],CRegName::GPR_Hi[UnknownReg],GetMipsRegMapHi(m_Opcode.rd));
					AndVariableToX86Reg(&_GPR[UnknownReg].W[0],CRegName::GPR_Lo[UnknownReg],GetMipsRegMapLo(m_Opcode.rd));
				} else {
					Map_GPR_32bit(m_Opcode.rd,IsSigned(KnownReg),KnownReg);
					AndVariableToX86Reg(&_GPR[UnknownReg].W[0],CRegName::GPR_Lo[UnknownReg],GetMipsRegMapLo(m_Opcode.rd));
				}
			} else {
				if (Is64Bit(KnownReg)) {
					Map_GPR_64bit(m_Opcode.rd,UnknownReg);
					AndX86RegToX86Reg(GetMipsRegMapHi(m_Opcode.rd),GetMipsRegMapHi(KnownReg));
					AndX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapLo(KnownReg));
				} else {
					Map_GPR_32bit(m_Opcode.rd,IsSigned(KnownReg),UnknownReg);
					AndX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapLo(KnownReg));
				}
			}
		}
	} else {
		if (g_System->b32BitCore())
		{
			Map_GPR_32bit(m_Opcode.rd,true,m_Opcode.rt);
		} else {
			Map_GPR_64bit(m_Opcode.rd,m_Opcode.rt);
			AndVariableToX86Reg(&_GPR[m_Opcode.rs].W[1],CRegName::GPR_Hi[m_Opcode.rs],GetMipsRegMapHi(m_Opcode.rd));
		}
		AndVariableToX86Reg(&_GPR[m_Opcode.rs].W[0],CRegName::GPR_Lo[m_Opcode.rs],GetMipsRegMapLo(m_Opcode.rd));
	}
}

void CRecompilerOps::SPECIAL_OR (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	if (IsKnown(m_Opcode.rt) && IsKnown(m_Opcode.rs)) {
		if (IsConst(m_Opcode.rt) && IsConst(m_Opcode.rs)) {
			if (IsMapped(m_Opcode.rd)) { UnMap_GPR(m_Opcode.rd, FALSE); }
			if (Is64Bit(m_Opcode.rt) || Is64Bit(m_Opcode.rs)) {				
				m_RegWorkingSet.SetMipsReg(m_Opcode.rd,
					(Is64Bit(m_Opcode.rt)?GetMipsReg(m_Opcode.rt):(__int64)GetMipsRegLo_S(m_Opcode.rt)) |
					(Is64Bit(m_Opcode.rs)?GetMipsReg(m_Opcode.rs):(__int64)GetMipsRegLo_S(m_Opcode.rs))
				);
				if (GetMipsRegLo_S(m_Opcode.rd) < 0 && GetMipsRegHi_S(m_Opcode.rd) == -1){ 
					m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
				} else if (GetMipsRegLo_S(m_Opcode.rd) >= 0 && GetMipsRegHi_S(m_Opcode.rd) == 0){ 
					m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
				} else {
					m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_64);
				}
			} else {
				m_RegWorkingSet.SetMipsRegLo(m_Opcode.rd, GetMipsRegLo(m_Opcode.rt) | GetMipsRegLo(m_Opcode.rs));
				m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
			}
		} else if (IsMapped(m_Opcode.rt) && IsMapped(m_Opcode.rs)) {
			int source1 = m_Opcode.rd == m_Opcode.rt?m_Opcode.rt:m_Opcode.rs;
			int source2 = m_Opcode.rd == m_Opcode.rt?m_Opcode.rs:m_Opcode.rt;
			
			ProtectGPR(m_Opcode.rt);
			ProtectGPR(m_Opcode.rs);
			if (Is64Bit(m_Opcode.rt) || Is64Bit(m_Opcode.rs)) {
				Map_GPR_64bit(m_Opcode.rd,source1);
				if (Is64Bit(source2)) {
					OrX86RegToX86Reg(GetMipsRegMapHi(m_Opcode.rd),GetMipsRegMapHi(source2));
				} else {
					OrX86RegToX86Reg(GetMipsRegMapHi(m_Opcode.rd),Map_TempReg(x86_Any,source2,TRUE));
				}
			} else {
				ProtectGPR(source2);
				Map_GPR_32bit(m_Opcode.rd,TRUE,source1);
			}
			OrX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapLo(source2));
		} else {
			DWORD ConstReg = IsConst(m_Opcode.rt)?m_Opcode.rt:m_Opcode.rs;
			DWORD MappedReg = IsConst(m_Opcode.rt)?m_Opcode.rs:m_Opcode.rt;

			if (Is64Bit(m_Opcode.rt) || Is64Bit(m_Opcode.rs)) {
				unsigned __int64 Value;

				if (Is64Bit(ConstReg)) {
					Value = GetMipsReg(ConstReg);
				} else {
					Value = IsSigned(ConstReg)?(__int64)GetMipsRegLo_S(ConstReg):GetMipsRegLo(ConstReg);
				}
				Map_GPR_64bit(m_Opcode.rd,MappedReg);
				if ((Value >> 32) != 0) {
					OrConstToX86Reg((DWORD)(Value >> 32),GetMipsRegMapHi(m_Opcode.rd));
				}
				DWORD dwValue = (DWORD)(Value & 0xFFFFFFFF);
				if (dwValue != 0) {
					OrConstToX86Reg(dwValue,GetMipsRegMapLo(m_Opcode.rd));
				}
			} else {
				int Value = GetMipsRegLo(ConstReg);
				Map_GPR_32bit(m_Opcode.rd,TRUE, MappedReg);
				if (Value != 0) { OrConstToX86Reg(Value,GetMipsRegMapLo(m_Opcode.rd)); }
			}
		}
	} else if (IsKnown(m_Opcode.rt) || IsKnown(m_Opcode.rs)) {
		int KnownReg = IsKnown(m_Opcode.rt)?m_Opcode.rt:m_Opcode.rs;
		int UnknownReg = IsKnown(m_Opcode.rt)?m_Opcode.rs:m_Opcode.rt;
		
		if (IsConst(KnownReg))
		{
			unsigned __int64 Value = Is64Bit(KnownReg)?GetMipsReg(KnownReg):GetMipsRegLo_S(KnownReg);
			DWORD dwValue = (DWORD)(Value & 0xFFFFFFFF);
			
			if (g_System->b32BitCore() && Is32Bit(KnownReg))
			{
				Map_GPR_32bit(m_Opcode.rd,true,UnknownReg);
				if (dwValue != 0) {
					OrConstToX86Reg(dwValue,GetMipsRegMapLo(m_Opcode.rd));
				}
			} else {
				Map_GPR_64bit(m_Opcode.rd,UnknownReg);
				if ((Value >> 32) != 0) {
					OrConstToX86Reg((DWORD)(Value >> 32),GetMipsRegMapHi(m_Opcode.rd));
				}
				if (dwValue != 0) {
					OrConstToX86Reg(dwValue,GetMipsRegMapLo(m_Opcode.rd));
				}
			}
		} else {
			if (g_System->b32BitCore())
			{
				Map_GPR_32bit(m_Opcode.rd,true,KnownReg);
				OrVariableToX86Reg(&_GPR[UnknownReg].W[0],CRegName::GPR_Lo[UnknownReg],GetMipsRegMapLo(m_Opcode.rd));
			} else {
				Map_GPR_64bit(m_Opcode.rd,KnownReg);
				OrVariableToX86Reg(&_GPR[UnknownReg].W[1],CRegName::GPR_Hi[UnknownReg],GetMipsRegMapHi(m_Opcode.rd));
				OrVariableToX86Reg(&_GPR[UnknownReg].W[0],CRegName::GPR_Lo[UnknownReg],GetMipsRegMapLo(m_Opcode.rd));
			}
		}
	} else {
		if (g_System->b32BitCore())
		{
			Map_GPR_32bit(m_Opcode.rd,true,m_Opcode.rt);
			OrVariableToX86Reg(&_GPR[m_Opcode.rs].W[0],CRegName::GPR_Lo[m_Opcode.rs],GetMipsRegMapLo(m_Opcode.rd));
		} else {
			Map_GPR_64bit(m_Opcode.rd,m_Opcode.rt);
			OrVariableToX86Reg(&_GPR[m_Opcode.rs].W[1],CRegName::GPR_Hi[m_Opcode.rs],GetMipsRegMapHi(m_Opcode.rd));
			OrVariableToX86Reg(&_GPR[m_Opcode.rs].W[0],CRegName::GPR_Lo[m_Opcode.rs],GetMipsRegMapLo(m_Opcode.rd));
		}
	}
	if (g_System->bFastSP() && m_Opcode.rd == 29) { 
		ResetX86Protection();
		g_MMU->ResetMemoryStack(); 
	}
}

void CRecompilerOps::SPECIAL_XOR (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (m_Opcode.rd == 0) { return; }

	if (m_Opcode.rt == m_Opcode.rs) {
		UnMap_GPR( m_Opcode.rd, FALSE);
		m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
		m_RegWorkingSet.SetMipsRegLo(m_Opcode.rd, 0);
		return;
	}
	if (IsKnown(m_Opcode.rt) && IsKnown(m_Opcode.rs)) {
		if (IsConst(m_Opcode.rt) && IsConst(m_Opcode.rs)) {
			if (IsMapped(m_Opcode.rd)) { UnMap_GPR(m_Opcode.rd, FALSE); }
			if (Is64Bit(m_Opcode.rt) || Is64Bit(m_Opcode.rs)) {
				if (bHaveDebugger()) { g_Notify->DisplayError(L"XOR 1"); }
				CRecompilerOps::UnknownOpcode();
			} else {
				m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
				m_RegWorkingSet.SetMipsRegLo(m_Opcode.rd, GetMipsRegLo(m_Opcode.rt) ^ GetMipsRegLo(m_Opcode.rs));
			}
		} else if (IsMapped(m_Opcode.rt) && IsMapped(m_Opcode.rs)) {
			int source1 = m_Opcode.rd == m_Opcode.rt?m_Opcode.rt:m_Opcode.rs;
			int source2 = m_Opcode.rd == m_Opcode.rt?m_Opcode.rs:m_Opcode.rt;
			
			ProtectGPR(source1);
			ProtectGPR(source2);
			if (Is64Bit(m_Opcode.rt) || Is64Bit(m_Opcode.rs)) {
				Map_GPR_64bit(m_Opcode.rd,source1);
				if (Is64Bit(source2)) {
					XorX86RegToX86Reg(GetMipsRegMapHi(m_Opcode.rd),GetMipsRegMapHi(source2));
				} else if (IsSigned(source2)) {
					XorX86RegToX86Reg(GetMipsRegMapHi(m_Opcode.rd),Map_TempReg(x86_Any,source2,TRUE));
				}
				XorX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapLo(source2));
			} else {
				if (IsSigned(m_Opcode.rt) != IsSigned(m_Opcode.rs)) {
					Map_GPR_32bit(m_Opcode.rd,TRUE,source1);
				} else {
					Map_GPR_32bit(m_Opcode.rd,IsSigned(m_Opcode.rt),source1);
				}
				XorX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapLo(source2));
			}
		} else {
			DWORD ConstReg = IsConst(m_Opcode.rt)?m_Opcode.rt:m_Opcode.rs;
			DWORD MappedReg = IsConst(m_Opcode.rt)?m_Opcode.rs:m_Opcode.rt;

			if (Is64Bit(m_Opcode.rt) || Is64Bit(m_Opcode.rs)) {
				DWORD ConstHi, ConstLo;

				ConstHi = Is32Bit(ConstReg)?(DWORD)(GetMipsRegLo_S(ConstReg) >> 31):GetMipsRegHi(ConstReg);
				ConstLo = GetMipsRegLo(ConstReg);
				Map_GPR_64bit(m_Opcode.rd,MappedReg);
				if (ConstHi != 0) { XorConstToX86Reg(GetMipsRegMapHi(m_Opcode.rd),ConstHi); }
				if (ConstLo != 0) { XorConstToX86Reg(GetMipsRegMapLo(m_Opcode.rd),ConstLo); }
			} else {
				int Value = GetMipsRegLo(ConstReg);
				if (IsSigned(m_Opcode.rt) != IsSigned(m_Opcode.rs)) {
					Map_GPR_32bit(m_Opcode.rd,TRUE, MappedReg);
				} else {
					Map_GPR_32bit(m_Opcode.rd,IsSigned(MappedReg)?TRUE:FALSE, MappedReg);
				}
				if (Value != 0) { XorConstToX86Reg(GetMipsRegMapLo(m_Opcode.rd),Value); }
			}
		}
	} else if (IsKnown(m_Opcode.rt) || IsKnown(m_Opcode.rs)) {
		int KnownReg = IsKnown(m_Opcode.rt)?m_Opcode.rt:m_Opcode.rs;
		int UnknownReg = IsKnown(m_Opcode.rt)?m_Opcode.rs:m_Opcode.rt;
		
		if (IsConst(KnownReg)) {
			unsigned __int64 Value;

			if (Is64Bit(KnownReg)) {
				Value = GetMipsReg(KnownReg);
				Map_GPR_64bit(m_Opcode.rd,UnknownReg);
				if ((Value >> 32) != 0) {
					XorConstToX86Reg(GetMipsRegMapHi(m_Opcode.rd),(DWORD)(Value >> 32));
				}
			} else {
				Map_GPR_32bit(m_Opcode.rd,true,UnknownReg);
				if (IsSigned(KnownReg)) {
					Value = (int)GetMipsRegLo(KnownReg);
				} else {
					Value = GetMipsRegLo(KnownReg);
				}
			}
			DWORD dwValue = (DWORD)(Value & 0xFFFFFFFF);
			if (dwValue != 0) {
				XorConstToX86Reg(GetMipsRegMapLo(m_Opcode.rd),dwValue);
			}
		} else {
			if (g_System->b32BitCore())
			{
				Map_GPR_32bit(m_Opcode.rd,true,KnownReg);
				XorVariableToX86reg(&_GPR[UnknownReg].W[0],CRegName::GPR_Lo[UnknownReg],GetMipsRegMapLo(m_Opcode.rd));
			} else {
				Map_GPR_64bit(m_Opcode.rd,KnownReg);
				XorVariableToX86reg(&_GPR[UnknownReg].W[1],CRegName::GPR_Hi[UnknownReg],GetMipsRegMapHi(m_Opcode.rd));
				XorVariableToX86reg(&_GPR[UnknownReg].W[0],CRegName::GPR_Lo[UnknownReg],GetMipsRegMapLo(m_Opcode.rd));
			}
		}
	} else if (g_System->b32BitCore()) {
		Map_GPR_32bit(m_Opcode.rd,true,m_Opcode.rt);
		XorVariableToX86reg(&_GPR[m_Opcode.rs].W[0],CRegName::GPR_Lo[m_Opcode.rs],GetMipsRegMapLo(m_Opcode.rd));
	} else {
		Map_GPR_64bit(m_Opcode.rd,m_Opcode.rt);
		XorVariableToX86reg(&_GPR[m_Opcode.rs].W[1],CRegName::GPR_Hi[m_Opcode.rs],GetMipsRegMapHi(m_Opcode.rd));
		XorVariableToX86reg(&_GPR[m_Opcode.rs].W[0],CRegName::GPR_Lo[m_Opcode.rs],GetMipsRegMapLo(m_Opcode.rd));
	}
}

void CRecompilerOps::SPECIAL_NOR (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	if (IsKnown(m_Opcode.rt) && IsKnown(m_Opcode.rs)) {
		if (IsConst(m_Opcode.rt) && IsConst(m_Opcode.rs)) {
			if (IsMapped(m_Opcode.rd)) { UnMap_GPR(m_Opcode.rd, FALSE); }
			if (Is64Bit(m_Opcode.rt) || Is64Bit(m_Opcode.rs)) {				
				m_RegWorkingSet.SetMipsReg(m_Opcode.rd,
					~((Is64Bit(m_Opcode.rt)?GetMipsReg(m_Opcode.rt):(__int64)GetMipsRegLo_S(m_Opcode.rt)) |
					(Is64Bit(m_Opcode.rs)?GetMipsReg(m_Opcode.rs):(__int64)GetMipsRegLo_S(m_Opcode.rs)))
				);
				if (GetMipsRegLo_S(m_Opcode.rd) < 0 && GetMipsRegHi_S(m_Opcode.rd) == -1){ 
					m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
				} else if (GetMipsRegLo_S(m_Opcode.rd) >= 0 && GetMipsRegHi_S(m_Opcode.rd) == 0){ 
					m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
				} else {
					m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_64);
				}
			} else {
				m_RegWorkingSet.SetMipsRegLo(m_Opcode.rd,~(GetMipsRegLo(m_Opcode.rt) | GetMipsRegLo(m_Opcode.rs)));
				m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
			}
		} else if (IsMapped(m_Opcode.rt) && IsMapped(m_Opcode.rs)) {
			int source1 = m_Opcode.rd == m_Opcode.rt?m_Opcode.rt:m_Opcode.rs;
			int source2 = m_Opcode.rd == m_Opcode.rt?m_Opcode.rs:m_Opcode.rt;

			ProtectGPR(m_Opcode.rt);
			ProtectGPR(m_Opcode.rs);
			if (Is64Bit(m_Opcode.rt) || Is64Bit(m_Opcode.rs)) {
				Map_GPR_64bit(m_Opcode.rd,source1);
				if (Is64Bit(source2)) {
					OrX86RegToX86Reg(GetMipsRegMapHi(m_Opcode.rd),GetMipsRegMapHi(source2));
				} else {
					OrX86RegToX86Reg(GetMipsRegMapHi(m_Opcode.rd),Map_TempReg(x86_Any,source2,TRUE));
				}
			} else {
				ProtectGPR(source2);
				Map_GPR_32bit(m_Opcode.rd,TRUE,source1);
			}
			OrX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapLo(source2));
		} else {
			DWORD ConstReg = IsConst(m_Opcode.rt)?m_Opcode.rt:m_Opcode.rs;
			DWORD MappedReg = IsConst(m_Opcode.rt)?m_Opcode.rs:m_Opcode.rt;

			if (Is64Bit(m_Opcode.rt) || Is64Bit(m_Opcode.rs)) {
				unsigned __int64 Value;

				if (Is64Bit(ConstReg)) {
					Value = GetMipsReg(ConstReg);
				} else {
					Value = IsSigned(ConstReg)?(__int64)GetMipsRegLo_S(ConstReg):GetMipsRegLo(ConstReg);
				}
				Map_GPR_64bit(m_Opcode.rd,MappedReg);
				if ((Value >> 32) != 0) {
					OrConstToX86Reg((DWORD)(Value >> 32),GetMipsRegMapHi(m_Opcode.rd));
				}
				DWORD dwValue = (DWORD)(Value & 0xFFFFFFFF);
				if (dwValue != 0) {
					OrConstToX86Reg(dwValue,GetMipsRegMapLo(m_Opcode.rd));
				}
			} else {
				int Value = GetMipsRegLo(ConstReg);
				Map_GPR_32bit(m_Opcode.rd,TRUE, MappedReg);
				if (Value != 0) { OrConstToX86Reg(Value,GetMipsRegMapLo(m_Opcode.rd)); }
			}
		}
	} else if (IsKnown(m_Opcode.rt) || IsKnown(m_Opcode.rs)) {
		int KnownReg = IsKnown(m_Opcode.rt)?m_Opcode.rt:m_Opcode.rs;
		int UnknownReg = IsKnown(m_Opcode.rt)?m_Opcode.rs:m_Opcode.rt;

		if (IsConst(KnownReg)) {
			unsigned __int64 Value = Is64Bit(KnownReg)?GetMipsReg(KnownReg):GetMipsRegLo_S(KnownReg);
			DWORD dwValue = (DWORD)(Value & 0xFFFFFFFF);

			if (g_System->b32BitCore() && Is32Bit(KnownReg))
			{
				Map_GPR_32bit(m_Opcode.rd,true,UnknownReg);
				if (dwValue != 0) {
					OrConstToX86Reg(dwValue,GetMipsRegMapLo(m_Opcode.rd));
				}
			} else {
				Map_GPR_64bit(m_Opcode.rd,UnknownReg);
				if ((Value >> 32) != 0) {
					OrConstToX86Reg((DWORD)(Value >> 32),GetMipsRegMapHi(m_Opcode.rd));
				}
				if (dwValue != 0) {
					OrConstToX86Reg(dwValue,GetMipsRegMapLo(m_Opcode.rd));
				}
			}
		} else {
			if (g_System->b32BitCore())
			{
				Map_GPR_32bit(m_Opcode.rd,true,KnownReg);
				OrVariableToX86Reg(&_GPR[UnknownReg].W[0],CRegName::GPR_Lo[UnknownReg],GetMipsRegMapLo(m_Opcode.rd));
			} else {
				Map_GPR_64bit(m_Opcode.rd,KnownReg);
				OrVariableToX86Reg(&_GPR[UnknownReg].W[1],CRegName::GPR_Hi[UnknownReg],GetMipsRegMapHi(m_Opcode.rd));
				OrVariableToX86Reg(&_GPR[UnknownReg].W[0],CRegName::GPR_Lo[UnknownReg],GetMipsRegMapLo(m_Opcode.rd));
			}
		}
	} else {
		if (g_System->b32BitCore())
		{
			Map_GPR_32bit(m_Opcode.rd,true,m_Opcode.rt);
			OrVariableToX86Reg(&_GPR[m_Opcode.rs].W[0],CRegName::GPR_Lo[m_Opcode.rs],GetMipsRegMapLo(m_Opcode.rd));
		} else {
			Map_GPR_64bit(m_Opcode.rd,m_Opcode.rt);
			OrVariableToX86Reg(&_GPR[m_Opcode.rs].W[1],CRegName::GPR_Hi[m_Opcode.rs],GetMipsRegMapHi(m_Opcode.rd));
			OrVariableToX86Reg(&_GPR[m_Opcode.rs].W[0],CRegName::GPR_Lo[m_Opcode.rs],GetMipsRegMapLo(m_Opcode.rd));
		}
	}

	if (IsMapped(m_Opcode.rd))
	{
		if (Is64Bit(m_Opcode.rd))
		{
			NotX86Reg(GetMipsRegMapHi(m_Opcode.rd));
		} 
		NotX86Reg(GetMipsRegMapLo(m_Opcode.rd));		
	}
}

void CRecompilerOps::SPECIAL_SLT (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (m_Opcode.rd == 0) { return; }

	if (IsKnown(m_Opcode.rt) && IsKnown(m_Opcode.rs)) {
		if (IsConst(m_Opcode.rt) && IsConst(m_Opcode.rs)) {
			if (Is64Bit(m_Opcode.rt) || Is64Bit(m_Opcode.rs)) {
				g_Notify->DisplayError(L"1");
				CRecompilerOps::UnknownOpcode();
			} else {
				if (IsMapped(m_Opcode.rd)) { UnMap_GPR(m_Opcode.rd, FALSE); }
				m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);	
				if (GetMipsRegLo_S(m_Opcode.rs) < GetMipsRegLo_S(m_Opcode.rt)) {
					m_RegWorkingSet.SetMipsRegLo(m_Opcode.rd,1);
				} else {
					m_RegWorkingSet.SetMipsRegLo(m_Opcode.rd,0);
				}
			}
		} else if (IsMapped(m_Opcode.rt) && IsMapped(m_Opcode.rs)) {
			ProtectGPR(m_Opcode.rt);
			ProtectGPR(m_Opcode.rs);
			if ((Is64Bit(m_Opcode.rt) && Is64Bit(m_Opcode.rs)) ||
				(!g_System->b32BitCore() && (Is64Bit(m_Opcode.rt) || Is64Bit(m_Opcode.rs))))
			{
				BYTE *Jump[2];

				CompX86RegToX86Reg(
					Is64Bit(m_Opcode.rs)?GetMipsRegMapHi(m_Opcode.rs):Map_TempReg(x86_Any,m_Opcode.rs,TRUE), 
					Is64Bit(m_Opcode.rt)?GetMipsRegMapHi(m_Opcode.rt):Map_TempReg(x86_Any,m_Opcode.rt,TRUE)
					);
				JeLabel8("Low Compare",0);
				Jump[0] = m_RecompPos - 1;
				SetlVariable(&m_BranchCompare,"m_BranchCompare");
				JmpLabel8("Continue",0);
				Jump[1] = m_RecompPos - 1;

				CPU_Message("");
				CPU_Message("      Low Compare:");
				SetJump8(Jump[0],m_RecompPos);
				CompX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rs), GetMipsRegMapLo(m_Opcode.rt));
				SetbVariable(&m_BranchCompare,"m_BranchCompare");
				CPU_Message("");
				CPU_Message("      Continue:");
				SetJump8(Jump[1],m_RecompPos);
				Map_GPR_32bit(m_Opcode.rd,TRUE, -1);
				MoveVariableToX86reg(&m_BranchCompare,"m_BranchCompare",GetMipsRegMapLo(m_Opcode.rd));
			} else {
				Map_GPR_32bit(m_Opcode.rd,TRUE, -1);
				CompX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rs), GetMipsRegMapLo(m_Opcode.rt));

				if (GetMipsRegMapLo(m_Opcode.rd) > x86_EBX) {
					SetlVariable(&m_BranchCompare,"m_BranchCompare");
					MoveVariableToX86reg(&m_BranchCompare,"m_BranchCompare",GetMipsRegMapLo(m_Opcode.rd));
				} else {					
					Setl(GetMipsRegMapLo(m_Opcode.rd));
					AndConstToX86Reg(GetMipsRegMapLo(m_Opcode.rd), 1);
				}
			}
		} else {
			DWORD ConstReg  = IsConst(m_Opcode.rs)?m_Opcode.rs:m_Opcode.rt;
			DWORD MappedReg = IsConst(m_Opcode.rs)?m_Opcode.rt:m_Opcode.rs;

			ProtectGPR(MappedReg);
			if (Is64Bit(m_Opcode.rt) || Is64Bit(m_Opcode.rs)) {
				BYTE *Jump[2];

				CompConstToX86reg(
					Is64Bit(MappedReg)?GetMipsRegMapHi(MappedReg):Map_TempReg(x86_Any,MappedReg,TRUE), 
					Is64Bit(ConstReg)?GetMipsRegHi(ConstReg):(GetMipsRegLo_S(ConstReg) >> 31)
					);
				JeLabel8("Low Compare",0);
				Jump[0] = m_RecompPos - 1;
				if (MappedReg == m_Opcode.rs) {
					SetlVariable(&m_BranchCompare,"m_BranchCompare");
				} else {
					SetgVariable(&m_BranchCompare,"m_BranchCompare");
				}
				JmpLabel8("Continue",0);
				Jump[1] = m_RecompPos - 1;

				CPU_Message("");
				CPU_Message("      Low Compare:");
				SetJump8(Jump[0],m_RecompPos);
				CompConstToX86reg(GetMipsRegMapLo(MappedReg), GetMipsRegLo(ConstReg));
				if (MappedReg == m_Opcode.rs) {
					SetbVariable(&m_BranchCompare,"m_BranchCompare");
				} else {
					SetaVariable(&m_BranchCompare,"m_BranchCompare");
				}
				CPU_Message("");
				CPU_Message("      Continue:");
				SetJump8(Jump[1],m_RecompPos);
				Map_GPR_32bit(m_Opcode.rd,TRUE, -1);
				MoveVariableToX86reg(&m_BranchCompare,"m_BranchCompare",GetMipsRegMapLo(m_Opcode.rd));
			} else {
				DWORD Constant = GetMipsRegLo(ConstReg);
				Map_GPR_32bit(m_Opcode.rd,TRUE, -1);
				CompConstToX86reg(GetMipsRegMapLo(MappedReg), Constant);

				if (GetMipsRegMapLo(m_Opcode.rd) > x86_EBX) {
					if (MappedReg == m_Opcode.rs) {
						SetlVariable(&m_BranchCompare,"m_BranchCompare");
					} else {
						SetgVariable(&m_BranchCompare,"m_BranchCompare");
					}
					MoveVariableToX86reg(&m_BranchCompare,"m_BranchCompare",GetMipsRegMapLo(m_Opcode.rd));
				} else {					
					if (MappedReg == m_Opcode.rs) {
						Setl(GetMipsRegMapLo(m_Opcode.rd));
					} else {
						Setg(GetMipsRegMapLo(m_Opcode.rd));
					}
					AndConstToX86Reg(GetMipsRegMapLo(m_Opcode.rd), 1);
				}
			}
		}		
	} else if (IsKnown(m_Opcode.rt) || IsKnown(m_Opcode.rs)) {
		DWORD KnownReg = IsKnown(m_Opcode.rt)?m_Opcode.rt:m_Opcode.rs;
		DWORD UnknownReg = IsKnown(m_Opcode.rt)?m_Opcode.rs:m_Opcode.rt;
		BYTE *Jump[2];

		if (!g_System->b32BitCore())
		{
			if (Is64Bit(KnownReg)) {
				if (IsConst(KnownReg)) {
					CompConstToVariable(GetMipsRegHi(KnownReg),&_GPR[UnknownReg].W[1],CRegName::GPR_Hi[UnknownReg]);
				} else {
					CompX86regToVariable(GetMipsRegMapHi(KnownReg),&_GPR[UnknownReg].W[1],CRegName::GPR_Hi[UnknownReg]);
				}
			} else {
				if (IsConst(KnownReg)) {
					CompConstToVariable((GetMipsRegLo_S(KnownReg) >> 31),&_GPR[UnknownReg].W[1],CRegName::GPR_Hi[UnknownReg]);
				} else {
					ProtectGPR(KnownReg);
					CompX86regToVariable(Map_TempReg(x86_Any,KnownReg,TRUE),&_GPR[UnknownReg].W[1],CRegName::GPR_Hi[UnknownReg]);
				}
			}
			JeLabel8("Low Compare",0);
			Jump[0] = m_RecompPos - 1;
			if (KnownReg == (IsConst(KnownReg)?m_Opcode.rs:m_Opcode.rt)) {
				SetgVariable(&m_BranchCompare,"m_BranchCompare");
			} else {
				SetlVariable(&m_BranchCompare,"m_BranchCompare");
			}
			JmpLabel8("Continue",0);
			Jump[1] = m_RecompPos - 1;

			CPU_Message("");
			CPU_Message("      Low Compare:");
			SetJump8(Jump[0],m_RecompPos);
			if (IsConst(KnownReg)) {
				CompConstToVariable(GetMipsRegLo(KnownReg),&_GPR[UnknownReg].W[0],CRegName::GPR_Lo[UnknownReg]);
			} else {
				CompX86regToVariable(GetMipsRegMapLo(KnownReg),&_GPR[UnknownReg].W[0],CRegName::GPR_Lo[UnknownReg]);
			}
			if (KnownReg == (IsConst(KnownReg)?m_Opcode.rs:m_Opcode.rt)) {
				SetaVariable(&m_BranchCompare,"m_BranchCompare");
			} else {
				SetbVariable(&m_BranchCompare,"m_BranchCompare");
			}
			CPU_Message("");
			CPU_Message("      Continue:");
			SetJump8(Jump[1],m_RecompPos);
			Map_GPR_32bit(m_Opcode.rd,TRUE, -1);
			MoveVariableToX86reg(&m_BranchCompare,"m_BranchCompare",GetMipsRegMapLo(m_Opcode.rd));
		} else {
			if (IsMapped(KnownReg))
			{
				ProtectGPR(KnownReg);
			}
			bool bConstant = IsConst(KnownReg);
			DWORD Value = IsConst(KnownReg) ? GetMipsRegLo(KnownReg) : 0;

			Map_GPR_32bit(m_Opcode.rd,TRUE, -1);
			if (bConstant) {
				CompConstToVariable(Value,&_GPR[UnknownReg].W[0],CRegName::GPR_Lo[UnknownReg]);
			} else {
				CompX86regToVariable(GetMipsRegMapLo(KnownReg),&_GPR[UnknownReg].W[0],CRegName::GPR_Lo[UnknownReg]);
			}
			if (GetMipsRegMapLo(m_Opcode.rd) > x86_EBX) {
				if (KnownReg == (bConstant?m_Opcode.rs:m_Opcode.rt)) {
					SetgVariable(&m_BranchCompare,"m_BranchCompare");
				} else {
					SetlVariable(&m_BranchCompare,"m_BranchCompare");
				}
				MoveVariableToX86reg(&m_BranchCompare,"m_BranchCompare",GetMipsRegMapLo(m_Opcode.rd));
			} else {					
				if (KnownReg == (bConstant?m_Opcode.rs:m_Opcode.rt)) {
					Setg(GetMipsRegMapLo(m_Opcode.rd));
				} else {
					Setl(GetMipsRegMapLo(m_Opcode.rd));
				}
				AndConstToX86Reg(GetMipsRegMapLo(m_Opcode.rd), 1);
			}
		}
	} else if (g_System->b32BitCore()) {
		x86Reg Reg = Map_TempReg(x86_Any,m_Opcode.rs,false);
		Map_GPR_32bit(m_Opcode.rd,false, -1);
		CompX86regToVariable(Reg,&_GPR[m_Opcode.rt].W[0],CRegName::GPR_Lo[m_Opcode.rt]);
		if (GetMipsRegMapLo(m_Opcode.rd) > x86_EBX) {
			SetlVariable(&m_BranchCompare,"m_BranchCompare");
			MoveVariableToX86reg(&m_BranchCompare,"m_BranchCompare",GetMipsRegMapLo(m_Opcode.rd));
		} else {					
			Setl(GetMipsRegMapLo(m_Opcode.rd));
			AndConstToX86Reg(GetMipsRegMapLo(m_Opcode.rd), 1);
		}
	} else {
		BYTE *Jump[2] = { NULL, NULL };

		x86Reg Reg = Map_TempReg(x86_Any,m_Opcode.rs,TRUE);
		CompX86regToVariable(Reg,&_GPR[m_Opcode.rt].W[1],CRegName::GPR_Hi[m_Opcode.rt]);
		JeLabel8("Low Compare",0);
		Jump[0] = m_RecompPos - 1;
		SetlVariable(&m_BranchCompare,"m_BranchCompare");
		JmpLabel8("Continue",0);
		Jump[1] = m_RecompPos - 1;

		CPU_Message("");
		CPU_Message("      Low Compare:");
		SetJump8(Jump[0],m_RecompPos);
		CompX86regToVariable(Map_TempReg(Reg,m_Opcode.rs,FALSE),&_GPR[m_Opcode.rt].W[0],CRegName::GPR_Lo[m_Opcode.rt]);
		SetbVariable(&m_BranchCompare,"m_BranchCompare");
		if (Jump[1])
		{
			CPU_Message("");
			CPU_Message("      Continue:");
			SetJump8(Jump[1],m_RecompPos);
		}
		Map_GPR_32bit(m_Opcode.rd,TRUE, -1);
		MoveVariableToX86reg(&m_BranchCompare,"m_BranchCompare",GetMipsRegMapLo(m_Opcode.rd));
	}
}

void CRecompilerOps::SPECIAL_SLTU (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (m_Opcode.rd == 0) { return; }

	if (IsKnown(m_Opcode.rt) && IsKnown(m_Opcode.rs)) {
		if (IsConst(m_Opcode.rt) && IsConst(m_Opcode.rs)) {
			if (Is64Bit(m_Opcode.rt) || Is64Bit(m_Opcode.rs)) {
				g_Notify->DisplayError(L"1");
				CRecompilerOps::UnknownOpcode();
			} else {
				if (IsMapped(m_Opcode.rd)) { UnMap_GPR(m_Opcode.rd, FALSE); }
				m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);	
				if (GetMipsRegLo(m_Opcode.rs) < GetMipsRegLo(m_Opcode.rt)) {
					m_RegWorkingSet.SetMipsRegLo(m_Opcode.rd,1);
				} else {
					m_RegWorkingSet.SetMipsRegLo(m_Opcode.rd,0);
				}
			}
		} else if (IsMapped(m_Opcode.rt) && IsMapped(m_Opcode.rs)) {
			ProtectGPR(m_Opcode.rt);
			ProtectGPR(m_Opcode.rs);
			if ((Is64Bit(m_Opcode.rt) && Is64Bit(m_Opcode.rs)) ||
				(!g_System->b32BitCore() && (Is64Bit(m_Opcode.rt) || Is64Bit(m_Opcode.rs))))
			{
				BYTE *Jump[2];

				CompX86RegToX86Reg(
					Is64Bit(m_Opcode.rs)?GetMipsRegMapHi(m_Opcode.rs):Map_TempReg(x86_Any,m_Opcode.rs,TRUE), 
					Is64Bit(m_Opcode.rt)?GetMipsRegMapHi(m_Opcode.rt):Map_TempReg(x86_Any,m_Opcode.rt,TRUE)
					);
				JeLabel8("Low Compare",0);
				Jump[0] = m_RecompPos - 1;
				SetbVariable(&m_BranchCompare,"m_BranchCompare");
				JmpLabel8("Continue",0);
				Jump[1] = m_RecompPos - 1;

				CPU_Message("");
				CPU_Message("      Low Compare:");
				SetJump8(Jump[0],m_RecompPos);
				CompX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rs), GetMipsRegMapLo(m_Opcode.rt));
				SetbVariable(&m_BranchCompare,"m_BranchCompare");
				CPU_Message("");
				CPU_Message("      Continue:");
				SetJump8(Jump[1],m_RecompPos);
				Map_GPR_32bit(m_Opcode.rd,TRUE, -1);
				MoveVariableToX86reg(&m_BranchCompare,"m_BranchCompare",GetMipsRegMapLo(m_Opcode.rd));
			} else {
				CompX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rs), GetMipsRegMapLo(m_Opcode.rt));
				SetbVariable(&m_BranchCompare,"m_BranchCompare");
				Map_GPR_32bit(m_Opcode.rd,TRUE, -1);
				MoveVariableToX86reg(&m_BranchCompare,"m_BranchCompare",GetMipsRegMapLo(m_Opcode.rd));
			}
		} else {
			if (Is64Bit(m_Opcode.rt) || Is64Bit(m_Opcode.rs)) {
				DWORD ConstHi, ConstLo, ConstReg, MappedReg;
				x86Reg MappedRegHi, MappedRegLo;
				BYTE *Jump[2];

				ConstReg  = IsConst(m_Opcode.rt)?m_Opcode.rt:m_Opcode.rs;
				MappedReg = IsConst(m_Opcode.rt)?m_Opcode.rs:m_Opcode.rt;

				ConstLo = GetMipsRegLo_S(ConstReg);
				ConstHi = GetMipsRegLo_S(ConstReg) >> 31;
				if (Is64Bit(ConstReg)) { ConstHi = GetMipsRegHi(ConstReg); }

				ProtectGPR(MappedReg);
				MappedRegLo = GetMipsRegMapLo(MappedReg);
				MappedRegHi = GetMipsRegMapHi(MappedReg);
				if (Is32Bit(MappedReg)) {
					MappedRegHi = Map_TempReg(x86_Any,MappedReg,TRUE);
				}


				Map_GPR_32bit(m_Opcode.rd,TRUE, -1);
				CompConstToX86reg(MappedRegHi, ConstHi);
				JeLabel8("Low Compare",0);
				Jump[0] = m_RecompPos - 1;
				if (MappedReg == m_Opcode.rs) {
					SetbVariable(&m_BranchCompare,"m_BranchCompare");
				} else {
					SetaVariable(&m_BranchCompare,"m_BranchCompare");
				}
				JmpLabel8("Continue",0);
				Jump[1] = m_RecompPos - 1;

				CPU_Message("");
				CPU_Message("      Low Compare:");
				SetJump8(Jump[0],m_RecompPos);
				CompConstToX86reg(MappedRegLo, ConstLo);
				if (MappedReg == m_Opcode.rs) {
					SetbVariable(&m_BranchCompare,"m_BranchCompare");
				} else {
					SetaVariable(&m_BranchCompare,"m_BranchCompare");
				}
				CPU_Message("");
				CPU_Message("      Continue:");
				SetJump8(Jump[1],m_RecompPos);
				Map_GPR_32bit(m_Opcode.rd,TRUE, -1);
				MoveVariableToX86reg(&m_BranchCompare,"m_BranchCompare",GetMipsRegMapLo(m_Opcode.rd));
			} else {
				DWORD Const = IsConst(m_Opcode.rs)?GetMipsRegLo(m_Opcode.rs):GetMipsRegLo(m_Opcode.rt);
				DWORD MappedReg = IsConst(m_Opcode.rt)?m_Opcode.rs:m_Opcode.rt;

				CompConstToX86reg(GetMipsRegMapLo(MappedReg), Const);
				if (MappedReg == m_Opcode.rs) {
					SetbVariable(&m_BranchCompare,"m_BranchCompare");
				} else {
					SetaVariable(&m_BranchCompare,"m_BranchCompare");
				}
				Map_GPR_32bit(m_Opcode.rd,TRUE, -1);
				MoveVariableToX86reg(&m_BranchCompare,"m_BranchCompare",GetMipsRegMapLo(m_Opcode.rd));
			}
		}		
	} else if (IsKnown(m_Opcode.rt) || IsKnown(m_Opcode.rs)) {
		DWORD KnownReg = IsKnown(m_Opcode.rt)?m_Opcode.rt:m_Opcode.rs;
		DWORD UnknownReg = IsKnown(m_Opcode.rt)?m_Opcode.rs:m_Opcode.rt;
		BYTE *Jump[2] = { NULL, NULL };

		ProtectGPR(KnownReg);
		if (g_System->b32BitCore())
		{
			DWORD TestReg = IsConst(KnownReg)?m_Opcode.rs:m_Opcode.rt;
			if (IsConst(KnownReg)) {
				DWORD Value = GetMipsRegLo(KnownReg);
				Map_GPR_32bit(m_Opcode.rd,TRUE,-1);
				CompConstToVariable(Value,&_GPR[UnknownReg].W[0],CRegName::GPR_Lo[UnknownReg]);
			} else {
				CompX86regToVariable(GetMipsRegMapLo(KnownReg),&_GPR[UnknownReg].W[0],CRegName::GPR_Lo[UnknownReg]);
			}
			if (KnownReg == TestReg) 
			{
				SetaVariable(&m_BranchCompare,"m_BranchCompare");
			} else {
				SetbVariable(&m_BranchCompare,"m_BranchCompare");
			}
		} else {
			if (IsConst(KnownReg)) {
				if (Is64Bit(KnownReg)) {
					CompConstToVariable(GetMipsRegHi(KnownReg),&_GPR[UnknownReg].W[1],CRegName::GPR_Hi[UnknownReg]);
				} else {
					CompConstToVariable((GetMipsRegLo_S(KnownReg) >> 31),&_GPR[UnknownReg].W[1],CRegName::GPR_Hi[UnknownReg]);
				}
			} else {
				if (Is64Bit(KnownReg)) {
					CompX86regToVariable(GetMipsRegMapHi(KnownReg),&_GPR[UnknownReg].W[1],CRegName::GPR_Hi[UnknownReg]);
				} else {
					ProtectGPR(KnownReg);
					CompX86regToVariable(Map_TempReg(x86_Any,KnownReg,TRUE),&_GPR[UnknownReg].W[1],CRegName::GPR_Hi[UnknownReg]);
				}			
			}
			JeLabel8("Low Compare",0);
			Jump[0] = m_RecompPos - 1;

			if (KnownReg == (IsConst(KnownReg)?m_Opcode.rs:m_Opcode.rt)) {
				SetaVariable(&m_BranchCompare,"m_BranchCompare");
			} else {
				SetbVariable(&m_BranchCompare,"m_BranchCompare");
			}
			JmpLabel8("Continue",0);
			Jump[1] = m_RecompPos - 1;

			CPU_Message("");
			CPU_Message("      Low Compare:");
			SetJump8(Jump[0],m_RecompPos);
			if (IsConst(KnownReg)) {
				CompConstToVariable(GetMipsRegLo(KnownReg),&_GPR[UnknownReg].W[0],CRegName::GPR_Lo[UnknownReg]);
			} else {
				CompX86regToVariable(GetMipsRegMapLo(KnownReg),&_GPR[UnknownReg].W[0],CRegName::GPR_Lo[UnknownReg]);
			}
			if (KnownReg == (IsConst(KnownReg)?m_Opcode.rs:m_Opcode.rt)) {
				SetaVariable(&m_BranchCompare,"m_BranchCompare");
			} else {
				SetbVariable(&m_BranchCompare,"m_BranchCompare");
			}
			if (Jump[1])
			{
				CPU_Message("");
				CPU_Message("      Continue:");
				SetJump8(Jump[1],m_RecompPos);
			}
		}
		Map_GPR_32bit(m_Opcode.rd,TRUE,-1);
		MoveVariableToX86reg(&m_BranchCompare,"m_BranchCompare",GetMipsRegMapLo(m_Opcode.rd));
	} else if (g_System->b32BitCore()) {
		x86Reg Reg = Map_TempReg(x86_Any,m_Opcode.rs,false);
		Map_GPR_32bit(m_Opcode.rd,false, -1);
		CompX86regToVariable(Reg,&_GPR[m_Opcode.rt].W[0],CRegName::GPR_Lo[m_Opcode.rt]);
		SetbVariable(&m_BranchCompare,"m_BranchCompare");
		MoveVariableToX86reg(&m_BranchCompare,"m_BranchCompare",GetMipsRegMapLo(m_Opcode.rd));
	} else {
		BYTE *Jump[2] = { NULL, NULL };

		x86Reg Reg = Map_TempReg(x86_Any,m_Opcode.rs,TRUE);
		CompX86regToVariable(Reg,&_GPR[m_Opcode.rt].W[1],CRegName::GPR_Hi[m_Opcode.rt]);
		JeLabel8("Low Compare",0);
		Jump[0] = m_RecompPos - 1;
		SetbVariable(&m_BranchCompare,"m_BranchCompare");
		JmpLabel8("Continue",0);
		Jump[1] = m_RecompPos - 1;
		
		CPU_Message("");
		CPU_Message("      Low Compare:");
		SetJump8(Jump[0],m_RecompPos);
		CompX86regToVariable(Map_TempReg(Reg,m_Opcode.rs,FALSE),&_GPR[m_Opcode.rt].W[0],CRegName::GPR_Lo[m_Opcode.rt]);
		SetbVariable(&m_BranchCompare,"m_BranchCompare");
		if (Jump[1])
		{
			CPU_Message("");
			CPU_Message("      Continue:");
			SetJump8(Jump[1],m_RecompPos);
		}
		Map_GPR_32bit(m_Opcode.rd,TRUE, -1);
		MoveVariableToX86reg(&m_BranchCompare,"m_BranchCompare",GetMipsRegMapLo(m_Opcode.rd));
	}
}

void CRecompilerOps::SPECIAL_DADD (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (m_Opcode.rd == 0) { return; }

	if (IsConst(m_Opcode.rt)  && IsConst(m_Opcode.rs)) {
		if (IsMapped(m_Opcode.rd)) { UnMap_GPR(m_Opcode.rd, FALSE); }
		m_RegWorkingSet.SetMipsReg(m_Opcode.rd,
			Is64Bit(m_Opcode.rs)?GetMipsReg(m_Opcode.rs):(__int64)GetMipsRegLo_S(m_Opcode.rs) +
			Is64Bit(m_Opcode.rt)?GetMipsReg(m_Opcode.rt):(__int64)GetMipsRegLo_S(m_Opcode.rt)
		);
		if (GetMipsRegLo_S(m_Opcode.rd) < 0 && GetMipsRegHi_S(m_Opcode.rd) == -1){ 
			m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
		} else if (GetMipsRegLo_S(m_Opcode.rd) >= 0 && GetMipsRegHi_S(m_Opcode.rd) == 0){ 
			m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
		} else {
			m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_64);
		}
	} else {
		int source1 = m_Opcode.rd == m_Opcode.rt?m_Opcode.rt:m_Opcode.rs;
		int source2 = m_Opcode.rd == m_Opcode.rt?m_Opcode.rs:m_Opcode.rt;

		if (IsMapped(source2)) { ProtectGPR(source2); }
		Map_GPR_64bit(m_Opcode.rd,source1);
		if (IsConst(source2)) {
			AddConstToX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegLo(source2));
			AddConstToX86Reg(GetMipsRegMapHi(m_Opcode.rd),GetMipsRegHi(source2));
		} else if (IsMapped(source2)) {
			x86Reg HiReg = Is64Bit(source2)?GetMipsRegMapHi(source2):Map_TempReg(x86_Any,source2,TRUE);
			AddX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapLo(source2));
			AdcX86RegToX86Reg(GetMipsRegMapHi(m_Opcode.rd),HiReg);
		} else {
			AddVariableToX86reg(GetMipsRegMapLo(m_Opcode.rd),&_GPR[source2].W[0],CRegName::GPR_Lo[source2]);
			AdcVariableToX86reg(GetMipsRegMapHi(m_Opcode.rd),&_GPR[source2].W[1],CRegName::GPR_Hi[source2]);
		}
	}
}

void CRecompilerOps::SPECIAL_DADDU (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (m_Opcode.rd == 0) { return; }

	if (IsConst(m_Opcode.rt)  && IsConst(m_Opcode.rs)) {
		__int64 ValRs = Is64Bit(m_Opcode.rs)?GetMipsReg(m_Opcode.rs):(__int64)GetMipsRegLo_S(m_Opcode.rs);
		__int64 ValRt = Is64Bit(m_Opcode.rt)?GetMipsReg(m_Opcode.rt):(__int64)GetMipsRegLo_S(m_Opcode.rt);
		if (IsMapped(m_Opcode.rd)) { UnMap_GPR(m_Opcode.rd, FALSE); }
		m_RegWorkingSet.SetMipsReg(m_Opcode.rd, ValRs + ValRt);
		if ((GetMipsRegHi(m_Opcode.rd) == 0) && (GetMipsRegLo(m_Opcode.rd) & 0x80000000) == 0) {
			m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
		} else if ((GetMipsRegHi(m_Opcode.rd) == 0xFFFFFFFF) && (GetMipsRegLo(m_Opcode.rd) & 0x80000000) != 0) {
			m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
		} else {
			m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_64);
		}
	} else {
		int source1 = m_Opcode.rd == m_Opcode.rt?m_Opcode.rt:m_Opcode.rs;
		int source2 = m_Opcode.rd == m_Opcode.rt?m_Opcode.rs:m_Opcode.rt;

		if (IsMapped(source2)) { ProtectGPR(source2); }
		Map_GPR_64bit(m_Opcode.rd,source1);
		if (IsConst(source2)) {
			AddConstToX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegLo(source2));
			AddConstToX86Reg(GetMipsRegMapHi(m_Opcode.rd),GetMipsRegHi(source2));
		} else if (IsMapped(source2)) {
			x86Reg HiReg = Is64Bit(source2)?GetMipsRegMapHi(source2):Map_TempReg(x86_Any,source2,TRUE);
			AddX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapLo(source2));
			AdcX86RegToX86Reg(GetMipsRegMapHi(m_Opcode.rd),HiReg);
		} else {
			AddVariableToX86reg(GetMipsRegMapLo(m_Opcode.rd),&_GPR[source2].W[0],CRegName::GPR_Lo[source2]);
			AdcVariableToX86reg(GetMipsRegMapHi(m_Opcode.rd),&_GPR[source2].W[1],CRegName::GPR_Hi[source2]);
		}
	}
}

void CRecompilerOps::SPECIAL_DSUB (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (m_Opcode.rd == 0) { return; }

	if (IsConst(m_Opcode.rt)  && IsConst(m_Opcode.rs)) {
		if (IsMapped(m_Opcode.rd)) { UnMap_GPR(m_Opcode.rd, FALSE); }
		m_RegWorkingSet.SetMipsReg(m_Opcode.rd,
			Is64Bit(m_Opcode.rs)?GetMipsReg(m_Opcode.rs):(__int64)GetMipsRegLo_S(m_Opcode.rs) -
			Is64Bit(m_Opcode.rt)?GetMipsReg(m_Opcode.rt):(__int64)GetMipsRegLo_S(m_Opcode.rt)
		);		
		if (GetMipsRegLo_S(m_Opcode.rd) < 0 && GetMipsRegHi_S(m_Opcode.rd) == -1){ 
			m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
		} else if (GetMipsRegLo_S(m_Opcode.rd) >= 0 && GetMipsRegHi_S(m_Opcode.rd) == 0){ 
			m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
		} else {
			m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_64);
		}
	} else {
		if (m_Opcode.rd == m_Opcode.rt) {
			x86Reg HiReg = Map_TempReg(x86_Any,m_Opcode.rt,TRUE);
			x86Reg LoReg = Map_TempReg(x86_Any,m_Opcode.rt,FALSE);
			Map_GPR_64bit(m_Opcode.rd,m_Opcode.rs);
			SubX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd),LoReg);
			SbbX86RegToX86Reg(GetMipsRegMapHi(m_Opcode.rd),HiReg);
			return;
		}
		
		if (IsMapped(m_Opcode.rt)) { ProtectGPR(m_Opcode.rt); }
		Map_GPR_64bit(m_Opcode.rd,m_Opcode.rs);
		if (IsConst(m_Opcode.rt)) {
			SubConstFromX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegLo(m_Opcode.rt));
			SbbConstFromX86Reg(GetMipsRegMapHi(m_Opcode.rd),GetMipsRegHi(m_Opcode.rt));
		} else if (IsMapped(m_Opcode.rt)) {
			x86Reg HiReg = Is64Bit(m_Opcode.rt)?GetMipsRegMapHi(m_Opcode.rt):Map_TempReg(x86_Any,m_Opcode.rt,TRUE);
			SubX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapLo(m_Opcode.rt));
			SbbX86RegToX86Reg(GetMipsRegMapHi(m_Opcode.rd),HiReg);
		} else {
			SubVariableFromX86reg(GetMipsRegMapLo(m_Opcode.rd),&_GPR[m_Opcode.rt].W[0],CRegName::GPR_Lo[m_Opcode.rt]);
			SbbVariableFromX86reg(GetMipsRegMapHi(m_Opcode.rd),&_GPR[m_Opcode.rt].W[1],CRegName::GPR_Hi[m_Opcode.rt]);
		}
	}
}

void CRecompilerOps::SPECIAL_DSUBU (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (m_Opcode.rd == 0) { return; }

	if (IsConst(m_Opcode.rt)  && IsConst(m_Opcode.rs)) {
		if (IsMapped(m_Opcode.rd)) { UnMap_GPR(m_Opcode.rd, FALSE); }
		m_RegWorkingSet.SetMipsReg(m_Opcode.rd, 
			Is64Bit(m_Opcode.rs)?GetMipsReg(m_Opcode.rs):(__int64)GetMipsRegLo_S(m_Opcode.rs) -
			Is64Bit(m_Opcode.rt)?GetMipsReg(m_Opcode.rt):(__int64)GetMipsRegLo_S(m_Opcode.rt)
		);
		if (GetMipsRegLo_S(m_Opcode.rd) < 0 && GetMipsRegHi_S(m_Opcode.rd) == -1){ 
			m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
		} else if (GetMipsRegLo_S(m_Opcode.rd) >= 0 && GetMipsRegHi_S(m_Opcode.rd) == 0){ 
			m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
		} else {
			m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_64);
		}
	} else {
		if (m_Opcode.rd == m_Opcode.rt) {
			x86Reg HiReg = Map_TempReg(x86_Any,m_Opcode.rt,TRUE);
			x86Reg LoReg = Map_TempReg(x86_Any,m_Opcode.rt,FALSE);
			Map_GPR_64bit(m_Opcode.rd,m_Opcode.rs);
			SubX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd),LoReg);
			SbbX86RegToX86Reg(GetMipsRegMapHi(m_Opcode.rd),HiReg);
			return;
		}
		if (IsMapped(m_Opcode.rt)) { ProtectGPR(m_Opcode.rt); }
		Map_GPR_64bit(m_Opcode.rd,m_Opcode.rs);
		if (IsConst(m_Opcode.rt)) {
			SubConstFromX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegLo(m_Opcode.rt));
			SbbConstFromX86Reg(GetMipsRegMapHi(m_Opcode.rd),GetMipsRegHi(m_Opcode.rt));
		} else if (IsMapped(m_Opcode.rt)) {
			x86Reg HiReg = Is64Bit(m_Opcode.rt)?GetMipsRegMapHi(m_Opcode.rt):Map_TempReg(x86_Any,m_Opcode.rt,TRUE);
			SubX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapLo(m_Opcode.rt));
			SbbX86RegToX86Reg(GetMipsRegMapHi(m_Opcode.rd),HiReg);
		} else {
			SubVariableFromX86reg(GetMipsRegMapLo(m_Opcode.rd),&_GPR[m_Opcode.rt].W[0],CRegName::GPR_Lo[m_Opcode.rt]);
			SbbVariableFromX86reg(GetMipsRegMapHi(m_Opcode.rd),&_GPR[m_Opcode.rt].W[1],CRegName::GPR_Hi[m_Opcode.rt]);
		}
	}
}

void CRecompilerOps::SPECIAL_DSLL (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	if (m_Opcode.rd == 0) { return; }

	if (IsConst(m_Opcode.rt)) 
	{
		if (IsMapped(m_Opcode.rd)) { UnMap_GPR(m_Opcode.rd, FALSE); }

		__int64 Value = Is64Bit(m_Opcode.rt)?GetMipsReg_S(m_Opcode.rt):(__int64)GetMipsRegLo_S(m_Opcode.rt);
		m_RegWorkingSet.SetMipsReg(m_Opcode.rd, Value << m_Opcode.sa);
		if (GetMipsRegLo_S(m_Opcode.rd) < 0 && GetMipsRegHi_S(m_Opcode.rd) == -1){ 
			m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
		} else if (GetMipsRegLo_S(m_Opcode.rd) >= 0 && GetMipsRegHi_S(m_Opcode.rd) == 0){ 
			m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
		} else {
			m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_64);
		}
		return;
	}
	
	Map_GPR_64bit(m_Opcode.rd,m_Opcode.rt);
	ShiftLeftDoubleImmed(GetMipsRegMapHi(m_Opcode.rd),GetMipsRegMapLo(m_Opcode.rd),(BYTE)m_Opcode.sa);
	ShiftLeftSignImmed(	GetMipsRegMapLo(m_Opcode.rd),(BYTE)m_Opcode.sa);
}

void CRecompilerOps::SPECIAL_DSRL (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	if (m_Opcode.rd == 0) { return; }

	if (IsConst(m_Opcode.rt)) {
		if (IsMapped(m_Opcode.rd)) { UnMap_GPR(m_Opcode.rd, FALSE); }

		__int64 Value = Is64Bit(m_Opcode.rt)?GetMipsReg_S(m_Opcode.rt):(__int64)GetMipsRegLo_S(m_Opcode.rt);
		m_RegWorkingSet.SetMipsReg(m_Opcode.rd,Value >> m_Opcode.sa);
		if (GetMipsRegLo_S(m_Opcode.rd) < 0 && GetMipsRegHi_S(m_Opcode.rd) == -1){ 
			m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
		} else if (GetMipsRegLo_S(m_Opcode.rd) >= 0 && GetMipsRegHi_S(m_Opcode.rd) == 0){ 
			m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
		} else {
			m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_64);
		}
		return;
	}	
	Map_GPR_64bit(m_Opcode.rd,m_Opcode.rt);
	ShiftRightDoubleImmed(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapHi(m_Opcode.rd),(BYTE)m_Opcode.sa);
	ShiftRightUnsignImmed(GetMipsRegMapHi(m_Opcode.rd),(BYTE)m_Opcode.sa);
}

void CRecompilerOps::SPECIAL_DSRA (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	if (m_Opcode.rd == 0) { return; }

	if (IsConst(m_Opcode.rt)) {
		if (IsMapped(m_Opcode.rd)) { UnMap_GPR(m_Opcode.rd, FALSE); }

		__int64 Value = Is64Bit(m_Opcode.rt)?GetMipsReg_S(m_Opcode.rt):(__int64)GetMipsRegLo_S(m_Opcode.rt);
		m_RegWorkingSet.SetMipsReg_S(m_Opcode.rd, Value >> m_Opcode.sa);
		if (GetMipsRegLo_S(m_Opcode.rd) < 0 && GetMipsRegHi_S(m_Opcode.rd) == -1){ 
			m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
		} else if (GetMipsRegLo_S(m_Opcode.rd) >= 0 && GetMipsRegHi_S(m_Opcode.rd) == 0){ 
			m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
		} else {
			m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_64);
		}
		return;
	}	
	Map_GPR_64bit(m_Opcode.rd,m_Opcode.rt);
	ShiftRightDoubleImmed(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapHi(m_Opcode.rd),(BYTE)m_Opcode.sa);
	ShiftRightSignImmed(GetMipsRegMapHi(m_Opcode.rd),(BYTE)m_Opcode.sa);
}

void CRecompilerOps::SPECIAL_DSLL32 (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	if (m_Opcode.rd == 0) { return; }
	if (IsConst(m_Opcode.rt)) {
		if (m_Opcode.rt != m_Opcode.rd) { UnMap_GPR(m_Opcode.rd, FALSE); }
		m_RegWorkingSet.SetMipsRegHi(m_Opcode.rd,GetMipsRegLo(m_Opcode.rt) << m_Opcode.sa);
		m_RegWorkingSet.SetMipsRegLo(m_Opcode.rd,0);
		if (GetMipsRegLo_S(m_Opcode.rd) < 0 && GetMipsRegHi_S(m_Opcode.rd) == -1){ 
			m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
		} else if (GetMipsRegLo_S(m_Opcode.rd) >= 0 && GetMipsRegHi_S(m_Opcode.rd) == 0){ 
			m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
		} else {
			m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_64);
		}

	} else if (IsMapped(m_Opcode.rt)) {
		ProtectGPR(m_Opcode.rt);
		Map_GPR_64bit(m_Opcode.rd,-1);		
		if (m_Opcode.rt != m_Opcode.rd) {
			MoveX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rt),GetMipsRegMapHi(m_Opcode.rd));
		} else {
			CPU_Message("    regcache: switch hi (%s) with lo (%s) for %s",x86_Name(GetMipsRegMapHi(m_Opcode.rt)),x86_Name(GetMipsRegMapLo(m_Opcode.rt)),CRegName::GPR[m_Opcode.rt]);
			x86Reg HiReg = GetMipsRegMapHi(m_Opcode.rt);
			m_RegWorkingSet.SetMipsRegMapHi(m_Opcode.rt,GetMipsRegMapLo(m_Opcode.rt));
			m_RegWorkingSet.SetMipsRegMapLo(m_Opcode.rt,HiReg);
		}
		if ((BYTE)m_Opcode.sa != 0) {
			ShiftLeftSignImmed(GetMipsRegMapHi(m_Opcode.rd),(BYTE)m_Opcode.sa);
		}
		XorX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapLo(m_Opcode.rd));
	} else {
		Map_GPR_64bit(m_Opcode.rd,-1);
		MoveVariableToX86reg(&_GPR[m_Opcode.rt],CRegName::GPR_Hi[m_Opcode.rt],GetMipsRegMapHi(m_Opcode.rd));
		if ((BYTE)m_Opcode.sa != 0) {
			ShiftLeftSignImmed(GetMipsRegMapHi(m_Opcode.rd),(BYTE)m_Opcode.sa);
		}
		XorX86RegToX86Reg(GetMipsRegMapLo(m_Opcode.rd),GetMipsRegMapLo(m_Opcode.rd));
	}
}

void CRecompilerOps::SPECIAL_DSRL32 (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	if (IsConst(m_Opcode.rt)) {
		if (m_Opcode.rt != m_Opcode.rd) { UnMap_GPR(m_Opcode.rd, FALSE); }
		m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_ZERO);
		m_RegWorkingSet.SetMipsRegLo(m_Opcode.rd, (DWORD)(GetMipsReg(m_Opcode.rt) >> (m_Opcode.sa + 32)));
	} else if (IsMapped(m_Opcode.rt)) {
		ProtectGPR(m_Opcode.rt);
		if (Is64Bit(m_Opcode.rt)) {
			if (m_Opcode.rt == m_Opcode.rd) {
				CPU_Message("    regcache: switch hi (%s) with lo (%s) for %s",x86_Name(GetMipsRegMapHi(m_Opcode.rt)),x86_Name(GetMipsRegMapLo(m_Opcode.rt)),CRegName::GPR[m_Opcode.rt]);
				x86Reg HiReg = GetMipsRegMapHi(m_Opcode.rt);
				m_RegWorkingSet.SetMipsRegMapHi(m_Opcode.rt,GetMipsRegMapLo(m_Opcode.rt));
				m_RegWorkingSet.SetMipsRegMapLo(m_Opcode.rt,HiReg);
				Map_GPR_32bit(m_Opcode.rd,FALSE,-1);
			} else {
				Map_GPR_32bit(m_Opcode.rd,FALSE,-1);
				MoveX86RegToX86Reg(GetMipsRegMapHi(m_Opcode.rt),GetMipsRegMapLo(m_Opcode.rd));
			}
			if ((BYTE)m_Opcode.sa != 0) {
				ShiftRightUnsignImmed(GetMipsRegMapLo(m_Opcode.rd),(BYTE)m_Opcode.sa);
			}
		} else {
			CRecompilerOps::UnknownOpcode();
		}
	} else {
		Map_GPR_32bit(m_Opcode.rd,FALSE,-1);
		MoveVariableToX86reg(&_GPR[m_Opcode.rt].UW[1],CRegName::GPR_Hi[m_Opcode.rt],GetMipsRegMapLo(m_Opcode.rd));
		if ((BYTE)m_Opcode.sa != 0) {
			ShiftRightUnsignImmed(GetMipsRegMapLo(m_Opcode.rd),(BYTE)m_Opcode.sa);
		}
	}
}

void CRecompilerOps::SPECIAL_DSRA32 (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	if (IsConst(m_Opcode.rt)) {
		if (m_Opcode.rt != m_Opcode.rd) { UnMap_GPR(m_Opcode.rd, FALSE); }
		m_RegWorkingSet.SetMipsRegState(m_Opcode.rd,CRegInfo::STATE_CONST_32_SIGN);
		m_RegWorkingSet.SetMipsRegLo(m_Opcode.rd,(DWORD)(GetMipsReg_S(m_Opcode.rt) >> (m_Opcode.sa + 32)));
	} else if (IsMapped(m_Opcode.rt)) {
		ProtectGPR(m_Opcode.rt);
		if (Is64Bit(m_Opcode.rt)) {
			if (m_Opcode.rt == m_Opcode.rd) {
				CPU_Message("    regcache: switch hi (%s) with lo (%s) for %s",x86_Name(GetMipsRegMapHi(m_Opcode.rt)),x86_Name(GetMipsRegMapLo(m_Opcode.rt)),CRegName::GPR[m_Opcode.rt]);
				x86Reg HiReg = GetMipsRegMapHi(m_Opcode.rt);
				m_RegWorkingSet.SetMipsRegMapHi(m_Opcode.rt,GetMipsRegMapLo(m_Opcode.rt));
				m_RegWorkingSet.SetMipsRegMapLo(m_Opcode.rt,HiReg);
				Map_GPR_32bit(m_Opcode.rd,TRUE,-1);
			} else {
				Map_GPR_32bit(m_Opcode.rd,TRUE,-1);
				MoveX86RegToX86Reg(GetMipsRegMapHi(m_Opcode.rt),GetMipsRegMapLo(m_Opcode.rd));
			}
			if ((BYTE)m_Opcode.sa != 0) {
				ShiftRightSignImmed(GetMipsRegMapLo(m_Opcode.rd),(BYTE)m_Opcode.sa);
			}
		} else {
			CRecompilerOps::UnknownOpcode();
		}
	} else {
		Map_GPR_32bit(m_Opcode.rd,TRUE,-1);
		MoveVariableToX86reg(&_GPR[m_Opcode.rt].UW[1],CRegName::GPR_Lo[m_Opcode.rt],GetMipsRegMapLo(m_Opcode.rd));
		if ((BYTE)m_Opcode.sa != 0) {
			ShiftRightSignImmed(GetMipsRegMapLo(m_Opcode.rd),(BYTE)m_Opcode.sa);
		}
	}
}

/************************** COP0 functions **************************/
void CRecompilerOps::COP0_MF(void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	switch (m_Opcode.rd) {
	case 9: //Count
		m_RegWorkingSet.SetBlockCycleCount(m_RegWorkingSet.GetBlockCycleCount() - g_System->CountPerOp()) ;
		UpdateCounters(m_RegWorkingSet,false, true);
		m_RegWorkingSet.SetBlockCycleCount(m_RegWorkingSet.GetBlockCycleCount() + g_System->CountPerOp()) ;
		BeforeCallDirect(m_RegWorkingSet);
		MoveConstToX86reg((DWORD)g_SystemTimer,x86_ECX);		
		Call_Direct(AddressOf(&CSystemTimer::UpdateTimers), "CSystemTimer::UpdateTimers");
		AfterCallDirect(m_RegWorkingSet);
	}
	Map_GPR_32bit(m_Opcode.rt,TRUE,-1);
	MoveVariableToX86reg(&_CP0[m_Opcode.rd],CRegName::Cop0[m_Opcode.rd],GetMipsRegMapLo(m_Opcode.rt));
}

void CRecompilerOps::COP0_MT (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	BYTE *Jump;

	switch (m_Opcode.rd) {
	case 0: //Index
	case 2: //EntryLo0
	case 3: //EntryLo1
	case 4: //Context
	case 5: //PageMask
	case 10: //Entry Hi
	case 14: //EPC
	case 16: //Config
	case 18: //WatchLo 
	case 19: //WatchHi
	case 28: //Tag lo
	case 29: //Tag Hi
	case 30: //ErrEPC
		if (IsConst(m_Opcode.rt)) {
			MoveConstToVariable(GetMipsRegLo(m_Opcode.rt), &_CP0[m_Opcode.rd], CRegName::Cop0[m_Opcode.rd]);
		} else if (IsMapped(m_Opcode.rt)) {
			MoveX86regToVariable(GetMipsRegMapLo(m_Opcode.rt), &_CP0[m_Opcode.rd], CRegName::Cop0[m_Opcode.rd]);
		} else {
			MoveX86regToVariable(Map_TempReg(x86_Any,m_Opcode.rt,FALSE), &_CP0[m_Opcode.rd], CRegName::Cop0[m_Opcode.rd]);
		}
		if (m_Opcode.rd == 4) //Context
		{
			AndConstToVariable(0xFF800000,&_CP0[m_Opcode.rd], CRegName::Cop0[m_Opcode.rd]);
		}
		break;
	case 11: //Compare
		m_RegWorkingSet.SetBlockCycleCount(m_RegWorkingSet.GetBlockCycleCount() - g_System->CountPerOp()) ;
		UpdateCounters(m_RegWorkingSet,false, true);
		m_RegWorkingSet.SetBlockCycleCount(m_RegWorkingSet.GetBlockCycleCount() + g_System->CountPerOp()) ;
		BeforeCallDirect(m_RegWorkingSet);
		MoveConstToX86reg((DWORD)g_SystemTimer,x86_ECX);		
		Call_Direct(AddressOf(&CSystemTimer::UpdateTimers), "CSystemTimer::UpdateTimers");
		AfterCallDirect(m_RegWorkingSet);
		if (IsConst(m_Opcode.rt)) {
			MoveConstToVariable(GetMipsRegLo(m_Opcode.rt), &_CP0[m_Opcode.rd], CRegName::Cop0[m_Opcode.rd]);
		} else if (IsMapped(m_Opcode.rt)) {
			MoveX86regToVariable(GetMipsRegMapLo(m_Opcode.rt), &_CP0[m_Opcode.rd], CRegName::Cop0[m_Opcode.rd]);
		} else {
			MoveX86regToVariable(Map_TempReg(x86_Any,m_Opcode.rt,FALSE), &_CP0[m_Opcode.rd], CRegName::Cop0[m_Opcode.rd]);
		}
		AndConstToVariable((DWORD)~CAUSE_IP7,&g_Reg->FAKE_CAUSE_REGISTER,"FAKE_CAUSE_REGISTER");
		BeforeCallDirect(m_RegWorkingSet);
		MoveConstToX86reg((DWORD)g_SystemTimer,x86_ECX);		
		Call_Direct(AddressOf(&CSystemTimer::UpdateCompareTimer), "CSystemTimer::UpdateCompareTimer");
		AfterCallDirect(m_RegWorkingSet);
		break;
	case 9: //Count
		m_RegWorkingSet.SetBlockCycleCount(m_RegWorkingSet.GetBlockCycleCount() - g_System->CountPerOp()) ;
		UpdateCounters(m_RegWorkingSet,false, true);
		m_RegWorkingSet.SetBlockCycleCount(m_RegWorkingSet.GetBlockCycleCount() + g_System->CountPerOp()) ;
		BeforeCallDirect(m_RegWorkingSet);
		MoveConstToX86reg((DWORD)g_SystemTimer,x86_ECX);		
		Call_Direct(AddressOf(&CSystemTimer::UpdateTimers), "CSystemTimer::UpdateTimers");
		AfterCallDirect(m_RegWorkingSet);
		if (IsConst(m_Opcode.rt)) {
			MoveConstToVariable(GetMipsRegLo(m_Opcode.rt), &_CP0[m_Opcode.rd], CRegName::Cop0[m_Opcode.rd]);
		} else if (IsMapped(m_Opcode.rt)) {
			MoveX86regToVariable(GetMipsRegMapLo(m_Opcode.rt), &_CP0[m_Opcode.rd], CRegName::Cop0[m_Opcode.rd]);
		} else {
			MoveX86regToVariable(Map_TempReg(x86_Any,m_Opcode.rt,FALSE), &_CP0[m_Opcode.rd], CRegName::Cop0[m_Opcode.rd]);
		}
		BeforeCallDirect(m_RegWorkingSet);
		MoveConstToX86reg((DWORD)g_SystemTimer,x86_ECX);		
		Call_Direct(AddressOf(&CSystemTimer::UpdateCompareTimer), "CSystemTimer::UpdateCompareTimer");
		AfterCallDirect(m_RegWorkingSet);
		break;
	case 12: //Status
		{
			x86Reg OldStatusReg = Map_TempReg(x86_Any,-1,FALSE);
			MoveVariableToX86reg(&_CP0[m_Opcode.rd],CRegName::Cop0[m_Opcode.rd],OldStatusReg);
			if (IsConst(m_Opcode.rt)) {
				MoveConstToVariable(GetMipsRegLo(m_Opcode.rt), &_CP0[m_Opcode.rd], CRegName::Cop0[m_Opcode.rd]);
			} else if (IsMapped(m_Opcode.rt)) {
				MoveX86regToVariable(GetMipsRegMapLo(m_Opcode.rt), &_CP0[m_Opcode.rd], CRegName::Cop0[m_Opcode.rd]);
			} else {
				MoveX86regToVariable(Map_TempReg(x86_Any,m_Opcode.rt,FALSE), &_CP0[m_Opcode.rd], CRegName::Cop0[m_Opcode.rd]);
			}
			XorVariableToX86reg(&_CP0[m_Opcode.rd], CRegName::Cop0[m_Opcode.rd],OldStatusReg);
			TestConstToX86Reg(STATUS_FR,OldStatusReg);
			JeLabel8("FpuFlagFine",0);
			Jump = m_RecompPos - 1;
			BeforeCallDirect(m_RegWorkingSet);
			MoveConstToX86reg((DWORD)g_Reg,x86_ECX); 
            Call_Direct(AddressOf(&CRegisters::FixFpuLocations),"CRegisters::FixFpuLocations");

			AfterCallDirect(m_RegWorkingSet);
			SetJump8(Jump,m_RecompPos);		
			
			//TestConstToX86Reg(STATUS_FR,OldStatusReg);
			//BreakPoint(__FILEW__,__LINE__); //m_Section->CompileExit(m_CompilePC+4,m_RegWorkingSet,ExitResetRecompCode,FALSE,JneLabel32);
			BeforeCallDirect(m_RegWorkingSet);
			MoveConstToX86reg((DWORD)g_Reg,x86_ECX);
			Call_Direct(AddressOf(&CRegisters::CheckInterrupts),"CRegisters::CheckInterrupts");
			AfterCallDirect(m_RegWorkingSet);
		}
		break;
	case 6: //Wired
		m_RegWorkingSet.SetBlockCycleCount(m_RegWorkingSet.GetBlockCycleCount() - g_System->CountPerOp()) ;
		UpdateCounters(m_RegWorkingSet,false, true);
		m_RegWorkingSet.SetBlockCycleCount(m_RegWorkingSet.GetBlockCycleCount() + g_System->CountPerOp()) ;

		BeforeCallDirect(m_RegWorkingSet);
		MoveConstToX86reg((DWORD)g_SystemTimer,x86_ECX);		
		Call_Direct(AddressOf(&CSystemTimer::UpdateTimers), "CSystemTimer::UpdateTimers");
		AfterCallDirect(m_RegWorkingSet);
		if (IsConst(m_Opcode.rt)) {
			MoveConstToVariable(GetMipsRegLo(m_Opcode.rt), &_CP0[m_Opcode.rd], CRegName::Cop0[m_Opcode.rd]);
		} else if (IsMapped(m_Opcode.rt)) {
			MoveX86regToVariable(GetMipsRegMapLo(m_Opcode.rt), &_CP0[m_Opcode.rd], CRegName::Cop0[m_Opcode.rd]);
		} else {
			MoveX86regToVariable(Map_TempReg(x86_Any,m_Opcode.rt,FALSE), &_CP0[m_Opcode.rd], CRegName::Cop0[m_Opcode.rd]);
		}
		break;
	case 13: //cause
		if (IsConst(m_Opcode.rt)) {
			AndConstToVariable(0xFFFFCFF,&_CP0[m_Opcode.rd], CRegName::Cop0[m_Opcode.rd]);
			if ((GetMipsRegLo(m_Opcode.rt) & 0x300) != 0 && bHaveDebugger() ){ g_Notify->DisplayError(L"Set IP0 or IP1"); }
		} else {
			UnknownOpcode(); 
			return;
		}
		BeforeCallDirect(m_RegWorkingSet);
		MoveConstToX86reg((DWORD)g_Reg,x86_ECX);
		Call_Direct(AddressOf(&CRegisters::CheckInterrupts),"CRegisters::CheckInterrupts");
		AfterCallDirect(m_RegWorkingSet);
		break;
	default:
		UnknownOpcode(); 
	}
}

/************************** COP0 CO functions ***********************/
void CRecompilerOps::COP0_CO_TLBR( void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (!g_System->bUseTlb()) {	return; }
	BeforeCallDirect(m_RegWorkingSet);
	MoveConstToX86reg((DWORD)g_TLB,x86_ECX);
	Call_Direct(AddressOf(&CTLB::ReadEntry),"CTLB::ReadEntry");
	AfterCallDirect(m_RegWorkingSet);
}

void CRecompilerOps::COP0_CO_TLBWI( void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (!g_System->bUseTlb()) {	return; }
	BeforeCallDirect(m_RegWorkingSet);
	PushImm32("FALSE",FALSE);
	MoveVariableToX86reg(&g_Reg->INDEX_REGISTER,"INDEX_REGISTER",x86_ECX);
	AndConstToX86Reg(x86_ECX,0x1F);
	Push(x86_ECX);
	MoveConstToX86reg((DWORD)g_TLB,x86_ECX);
	Call_Direct(AddressOf(&CTLB::WriteEntry),"CTLB::WriteEntry");
	AfterCallDirect(m_RegWorkingSet);
}

void CRecompilerOps::COP0_CO_TLBWR( void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	if (!g_System->bUseTlb()) {	return; }

	m_RegWorkingSet.SetBlockCycleCount(m_RegWorkingSet.GetBlockCycleCount() - g_System->CountPerOp()) ;
	UpdateCounters(m_RegWorkingSet,false, true);
	m_RegWorkingSet.SetBlockCycleCount(m_RegWorkingSet.GetBlockCycleCount() + g_System->CountPerOp()) ;
	BeforeCallDirect(m_RegWorkingSet);
	MoveConstToX86reg((DWORD)g_SystemTimer,x86_ECX);		
	Call_Direct(AddressOf(&CSystemTimer::UpdateTimers), "CSystemTimer::UpdateTimers");

	PushImm32("true",true);
	MoveVariableToX86reg(&g_Reg->RANDOM_REGISTER,"RANDOM_REGISTER",x86_ECX);
	AndConstToX86Reg(x86_ECX,0x1F);
	Push(x86_ECX);
	MoveConstToX86reg((DWORD)g_TLB,x86_ECX);
	Call_Direct(AddressOf(&CTLB::WriteEntry),"CTLB::WriteEntry");
	AfterCallDirect(m_RegWorkingSet);
}

void CRecompilerOps::COP0_CO_TLBP( void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	if (!g_System->bUseTlb()) {	return; }
	BeforeCallDirect(m_RegWorkingSet);
	MoveConstToX86reg((DWORD)g_TLB,x86_ECX);		
	Call_Direct(AddressOf(&CTLB::Probe), "CTLB::TLB_Probe");
	AfterCallDirect(m_RegWorkingSet);
}

void compiler_COP0_CO_ERET (void) {
	if ((g_Reg->STATUS_REGISTER & STATUS_ERL) != 0) {
		g_Reg->m_PROGRAM_COUNTER = g_Reg->ERROREPC_REGISTER;
		g_Reg->STATUS_REGISTER &= ~STATUS_ERL;
	} else {
		g_Reg->m_PROGRAM_COUNTER = g_Reg->EPC_REGISTER;
		g_Reg->STATUS_REGISTER &= ~STATUS_EXL;
	}
	g_Reg->m_LLBit = 0;
	g_Reg->CheckInterrupts();
}

void CRecompilerOps::COP0_CO_ERET( void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	m_RegWorkingSet.WriteBackRegisters();
	Call_Direct(compiler_COP0_CO_ERET,"compiler_COP0_CO_ERET");

	UpdateCounters(m_RegWorkingSet,true,true);
	m_Section->CompileExit(m_CompilePC, (DWORD)-1,m_RegWorkingSet,CExitInfo::Normal,TRUE,NULL);
	m_NextInstruction = END_BLOCK;
}

/************************** FPU Options **************************/
void CRecompilerOps::ChangeDefaultRoundingModel (void) {
	switch((_FPCR[31] & 3)) {
	case 0: *_RoundingModel = ROUND_NEAR; break;
	case 1: *_RoundingModel = ROUND_CHOP; break;
	case 2: *_RoundingModel = ROUND_UP;   break;
	case 3: *_RoundingModel = ROUND_DOWN; break;
	}
}

/************************** COP1 functions **************************/
void CRecompilerOps::COP1_MF (void) {
	x86Reg TempReg;

	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	m_Section->CompileCop1Test();

	UnMap_FPR(m_Opcode.fs,TRUE);
	Map_GPR_32bit(m_Opcode.rt, TRUE, -1);
	TempReg = Map_TempReg(x86_Any,-1,FALSE);
	char Name[100];
	sprintf(Name,"_FPR_S[%d]",m_Opcode.fs);
	MoveVariableToX86reg((BYTE *)&_FPR_S[m_Opcode.fs],Name,TempReg);
	MoveX86PointerToX86reg(GetMipsRegMapLo(m_Opcode.rt),TempReg);		
}

void CRecompilerOps::COP1_DMF (void) {
	x86Reg TempReg;
	char Name[50];

	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	m_Section->CompileCop1Test();

	UnMap_FPR(m_Opcode.fs,TRUE);
	Map_GPR_64bit(m_Opcode.rt, -1);
	TempReg = Map_TempReg(x86_Any,-1,FALSE);
	sprintf(Name,"_FPR_D[%d]",m_Opcode.fs);
	MoveVariableToX86reg((BYTE *)&_FPR_D[m_Opcode.fs],Name,TempReg);
	AddConstToX86Reg(TempReg,4);
	MoveX86PointerToX86reg(GetMipsRegMapHi(m_Opcode.rt),TempReg);		
	sprintf(Name,"_FPR_D[%d]",m_Opcode.fs);
	MoveVariableToX86reg((BYTE *)&_FPR_D[m_Opcode.fs],Name,TempReg);
	MoveX86PointerToX86reg(GetMipsRegMapLo(m_Opcode.rt),TempReg);		
}

void CRecompilerOps::COP1_CF(void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	m_Section->CompileCop1Test();
	
	if (m_Opcode.fs != 31 && m_Opcode.fs != 0) { UnknownOpcode(); return; }
	Map_GPR_32bit(m_Opcode.rt,TRUE,-1);
	MoveVariableToX86reg(&_FPCR[m_Opcode.fs],CRegName::FPR_Ctrl[m_Opcode.fs],GetMipsRegMapLo(m_Opcode.rt));
}

void CRecompilerOps::COP1_MT( void) {	
	x86Reg TempReg;

	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	m_Section->CompileCop1Test();
	
	if ((m_Opcode.fs & 1) != 0) {
		if (RegInStack(m_Opcode.fs-1,CRegInfo::FPU_Double) || RegInStack(m_Opcode.fs-1,CRegInfo::FPU_Qword)) {
			UnMap_FPR(m_Opcode.fs-1,TRUE);
		}
	}
	UnMap_FPR(m_Opcode.fs,TRUE);
	TempReg = Map_TempReg(x86_Any,-1,FALSE);
	char Name[50];
	sprintf(Name,"_FPR_S[%d]",m_Opcode.fs);
	MoveVariableToX86reg((BYTE *)&_FPR_S[m_Opcode.fs],Name,TempReg);

	if (IsConst(m_Opcode.rt)) {
		MoveConstToX86Pointer(GetMipsRegLo(m_Opcode.rt),TempReg);
	} else if (IsMapped(m_Opcode.rt)) {
		MoveX86regToX86Pointer(GetMipsRegMapLo(m_Opcode.rt),TempReg);
	} else {
		MoveX86regToX86Pointer(Map_TempReg(x86_Any, m_Opcode.rt, FALSE),TempReg);
	}
}

void CRecompilerOps::COP1_DMT( void) {
	x86Reg TempReg;

	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	m_Section->CompileCop1Test();
	
	if ((m_Opcode.fs & 1) == 0) {
		if (RegInStack(m_Opcode.fs+1,CRegInfo::FPU_Float) || RegInStack(m_Opcode.fs+1,CRegInfo::FPU_Dword)) {
			UnMap_FPR(m_Opcode.fs+1,TRUE);
		}
	}
	UnMap_FPR(m_Opcode.fs,TRUE);
	TempReg = Map_TempReg(x86_Any,-1,FALSE);
	char Name[50];
	sprintf(Name,"_FPR_D[%d]",m_Opcode.fs);
	MoveVariableToX86reg((BYTE *)&_FPR_D[m_Opcode.fs],Name,TempReg);
		
	if (IsConst(m_Opcode.rt)) {
		MoveConstToX86Pointer(GetMipsRegLo(m_Opcode.rt),TempReg);
		AddConstToX86Reg(TempReg,4);
		if (Is64Bit(m_Opcode.rt)) {
			MoveConstToX86Pointer(GetMipsRegHi(m_Opcode.rt),TempReg);
		} else {
			MoveConstToX86Pointer(GetMipsRegLo_S(m_Opcode.rt) >> 31,TempReg);
		}
	} else if (IsMapped(m_Opcode.rt)) {
		MoveX86regToX86Pointer(GetMipsRegMapLo(m_Opcode.rt),TempReg);
		AddConstToX86Reg(TempReg,4);
		if (Is64Bit(m_Opcode.rt)) {
			MoveX86regToX86Pointer(GetMipsRegMapHi(m_Opcode.rt),TempReg);
		} else {
			MoveX86regToX86Pointer(Map_TempReg(x86_Any, m_Opcode.rt, TRUE),TempReg);
		}
	} else {
		x86Reg Reg= Map_TempReg(x86_Any, m_Opcode.rt, FALSE);
		MoveX86regToX86Pointer(Reg,TempReg);
		AddConstToX86Reg(TempReg,4);
		MoveX86regToX86Pointer(Map_TempReg(Reg, m_Opcode.rt, TRUE),TempReg);
	}
}


void CRecompilerOps::COP1_CT(void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	m_Section->CompileCop1Test();
	if (m_Opcode.fs != 31) { UnknownOpcode(); return; }

	if (IsConst(m_Opcode.rt)) {
		MoveConstToVariable(GetMipsRegLo(m_Opcode.rt),&_FPCR[m_Opcode.fs],CRegName::FPR_Ctrl[m_Opcode.fs]);
	} else if (IsMapped(m_Opcode.rt)) {
		MoveX86regToVariable(GetMipsRegMapLo(m_Opcode.rt),&_FPCR[m_Opcode.fs],CRegName::FPR_Ctrl[m_Opcode.fs]);
	} else {
		MoveX86regToVariable(Map_TempReg(x86_Any,m_Opcode.rt,FALSE),&_FPCR[m_Opcode.fs],CRegName::FPR_Ctrl[m_Opcode.fs]);		
	}
	BeforeCallDirect(m_RegWorkingSet);
	Call_Direct(ChangeDefaultRoundingModel, "ChangeDefaultRoundingModel");
	AfterCallDirect(m_RegWorkingSet);
	m_RegWorkingSet.SetRoundingModel(CRegInfo::RoundUnknown);
}

/************************** COP1: S functions ************************/
void CRecompilerOps::COP1_S_ADD (void) {
	DWORD Reg1 = m_Opcode.ft == m_Opcode.fd?m_Opcode.ft:m_Opcode.fs;
	DWORD Reg2 = m_Opcode.ft == m_Opcode.fd?m_Opcode.fs:m_Opcode.ft;
	
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	FixRoundModel(CRegInfo::RoundDefault);

	Load_FPR_ToTop(m_Opcode.fd,Reg1, CRegInfo::FPU_Float);
	if (RegInStack(Reg2, CRegInfo::FPU_Float)) {
		fpuAddReg(StackPosition(Reg2));
	} else {
		x86Reg TempReg;

		UnMap_FPR(Reg2,TRUE);
		TempReg = Map_TempReg(x86_Any,-1,FALSE);
		char Name[50];
		sprintf(Name,"_FPR_S[%d]",Reg2);
		MoveVariableToX86reg((BYTE *)&_FPR_S[Reg2],Name,TempReg);
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fd, CRegInfo::FPU_Float);
		fpuAddDwordRegPointer(TempReg);
	}
	UnMap_FPR(m_Opcode.fd,TRUE);
}

void CRecompilerOps::COP1_S_SUB (void) {
	DWORD Reg1 = m_Opcode.ft == m_Opcode.fd?m_Opcode.ft:m_Opcode.fs;
	DWORD Reg2 = m_Opcode.ft == m_Opcode.fd?m_Opcode.fs:m_Opcode.ft;
	x86Reg TempReg;
	char Name[50];		
	
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	FixRoundModel(CRegInfo::RoundDefault);

	if (m_Opcode.fd == m_Opcode.ft) {
		UnMap_FPR(m_Opcode.fd,TRUE);
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Float);

		TempReg = Map_TempReg(x86_Any,-1,FALSE);
		sprintf(Name,"_FPR_S[%d]",m_Opcode.ft);
		MoveVariableToX86reg((BYTE *)&_FPR_S[m_Opcode.ft],Name,TempReg);
		fpuSubDwordRegPointer(TempReg);
	} else {
		Load_FPR_ToTop(m_Opcode.fd,Reg1, CRegInfo::FPU_Float);
		if (RegInStack(Reg2, CRegInfo::FPU_Float)) {
			fpuSubReg(StackPosition(Reg2));
		} else {
			UnMap_FPR(Reg2,TRUE);
			Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fd, CRegInfo::FPU_Float);

			TempReg = Map_TempReg(x86_Any,-1,FALSE);
			sprintf(Name,"_FPR_S[%d]",Reg2);
			MoveVariableToX86reg((BYTE *)&_FPR_S[Reg2],Name,TempReg);
			fpuSubDwordRegPointer(TempReg);			
		}
	}
	UnMap_FPR(m_Opcode.fd,TRUE);
}

void CRecompilerOps::COP1_S_MUL (void) {
	DWORD Reg1 = m_Opcode.ft == m_Opcode.fd?m_Opcode.ft:m_Opcode.fs;
	DWORD Reg2 = m_Opcode.ft == m_Opcode.fd?m_Opcode.fs:m_Opcode.ft;
	x86Reg TempReg;
	
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	FixRoundModel(CRegInfo::RoundDefault);

	Load_FPR_ToTop(m_Opcode.fd,Reg1, CRegInfo::FPU_Float);
	if (RegInStack(Reg2, CRegInfo::FPU_Float)) {
		fpuMulReg(StackPosition(Reg2));
	} else {
		UnMap_FPR(Reg2,TRUE);
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fd, CRegInfo::FPU_Float);

		TempReg = Map_TempReg(x86_Any,-1,FALSE);
		char Name[50];
		sprintf(Name,"_FPR_S[%d]",Reg2);
		MoveVariableToX86reg((BYTE *)&_FPR_S[Reg2],Name,TempReg);
		fpuMulDwordRegPointer(TempReg);			
	}
	UnMap_FPR(m_Opcode.fd,TRUE);
}

void CRecompilerOps::COP1_S_DIV (void) {
	DWORD Reg1 = m_Opcode.ft == m_Opcode.fd?m_Opcode.ft:m_Opcode.fs;
	DWORD Reg2 = m_Opcode.ft == m_Opcode.fd?m_Opcode.fs:m_Opcode.ft;
	x86Reg TempReg;
	char Name[50];
	
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	FixRoundModel(CRegInfo::RoundDefault);

	if (m_Opcode.fd == m_Opcode.ft) {
		UnMap_FPR(m_Opcode.fd,TRUE);
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Float);

		TempReg = Map_TempReg(x86_Any,-1,FALSE);
		sprintf(Name,"_FPR_S[%d]",m_Opcode.ft);
		MoveVariableToX86reg((BYTE *)&_FPR_S[m_Opcode.ft],Name,TempReg);
		fpuDivDwordRegPointer(TempReg);
	} else {
		Load_FPR_ToTop(m_Opcode.fd,Reg1, CRegInfo::FPU_Float);
		if (RegInStack(Reg2, CRegInfo::FPU_Float)) {
			fpuDivReg(StackPosition(Reg2));
		} else {
			UnMap_FPR(Reg2,TRUE);
			Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fd, CRegInfo::FPU_Float);

			TempReg = Map_TempReg(x86_Any,-1,FALSE);
			sprintf(Name,"_FPR_S[%d]",Reg2);
			MoveVariableToX86reg((BYTE *)&_FPR_S[Reg2],Name,TempReg);
			fpuDivDwordRegPointer(TempReg);			
		}
	}

	UnMap_FPR(m_Opcode.fd,TRUE);
}

void CRecompilerOps::COP1_S_ABS (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	m_Section->CompileCop1Test();	
	FixRoundModel(CRegInfo::RoundDefault);
	Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Float);
	fpuAbs();
	UnMap_FPR(m_Opcode.fd,TRUE);
}

void CRecompilerOps::COP1_S_NEG (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	m_Section->CompileCop1Test();	
	FixRoundModel(CRegInfo::RoundDefault);
	Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Float);
	fpuNeg();
	UnMap_FPR(m_Opcode.fd,TRUE);
}

void CRecompilerOps::COP1_S_SQRT (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	m_Section->CompileCop1Test();	
	FixRoundModel(CRegInfo::RoundDefault);
	Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Float);
	fpuSqrt();
	UnMap_FPR(m_Opcode.fd,TRUE);
}

void CRecompilerOps::COP1_S_MOV (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	m_Section->CompileCop1Test();	
	FixRoundModel(CRegInfo::RoundDefault);
	Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Float);
}

void CRecompilerOps::COP1_S_TRUNC_L (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	if (m_Opcode.fd != m_Opcode.fs || !RegInStack(m_Opcode.fd,CRegInfo::FPU_Float)) { 
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Float); 
	}
	ChangeFPURegFormat(m_Opcode.fd,CRegInfo::FPU_Float,CRegInfo::FPU_Qword,CRegInfo::RoundTruncate);
}

void CRecompilerOps::COP1_S_CEIL_L (void) {			//added by Witten
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	if (m_Opcode.fd != m_Opcode.fs || !RegInStack(m_Opcode.fd,CRegInfo::FPU_Float)) { 
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Float); 
	}
	ChangeFPURegFormat(m_Opcode.fd,CRegInfo::FPU_Float,CRegInfo::FPU_Qword,CRegInfo::RoundUp);
}

void CRecompilerOps::COP1_S_FLOOR_L (void) {			//added by Witten
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	if (m_Opcode.fd != m_Opcode.fs || !RegInStack(m_Opcode.fd,CRegInfo::FPU_Float)) { 
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Float); 
	}
	ChangeFPURegFormat(m_Opcode.fd,CRegInfo::FPU_Float,CRegInfo::FPU_Qword,CRegInfo::RoundDown);
}

void CRecompilerOps::COP1_S_ROUND_W (void) 
{
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	if (m_Opcode.fd != m_Opcode.fs || !RegInStack(m_Opcode.fd,CRegInfo::FPU_Float)) { 
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Float); 
	}
	ChangeFPURegFormat(m_Opcode.fd,CRegInfo::FPU_Float,CRegInfo::FPU_Dword,CRegInfo::RoundNearest);
}

void CRecompilerOps::COP1_S_TRUNC_W (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	if (m_Opcode.fd != m_Opcode.fs || !RegInStack(m_Opcode.fd,CRegInfo::FPU_Float)) { 
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Float); 
	}
	ChangeFPURegFormat(m_Opcode.fd,CRegInfo::FPU_Float,CRegInfo::FPU_Dword,CRegInfo::RoundTruncate);
}

void CRecompilerOps::COP1_S_CEIL_W (void) {			// added by Witten
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	if (m_Opcode.fd != m_Opcode.fs || !RegInStack(m_Opcode.fd,CRegInfo::FPU_Float)) { 
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Float); 
	}
	ChangeFPURegFormat(m_Opcode.fd,CRegInfo::FPU_Float,CRegInfo::FPU_Dword,CRegInfo::RoundUp);
}

void CRecompilerOps::COP1_S_FLOOR_W (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	if (m_Opcode.fd != m_Opcode.fs || !RegInStack(m_Opcode.fd,CRegInfo::FPU_Float)) { 
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Float); 
	}
	ChangeFPURegFormat(m_Opcode.fd,CRegInfo::FPU_Float,CRegInfo::FPU_Dword,CRegInfo::RoundDown);
}

void CRecompilerOps::COP1_S_CVT_D (void) 
{
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	if (m_Opcode.fd != m_Opcode.fs || !RegInStack(m_Opcode.fd,CRegInfo::FPU_Float)) {
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Float);
	}
	ChangeFPURegFormat(m_Opcode.fd,CRegInfo::FPU_Float,CRegInfo::FPU_Double,CRegInfo::RoundDefault);
}

void CRecompilerOps::COP1_S_CVT_W (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	if (m_Opcode.fd != m_Opcode.fs || !RegInStack(m_Opcode.fd,CRegInfo::FPU_Float)) {
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Float);
	}
	ChangeFPURegFormat(m_Opcode.fd,CRegInfo::FPU_Float,CRegInfo::FPU_Dword,CRegInfo::RoundDefault);
}

void CRecompilerOps::COP1_S_CVT_L (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	if (m_Opcode.fd != m_Opcode.fs || !RegInStack(m_Opcode.fd,CRegInfo::FPU_Float)) {
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Float);
	}
	ChangeFPURegFormat(m_Opcode.fd,CRegInfo::FPU_Float,CRegInfo::FPU_Qword,CRegInfo::RoundDefault);
}

void CRecompilerOps::COP1_S_CMP (void) {
	DWORD Reg1 = m_Opcode.fs; 
	DWORD Reg2 = m_Opcode.ft;
	DWORD cmp = 0;

	if ((m_Opcode.funct & 4) == 0) 
	{ 
		Reg1 = RegInStack(m_Opcode.ft, CRegInfo::FPU_Float)?m_Opcode.ft:m_Opcode.fs;
		Reg2 = RegInStack(m_Opcode.ft, CRegInfo::FPU_Float)?m_Opcode.fs:m_Opcode.ft;
	}
	
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	if ((m_Opcode.funct & 7) == 0) { CRecompilerOps::UnknownOpcode(); }
	if ((m_Opcode.funct & 2) != 0) { cmp |= 0x4000; }
	if ((m_Opcode.funct & 4) != 0) { cmp |= 0x0100; }
	
	Load_FPR_ToTop(Reg1,Reg1, CRegInfo::FPU_Float);
	Map_TempReg(x86_EAX, 0, FALSE);
	if (RegInStack(Reg2, CRegInfo::FPU_Float)) {
		fpuComReg(StackPosition(Reg2),FALSE);
	} else {
		UnMap_FPR(Reg2,TRUE);
		Load_FPR_ToTop(Reg1,Reg1, CRegInfo::FPU_Float);

		x86Reg TempReg = Map_TempReg(x86_Any,-1,FALSE);
		char Name[50];
		sprintf(Name,"_FPR_S[%d]",Reg2);
		MoveVariableToX86reg((BYTE *)&_FPR_S[Reg2],Name,TempReg);
		fpuComDwordRegPointer(TempReg,FALSE);
	}
	AndConstToVariable((DWORD)~FPCSR_C, &_FPCR[31], "_FPCR[31]");
	fpuStoreStatus();
	x86Reg Reg = Map_TempReg(x86_Any8Bit, 0, FALSE);
	TestConstToX86Reg(cmp,x86_EAX);	
	Setnz(Reg);
	
	if (cmp != 0) {
		TestConstToX86Reg(cmp,x86_EAX);	
		Setnz(Reg);
		
		if ((m_Opcode.funct & 1) != 0) {
			x86Reg Reg2 = Map_TempReg(x86_Any8Bit, 0, FALSE);
			AndConstToX86Reg(x86_EAX, 0x4300);
			CompConstToX86reg(x86_EAX, 0x4300);
			Setz(Reg2);
	
			OrX86RegToX86Reg(Reg, Reg2);
		}
	} else if ((m_Opcode.funct & 1) != 0) {
		AndConstToX86Reg(x86_EAX, 0x4300);
		CompConstToX86reg(x86_EAX, 0x4300);
		Setz(Reg);
	}
	ShiftLeftSignImmed(Reg, 23);
	OrX86RegToVariable(&_FPCR[31], "_FPCR[31]", Reg);
}

/************************** COP1: D functions ************************/
void CRecompilerOps::COP1_D_ADD (void) {
	DWORD Reg1 = m_Opcode.ft == m_Opcode.fd?m_Opcode.ft:m_Opcode.fs;
	DWORD Reg2 = m_Opcode.ft == m_Opcode.fd?m_Opcode.fs:m_Opcode.ft;
	char Name[50];
	
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	

	Load_FPR_ToTop(m_Opcode.fd,Reg1, CRegInfo::FPU_Double);
	if (RegInStack(Reg2, CRegInfo::FPU_Double)) {
		fpuAddReg(StackPosition(Reg2));
	} else {
		x86Reg TempReg;

		UnMap_FPR(Reg2,TRUE);
		TempReg = Map_TempReg(x86_Any,-1,FALSE);
		sprintf(Name,"_FPR_D[%d]",Reg2);
		MoveVariableToX86reg((BYTE *)&_FPR_D[Reg2],Name,TempReg);
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fd, CRegInfo::FPU_Double);
		fpuAddQwordRegPointer(TempReg);	
	}
}

void CRecompilerOps::COP1_D_SUB (void) {
	DWORD Reg1 = m_Opcode.ft == m_Opcode.fd?m_Opcode.ft:m_Opcode.fs;
	DWORD Reg2 = m_Opcode.ft == m_Opcode.fd?m_Opcode.fs:m_Opcode.ft;
	x86Reg TempReg;
	char Name[50];
	
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	

	if (m_Opcode.fd == m_Opcode.ft) {
		UnMap_FPR(m_Opcode.fd,TRUE);
		TempReg = Map_TempReg(x86_Any,-1,FALSE);
		sprintf(Name,"_FPR_D[%d]",m_Opcode.ft);
		MoveVariableToX86reg((BYTE *)&_FPR_D[m_Opcode.ft],Name,TempReg);
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Double);
		fpuSubQwordRegPointer(TempReg);
	} else {
		Load_FPR_ToTop(m_Opcode.fd,Reg1, CRegInfo::FPU_Double);
		if (RegInStack(Reg2, CRegInfo::FPU_Double)) {
			fpuSubReg(StackPosition(Reg2));
		} else {
			UnMap_FPR(Reg2,TRUE);

			TempReg = Map_TempReg(x86_Any,-1,FALSE);
			sprintf(Name,"_FPR_D[%d]",Reg2);
			MoveVariableToX86reg((BYTE *)&_FPR_D[Reg2],Name,TempReg);
			Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fd, CRegInfo::FPU_Double);
			fpuSubQwordRegPointer(TempReg);
		}
	}
}

void CRecompilerOps::COP1_D_MUL (void) {
	DWORD Reg1 = m_Opcode.ft == m_Opcode.fd?m_Opcode.ft:m_Opcode.fs;
	DWORD Reg2 = m_Opcode.ft == m_Opcode.fd?m_Opcode.fs:m_Opcode.ft;
	x86Reg TempReg;
	char Name[50];
	
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	FixRoundModel(CRegInfo::RoundDefault);

	Load_FPR_ToTop(m_Opcode.fd,Reg1, CRegInfo::FPU_Double);
	if (RegInStack(Reg2, CRegInfo::FPU_Double)) {
		fpuMulReg(StackPosition(Reg2));
	} else {
		UnMap_FPR(Reg2,TRUE);
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fd, CRegInfo::FPU_Double);
		TempReg = Map_TempReg(x86_Any,-1,FALSE);
		sprintf(Name,"_FPR_D[%d]",Reg2);
		MoveVariableToX86reg((BYTE *)&_FPR_D[Reg2],Name,TempReg);
		fpuMulQwordRegPointer(TempReg);
	}
}

void CRecompilerOps::COP1_D_DIV (void) {
	DWORD Reg1 = m_Opcode.ft == m_Opcode.fd?m_Opcode.ft:m_Opcode.fs;
	DWORD Reg2 = m_Opcode.ft == m_Opcode.fd?m_Opcode.fs:m_Opcode.ft;
	x86Reg TempReg;
	char Name[50];
	
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	

	if (m_Opcode.fd == m_Opcode.ft) {
		UnMap_FPR(m_Opcode.fd,TRUE);
		TempReg = Map_TempReg(x86_Any,-1,FALSE);
		sprintf(Name,"_FPR_D[%d]",m_Opcode.ft);
		MoveVariableToX86reg((BYTE *)&_FPR_D[m_Opcode.ft],Name,TempReg);
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Double);
		fpuDivQwordRegPointer(TempReg);
	} else {
		Load_FPR_ToTop(m_Opcode.fd,Reg1, CRegInfo::FPU_Double);
		if (RegInStack(Reg2, CRegInfo::FPU_Double)) {
			fpuDivReg(StackPosition(Reg2));
		} else {
			UnMap_FPR(Reg2,TRUE);
			TempReg = Map_TempReg(x86_Any,-1,FALSE);
			sprintf(Name,"_FPR_D[%d]",Reg2);
			MoveVariableToX86reg((BYTE *)&_FPR_D[Reg2],Name,TempReg);
			Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fd, CRegInfo::FPU_Double);
			fpuDivQwordRegPointer(TempReg);
		}
	}
}

void CRecompilerOps::COP1_D_ABS (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Double);
	fpuAbs();
}

void CRecompilerOps::COP1_D_NEG (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Double);
	fpuNeg();
}

void CRecompilerOps::COP1_D_SQRT (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Double);
	fpuSqrt();
}

void CRecompilerOps::COP1_D_MOV (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Double);
}

void CRecompilerOps::COP1_D_TRUNC_L (void) {			//added by Witten
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	if (RegInStack(m_Opcode.fs,CRegInfo::FPU_Double) || RegInStack(m_Opcode.fs,CRegInfo::FPU_Qword)) {
		UnMap_FPR(m_Opcode.fs,TRUE);
	}
	if (m_Opcode.fd != m_Opcode.fs || !RegInStack(m_Opcode.fd,CRegInfo::FPU_Double)) { 
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Double); 
	}
	ChangeFPURegFormat(m_Opcode.fd,CRegInfo::FPU_Double,CRegInfo::FPU_Qword,CRegInfo::RoundTruncate);
}

void CRecompilerOps::COP1_D_CEIL_L (void) {			//added by Witten
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	if (RegInStack(m_Opcode.fs,CRegInfo::FPU_Double) || RegInStack(m_Opcode.fs,CRegInfo::FPU_Qword)) {
		UnMap_FPR(m_Opcode.fs,TRUE);
	}
	if (m_Opcode.fd != m_Opcode.fs || !RegInStack(m_Opcode.fd,CRegInfo::FPU_Double)) { 
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Double); 
	}
	ChangeFPURegFormat(m_Opcode.fd,CRegInfo::FPU_Double,CRegInfo::FPU_Qword,CRegInfo::RoundUp);
}

void CRecompilerOps::COP1_D_FLOOR_L (void) {			//added by Witten
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	if (RegInStack(m_Opcode.fs,CRegInfo::FPU_Double) || RegInStack(m_Opcode.fs,CRegInfo::FPU_Qword)) {
		UnMap_FPR(m_Opcode.fs,TRUE);
	}
	if (m_Opcode.fd != m_Opcode.fs || !RegInStack(m_Opcode.fd,CRegInfo::FPU_Double)) { 
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Double); 
	}
	ChangeFPURegFormat(m_Opcode.fd,CRegInfo::FPU_Double,CRegInfo::FPU_Qword,CRegInfo::RoundDown);
}

void CRecompilerOps::COP1_D_ROUND_W (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	if (RegInStack(m_Opcode.fs,CRegInfo::FPU_Double) || RegInStack(m_Opcode.fs,CRegInfo::FPU_Qword)) {
		UnMap_FPR(m_Opcode.fs,TRUE);
	}
	if (m_Opcode.fd != m_Opcode.fs || !RegInStack(m_Opcode.fd,CRegInfo::FPU_Double)) { 
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Double); 
	}
	ChangeFPURegFormat(m_Opcode.fd,CRegInfo::FPU_Double,CRegInfo::FPU_Dword,CRegInfo::RoundNearest);
}

void CRecompilerOps::COP1_D_TRUNC_W (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	if (RegInStack(m_Opcode.fd,CRegInfo::FPU_Double) || RegInStack(m_Opcode.fd,CRegInfo::FPU_Qword)) {
		UnMap_FPR(m_Opcode.fd,TRUE);
	}
	if (m_Opcode.fd != m_Opcode.fs || !RegInStack(m_Opcode.fd,CRegInfo::FPU_Double)) { 
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Double); 
	}
	ChangeFPURegFormat(m_Opcode.fd,CRegInfo::FPU_Double,CRegInfo::FPU_Dword,CRegInfo::RoundTruncate);
}

void CRecompilerOps::COP1_D_CEIL_W (void) {				// added by Witten
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	if (RegInStack(m_Opcode.fs,CRegInfo::FPU_Double) || RegInStack(m_Opcode.fs,CRegInfo::FPU_Qword)) {
		UnMap_FPR(m_Opcode.fs,TRUE);
	}
	if (m_Opcode.fd != m_Opcode.fs || !RegInStack(m_Opcode.fd,CRegInfo::FPU_Double)) { 
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Double); 
	}
	ChangeFPURegFormat(m_Opcode.fd,CRegInfo::FPU_Double,CRegInfo::FPU_Dword,CRegInfo::RoundUp);
}

void CRecompilerOps::COP1_D_FLOOR_W (void) {			//added by Witten
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	if (RegInStack(m_Opcode.fs,CRegInfo::FPU_Double) || RegInStack(m_Opcode.fs,CRegInfo::FPU_Qword)) {
		UnMap_FPR(m_Opcode.fs,TRUE);
	}
	if (m_Opcode.fd != m_Opcode.fs || !RegInStack(m_Opcode.fd,CRegInfo::FPU_Double)) { 
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Double); 
	}
	ChangeFPURegFormat(m_Opcode.fd,CRegInfo::FPU_Double,CRegInfo::FPU_Dword,CRegInfo::RoundDown);
}

void CRecompilerOps::COP1_D_CVT_S (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	if (RegInStack(m_Opcode.fd,CRegInfo::FPU_Double) || RegInStack(m_Opcode.fd,CRegInfo::FPU_Qword)) {
		UnMap_FPR(m_Opcode.fd,TRUE);
	}
	if (m_Opcode.fd != m_Opcode.fs || !RegInStack(m_Opcode.fd,CRegInfo::FPU_Double)) { 
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Double); 
	}
	ChangeFPURegFormat(m_Opcode.fd,CRegInfo::FPU_Double,CRegInfo::FPU_Float,CRegInfo::RoundDefault);
}

void CRecompilerOps::COP1_D_CVT_W (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	if (RegInStack(m_Opcode.fs,CRegInfo::FPU_Double) || RegInStack(m_Opcode.fs,CRegInfo::FPU_Qword)) {
		UnMap_FPR(m_Opcode.fs,TRUE);
	}
	if (m_Opcode.fd != m_Opcode.fs || !RegInStack(m_Opcode.fd,CRegInfo::FPU_Double)) { 
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Double); 
	}
	ChangeFPURegFormat(m_Opcode.fd,CRegInfo::FPU_Double,CRegInfo::FPU_Dword,CRegInfo::RoundDefault);
}

void CRecompilerOps::COP1_D_CVT_L (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	if (RegInStack(m_Opcode.fs,CRegInfo::FPU_Double) || RegInStack(m_Opcode.fs,CRegInfo::FPU_Qword)) {
		UnMap_FPR(m_Opcode.fs,TRUE);
	}
	if (m_Opcode.fd != m_Opcode.fs || !RegInStack(m_Opcode.fd,CRegInfo::FPU_Double)) { 
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Double); 
	}
	ChangeFPURegFormat(m_Opcode.fd,CRegInfo::FPU_Double,CRegInfo::FPU_Qword,CRegInfo::RoundDefault);
}

void CRecompilerOps::COP1_D_CMP (void) {
	DWORD Reg1 = m_Opcode.fs; 
	DWORD Reg2 = m_Opcode.ft;
	DWORD cmp = 0;

	if ((m_Opcode.funct & 4) == 0) 
	{ 
		Reg1 = RegInStack(m_Opcode.ft, CRegInfo::FPU_Double)?m_Opcode.ft:m_Opcode.fs;
		Reg2 = RegInStack(m_Opcode.ft, CRegInfo::FPU_Double)?m_Opcode.fs:m_Opcode.ft;
	}
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	if ((m_Opcode.funct & 7) == 0) { CRecompilerOps::UnknownOpcode(); }
	if ((m_Opcode.funct & 2) != 0) { cmp |= 0x4000; }
	if ((m_Opcode.funct & 4) != 0) { cmp |= 0x0100; }
	
	Load_FPR_ToTop(Reg1,Reg1, CRegInfo::FPU_Double);
	Map_TempReg(x86_EAX, 0, FALSE);
	if (RegInStack(Reg2, CRegInfo::FPU_Double)) {
		fpuComReg(StackPosition(Reg2),FALSE);
	} else {
		char Name[50];

		UnMap_FPR(Reg2,TRUE);
		x86Reg TempReg = Map_TempReg(x86_Any,-1,FALSE);
		sprintf(Name,"_FPR_D[%d]",Reg2);
		MoveVariableToX86reg((BYTE *)&_FPR_D[Reg2],Name,TempReg);
		Load_FPR_ToTop(Reg1,Reg1, CRegInfo::FPU_Double);
		fpuComQwordRegPointer(TempReg,FALSE);
	}
	AndConstToVariable((DWORD)~FPCSR_C, &_FPCR[31], "_FPCR[31]");
	fpuStoreStatus();
	x86Reg Reg = Map_TempReg(x86_Any8Bit, 0, FALSE);
	TestConstToX86Reg(cmp,x86_EAX);	
	Setnz(Reg);
	if (cmp != 0) {
		TestConstToX86Reg(cmp,x86_EAX);	
		Setnz(Reg);
		
		if ((m_Opcode.funct & 1) != 0) {
			x86Reg Reg2 = Map_TempReg(x86_Any8Bit, 0, FALSE);
			AndConstToX86Reg(x86_EAX, 0x4300);
			CompConstToX86reg(x86_EAX, 0x4300);
			Setz(Reg2);
	
			OrX86RegToX86Reg(Reg, Reg2);
		}
	} else if ((m_Opcode.funct & 1) != 0) {
		AndConstToX86Reg(x86_EAX, 0x4300);
		CompConstToX86reg(x86_EAX, 0x4300);
		Setz(Reg);
	}
	ShiftLeftSignImmed(Reg, 23);
	OrX86RegToVariable(&_FPCR[31], "_FPCR[31]", Reg);
}

/************************** COP1: W functions ************************/
void CRecompilerOps::COP1_W_CVT_S (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	if (m_Opcode.fd != m_Opcode.fs || !RegInStack(m_Opcode.fd,CRegInfo::FPU_Dword)) { 
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Dword); 
	}
	ChangeFPURegFormat(m_Opcode.fd,CRegInfo::FPU_Dword,CRegInfo::FPU_Float,CRegInfo::RoundDefault);
}

void CRecompilerOps::COP1_W_CVT_D (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	if (m_Opcode.fd != m_Opcode.fs || !RegInStack(m_Opcode.fd,CRegInfo::FPU_Dword)) { 
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Dword); 
	}
	ChangeFPURegFormat(m_Opcode.fd,CRegInfo::FPU_Dword,CRegInfo::FPU_Double,CRegInfo::RoundDefault);
}

/************************** COP1: L functions ************************/
void CRecompilerOps::COP1_L_CVT_S (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	if (m_Opcode.fd != m_Opcode.fs || !RegInStack(m_Opcode.fd,CRegInfo::FPU_Qword)) { 
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Qword); 
	}
	ChangeFPURegFormat(m_Opcode.fd,CRegInfo::FPU_Qword,CRegInfo::FPU_Float,CRegInfo::RoundDefault);
}

void CRecompilerOps::COP1_L_CVT_D (void) {
	CPU_Message("  %X %s",m_CompilePC,R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));
	
	m_Section->CompileCop1Test();	
	if (m_Opcode.fd != m_Opcode.fs || !RegInStack(m_Opcode.fd,CRegInfo::FPU_Qword)) { 
		Load_FPR_ToTop(m_Opcode.fd,m_Opcode.fs,CRegInfo::FPU_Qword); 
	}
	ChangeFPURegFormat(m_Opcode.fd,CRegInfo::FPU_Qword,CRegInfo::FPU_Double,CRegInfo::RoundDefault);
}

/************************** Other functions **************************/
void CRecompilerOps::UnknownOpcode (void) {
	CPU_Message("  %X Unhandled Opcode: %s",m_CompilePC, R4300iOpcodeName(m_Opcode.Hex,m_CompilePC));

	m_RegWorkingSet.WriteBackRegisters();
	UpdateCounters(m_RegWorkingSet,false,true);
	MoveConstToVariable(m_CompilePC,&g_Reg->m_PROGRAM_COUNTER,"PROGRAM_COUNTER");
	if (g_SyncSystem) { 
		MoveConstToX86reg((DWORD)g_BaseSystem,x86_ECX);
		Call_Direct(AddressOf(&CN64System::SyncSystem), "CN64System::SyncSystem"); 
	}
	m_RegWorkingSet.SetBlockCycleCount(m_RegWorkingSet.GetBlockCycleCount() - g_System->CountPerOp());

	MoveConstToVariable(m_Opcode.Hex, &R4300iOp::m_Opcode.Hex, "R4300iOp::m_Opcode.Hex");
	Call_Direct(R4300iOp::UnknownOpcode, "R4300iOp::UnknownOpcode");
	Ret();
	if (m_NextInstruction == NORMAL) { m_NextInstruction = END_BLOCK; }
}

void CRecompilerOps::BeforeCallDirect ( CRegInfo  & RegSet )
{
	RegSet.UnMap_AllFPRs();
	Pushad();
}

void CRecompilerOps::AfterCallDirect ( CRegInfo  & RegSet )
{
	Popad();
	RegSet.SetRoundingModel(CRegInfo::RoundUnknown);
}

void CRecompilerOps::EnterCodeBlock ( void )
{
#ifdef _DEBUG
	Push(x86_ESI);
#else
	Push(x86_EDI);
	Push(x86_ESI);
	Push(x86_EBX);
#endif
}

void CRecompilerOps::ExitCodeBlock ( void )
{
#ifdef _DEBUG
	Pop(x86_ESI);
#else
	Pop(x86_EBX);
	Pop(x86_ESI);
	Pop(x86_EDI);
#endif
	Ret();
}

void CRecompilerOps::UpdateSyncCPU ( CRegInfo & RegSet, DWORD Cycles )
{
	if (!g_SyncSystem) 
	{
		return;
	}

	WriteX86Comment("Updating Sync CPU");
	BeforeCallDirect(RegSet);
	PushImm32(stdstr_f("%d",Cycles).c_str(),Cycles);
	PushImm32("g_SyncSystem",(DWORD)g_SyncSystem);
	MoveConstToX86reg((DWORD)g_System,x86_ECX);		
	Call_Direct(AddressOf(&CN64System::UpdateSyncCPU),"CN64System::UpdateSyncCPU");
	AfterCallDirect(RegSet);
}

void CRecompilerOps::UpdateCounters ( CRegInfo & RegSet, bool CheckTimer, bool ClearValues )
{
	if (RegSet.GetBlockCycleCount() != 0)
	{
		UpdateSyncCPU(RegSet,RegSet.GetBlockCycleCount());
		WriteX86Comment("Update Counter");
		SubConstFromVariable(RegSet.GetBlockCycleCount(),g_NextTimer,"g_NextTimer"); // updates compare flag
		if (ClearValues)
		{
			RegSet.SetBlockCycleCount(0);
		}
	} else if (CheckTimer)	{
		CompConstToVariable(0,g_NextTimer,"g_NextTimer");
	}

	if (CheckTimer)
	{
		JnsLabel8("Continue_From_Timer_Test",0);
		BYTE * Jump = m_RecompPos - 1;
		Pushad();
		MoveConstToX86reg((DWORD)g_SystemTimer,x86_ECX);		
		Call_Direct(AddressOf(&CSystemTimer::TimerDone),"CSystemTimer::TimerDone");
		Popad();
	
		CPU_Message("");
		CPU_Message("      $Continue_From_Timer_Test:");
		SetJump8(Jump,m_RecompPos);		
	}
}

void CRecompilerOps::CompileSystemCheck (DWORD TargetPC, const CRegInfo & RegSet)
{
	CompConstToVariable(0,(void *)&g_SystemEvents->DoSomething(),"g_SystemEvents->DoSomething()");
	JeLabel32("Continue_From_Interrupt_Test",0);
	DWORD * Jump = (DWORD *)(m_RecompPos - 4);
	if (TargetPC != (DWORD)-1) 
	{
		MoveConstToVariable(TargetPC,&g_Reg->m_PROGRAM_COUNTER,"PROGRAM_COUNTER"); 
	}

	CRegInfo RegSetCopy(RegSet);
	RegSetCopy.WriteBackRegisters();

	MoveConstToX86reg((DWORD)g_SystemEvents,x86_ECX);		
	Call_Direct(AddressOf(&CSystemEvents::ExecuteEvents),"CSystemEvents::ExecuteEvents");
	if (g_SyncSystem) { 
		MoveConstToX86reg((DWORD)g_BaseSystem,x86_ECX);
		Call_Direct(AddressOf(&CN64System::SyncSystem), "CN64System::SyncSystem");
	}
	ExitCodeBlock();
	CPU_Message("");
	CPU_Message("      $Continue_From_Interrupt_Test:");
	SetJump32(Jump,(DWORD *)m_RecompPos);	
}

void CRecompilerOps::OverflowDelaySlot (BOOL TestTimer)
{
	m_RegWorkingSet.WriteBackRegisters();
	UpdateCounters(m_RegWorkingSet,false,true);
	MoveConstToVariable(CompilePC() + 4,_PROGRAM_COUNTER,"PROGRAM_COUNTER");
	if (g_SyncSystem) { 
		MoveConstToX86reg((DWORD)g_BaseSystem,x86_ECX);
		Call_Direct(AddressOf(&CN64System::SyncSystem), "CN64System::SyncSystem"); 
	}
	MoveConstToVariable(JUMP,&R4300iOp::m_NextInstruction,"R4300iOp::m_NextInstruction");
	if (TestTimer)
	{
		MoveConstToVariable(TestTimer,&R4300iOp::m_TestTimer,"R4300iOp::m_TestTimer");
	}
	PushImm32("g_System->CountPerOp()",g_System->CountPerOp());
	Call_Direct(CInterpreterCPU::ExecuteOps, "CInterpreterCPU::ExecuteOps");
	AddConstToX86Reg(x86_ESP,4);
	if (g_System->bFastSP() && g_Recompiler)
	{
		MoveConstToX86reg((DWORD)g_Recompiler,x86_ECX);		
		Call_Direct(AddressOf(&CRecompiler::ResetMemoryStackPos), "CRecompiler::ResetMemoryStackPos");
	}

	if (g_SyncSystem) 
	{ 
		UpdateSyncCPU(m_RegWorkingSet,g_System->CountPerOp());
		MoveConstToX86reg((DWORD)g_BaseSystem,x86_ECX);
		Call_Direct(AddressOf(&CN64System::SyncSystem), "CN64System::SyncSystem"); 
	}
	ExitCodeBlock();
	m_NextInstruction = END_BLOCK;
}
