From f872807de2d2fec7cd7c76936fa06cca1cf1c1ad Mon Sep 17 00:00:00 2001
From: bunnei <ericbunnie@gmail.com>
Date: Fri, 16 May 2014 00:52:42 -0400
Subject: [PATCH] added maverick.cpp to ARM core from skyeye

---
 src/core/CMakeLists.txt                   |    3 +-
 src/core/arm/interpreter/mmu/maverick.cpp | 1206 +++++++++++++++++++++
 src/core/core.vcxproj                     |    1 +
 src/core/core.vcxproj.filters             |    3 +
 4 files changed, 1212 insertions(+), 1 deletion(-)
 create mode 100644 src/core/arm/interpreter/mmu/maverick.cpp

diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 25f92963c..2bd60f745 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -21,8 +21,9 @@ set(SRCS    core.cpp
             arm/interpreter/vfp/vfpsingle.cpp
             arm/interpreter/mmu/arm1176jzf_s_mmu.cpp
             arm/interpreter/mmu/cache.cpp
-            arm/interpreter/mmu/sa_mmu.cpp
+            arm/interpreter/mmu/maverick.cpp
             arm/interpreter/mmu/rb.cpp
+            arm/interpreter/mmu/sa_mmu.cpp
             arm/interpreter/mmu/tlb.cpp
             arm/interpreter/mmu/wb.cpp
             arm/interpreter/mmu/xscale_copro.cpp
diff --git a/src/core/arm/interpreter/mmu/maverick.cpp b/src/core/arm/interpreter/mmu/maverick.cpp
new file mode 100644
index 000000000..0e98ef22b
--- /dev/null
+++ b/src/core/arm/interpreter/mmu/maverick.cpp
@@ -0,0 +1,1206 @@
+/*  maverick.c -- Cirrus/DSP co-processor interface.
+    Copyright (C) 2003 Free Software Foundation, Inc.
+    Contributed by Aldy Hernandez (aldyh@redhat.com).
+ 
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+ 
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+ 
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+
+#include "core/arm/interpreter/armdefs.h"
+#include "core/arm/interpreter/armemu.h"
+
+
+/*#define CIRRUS_DEBUG 1	*/
+#if CIRRUS_DEBUG
+#  define printfdbg printf
+#else
+#  define printfdbg printf_nothing
+#endif
+
+#define POS64(i) ( (~(i)) >> 63 )
+#define NEG64(i) ( (i) >> 63 )
+
+/* Define Co-Processor instruction handlers here.  */
+
+/* Here's ARMulator's DSP definition.  A few things to note:
+   1) it has 16 64-bit registers and 4 72-bit accumulators
+   2) you can only access its registers with MCR and MRC.  */
+
+/* We can't define these in here because this file might not be linked
+   unless the target is arm9e-*.  They are defined in wrapper.c.
+   Eventually the simulator should be made to handle any coprocessor
+   at run time.  */
+struct maverick_regs
+{
+	union
+	{
+		int i;
+		float f;
+	} upper;
+
+	union
+	{
+		int i;
+		float f;
+	} lower;
+};
+
+union maverick_acc_regs
+{
+	long double ld;		/* Acc registers are 72-bits.  */
+};
+
+struct maverick_regs DSPregs[16];
+union maverick_acc_regs DSPacc[4];
+ARMword DSPsc;
+
+#define DEST_REG	(BITS (12, 15))
+#define SRC1_REG	(BITS (16, 19))
+#define SRC2_REG	(BITS (0, 3))
+
+static int lsw_int_index, msw_int_index;
+static int lsw_float_index, msw_float_index;
+
+static double mv_getRegDouble (int);
+static long long mv_getReg64int (int);
+static void mv_setRegDouble (int, double val);
+static void mv_setReg64int (int, long long val);
+
+static union
+{
+	double d;
+	long long ll;
+	int ints[2];
+} reg_conv;
+
+static void
+printf_nothing (void *foo, ...)
+{
+}
+
+static void
+cirrus_not_implemented (char *insn)
+{
+	fprintf (stderr, "Cirrus instruction '%s' not implemented.\n", insn);
+	fprintf (stderr, "aborting!\n");
+
+	// skyeye_exit (1);
+}
+
+static unsigned
+DSPInit (ARMul_State * state)
+{
+	NOTICE_LOG(ARM11, "ARMul_ConsolePrint: DSP present");
+	return TRUE;
+}
+
+unsigned
+DSPMRC4 (ARMul_State * state,
+	 unsigned type, ARMword instr, ARMword * value)
+{
+	switch (BITS (5, 7)) {
+	case 0:		/* cfmvrdl */
+		/* Move lower half of a DF stored in a DSP reg into an Arm reg.  */
+		printfdbg ("cfmvrdl\n");
+		printfdbg ("\tlower half=0x%x\n", DSPregs[SRC1_REG].lower.i);
+		printfdbg ("\tentire thing=%g\n", mv_getRegDouble (SRC1_REG));
+
+		*value = (ARMword) DSPregs[SRC1_REG].lower.i;
+		break;
+
+	case 1:		/* cfmvrdh */
+		/* Move upper half of a DF stored in a DSP reg into an Arm reg.  */
+		printfdbg ("cfmvrdh\n");
+		printfdbg ("\tupper half=0x%x\n", DSPregs[SRC1_REG].upper.i);
+		printfdbg ("\tentire thing=%g\n", mv_getRegDouble (SRC1_REG));
+
+		*value = (ARMword) DSPregs[SRC1_REG].upper.i;
+		break;
+
+	case 2:		/* cfmvrs */
+		/* Move SF from upper half of a DSP register to an Arm register.  */
+		*value = (ARMword) DSPregs[SRC1_REG].upper.i;
+		printfdbg ("cfmvrs = mvf%d <-- %f\n",
+			   SRC1_REG, DSPregs[SRC1_REG].upper.f);
+		break;
+
+#ifdef doesnt_work
+	case 4:		/* cfcmps */
+		{
+			float a, b;
+			int n, z, c, v;
+
+			a = DSPregs[SRC1_REG].upper.f;
+			b = DSPregs[SRC2_REG].upper.f;
+
+			printfdbg ("cfcmps\n");
+			printfdbg ("\tcomparing %f and %f\n", a, b);
+
+			z = a == b;	/* zero */
+			n = a != b;	/* negative */
+			v = a > b;	/* overflow */
+			c = 0;	/* carry */
+			*value = (n << 31) | (z << 30) | (c << 29) | (v <<
+								      28);
+			break;
+		}
+
+	case 5:		/* cfcmpd */
+		{
+			double a, b;
+			int n, z, c, v;
+
+			a = mv_getRegDouble (SRC1_REG);
+			b = mv_getRegDouble (SRC2_REG);
+
+			printfdbg ("cfcmpd\n");
+			printfdbg ("\tcomparing %g and %g\n", a, b);
+
+			z = a == b;	/* zero */
+			n = a != b;	/* negative */
+			v = a > b;	/* overflow */
+			c = 0;	/* carry */
+			*value = (n << 31) | (z << 30) | (c << 29) | (v <<
+								      28);
+			break;
+		}
+#else
+	case 4:		/* cfcmps */
+		{
+			float a, b;
+			int n, z, c, v;
+
+			a = DSPregs[SRC1_REG].upper.f;
+			b = DSPregs[SRC2_REG].upper.f;
+
+			printfdbg ("cfcmps\n");
+			printfdbg ("\tcomparing %f and %f\n", a, b);
+
+			z = a == b;	/* zero */
+			n = a < b;	/* negative */
+			c = a > b;	/* carry */
+			v = 0;	/* fixme */
+			printfdbg ("\tz = %d, n = %d\n", z, n);
+			*value = (n << 31) | (z << 30) | (c << 29) | (v <<
+								      28);
+			break;
+		}
+
+	case 5:		/* cfcmpd */
+		{
+			double a, b;
+			int n, z, c, v;
+
+			a = mv_getRegDouble (SRC1_REG);
+			b = mv_getRegDouble (SRC2_REG);
+
+			printfdbg ("cfcmpd\n");
+			printfdbg ("\tcomparing %g and %g\n", a, b);
+
+			z = a == b;	/* zero */
+			n = a < b;	/* negative */
+			c = a > b;	/* carry */
+			v = 0;	/* fixme */
+			*value = (n << 31) | (z << 30) | (c << 29) | (v <<
+								      28);
+			break;
+		}
+#endif
+	default:
+		fprintf (stderr, "unknown opcode in DSPMRC4 0x%x\n", instr);
+		cirrus_not_implemented ("unknown");
+		break;
+	}
+
+	return ARMul_DONE;
+}
+
+unsigned
+DSPMRC5 (ARMul_State * state,
+	 unsigned type, ARMword instr, ARMword * value)
+{
+	switch (BITS (5, 7)) {
+	case 0:		/* cfmvr64l */
+		/* Move lower half of 64bit int from Cirrus to Arm.  */
+		*value = (ARMword) DSPregs[SRC1_REG].lower.i;
+		printfdbg ("cfmvr64l ARM_REG = mvfx%d <-- %d\n",
+			   DEST_REG, (int) *value);
+		break;
+
+	case 1:		/* cfmvr64h */
+		/* Move upper half of 64bit int from Cirrus to Arm.  */
+		*value = (ARMword) DSPregs[SRC1_REG].upper.i;
+		printfdbg ("cfmvr64h <-- %d\n", (int) *value);
+		break;
+
+	case 4:		/* cfcmp32 */
+		{
+			int res;
+			int n, z, c, v;
+			unsigned int a, b;
+
+			printfdbg ("cfcmp32 mvfx%d - mvfx%d\n", SRC1_REG,
+				   SRC2_REG);
+
+			/* FIXME: see comment for cfcmps.  */
+			a = DSPregs[SRC1_REG].lower.i;
+			b = DSPregs[SRC2_REG].lower.i;
+
+			res = DSPregs[SRC1_REG].lower.i -
+				DSPregs[SRC2_REG].lower.i;
+			/* zero */
+			z = res == 0;
+			/* negative */
+			n = res < 0;
+			/* overflow */
+			v = SubOverflow (DSPregs[SRC1_REG].lower.i,
+					 DSPregs[SRC2_REG].lower.i, res);
+			/* carry */
+			c = (NEG (a) && POS (b) ||
+			     (NEG (a) && POS (res)) || (POS (b)
+							&& POS (res)));
+
+			*value = (n << 31) | (z << 30) | (c << 29) | (v <<
+								      28);
+			break;
+		}
+
+	case 5:		/* cfcmp64 */
+		{
+			long long res;
+			int n, z, c, v;
+			unsigned long long a, b;
+
+			printfdbg ("cfcmp64 mvdx%d - mvdx%d\n", SRC1_REG,
+				   SRC2_REG);
+
+			/* fixme: see comment for cfcmps.  */
+
+			a = mv_getReg64int (SRC1_REG);
+			b = mv_getReg64int (SRC2_REG);
+
+			res = mv_getReg64int (SRC1_REG) -
+				mv_getReg64int (SRC2_REG);
+			/* zero */
+			z = res == 0;
+			/* negative */
+			n = res < 0;
+			/* overflow */
+			v = ((NEG64 (a) && POS64 (b) && POS64 (res))
+			     || (POS64 (a) && NEG64 (b) && NEG64 (res)));
+			/* carry */
+			c = (NEG64 (a) && POS64 (b) ||
+			     (NEG64 (a) && POS64 (res)) || (POS64 (b)
+							    && POS64 (res)));
+
+			*value = (n << 31) | (z << 30) | (c << 29) | (v <<
+								      28);
+			break;
+		}
+
+	default:
+		fprintf (stderr, "unknown opcode in DSPMRC5 0x%x\n", instr);
+		cirrus_not_implemented ("unknown");
+		break;
+	}
+
+	return ARMul_DONE;
+}
+
+unsigned
+DSPMRC6 (ARMul_State * state,
+	 unsigned type, ARMword instr, ARMword * value)
+{
+	switch (BITS (5, 7)) {
+	case 0:		/* cfmval32 */
+		cirrus_not_implemented ("cfmval32");
+		break;
+
+	case 1:		/* cfmvam32 */
+		cirrus_not_implemented ("cfmvam32");
+		break;
+
+	case 2:		/* cfmvah32 */
+		cirrus_not_implemented ("cfmvah32");
+		break;
+
+	case 3:		/* cfmva32 */
+		cirrus_not_implemented ("cfmva32");
+		break;
+
+	case 4:		/* cfmva64 */
+		cirrus_not_implemented ("cfmva64");
+		break;
+
+	case 5:		/* cfmvsc32 */
+		cirrus_not_implemented ("cfmvsc32");
+		break;
+
+	default:
+		fprintf (stderr, "unknown opcode in DSPMRC6 0x%x\n", instr);
+		cirrus_not_implemented ("unknown");
+		break;
+	}
+
+	return ARMul_DONE;
+}
+
+unsigned
+DSPMCR4 (ARMul_State * state,
+	 unsigned type, ARMword instr, ARMword value)
+{
+	switch (BITS (5, 7)) {
+	case 0:		/* cfmvdlr */
+		/* Move the lower half of a DF value from an Arm register into
+		   the lower half of a Cirrus register.  */
+		printfdbg ("cfmvdlr <-- 0x%x\n", (int) value);
+		DSPregs[SRC1_REG].lower.i = (int) value;
+		break;
+
+	case 1:		/* cfmvdhr */
+		/* Move the upper half of a DF value from an Arm register into
+		   the upper half of a Cirrus register.  */
+		printfdbg ("cfmvdhr <-- 0x%x\n", (int) value);
+		DSPregs[SRC1_REG].upper.i = (int) value;
+		break;
+
+	case 2:		/* cfmvsr */
+		/* Move SF from Arm register into upper half of Cirrus register.  */
+		printfdbg ("cfmvsr <-- 0x%x\n", (int) value);
+		DSPregs[SRC1_REG].upper.i = (int) value;
+		break;
+
+	default:
+		fprintf (stderr, "unknown opcode in DSPMCR4 0x%x\n", instr);
+		cirrus_not_implemented ("unknown");
+		break;
+	}
+
+	return ARMul_DONE;
+}
+
+unsigned
+DSPMCR5 (ARMul_State * state,
+	 unsigned type, ARMword instr, ARMword value)
+{
+	union
+	{
+		int s;
+		unsigned int us;
+	} val;
+
+	switch (BITS (5, 7)) {
+	case 0:		/* cfmv64lr */
+		/* Move lower half of a 64bit int from an ARM register into the
+		   lower half of a DSP register and sign extend it.  */
+		printfdbg ("cfmv64lr mvdx%d <-- 0x%x\n", SRC1_REG,
+			   (int) value);
+		DSPregs[SRC1_REG].lower.i = (int) value;
+		break;
+
+	case 1:		/* cfmv64hr */
+		/* Move upper half of a 64bit int from an ARM register into the
+		   upper half of a DSP register.  */
+		printfdbg ("cfmv64hr ARM_REG = mvfx%d <-- 0x%x\n",
+			   SRC1_REG, (int) value);
+		DSPregs[SRC1_REG].upper.i = (int) value;
+		break;
+
+	case 2:		/* cfrshl32 */
+		printfdbg ("cfrshl32\n");
+		val.us = value;
+		if (val.s > 0)
+			DSPregs[SRC2_REG].lower.i =
+				DSPregs[SRC1_REG].lower.i << value;
+		else
+			DSPregs[SRC2_REG].lower.i =
+				DSPregs[SRC1_REG].lower.i >> -value;
+		break;
+
+	case 3:		/* cfrshl64 */
+		printfdbg ("cfrshl64\n");
+		val.us = value;
+		if (val.s > 0)
+			mv_setReg64int (SRC2_REG,
+					mv_getReg64int (SRC1_REG) << value);
+		else
+			mv_setReg64int (SRC2_REG,
+					mv_getReg64int (SRC1_REG) >> -value);
+		break;
+
+	default:
+		fprintf (stderr, "unknown opcode in DSPMCR5 0x%x\n", instr);
+		cirrus_not_implemented ("unknown");
+		break;
+	}
+
+	return ARMul_DONE;
+}
+
+unsigned
+DSPMCR6 (ARMul_State * state,
+	 unsigned type, ARMword instr, ARMword value)
+{
+	switch (BITS (5, 7)) {
+	case 0:		/* cfmv32al */
+		cirrus_not_implemented ("cfmv32al");
+		break;
+
+	case 1:		/* cfmv32am */
+		cirrus_not_implemented ("cfmv32am");
+		break;
+
+	case 2:		/* cfmv32ah */
+		cirrus_not_implemented ("cfmv32ah");
+		break;
+
+	case 3:		/* cfmv32a */
+		cirrus_not_implemented ("cfmv32a");
+		break;
+
+	case 4:		/* cfmv64a */
+		cirrus_not_implemented ("cfmv64a");
+		break;
+
+	case 5:		/* cfmv32sc */
+		cirrus_not_implemented ("cfmv32sc");
+		break;
+
+	default:
+		fprintf (stderr, "unknown opcode in DSPMCR6 0x%x\n", instr);
+		cirrus_not_implemented ("unknown");
+		break;
+	}
+
+	return ARMul_DONE;
+}
+
+unsigned
+DSPLDC4 (ARMul_State * state,
+	 unsigned type, ARMword instr, ARMword data)
+{
+	static unsigned words;
+
+	if (type != ARMul_DATA) {
+		words = 0;
+		return ARMul_DONE;
+	}
+
+	if (BIT (22)) {		/* it's a long access, get two words */
+		/* cfldrd */
+
+		printfdbg
+			("cfldrd: %x (words = %d) (bigend = %d) DESTREG = %d\n",
+			 data, words, state->bigendSig, DEST_REG);
+
+		if (words == 0) {
+			if (state->bigendSig)
+				DSPregs[DEST_REG].upper.i = (int) data;
+			else
+				DSPregs[DEST_REG].lower.i = (int) data;
+		}
+		else {
+			if (state->bigendSig)
+				DSPregs[DEST_REG].lower.i = (int) data;
+			else
+				DSPregs[DEST_REG].upper.i = (int) data;
+		}
+
+		++words;
+
+		if (words == 2) {
+			printfdbg ("\tmvd%d <-- mem = %g\n", DEST_REG,
+				   mv_getRegDouble (DEST_REG));
+
+			return ARMul_DONE;
+		}
+		else
+			return ARMul_INC;
+	}
+	else {
+		/* Get just one word.  */
+
+		/* cfldrs */
+		printfdbg ("cfldrs\n");
+
+		DSPregs[DEST_REG].upper.i = (int) data;
+
+		printfdbg ("\tmvf%d <-- mem = %f\n", DEST_REG,
+			   DSPregs[DEST_REG].upper.f);
+
+		return ARMul_DONE;
+	}
+}
+
+unsigned
+DSPLDC5 (ARMul_State * state,
+	 unsigned type, ARMword instr, ARMword data)
+{
+	static unsigned words;
+
+	if (type != ARMul_DATA) {
+		words = 0;
+		return ARMul_DONE;
+	}
+
+	if (BIT (22)) {
+		/* It's a long access, get two words.  */
+
+		/* cfldr64 */
+		printfdbg ("cfldr64: %d\n", data);
+
+		if (words == 0) {
+			if (state->bigendSig)
+				DSPregs[DEST_REG].upper.i = (int) data;
+			else
+				DSPregs[DEST_REG].lower.i = (int) data;
+		}
+		else {
+			if (state->bigendSig)
+				DSPregs[DEST_REG].lower.i = (int) data;
+			else
+				DSPregs[DEST_REG].upper.i = (int) data;
+		}
+
+		++words;
+
+		if (words == 2) {
+			printfdbg ("\tmvdx%d <-- mem = %lld\n", DEST_REG,
+				   mv_getReg64int (DEST_REG));
+
+			return ARMul_DONE;
+		}
+		else
+			return ARMul_INC;
+	}
+	else {
+		/* Get just one word.  */
+
+		/* cfldr32 */
+		printfdbg ("cfldr32 mvfx%d <-- %d\n", DEST_REG, (int) data);
+
+		/* 32bit ints should be sign extended to 64bits when loaded.  */
+		mv_setReg64int (DEST_REG, (long long) data);
+
+		return ARMul_DONE;
+	}
+}
+
+unsigned
+DSPSTC4 (ARMul_State * state,
+	 unsigned type, ARMword instr, ARMword * data)
+{
+	static unsigned words;
+
+	if (type != ARMul_DATA) {
+		words = 0;
+		return ARMul_DONE;
+	}
+
+	if (BIT (22)) {
+		/* It's a long access, get two words.  */
+		/* cfstrd */
+		printfdbg ("cfstrd\n");
+
+		if (words == 0) {
+			if (state->bigendSig)
+				*data = (ARMword) DSPregs[DEST_REG].upper.i;
+			else
+				*data = (ARMword) DSPregs[DEST_REG].lower.i;
+		}
+		else {
+			if (state->bigendSig)
+				*data = (ARMword) DSPregs[DEST_REG].lower.i;
+			else
+				*data = (ARMword) DSPregs[DEST_REG].upper.i;
+		}
+
+		++words;
+
+		if (words == 2) {
+			printfdbg ("\tmem = mvd%d = %g\n", DEST_REG,
+				   mv_getRegDouble (DEST_REG));
+
+			return ARMul_DONE;
+		}
+		else
+			return ARMul_INC;
+	}
+	else {
+		/* Get just one word.  */
+		/* cfstrs */
+		printfdbg ("cfstrs mvf%d <-- %f\n", DEST_REG,
+			   DSPregs[DEST_REG].upper.f);
+
+		*data = (ARMword) DSPregs[DEST_REG].upper.i;
+
+		return ARMul_DONE;
+	}
+}
+
+unsigned
+DSPSTC5 (ARMul_State * state,
+	 unsigned type, ARMword instr, ARMword * data)
+{
+	static unsigned words;
+
+	if (type != ARMul_DATA) {
+		words = 0;
+		return ARMul_DONE;
+	}
+
+	if (BIT (22)) {
+		/* It's a long access, store two words.  */
+		/* cfstr64 */
+		printfdbg ("cfstr64\n");
+
+		if (words == 0) {
+			if (state->bigendSig)
+				*data = (ARMword) DSPregs[DEST_REG].upper.i;
+			else
+				*data = (ARMword) DSPregs[DEST_REG].lower.i;
+		}
+		else {
+			if (state->bigendSig)
+				*data = (ARMword) DSPregs[DEST_REG].lower.i;
+			else
+				*data = (ARMword) DSPregs[DEST_REG].upper.i;
+		}
+
+		++words;
+
+		if (words == 2) {
+			printfdbg ("\tmem = mvd%d = %lld\n", DEST_REG,
+				   mv_getReg64int (DEST_REG));
+
+			return ARMul_DONE;
+		}
+		else
+			return ARMul_INC;
+	}
+	else {
+		/* Store just one word.  */
+		/* cfstr32 */
+		*data = (ARMword) DSPregs[DEST_REG].lower.i;
+
+		printfdbg ("cfstr32 MEM = %d\n", (int) *data);
+
+		return ARMul_DONE;
+	}
+}
+
+unsigned
+DSPCDP4 (ARMul_State * state, unsigned type, ARMword instr)
+{
+	int opcode2;
+
+	opcode2 = BITS (5, 7);
+
+	switch (BITS (20, 21)) {
+	case 0:
+		switch (opcode2) {
+		case 0:	/* cfcpys */
+			printfdbg ("cfcpys mvf%d = mvf%d = %f\n",
+				   DEST_REG, SRC1_REG,
+				   DSPregs[SRC1_REG].upper.f);
+			DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f;
+			break;
+
+		case 1:	/* cfcpyd */
+			printfdbg ("cfcpyd mvd%d = mvd%d = %g\n",
+				   DEST_REG, SRC1_REG,
+				   mv_getRegDouble (SRC1_REG));
+			mv_setRegDouble (DEST_REG,
+					 mv_getRegDouble (SRC1_REG));
+			break;
+
+		case 2:	/* cfcvtds */
+			printfdbg ("cfcvtds mvf%d = (float) mvd%d = %f\n",
+				   DEST_REG, SRC1_REG,
+				   (float) mv_getRegDouble (SRC1_REG));
+			DSPregs[DEST_REG].upper.f =
+				(float) mv_getRegDouble (SRC1_REG);
+			break;
+
+		case 3:	/* cfcvtsd */
+			printfdbg ("cfcvtsd mvd%d = mvf%d = %g\n",
+				   DEST_REG, SRC1_REG,
+				   (double) DSPregs[SRC1_REG].upper.f);
+			mv_setRegDouble (DEST_REG,
+					 (double) DSPregs[SRC1_REG].upper.f);
+			break;
+
+		case 4:	/* cfcvt32s */
+			printfdbg ("cfcvt32s mvf%d = mvfx%d = %f\n",
+				   DEST_REG, SRC1_REG,
+				   (float) DSPregs[SRC1_REG].lower.i);
+			DSPregs[DEST_REG].upper.f =
+				(float) DSPregs[SRC1_REG].lower.i;
+			break;
+
+		case 5:	/* cfcvt32d */
+			printfdbg ("cfcvt32d mvd%d = mvfx%d = %g\n",
+				   DEST_REG, SRC1_REG,
+				   (double) DSPregs[SRC1_REG].lower.i);
+			mv_setRegDouble (DEST_REG,
+					 (double) DSPregs[SRC1_REG].lower.i);
+			break;
+
+		case 6:	/* cfcvt64s */
+			printfdbg ("cfcvt64s mvf%d = mvdx%d = %f\n",
+				   DEST_REG, SRC1_REG,
+				   (float) mv_getReg64int (SRC1_REG));
+			DSPregs[DEST_REG].upper.f =
+				(float) mv_getReg64int (SRC1_REG);
+			break;
+
+		case 7:	/* cfcvt64d */
+			printfdbg ("cfcvt64d mvd%d = mvdx%d = %g\n",
+				   DEST_REG, SRC1_REG,
+				   (double) mv_getReg64int (SRC1_REG));
+			mv_setRegDouble (DEST_REG,
+					 (double) mv_getReg64int (SRC1_REG));
+			break;
+		}
+		break;
+
+	case 1:
+		switch (opcode2) {
+		case 0:	/* cfmuls */
+			printfdbg ("cfmuls mvf%d = mvf%d = %f\n",
+				   DEST_REG,
+				   SRC1_REG,
+				   DSPregs[SRC1_REG].upper.f *
+				   DSPregs[SRC2_REG].upper.f);
+
+			DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f
+				* DSPregs[SRC2_REG].upper.f;
+			break;
+
+		case 1:	/* cfmuld */
+			printfdbg ("cfmuld mvd%d = mvd%d = %g\n",
+				   DEST_REG,
+				   SRC1_REG,
+				   mv_getRegDouble (SRC1_REG) *
+				   mv_getRegDouble (SRC2_REG));
+
+			mv_setRegDouble (DEST_REG, mv_getRegDouble (SRC1_REG)
+					 * mv_getRegDouble (SRC2_REG));
+			break;
+
+		default:
+			fprintf (stderr, "unknown opcode in DSPCDP4 0x%x\n",
+				 instr);
+			cirrus_not_implemented ("unknown");
+			break;
+		}
+		break;
+
+	case 3:
+		switch (opcode2) {
+		case 0:	/* cfabss */
+			DSPregs[DEST_REG].upper.f =
+				(DSPregs[SRC1_REG].upper.f <
+				 0.0F ? -DSPregs[SRC1_REG].upper.
+				 f : DSPregs[SRC1_REG].upper.f);
+			printfdbg ("cfabss mvf%d = |mvf%d| = %f\n", DEST_REG,
+				   SRC1_REG, DSPregs[DEST_REG].upper.f);
+			break;
+
+		case 1:	/* cfabsd */
+			mv_setRegDouble (DEST_REG,
+					 (mv_getRegDouble (SRC1_REG) < 0.0 ?
+					  -mv_getRegDouble (SRC1_REG)
+					  : mv_getRegDouble (SRC1_REG)));
+			printfdbg ("cfabsd mvd%d = |mvd%d| = %g\n",
+				   DEST_REG, SRC1_REG,
+				   mv_getRegDouble (DEST_REG));
+			break;
+
+		case 2:	/* cfnegs */
+			DSPregs[DEST_REG].upper.f =
+				-DSPregs[SRC1_REG].upper.f;
+			printfdbg ("cfnegs mvf%d = -mvf%d = %f\n", DEST_REG,
+				   SRC1_REG, DSPregs[DEST_REG].upper.f);
+			break;
+
+		case 3:	/* cfnegd */
+			mv_setRegDouble (DEST_REG,
+					 -mv_getRegDouble (SRC1_REG));
+			printfdbg ("cfnegd mvd%d = -mvd%d = %g\n", DEST_REG,
+				   mv_getRegDouble (DEST_REG));
+			break;
+
+		case 4:	/* cfadds */
+			DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f
+				+ DSPregs[SRC2_REG].upper.f;
+			printfdbg ("cfadds mvf%d = mvf%d + mvf%d = %f\n",
+				   DEST_REG, SRC1_REG, SRC2_REG,
+				   DSPregs[DEST_REG].upper.f);
+			break;
+
+		case 5:	/* cfaddd */
+			mv_setRegDouble (DEST_REG, mv_getRegDouble (SRC1_REG)
+					 + mv_getRegDouble (SRC2_REG));
+			printfdbg ("cfaddd: mvd%d = mvd%d + mvd%d = %g\n",
+				   DEST_REG,
+				   SRC1_REG, SRC2_REG,
+				   mv_getRegDouble (DEST_REG));
+			break;
+
+		case 6:	/* cfsubs */
+			DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f
+				- DSPregs[SRC2_REG].upper.f;
+			printfdbg ("cfsubs: mvf%d = mvf%d - mvf%d = %f\n",
+				   DEST_REG, SRC1_REG, SRC2_REG,
+				   DSPregs[DEST_REG].upper.f);
+			break;
+
+		case 7:	/* cfsubd */
+			mv_setRegDouble (DEST_REG, mv_getRegDouble (SRC1_REG)
+					 - mv_getRegDouble (SRC2_REG));
+			printfdbg ("cfsubd: mvd%d = mvd%d - mvd%d = %g\n",
+				   DEST_REG,
+				   SRC1_REG, SRC2_REG,
+				   mv_getRegDouble (DEST_REG));
+			break;
+		}
+		break;
+
+	default:
+		fprintf (stderr, "unknown opcode in DSPCDP4 0x%x\n", instr);
+		cirrus_not_implemented ("unknown");
+		break;
+	}
+
+	return ARMul_DONE;
+}
+
+unsigned
+DSPCDP5 (ARMul_State * state, unsigned type, ARMword instr)
+{
+	int opcode2;
+	char shift;
+
+	opcode2 = BITS (5, 7);
+
+	/* Shift constants are 7bit signed numbers in bits 0..3|5..7.  */
+	shift = BITS (0, 3) | (BITS (5, 7)) << 4;
+	if (shift & 0x40)
+		shift |= 0xc0;
+
+	switch (BITS (20, 21)) {
+	case 0:
+		/* cfsh32 */
+		printfdbg ("cfsh32 %s amount=%d\n",
+			   shift < 0 ? "right" : "left", shift);
+		if (shift < 0)
+			/* Negative shift is a right shift.  */
+			DSPregs[DEST_REG].lower.i =
+				DSPregs[SRC1_REG].lower.i >> -shift;
+		else
+			/* Positive shift is a left shift.  */
+			DSPregs[DEST_REG].lower.i =
+				DSPregs[SRC1_REG].lower.i << shift;
+		break;
+
+	case 1:
+		switch (opcode2) {
+		case 0:	/* cfmul32 */
+			DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i
+				* DSPregs[SRC2_REG].lower.i;
+			printfdbg ("cfmul32 mvfx%d = mvfx%d * mvfx%d = %d\n",
+				   DEST_REG, SRC1_REG, SRC2_REG,
+				   DSPregs[DEST_REG].lower.i);
+			break;
+
+		case 1:	/* cfmul64 */
+			mv_setReg64int (DEST_REG, mv_getReg64int (SRC1_REG)
+					* mv_getReg64int (SRC2_REG));
+			printfdbg
+				("cfmul64 mvdx%d = mvdx%d * mvdx%d = %lld\n",
+				 DEST_REG, SRC1_REG, SRC2_REG,
+				 mv_getReg64int (DEST_REG));
+			break;
+
+		case 2:	/* cfmac32 */
+			DSPregs[DEST_REG].lower.i
+				+=
+				DSPregs[SRC1_REG].lower.i *
+				DSPregs[SRC2_REG].lower.i;
+			printfdbg ("cfmac32 mvfx%d += mvfx%d * mvfx%d = %d\n",
+				   DEST_REG, SRC1_REG, SRC2_REG,
+				   DSPregs[DEST_REG].lower.i);
+			break;
+
+		case 3:	/* cfmsc32 */
+			DSPregs[DEST_REG].lower.i
+				-=
+				DSPregs[SRC1_REG].lower.i *
+				DSPregs[SRC2_REG].lower.i;
+			printfdbg ("cfmsc32 mvfx%d -= mvfx%d * mvfx%d = %d\n",
+				   DEST_REG, SRC1_REG, SRC2_REG,
+				   DSPregs[DEST_REG].lower.i);
+			break;
+
+		case 4:	/* cfcvts32 */
+			/* fixme: this should round */
+			DSPregs[DEST_REG].lower.i =
+				(int) DSPregs[SRC1_REG].upper.f;
+			printfdbg ("cfcvts32 mvfx%d = mvf%d = %d\n", DEST_REG,
+				   SRC1_REG, DSPregs[DEST_REG].lower.i);
+			break;
+
+		case 5:	/* cfcvtd32 */
+			/* fixme: this should round */
+			DSPregs[DEST_REG].lower.i =
+				(int) mv_getRegDouble (SRC1_REG);
+			printfdbg ("cfcvtd32 mvdx%d = mvd%d = %d\n", DEST_REG,
+				   SRC1_REG, DSPregs[DEST_REG].lower.i);
+			break;
+
+		case 6:	/* cftruncs32 */
+			DSPregs[DEST_REG].lower.i =
+				(int) DSPregs[SRC1_REG].upper.f;
+			printfdbg ("cftruncs32 mvfx%d = mvf%d = %d\n",
+				   DEST_REG, SRC1_REG,
+				   DSPregs[DEST_REG].lower.i);
+			break;
+
+		case 7:	/* cftruncd32 */
+			DSPregs[DEST_REG].lower.i =
+				(int) mv_getRegDouble (SRC1_REG);
+			printfdbg ("cftruncd32 mvfx%d = mvd%d = %d\n",
+				   DEST_REG, SRC1_REG,
+				   DSPregs[DEST_REG].lower.i);
+			break;
+		}
+		break;
+
+	case 2:
+		/* cfsh64 */
+		printfdbg ("cfsh64\n");
+
+		if (shift < 0)
+			/* Negative shift is a right shift.  */
+			mv_setReg64int (DEST_REG,
+					mv_getReg64int (SRC1_REG) >> -shift);
+		else
+			/* Positive shift is a left shift.  */
+			mv_setReg64int (DEST_REG,
+					mv_getReg64int (SRC1_REG) << shift);
+		printfdbg ("\t%llx\n", mv_getReg64int (DEST_REG));
+		break;
+
+	case 3:
+		switch (opcode2) {
+		case 0:	/* cfabs32 */
+			DSPregs[DEST_REG].lower.i =
+				(DSPregs[SRC1_REG].lower.i <
+				 0 ? -DSPregs[SRC1_REG].lower.
+				 i : DSPregs[SRC1_REG].lower.i);
+			printfdbg ("cfabs32 mvfx%d = |mvfx%d| = %d\n",
+				   DEST_REG, SRC1_REG, SRC2_REG,
+				   DSPregs[DEST_REG].lower.i);
+			break;
+
+		case 1:	/* cfabs64 */
+			mv_setReg64int (DEST_REG,
+					(mv_getReg64int (SRC1_REG) < 0
+					 ? -mv_getReg64int (SRC1_REG)
+					 : mv_getReg64int (SRC1_REG)));
+			printfdbg ("cfabs64 mvdx%d = |mvdx%d| = %lld\n",
+				   DEST_REG, SRC1_REG, SRC2_REG,
+				   mv_getReg64int (DEST_REG));
+			break;
+
+		case 2:	/* cfneg32 */
+			DSPregs[DEST_REG].lower.i =
+				-DSPregs[SRC1_REG].lower.i;
+			printfdbg ("cfneg32 mvfx%d = -mvfx%d = %d\n",
+				   DEST_REG, SRC1_REG, SRC2_REG,
+				   DSPregs[DEST_REG].lower.i);
+			break;
+
+		case 3:	/* cfneg64 */
+			mv_setReg64int (DEST_REG, -mv_getReg64int (SRC1_REG));
+			printfdbg ("cfneg64 mvdx%d = -mvdx%d = %lld\n",
+				   DEST_REG, SRC1_REG, SRC2_REG,
+				   mv_getReg64int (DEST_REG));
+			break;
+
+		case 4:	/* cfadd32 */
+			DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i
+				+ DSPregs[SRC2_REG].lower.i;
+			printfdbg ("cfadd32 mvfx%d = mvfx%d + mvfx%d = %d\n",
+				   DEST_REG, SRC1_REG, SRC2_REG,
+				   DSPregs[DEST_REG].lower.i);
+			break;
+
+		case 5:	/* cfadd64 */
+			mv_setReg64int (DEST_REG, mv_getReg64int (SRC1_REG)
+					+ mv_getReg64int (SRC2_REG));
+			printfdbg
+				("cfadd64 mvdx%d = mvdx%d + mvdx%d = %lld\n",
+				 DEST_REG, SRC1_REG, SRC2_REG,
+				 mv_getReg64int (DEST_REG));
+			break;
+
+		case 6:	/* cfsub32 */
+			DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i
+				- DSPregs[SRC2_REG].lower.i;
+			printfdbg ("cfsub32 mvfx%d = mvfx%d - mvfx%d = %d\n",
+				   DEST_REG, SRC1_REG, SRC2_REG,
+				   DSPregs[DEST_REG].lower.i);
+			break;
+
+		case 7:	/* cfsub64 */
+			mv_setReg64int (DEST_REG, mv_getReg64int (SRC1_REG)
+					- mv_getReg64int (SRC2_REG));
+			printfdbg ("cfsub64 mvdx%d = mvdx%d - mvdx%d = %d\n",
+				   DEST_REG, SRC1_REG, SRC2_REG,
+				   mv_getReg64int (DEST_REG));
+			break;
+		}
+		break;
+
+	default:
+		fprintf (stderr, "unknown opcode in DSPCDP5 0x%x\n", instr);
+		cirrus_not_implemented ("unknown");
+		break;
+	}
+
+	return ARMul_DONE;
+}
+
+unsigned
+DSPCDP6 (ARMul_State * state, unsigned type, ARMword instr)
+{
+	int opcode2;
+
+	opcode2 = BITS (5, 7);
+
+	switch (BITS (20, 21)) {
+	case 0:
+		/* cfmadd32 */
+		cirrus_not_implemented ("cfmadd32");
+		break;
+
+	case 1:
+		/* cfmsub32 */
+		cirrus_not_implemented ("cfmsub32");
+		break;
+
+	case 2:
+		/* cfmadda32 */
+		cirrus_not_implemented ("cfmadda32");
+		break;
+
+	case 3:
+		/* cfmsuba32 */
+		cirrus_not_implemented ("cfmsuba32");
+		break;
+
+	default:
+		fprintf (stderr, "unknown opcode in DSPCDP6 0x%x\n", instr);
+	}
+
+	return ARMul_DONE;
+}
+
+/* Conversion functions.
+
+   32-bit integers are stored in the LOWER half of a 64-bit physical
+   register.
+
+   Single precision floats are stored in the UPPER half of a 64-bit
+   physical register.  */
+
+static double
+mv_getRegDouble (int regnum)
+{
+	reg_conv.ints[lsw_float_index] = DSPregs[regnum].upper.i;
+	reg_conv.ints[msw_float_index] = DSPregs[regnum].lower.i;
+	return reg_conv.d;
+}
+
+static void
+mv_setRegDouble (int regnum, double val)
+{
+	reg_conv.d = val;
+	DSPregs[regnum].upper.i = reg_conv.ints[lsw_float_index];
+	DSPregs[regnum].lower.i = reg_conv.ints[msw_float_index];
+}
+
+static long long
+mv_getReg64int (int regnum)
+{
+	reg_conv.ints[lsw_int_index] = DSPregs[regnum].lower.i;
+	reg_conv.ints[msw_int_index] = DSPregs[regnum].upper.i;
+	return reg_conv.ll;
+}
+
+static void
+mv_setReg64int (int regnum, long long val)
+{
+	reg_conv.ll = val;
+	DSPregs[regnum].lower.i = reg_conv.ints[lsw_int_index];
+	DSPregs[regnum].upper.i = reg_conv.ints[msw_int_index];
+}
+
+/* Compute LSW in a double and a long long.  */
+
+void
+mv_compute_host_endianness (ARMul_State * state)
+{
+	static union
+	{
+		long long ll;
+		int ints[2];
+		int i;
+		double d;
+		float floats[2];
+		float f;
+	} conv;
+
+	/* Calculate where's the LSW in a 64bit int.  */
+	conv.ll = 45;
+
+	if (conv.ints[0] == 0) {
+		msw_int_index = 0;
+		lsw_int_index = 1;
+	}
+	else {
+		assert (conv.ints[1] == 0);
+		msw_int_index = 1;
+		lsw_int_index = 0;
+	}
+
+	/* Calculate where's the LSW in a double.  */
+	conv.d = 3.0;
+
+	if (conv.ints[0] == 0) {
+		msw_float_index = 0;
+		lsw_float_index = 1;
+	}
+	else {
+		assert (conv.ints[1] == 0);
+		msw_float_index = 1;
+		lsw_float_index = 0;
+	}
+
+	printfdbg ("lsw_int_index   %d\n", lsw_int_index);
+	printfdbg ("lsw_float_index %d\n", lsw_float_index);
+}
diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj
index 9d8b0ddcf..41af5801d 100644
--- a/src/core/core.vcxproj
+++ b/src/core/core.vcxproj
@@ -149,6 +149,7 @@
     <ClCompile Include="arm\interpreter\arm_interpreter.cpp" />
     <ClCompile Include="arm\interpreter\mmu\arm1176jzf_s_mmu.cpp" />
     <ClCompile Include="arm\interpreter\mmu\cache.cpp" />
+    <ClCompile Include="arm\interpreter\mmu\maverick.cpp" />
     <ClCompile Include="arm\interpreter\mmu\rb.cpp" />
     <ClCompile Include="arm\interpreter\mmu\sa_mmu.cpp" />
     <ClCompile Include="arm\interpreter\mmu\tlb.cpp" />
diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters
index e92cb9106..edf34ce2f 100644
--- a/src/core/core.vcxproj.filters
+++ b/src/core/core.vcxproj.filters
@@ -150,6 +150,9 @@
     <ClCompile Include="arm\interpreter\armcopro.cpp">
       <Filter>arm</Filter>
     </ClCompile>
+    <ClCompile Include="arm\interpreter\mmu\maverick.cpp">
+      <Filter>arm\interpreter\mmu</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="arm\disassembler\arm_disasm.h">