diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.h b/Source/Core/Core/PowerPC/JitArm64/Jit.h
index 3d31c202de..2a851e3339 100644
--- a/Source/Core/Core/PowerPC/JitArm64/Jit.h
+++ b/Source/Core/Core/PowerPC/JitArm64/Jit.h
@@ -112,6 +112,7 @@ public:
 	void mfspr(UGeckoInstruction inst);
 	void mftb(UGeckoInstruction inst);
 	void mtspr(UGeckoInstruction inst);
+	void crXXX(UGeckoInstruction inst);
 
 	// LoadStore
 	void lXX(UGeckoInstruction inst);
diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp
index 058a9f1d9d..0c79ac16a9 100644
--- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp
+++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp
@@ -373,3 +373,209 @@ void JitArm64::mtspr(UGeckoInstruction inst)
 	ARM64Reg RD = gpr.R(inst.RD);
 	STR(INDEX_UNSIGNED, RD, X29,  PPCSTATE_OFF(spr) + iIndex * 4);
 }
+
+void JitArm64::crXXX(UGeckoInstruction inst)
+{
+	INSTRUCTION_START
+	JITDISABLE(bJITSystemRegistersOff);
+
+	// Special case: crclr
+	if (inst.CRBA == inst.CRBB && inst.CRBA == inst.CRBD && inst.SUBOP10 == 193)
+	{
+		// Clear CR field bit
+		int field = inst.CRBD >> 2;
+		int bit = 3 - (inst.CRBD & 3);
+
+		ARM64Reg WA = gpr.GetReg();
+		ARM64Reg XA = EncodeRegTo64(WA);
+		LDR(INDEX_UNSIGNED, XA, X29, PPCSTATE_OFF(cr_val) + 8 * field);
+		switch (bit)
+		{
+		case CR_SO_BIT:
+			AND(XA, XA, 64 - 62, 62, true); // XA & ~(1<<61)
+			break;
+
+		case CR_EQ_BIT:
+			ORR(XA, XA, 0, 0, true); // XA | 1<<0
+			break;
+
+		case CR_GT_BIT:
+			ORR(XA, XA, 64 - 63, 0, true); // XA | 1<<63
+			break;
+
+		case CR_LT_BIT:
+			AND(XA, XA, 64 - 63, 62, true); // XA & ~(1<<62)
+			break;
+		}
+		STR(INDEX_UNSIGNED, XA, X29, PPCSTATE_OFF(cr_val) + 8 * field);
+		gpr.Unlock(WA);
+		return;
+	}
+
+	// Special case: crset
+	if (inst.CRBA == inst.CRBB && inst.CRBA == inst.CRBD && inst.SUBOP10 == 289)
+	{
+		// SetCRFieldBit
+		int field = inst.CRBD >> 2;
+		int bit = 3 - (inst.CRBD & 3);
+
+		ARM64Reg WA = gpr.GetReg();
+		ARM64Reg XA = EncodeRegTo64(WA);
+		LDR(INDEX_UNSIGNED, XA, X29, PPCSTATE_OFF(cr_val) + 8 * field);
+
+		if (bit != CR_GT_BIT)
+		{
+			ARM64Reg WB = gpr.GetReg();
+			ARM64Reg XB = EncodeRegTo64(WB);
+			ORR(XB, XA, 64 - 63, 0, true); // XA | 1<<63
+			CMP(XA, ZR);
+			CSEL(XA, XA, XB, CC_NEQ);
+			gpr.Unlock(WB);
+		}
+
+		switch (bit)
+		{
+		case CR_SO_BIT:
+			ORR(XA, XA, 64 - 61, 0, true); // XA | 1<<61
+			break;
+
+		case CR_EQ_BIT:
+			AND(XA, XA, 32, 31, true); // Clear lower 32bits
+			break;
+
+		case CR_GT_BIT:
+			AND(XA, XA, 0, 62, true); // XA & ~(1<<63)
+			break;
+
+		case CR_LT_BIT:
+			ORR(XA, XA, 64 - 62, 0, true); // XA | 1<<62
+			break;
+		}
+
+		ORR(XA, XA, 32, 0, true); // XA | 1<<32
+
+		STR(INDEX_UNSIGNED, XA, X29, PPCSTATE_OFF(cr_val) + 8 * field);
+		gpr.Unlock(WA);
+		return;
+	}
+
+	ARM64Reg WA = gpr.GetReg();
+	ARM64Reg XA = EncodeRegTo64(WA);
+	ARM64Reg WB = gpr.GetReg();
+	ARM64Reg XB = EncodeRegTo64(WB);
+
+	// creqv or crnand or crnor
+	bool negateA = inst.SUBOP10 == 289 || inst.SUBOP10 == 225 || inst.SUBOP10 == 33;
+	// crandc or crorc or crnand or crnor
+	bool negateB = inst.SUBOP10 == 129 || inst.SUBOP10 == 417 || inst.SUBOP10 == 225 || inst.SUBOP10 == 33;
+
+	// GetCRFieldBit
+	for (int i = 0; i < 2; i++)
+	{
+		int field = i ? inst.CRBB >> 2 : inst.CRBA >> 2;
+		int bit = i ? 3 - (inst.CRBB & 3) : 3 - (inst.CRBA & 3);
+		ARM64Reg out = i ? XB : XA;
+		bool negate = i ? negateB : negateA;
+
+		ARM64Reg WC = gpr.GetReg();
+		ARM64Reg XC = EncodeRegTo64(WC);
+		LDR(INDEX_UNSIGNED, XC, X29, PPCSTATE_OFF(cr_val) + 8 * field);
+		switch (bit)
+		{
+		case CR_SO_BIT:  // check bit 61 set
+			UBFX(out, XC, 61, 1);
+			if (negate)
+				EOR(out, out, 0, 0, true); // XC ^ 1
+			break;
+
+		case CR_EQ_BIT:  // check bits 31-0 == 0
+			CMP(WC, WZR);
+			CSET(out, negate ? CC_NEQ : CC_EQ);
+			break;
+
+		case CR_GT_BIT:  // check val > 0
+			CMP(XC, ZR);
+			CSET(out, negate ? CC_LE : CC_GT);
+			break;
+
+		case CR_LT_BIT:  // check bit 62 set
+			UBFX(out, XC, 62, 1);
+			if (negate)
+				EOR(out, out, 0, 0, true); // XC ^ 1
+			break;
+
+		default:
+			_assert_msg_(DYNA_REC, false, "Invalid CR bit");
+		}
+		gpr.Unlock(WC);
+	}
+
+
+	// Compute combined bit
+	switch (inst.SUBOP10)
+	{
+	case 33:  // crnor: ~(A || B) == (~A && ~B)
+	case 129: // crandc: A && ~B
+	case 257: // crand:  A && B
+		AND(XA, XA, XB);
+		break;
+
+	case 193: // crxor: A ^ B
+	case 289: // creqv: ~(A ^ B) = ~A ^ B
+		EOR(XA, XA, XB);
+		break;
+
+	case 225: // crnand: ~(A && B) == (~A || ~B)
+	case 417: // crorc: A || ~B
+	case 449: // cror:  A || B
+		ORR(XA, XA, XB);
+		break;
+	}
+
+	// Store result bit in CRBD
+	int field = inst.CRBD >> 2;
+	int bit = 3 - (inst.CRBD & 3);
+
+	LDR(INDEX_UNSIGNED, XB, X29, PPCSTATE_OFF(cr_val) + 8 * field);
+
+	// Gross but necessary; if the input is totally zero and we set SO or LT,
+	// or even just add the (1<<32), GT will suddenly end up set without us
+	// intending to. This can break actual games, so fix it up.
+	if (bit != CR_GT_BIT)
+	{
+		ARM64Reg WC = gpr.GetReg();
+		ARM64Reg XC = EncodeRegTo64(WC);
+		ORR(XC, XB, 64 - 63, 0, true); // XB | 1<<63
+		CMP(XB, ZR);
+		CSEL(XB, XB, XC, CC_NEQ);
+		gpr.Unlock(WC);
+	}
+
+	switch (bit)
+	{
+	case CR_SO_BIT:  // set bit 61 to input
+		BFI(XB, XA, 61, 1);
+		break;
+
+	case CR_EQ_BIT:  // clear low 32 bits, set bit 0 to !input
+		AND(XB, XB, 32, 31, true); // Clear lower 32bits
+		EOR(XA, XA, 0, 0); // XA ^ 1<<0
+		ORR(XB, XB, XA);
+		break;
+
+	case CR_GT_BIT:  // set bit 63 to !input
+		EOR(XA, XA, 0, 0); // XA ^ 1<<0
+		BFI(XB, XA, 63, 1);
+		break;
+
+	case CR_LT_BIT:  // set bit 62 to input
+		BFI(XB, XA, 62, 1);
+		break;
+	}
+
+	ORR(XA, XA, 32, 0, true); // XA | 1<<32
+	STR(INDEX_UNSIGNED, XB, X29, PPCSTATE_OFF(cr_val) + 8 * field);
+
+	gpr.Unlock(WA);
+	gpr.Unlock(WB);
+}
diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp
index 34fd5b2ed9..a2c71acf91 100644
--- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp
+++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp
@@ -152,14 +152,14 @@ static GekkoOPTemplate table19[] =
 {
 	{528, &JitArm64::bcctrx},                   // bcctrx
 	{16,  &JitArm64::bclrx},                    // bclrx
-	{257, &JitArm64::FallBackToInterpreter},    // crand
-	{129, &JitArm64::FallBackToInterpreter},    // crandc
-	{289, &JitArm64::FallBackToInterpreter},    // creqv
-	{225, &JitArm64::FallBackToInterpreter},    // crnand
-	{33,  &JitArm64::FallBackToInterpreter},    // crnor
-	{449, &JitArm64::FallBackToInterpreter},    // cror
-	{417, &JitArm64::FallBackToInterpreter},    // crorc
-	{193, &JitArm64::FallBackToInterpreter},    // crxor
+	{257, &JitArm64::crXXX},                    // crand
+	{129, &JitArm64::crXXX},                    // crandc
+	{289, &JitArm64::crXXX},                    // creqv
+	{225, &JitArm64::crXXX},                    // crnand
+	{33,  &JitArm64::crXXX},                    // crnor
+	{449, &JitArm64::crXXX},                    // cror
+	{417, &JitArm64::crXXX},                    // crorc
+	{193, &JitArm64::crXXX},                    // crxor
 
 	{150, &JitArm64::DoNothing},                // isync
 	{0,   &JitArm64::mcrf},                     // mcrf