diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index 1fc342d02..88eb49e34 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -3697,6 +3697,7 @@ unsigned InterpreterMainLoop(ARMul_State* state) {
     #undef RS
 
     #define CRn             inst_cream->crn
+    #define OPCODE_1        inst_cream->opcode_1
     #define OPCODE_2        inst_cream->opcode_2
     #define CRm             inst_cream->crm
     #define CP15_REG(n)     cpu->CP15[CP15(n)]
@@ -4922,50 +4923,8 @@ unsigned InterpreterMainLoop(ARMul_State* state) {
                 CITRA_IGNORE_EXIT(-1);
                 goto END;
             } else {
-                if (inst_cream->cp_num == 15) {
-                    if(CRn == 0 && OPCODE_2 == 0 && CRm == 0) {
-                        RD = cpu->CP15[CP15(CP15_MAIN_ID)];
-                    } else if (CRn == 0 && CRm == 0 && OPCODE_2 == 1) {
-                        RD = cpu->CP15[CP15(CP15_CACHE_TYPE)];
-                    } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 0) {
-                        RD = cpu->CP15[CP15(CP15_CONTROL)];
-                    } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 1) {
-                        RD = cpu->CP15[CP15(CP15_AUXILIARY_CONTROL)];
-                    } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 2) {
-                        RD = cpu->CP15[CP15(CP15_COPROCESSOR_ACCESS_CONTROL)];
-                    } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 0) {
-                        RD = cpu->CP15[CP15(CP15_TRANSLATION_BASE_TABLE_0)];
-                    } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 1) {
-                        RD = cpu->CP15[CP15(CP15_TRANSLATION_BASE_TABLE_1)];
-                    } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 2) {
-                        RD = cpu->CP15[CP15(CP15_TRANSLATION_BASE_CONTROL)];
-                    } else if (CRn == 3 && CRm == 0 && OPCODE_2 == 0) {
-                        RD = cpu->CP15[CP15(CP15_DOMAIN_ACCESS_CONTROL)];
-                    } else if (CRn == 5 && CRm == 0 && OPCODE_2 == 0) {
-                        RD = cpu->CP15[CP15(CP15_FAULT_STATUS)];
-                    } else if (CRn == 5 && CRm == 0 && OPCODE_2 == 1) {
-                        RD = cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)];
-                    } else if (CRn == 6 && CRm == 0 && OPCODE_2 == 0) {
-                        RD = cpu->CP15[CP15(CP15_FAULT_ADDRESS)];
-                    } else if (CRn == 13) {
-                        if(OPCODE_2 == 0) {
-                            RD = CP15_REG(CP15_PID);
-                        } else if(OPCODE_2 == 1) {
-                            RD = CP15_REG(CP15_CONTEXT_ID);
-                        } else if (OPCODE_2 == 2) {
-                            RD = CP15_REG(CP15_THREAD_UPRW);
-                        } else if(OPCODE_2 == 3) {
-                            RD = Memory::KERNEL_MEMORY_VADDR;
-                        } else if (OPCODE_2 == 4) {
-                            if (InAPrivilegedMode(cpu))
-                                RD = CP15_REG(CP15_THREAD_PRW);
-                        } else {
-                            LOG_ERROR(Core_ARM11, "mmu_mrr wrote UNKNOWN - reg %d", CRn);
-                        }
-                    } else {
-                        LOG_ERROR(Core_ARM11, "mrc CRn=%d, CRm=%d, OP2=%d is not implemented", CRn, CRm, OPCODE_2);
-                    }
-                }
+                if (inst_cream->cp_num == 15)
+                     RD = ReadCP15Register(cpu, CRn, OPCODE_1, CRm, OPCODE_2);
             }
         }
         cpu->Reg[15] += GET_INST_SIZE(cpu);
diff --git a/src/core/arm/interpreter/armsupp.cpp b/src/core/arm/interpreter/armsupp.cpp
index f826ccb2d..ad713b561 100644
--- a/src/core/arm/interpreter/armsupp.cpp
+++ b/src/core/arm/interpreter/armsupp.cpp
@@ -15,7 +15,9 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
 
+#include "core/mem_map.h"
 #include "core/arm/skyeye_common/armdefs.h"
+#include "core/arm/skyeye_common/arm_regformat.h"
 
 // Unsigned sum of absolute difference
 u8 ARMul_UnsignedAbsoluteDifference(u8 left, u8 right)
@@ -213,3 +215,197 @@ bool InAPrivilegedMode(ARMul_State* cpu)
 {
     return (cpu->Mode != USER32MODE);
 }
+
+// Reads from the CP15 registers. Used with implementation of the MRC instruction.
+// Note that since the 3DS does not have the hypervisor extensions, these registers
+// are not implemented.
+u32 ReadCP15Register(ARMul_State* cpu, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2)
+{
+    // Unprivileged registers
+    if (crn == 13 && opcode_1 == 0 && crm == 0)
+    {
+        if (opcode_2 == 2)
+            return cpu->CP15[CP15(CP15_THREAD_UPRW)];
+
+        // TODO: Whenever TLS is implemented, this should return
+        // "cpu->CP15[CP15(CP15_THREAD_URO)];"
+        // which contains the address of the 0x200-byte TLS
+        if (opcode_2 == 3)
+            return Memory::KERNEL_MEMORY_VADDR;
+    }
+
+    if (InAPrivilegedMode(cpu))
+    {
+        if (crn == 0 && opcode_1 == 0)
+        {
+            if (crm == 0)
+            {
+                if (opcode_2 == 0)
+                    return cpu->CP15[CP15(CP15_MAIN_ID)];
+
+                if (opcode_2 == 1)
+                    return cpu->CP15[CP15(CP15_CACHE_TYPE)];
+
+                if (opcode_2 == 3)
+                    return cpu->CP15[CP15(CP15_TLB_TYPE)];
+
+                if (opcode_2 == 5)
+                    return cpu->CP15[CP15(CP15_CPU_ID)];
+            }
+            else if (crm == 1)
+            {
+                if (opcode_2 == 0)
+                    return cpu->CP15[CP15(CP15_PROCESSOR_FEATURE_0)];
+
+                if (opcode_2 == 1)
+                    return cpu->CP15[CP15(CP15_PROCESSOR_FEATURE_1)];
+
+                if (opcode_2 == 2)
+                    return cpu->CP15[CP15(CP15_DEBUG_FEATURE_0)];
+
+                if (opcode_2 == 4)
+                    return cpu->CP15[CP15(CP15_MEMORY_MODEL_FEATURE_0)];
+
+                if (opcode_2 == 5)
+                    return cpu->CP15[CP15(CP15_MEMORY_MODEL_FEATURE_1)];
+
+                if (opcode_2 == 6)
+                    return cpu->CP15[CP15(CP15_MEMORY_MODEL_FEATURE_2)];
+
+                if (opcode_2 == 7)
+                    return cpu->CP15[CP15(CP15_MEMORY_MODEL_FEATURE_3)];
+            }
+            else if (crm == 2)
+            {
+                if (opcode_2 == 0)
+                    return cpu->CP15[CP15(CP15_ISA_FEATURE_0)];
+
+                if (opcode_2 == 1)
+                    return cpu->CP15[CP15(CP15_ISA_FEATURE_1)];
+
+                if (opcode_2 == 2)
+                    return cpu->CP15[CP15(CP15_ISA_FEATURE_2)];
+
+                if (opcode_2 == 3)
+                    return cpu->CP15[CP15(CP15_ISA_FEATURE_3)];
+
+                if (opcode_2 == 4)
+                    return cpu->CP15[CP15(CP15_ISA_FEATURE_4)];
+            }
+        }
+
+        if (crn == 1 && opcode_1 == 0 && crm == 0)
+        {
+            if (opcode_2 == 0)
+                return cpu->CP15[CP15(CP15_CONTROL)];
+
+            if (opcode_2 == 1)
+                return cpu->CP15[CP15(CP15_AUXILIARY_CONTROL)];
+
+            if (opcode_2 == 2)
+                return cpu->CP15[CP15(CP15_COPROCESSOR_ACCESS_CONTROL)];
+        }
+
+        if (crn == 2 && opcode_1 == 0 && crm == 0)
+        {
+            if (opcode_2 == 0)
+                return cpu->CP15[CP15(CP15_TRANSLATION_BASE_TABLE_0)];
+
+            if (opcode_2 == 1)
+                return cpu->CP15[CP15(CP15_TRANSLATION_BASE_TABLE_1)];
+
+            if (opcode_2 == 2)
+                return cpu->CP15[CP15(CP15_TRANSLATION_BASE_CONTROL)];
+        }
+
+        if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
+            return cpu->CP15[CP15(CP15_DOMAIN_ACCESS_CONTROL)];
+
+        if (crn == 5 && opcode_1 == 0 && crm == 0)
+        {
+            if (opcode_2 == 0)
+                return cpu->CP15[CP15(CP15_FAULT_STATUS)];
+
+            if (opcode_2 == 1)
+                return cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)];
+        }
+
+        if (crn == 6 && opcode_1 == 0 && crm == 0)
+        {
+            if (opcode_2 == 0)
+                return cpu->CP15[CP15(CP15_FAULT_ADDRESS)];
+
+            if (opcode_2 == 1)
+                return cpu->CP15[CP15(CP15_WFAR)];
+        }
+
+        if (crn == 7 && opcode_1 == 0 && crm == 4 && opcode_2 == 0)
+            return cpu->CP15[CP15(CP15_PHYS_ADDRESS)];
+
+        if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
+            return cpu->CP15[CP15(CP15_DATA_CACHE_LOCKDOWN)];
+
+        if (crn == 10 && opcode_1 == 0)
+        {
+            if (crm == 0 && opcode_2 == 0)
+                return cpu->CP15[CP15(CP15_TLB_LOCKDOWN)];
+
+            if (crm == 2)
+            {
+                if (opcode_2 == 0)
+                    return cpu->CP15[CP15(CP15_PRIMARY_REGION_REMAP)];
+
+                if (opcode_2 == 1)
+                    return cpu->CP15[CP15(CP15_NORMAL_REGION_REMAP)];
+            }
+        }
+
+        if (crn == 13 && crm == 0)
+        {
+            if (opcode_2 == 0)
+                return cpu->CP15[CP15(CP15_PID)];
+
+            if (opcode_2 == 1)
+                return cpu->CP15[CP15(CP15_CONTEXT_ID)];
+
+            if (opcode_2 == 4)
+                return cpu->CP15[CP15(CP15_THREAD_PRW)];
+        }
+
+        if (crn == 15)
+        {
+            if (opcode_1 == 0 && crm == 12)
+            {
+                if (opcode_2 == 0)
+                    return cpu->CP15[CP15(CP15_PERFORMANCE_MONITOR_CONTROL)];
+
+                if (opcode_2 == 1)
+                    return cpu->CP15[CP15(CP15_CYCLE_COUNTER)];
+
+                if (opcode_2 == 2)
+                    return cpu->CP15[CP15(CP15_COUNT_0)];
+
+                if (opcode_2 == 3)
+                    return cpu->CP15[CP15(CP15_COUNT_1)];
+            }
+
+            if (opcode_1 == 5 && opcode_2 == 2)
+            {
+                if (crm == 5)
+                    return cpu->CP15[CP15(CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS)];
+
+                if (crm == 6)
+                    return cpu->CP15[CP15(CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS)];
+
+                if (crm == 7)
+                    return cpu->CP15[CP15(CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE)];
+            }
+
+            if (opcode_1 == 7 && crm == 1 && opcode_2 == 0)
+                return cpu->CP15[CP15(CP15_TLB_DEBUG_CONTROL)];
+        }
+    }
+
+    LOG_ERROR(Core_ARM11, "MRC CRn=%u, CRm=%u, OP1=%u OP2=%u is not implemented. Returning zero.", crn, crm, opcode_1, opcode_2);
+    return 0;
+}
diff --git a/src/core/arm/skyeye_common/arm_regformat.h b/src/core/arm/skyeye_common/arm_regformat.h
index 5be3a561f..fb5b70f1e 100644
--- a/src/core/arm/skyeye_common/arm_regformat.h
+++ b/src/core/arm/skyeye_common/arm_regformat.h
@@ -50,6 +50,8 @@ enum {
     EXCLUSIVE_TAG,
     EXCLUSIVE_STATE,
     EXCLUSIVE_RESULT,
+
+    // c0 - Information registers
     CP15_BASE,
     CP15_C0 = CP15_BASE,
     CP15_C0_C0 = CP15_C0,
@@ -57,15 +59,30 @@ enum {
     CP15_CACHE_TYPE,
     CP15_TCM_STATUS,
     CP15_TLB_TYPE,
+    CP15_CPU_ID,
     CP15_C0_C1,
     CP15_PROCESSOR_FEATURE_0 = CP15_C0_C1,
     CP15_PROCESSOR_FEATURE_1,
     CP15_DEBUG_FEATURE_0,
     CP15_AUXILIARY_FEATURE_0,
+    CP15_MEMORY_MODEL_FEATURE_0,
+    CP15_MEMORY_MODEL_FEATURE_1,
+    CP15_MEMORY_MODEL_FEATURE_2,
+    CP15_MEMORY_MODEL_FEATURE_3,
+    CP15_C0_C2,
+    CP15_ISA_FEATURE_0 = CP15_C0_C2,
+    CP15_ISA_FEATURE_1,
+    CP15_ISA_FEATURE_2,
+    CP15_ISA_FEATURE_3,
+    CP15_ISA_FEATURE_4,
+
+    // c1 - Control registers
     CP15_C1_C0,
     CP15_CONTROL = CP15_C1_C0,
     CP15_AUXILIARY_CONTROL,
     CP15_COPROCESSOR_ACCESS_CONTROL,
+
+    // c2 - Translation table registers
     CP15_C2,
     CP15_C2_C0 = CP15_C2,
     CP15_TRANSLATION_BASE = CP15_C2_C0,
@@ -74,24 +91,54 @@ enum {
     CP15_TRANSLATION_BASE_CONTROL,
     CP15_DOMAIN_ACCESS_CONTROL,
     CP15_RESERVED,
-    /* Fault status */
+
+    // c5 - Fault status registers
     CP15_FAULT_STATUS,
     CP15_INSTR_FAULT_STATUS,
     CP15_COMBINED_DATA_FSR = CP15_FAULT_STATUS,
     CP15_INST_FSR,
-    /* Fault Address register */
+
+    // c6 - Fault Address registers
     CP15_FAULT_ADDRESS,
     CP15_COMBINED_DATA_FAR = CP15_FAULT_ADDRESS,
     CP15_WFAR,
     CP15_IFAR,
+
+    // c7 - Cache operation registers
+    CP15_PHYS_ADDRESS,
+
+    // c9 - Data cache lockdown register
+    CP15_DATA_CACHE_LOCKDOWN,
+
+    // c10 - TLB/Memory map registers
+    CP15_TLB_LOCKDOWN,
+    CP15_PRIMARY_REGION_REMAP,
+    CP15_NORMAL_REGION_REMAP,
+
+    // c13 - Thread related registers
     CP15_PID,
     CP15_CONTEXT_ID,
     CP15_THREAD_UPRW, // Thread ID register - User/Privileged Read/Write
     CP15_THREAD_URO,  // Thread ID register - User Read Only (Privileged R/W)
     CP15_THREAD_PRW,  // Thread ID register - Privileged R/W only.
-    CP15_TLB_FAULT_ADDR, /* defined by SkyEye */
-    CP15_TLB_FAULT_STATUS, /* defined by SkyEye */
-    /* VFP registers */
+
+    // c15 - Performance and TLB lockdown registers
+    CP15_PERFORMANCE_MONITOR_CONTROL,
+    CP15_CYCLE_COUNTER,
+    CP15_COUNT_0,
+    CP15_COUNT_1,
+    CP15_READ_MAIN_TLB_LOCKDOWN_ENTRY,
+    CP15_WRITE_MAIN_TLB_LOCKDOWN_ENTRY,
+    CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS,
+    CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS,
+    CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE,
+    CP15_TLB_DEBUG_CONTROL,
+
+    // Skyeye defined
+    CP15_TLB_FAULT_ADDR,
+    CP15_TLB_FAULT_STATUS,
+
+    // VFP registers
     VFP_BASE,
     VFP_FPSID = VFP_BASE,
     VFP_FPSCR,
diff --git a/src/core/arm/skyeye_common/armdefs.h b/src/core/arm/skyeye_common/armdefs.h
index 633649d3e..14f2a39d1 100644
--- a/src/core/arm/skyeye_common/armdefs.h
+++ b/src/core/arm/skyeye_common/armdefs.h
@@ -358,3 +358,5 @@ extern u32 ARMul_UnsignedSatQ(s32, u8, bool*);
 
 extern bool InBigEndianMode(ARMul_State*);
 extern bool InAPrivilegedMode(ARMul_State*);
+
+extern u32 ReadCP15Register(ARMul_State* cpu, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2);