From 75a05652e5851d9b6189088093a13b391e2a8b0c Mon Sep 17 00:00:00 2001
From: Neil Millstone
Date: Sat, 30 Jun 2007 23:03:03 +0000
Subject: - Show mouse cursor option - Support for SAGA, CINE, and AGI - Key
 bindings for Gob3 - Assembler optimisations submitted by Robin Watts

svn-id: r27803
---
 backends/platform/ds/arm9/data/icons.raw           | Bin 15360 -> 24576 bytes
 backends/platform/ds/arm9/makefile                 | 121 ++++++-
 backends/platform/ds/arm9/source/blitters.cpp      | 402 ---------------------
 backends/platform/ds/arm9/source/blitters.h        |  18 +
 backends/platform/ds/arm9/source/blitters.s        | 339 +++++++++++++++++
 backends/platform/ds/arm9/source/dsmain.cpp        | 361 ++++++++++++++----
 backends/platform/ds/arm9/source/dsmain.h          |  25 +-
 backends/platform/ds/arm9/source/dsoptions.cpp     |  54 ++-
 backends/platform/ds/arm9/source/dsoptions.h       |   3 +-
 backends/platform/ds/arm9/source/fat/disc_io.c     |   2 +-
 backends/platform/ds/arm9/source/fat/disc_io.h     |   4 +
 backends/platform/ds/arm9/source/fat/gba_nds_fat.c |  13 +-
 backends/platform/ds/arm9/source/fat/io_dldi.h     |   2 +-
 backends/platform/ds/arm9/source/gbampsave.cpp     |  15 +-
 backends/platform/ds/arm9/source/gbampsave.h       |   2 +-
 backends/platform/ds/arm9/source/osystem_ds.cpp    |  61 ++--
 backends/platform/ds/arm9/source/osystem_ds.h      |  22 +-
 backends/platform/ds/arm9/source/touchkeyboard.cpp | 180 ++++++++-
 backends/platform/ds/arm9/source/touchkeyboard.h   |   7 +
 .../platform/ds/arm9/source/wordcompletion.cpp     |  67 ++++
 backends/platform/ds/arm9/source/wordcompletion.h  |   8 +
 backends/platform/ds/arm9/source/zipreader.cpp     |   6 +-
 22 files changed, 1144 insertions(+), 568 deletions(-)
 delete mode 100644 backends/platform/ds/arm9/source/blitters.cpp
 create mode 100644 backends/platform/ds/arm9/source/blitters.s
 create mode 100644 backends/platform/ds/arm9/source/wordcompletion.cpp
 create mode 100644 backends/platform/ds/arm9/source/wordcompletion.h

(limited to 'backends')

diff --git a/backends/platform/ds/arm9/data/icons.raw b/backends/platform/ds/arm9/data/icons.raw
index c2915b2914..c8fbfd6e9a 100644
Binary files a/backends/platform/ds/arm9/data/icons.raw and b/backends/platform/ds/arm9/data/icons.raw differ
diff --git a/backends/platform/ds/arm9/makefile b/backends/platform/ds/arm9/makefile
index cb41774064..c9ca5467f3 100644
--- a/backends/platform/ds/arm9/makefile
+++ b/backends/platform/ds/arm9/makefile
@@ -4,18 +4,32 @@ libndsdir = /home/neil/devkitpro/libnds
 
 # Select the build you want by uncommenting one of the following lines:
 
-DS_BUILD_A = 1
+
+#DS_BUILD_A = 1
 #DS_BUILD_B = 1
 #DS_BUILD_C = 1
-#DS_BUILD_D = 1
+DS_BUILD_D = 1
+#DS_BUILD_E = 1
+#DS_BUILD_F = 1
 
 # Uncomment the following line to build in support for MP3 audio
 # using libmad:
-USE_MAD = 1
+
+ifdef DS_BUILD_F
+	# TODO: Fix this.  When libmad is compiled in, the Kyrandia resource loading
+	# searches through it's entire index to find an mp3 each time a voice sample is requested
+	# this causes a nasty pause.
+else
+	USE_MAD = 1
+endif
 
 # Uncomment the following line to enable support for the
 # ace DS Debugger (remembering to make the same change in the arm7 makefile):
 #USE_DEBUGGER = 1
+
+# Uncomment the following line to enable the profiler
+#USE_PROFILER = 1
+
 # NOTE: The header and libs for the debugger is assumed to be in the libnds
 # folder.
 
@@ -24,6 +38,7 @@ VPATH = $(srcdir)
 # Command to build libmad is:
 # ./configure --host=arm-elf --enable-speed --enable-sso -enable-fpm=arm CFLAGS='-specs=ds_arm9.specs -mthumb-interwork'
 
+ARM = 1
 
 ifdef DS_BUILD_A
 	DEFINES = -DDS_SCUMM_BUILD -DDS_BUILD_A
@@ -44,6 +59,7 @@ ifdef DS_BUILD_A
 	DISABLE_AGI = 1
 	DISABLE_TOUCHE = 1
 	DISABLE_PARALLACTION = 1
+	DISABLE_CRUISE = 1
 	BUILD=scummvm-A
 endif
 
@@ -66,6 +82,7 @@ ifdef DS_BUILD_B
 	DISABLE_AGI = 1
 	DISABLE_TOUCHE = 1
 	DISABLE_PARALLACTION = 1
+	DISABLE_CRUISE = 1
 	BUILD=scummvm-B
 endif
 
@@ -81,13 +98,14 @@ ifdef DS_BUILD_C
 	DISABLE_SWORD2 = 1
 	DISABLE_QUEEN = 1
 	DISABLE_SAGA = 1
-	#DISABLE_KYRA = 1
-	#DISABLE_GOB = 1
+	DISABLE_KYRA = 1
+	DISABLE_GOB = 1
 	DISABLE_LURE = 1
 	DISABLE_CINE = 1
 	DISABLE_AGI = 1
 	DISABLE_TOUCHE = 1
 	DISABLE_PARALLACTION = 1
+	DISABLE_CRUISE = 1
 	BUILD=scummvm-C
 endif
 
@@ -104,15 +122,62 @@ ifdef DS_BUILD_D
 	DISABLE_QUEEN = 1
 	DISABLE_SAGA = 1
 	DISABLE_KYRA = 1
-	DISABLE_GOB = 1
+	#DISABLE_GOB = 1
 	DISABLE_LURE = 1
 	#DISABLE_CINE = 1
 	#DISABLE_AGI = 1
 	DISABLE_TOUCHE = 1
 	DISABLE_PARALLACTION = 1
-	BUILD=scummvm-A
+	DISABLE_CRUISE = 1
+	BUILD=scummvm-D
 endif
 
+ifdef DS_BUILD_E
+	DEFINES = -DDS_NON_SCUMM_BUILD -DDS_BUILD_E
+	LOGO = logoc.bmp
+	DISABLE_HE = 1
+	DISABLE_SCUMM = 1
+	DISABLE_SCUMM_7_8 = 1
+	DISABLE_AGOS = 1
+	DISABLE_SKY = 1
+	DISABLE_SWORD1 = 1
+	DISABLE_SWORD2 = 1
+	DISABLE_QUEEN = 1
+	#DISABLE_SAGA = 1
+	DISABLE_KYRA = 1
+	DISABLE_GOB = 1
+	DISABLE_LURE = 1
+	DISABLE_CINE = 1
+	DISABLE_AGI = 1
+	DISABLE_TOUCHE = 1
+	DISABLE_PARALLACTION = 1
+	DISABLE_CRUISE = 1
+	BUILD=scummvm-E
+endif
+
+ifdef DS_BUILD_F
+	DEFINES = -DDS_NON_SCUMM_BUILD -DDS_BUILD_F
+	LOGO = logoc.bmp
+	DISABLE_HE = 1
+	DISABLE_SCUMM = 1
+	DISABLE_SCUMM_7_8 = 1
+	DISABLE_AGOS = 1
+	DISABLE_SKY = 1
+	DISABLE_SWORD1 = 1
+	DISABLE_SWORD2 = 1
+	DISABLE_QUEEN = 1
+	DISABLE_SAGA = 1
+	#DISABLE_KYRA = 1
+	DISABLE_GOB = 1
+	DISABLE_LURE = 1
+	DISABLE_CINE = 1
+	DISABLE_AGI = 1
+	DISABLE_TOUCHE = 1
+	DISABLE_PARALLACTION = 1
+	DISABLE_CRUISE = 1
+	BUILD=scummvm-F
+
+endif
 
 ARM7BIN	:= -7 $(CURDIR)/../../arm7/arm7.bin
 ICON 		:= -b ../../../logo.bmp "ScummVM;By Neil Millstone;"
@@ -120,7 +185,7 @@ ICON 		:= -b ../../../logo.bmp "ScummVM;By Neil Millstone;"
 CC      = arm-eabi-gcc
 CXX     = arm-eabi-g++
 
-CFLAGS	=	-Wno-multichar -Wall -Os\
+CFLAGS	=	-Wno-multichar -Wall\
 		-Wno-multichar -mcpu=arm9tdmi -mtune=arm9tdmi \
  		-mcpu=arm9tdmi -mtune=arm9tdmi -fomit-frame-pointer\
 		-ffast-math -mthumb-interwork
@@ -129,12 +194,17 @@ ifdef USE_DEBUGGER
 	DEFINES += -DUSE_DEBUGGER
 	CFLAGS += -g
 endif
+
+ifdef USE_PROFILER
+	CFLAGS += -mpoke-function-name -finstrument-functions -g
+	DEFINES += -DUSE_PROFILER
+endif
 		
 CXXFLAGS=	$(CFLAGS) -Wno-non-virtual-dtor	 -Wno-non-virtual-dtor \
 		-fno-exceptions -fno-rtti
 
 ASFLAGS = -mcpu=arm9tdmi -mthumb-interwork
-DEFINES += -D__DS__ -DNDS -DARM9 -DNONSTANDARD_PORT -DDISABLE_FANCY_THEMES -DDISABLE_DEFAULT_SAVEFILEMANAGER
+DEFINES += -D__DS__ -DNDS -DARM9 -DNONSTANDARD_PORT -DDISABLE_FANCY_THEMES -DDISABLE_DEFAULT_SAVEFILEMANAGER -DARM
 ifdef USE_MAD
 	DEFINES += -DUSE_MAD
 endif
@@ -182,9 +252,14 @@ PORT_OBJS :=	$(portdir)/source/blitters.o $(portdir)/source/cdaudio.o $(portdir)
 		$(portdir)/../../../fs/ds/ds-fs.o $(portdir)/source/gbampsave.o $(portdir)/source/scummhelp.o\
 		$(portdir)/source/osystem_ds.o $(portdir)/source/portdefs.o $(portdir)/source/ramsave.o\
 		$(portdir)/source/scummconsole.o $(portdir)/source/touchkeyboard.o $(portdir)/source/zipreader.o\
-		$(portdir)/source/dsoptions.o $(portdir)/source/keys.o
+		$(portdir)/source/dsoptions.o $(portdir)/source/keys.o $(portdir)/source/wordcompletion.o
 		
-DATA_OBJS := $(portdir)/data/icons.o $(portdir)/data/keyboard.o $(portdir)/data/keyboard_pal.o $(portdir)/data/default_font.o
+ifdef USE_PROFILER
+	PORT_OBJS += $(portdir)/source/profiler/cyg-profile.o
+endif
+
+
+DATA_OBJS := $(portdir)/data/icons.o $(portdir)/data/keyboard.o $(portdir)/data/keyboard_pal.o $(portdir)/data/default_font.o $(portdir)/data/8x8font_tga.o
 			
 		
 COMPRESSOR_OBJS := $(portdir)/source/compressor/lz.o
@@ -209,7 +284,9 @@ FAT_OBJS :=  $(portdir)/source/fat/disc_io.o $(portdir)/source/fat/gba_nds_fat.o
 
 LIBCARTRESET_OBJS := $(portdir)/source/libcartreset/cartreset.o
 			
-			
+# Files in this list will be compiled with -O2, otherwise they will be compiled with -Os
+OPTLIST := actor.cpp ds_main.cpp osystem_ds.cpp blitters.cpp fmopl.cpp rate.cpp mixer.cpp
+#OPTLIST := 
 			
 OBJS := $(DATA_OBJS) $(LIBCARTRESET_OBJS) $(PORT_OBJS) $(COMPRESSOR_OBJS) $(FAT_OBJS) 
 		
@@ -269,6 +346,7 @@ endef
 #	rm $(*).tmp
 #endef
 
+
 ##############
 # Replacement rule for the one in makefile.common
 ##############
@@ -276,6 +354,7 @@ ifndef HAVE_GCC3
 # If you use GCC, disable the above and enable this for intelligent
 # dependency tracking. 
 .cpp.o:
+
 	$(MKDIR) $(*D)/$(DEPDIR)
 	$(CXX) -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d2" $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o
 #	$(ECHO) "$(*D)/" > $(*D)/$(DEPDIR)/$(*F).d
@@ -287,9 +366,19 @@ else
 # Also, with this GCC inserts additional dummy rules for the involved headers,
 # which ensures a smooth compilation even if said headers become obsolete.
 .cpp.o:
+#	echo !!!!!!!!!!!! $(notdir $<)
+#	ifeq ( $(notdir $<), $(findstring $(notdir $<), $(OPTLIST)) )
+#	 OPTFLAG=-O3
+#	else
+#	 OPTFLAG=-Os
+#	endif
+
+#	export OPTFLAG = ;
+#	echo !!!!!!!! $(OPTFLAG)
+
 	$(MKDIR) $(*D)/$(DEPDIR)
-#	$(CXX) -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o
-	$(CXX) -MMD -MF "$(*D)/$(DEPDIR)/$(*F).d"              $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o
+	$(CXX) -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o
+	$(CXX) -MMD -MF "$(*D)/$(DEPDIR)/$(*F).d"              $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o $(if $(findstring $(notdir $<), $(OPTLIST)), -O2, -Os)
 endif
 
 
@@ -333,8 +422,8 @@ endif
 
 #---------------------------------------------------------------------------------
 %.nds: %.bin
-	@echo ndstool -c $@ -9 scummvm.bin $(ARM7BIN) -b ../../$(LOGO) "$(shell basename $@);ScummVM 0.11.0svn;DS Port"
-	ndstool -c $@ -9 scummvm.bin $(ARM7BIN) -b ../../$(LOGO) "$(shell basename $@);ScummVM 0.11.0svn;DS Port"
+	@echo ndstool -c $@ -9 scummvm.bin $(ARM7BIN) -b ../../$(LOGO) "$(shell basename $@);ScummVM 0.10.0;DS Port"
+	ndstool -c $@ -9 scummvm.bin $(ARM7BIN) -b ../../$(LOGO) "$(shell basename $@);ScummVM 0.10.0;DS Port"
 	dsbuild $@ -l ../ndsloader.bin
 
 	padbin 16 $(basename $@).ds.gba
diff --git a/backends/platform/ds/arm9/source/blitters.cpp b/backends/platform/ds/arm9/source/blitters.cpp
deleted file mode 100644
index 9af3c5d611..0000000000
--- a/backends/platform/ds/arm9/source/blitters.cpp
+++ /dev/null
@@ -1,402 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * 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 "stdafx.h"
-#include "blitters.h"
-#define CHARSET_MASK_TRANSPARENCY 253
-
-//#define PERFECT_5_TO_4_RESCALING
-
-namespace DS {
-
-void asmDrawStripToScreen(int height, int width, byte const* text, byte const* src, byte* dst, 
-	int vsPitch, int vmScreenWidth, int textSurfacePitch) {
-
-
-	if (height <= 0) height = 1;
-	if (width < 4) return;
-	
-	
-	width &= ~4;
-//	src = (const byte *) (((int) (src)) & (~4));
-//	dst = (byte *) (((int) (dst)) & (~4));
-//	text = (const byte *) (((int) (text)) & (~4));
-	
-	asm (	"mov r5, %0\n"				// Height
-			"yLoop:\n"			
-			"mov r3, #0\n"				// X pos
-			
-			"xLoop:\n"
-			
-			"ldr r4, [%2, r3]\n"		// Load text layer word
-			"cmp r4, %5\n"
-			"bne singleByteCompare\n"
-			"ldr r4, [%3, r3]\n"
-			"str r4, [%4, r3]\n"
-			"add r3, r3, #4\n"
-			"cmp r3, %1\n"				// x == width?
-			"blt xLoop\n"
-			
-			"add %2, %2, %8\n"			// src += vs->pitch
-			"add %3, %3, %6\n"			// dst += _vm->_screenWidth
-			"add %4, %4, %7\n"			// text += _textSurface.pitch
-			"sub r5, r5, #1\n"			// y -= 1
-			"cmp r5, #0\n"				// y == 0?
-			"bne yLoop\n"
-			"b end\n"
-			
-			
-			"singleByteCompare:\n"
-			"ldrb r4, [%2, r3]\n"		// Load text byte
-			"cmps r4, %5, lsr #24\n"	// Compare with mask
-			"strneb r4, [%4, r3]\n"		// Store if not equal
-			"ldreqb r4, [%3, r3]\n"		// Otherwise Load src byte
-			"streqb r4, [%4, r3]\n"		// Store it
-			"add r3, r3, #1\n"
-
-			"ldrb r4, [%2, r3]\n"		// Load text byte
-			"cmps r4, %5, lsr #24\n"	// Compare with mask
-			"strneb r4, [%4, r3]\n"		// Store if not equal
-			"ldreqb r4, [%3, r3]\n"		// Otherwise Load src byte
-			"streqb r4, [%4, r3]\n"		// Store it
-			"add r3, r3, #1\n"
-			
-			"ldrb r4, [%2, r3]\n"		// Load text byte
-			"cmps r4, %5, lsr #24\n"	// Compare with mask
-			"strneb r4, [%4, r3]\n"		// Store if not equal
-			"ldreqb r4, [%3, r3]\n"		// Otherwise Load src byte
-			"streqb r4, [%4, r3]\n"		// Store it
-			"add r3, r3, #1\n"
-
-			"ldrb r4, [%2, r3]\n"		// Load text byte
-			"cmps r4, %5, lsr #24\n"	// Compare with mask
-			"strneb r4, [%4, r3]\n"		// Store if not equal
-			"ldreqb r4, [%3, r3]\n"		// Otherwise Load src byte
-			"streqb r4, [%4, r3]\n"		// Store it
-			"add r3, r3, #1\n"			
-
-			"cmps r3, %1\n"				// x == width?
-			"blt xLoop\n"				// Repeat
-			"add %2, %2, %8\n"			// src += vs->pitch
-			"add %3, %3, %6\n"			// dst += _vm->_screenWidth
-			"add %4, %4, %7\n"			// text += _textSurface.pitch
-			"sub r5, r5, #1\n"			// y -= 1
-			"cmp r5, #0\n"				// y == 0?
-			"bne yLoop\n"
-			
-			"end:\n"
-		: /* no output registers */
-		: "r" (height), "r" (width), "r" (text), "r" (src), "r" (dst), "r" (CHARSET_MASK_TRANSPARENCY | (CHARSET_MASK_TRANSPARENCY << 8) | (CHARSET_MASK_TRANSPARENCY << 16) | (CHARSET_MASK_TRANSPARENCY << 24)), 
-			"r" (vsPitch), "r" (vmScreenWidth), "r" (textSurfacePitch)
-		: "r5", "r3", "r4", "%2", "%3", "%4", "memory");
-}
-
-
-
-void asmCopy8Col(byte* dst, int dstPitch, const byte* src, int height) {
-	asm("ands r0, %3, #1\n"
-		 "addne %3, %3, #1\n"
-		 "bne roll2\n"
-			
-		 "yLoop2:\n"
-		 "ldr r0, [%2, #0]\n"
-		 "str r0, [%0, #0]\n"
-		 "ldr r0, [%2, #4]\n"
-		 "str r0, [%0, #4]\n"
-		 "add %0, %0, %1\n"
-		 "add %2, %2, %1\n"
-		 "roll2:\n"
-		 "ldr r0, [%2, #0]\n"
-		 "str r0, [%0, #0]\n"
-		 "ldr r0, [%2, #4]\n"
-		 "str r0, [%0, #4]\n"
-		 "add %0, %0, %1\n"
-		 "add %2, %2, %1\n"
-		 "subs %3, %3, #2\n"
-		 "bne yLoop2\n"		 
-
-		: /* no output registers */
-		: "r" (dst), "r" (dstPitch), "r" (src), "r" (height)
-		: "r0", "%0", "%2", "%3");
-}
-
-static bool isDivBy5Ready = false;
-static u32  DIV_BY_5[160];
-
-void ComputeDivBy5TableIFN()
-{
-    if (isDivBy5Ready)
-        return;
-    isDivBy5Ready = true;
-
-    for(int i=0; i<160; ++i)
-    {
-        DIV_BY_5[i] = (2*i+5)/10;
-    }                
-}
-
-#ifdef PERFECT_5_TO_4_RESCALING
-static inline void RescaleBlock_5x1555_To_4x1555( u16 s0, u16 s1, u16 s2, u16 s3, u16 s4,
-                                                    u16* dest)
-{
-    u32 bs0 = s0 & 0x1F;
-    u32 bs1 = s1 & 0x1F;
-    u32 bs2 = s2 & 0x1F;
-    u32 bs3 = s3 & 0x1F;
-    u32 bs4 = s4 & 0x1F;
-
-#if 0    
-    u32 gs0 = (s0 >> 5) & 0x1F;
-    u32 gs1 = (s1 >> 5) & 0x1F;
-    u32 gs2 = (s2 >> 5) & 0x1F;
-    u32 gs3 = (s3 >> 5) & 0x1F;
-    u32 gs4 = (s4 >> 5) & 0x1F;
-    
-    u32 rs0 = (s0 >> 10) & 0x1F;
-    u32 rs1 = (s1 >> 10) & 0x1F;
-    u32 rs2 = (s2 >> 10) & 0x1F;
-    u32 rs3 = (s3 >> 10) & 0x1F;
-    u32 rs4 = (s4 >> 10) & 0x1F;
-#else
-    // The compiler absolutely wants to use 0x1F as an immediate, which makes it unable to fold the shift during the and
-    u32 mask = 0x1F;
-    u32 gs0, gs1, gs2, gs3, gs4;
-    asm("and %0, %2, %1, lsr #5" : "=r"(gs0) : "r"(s0), "r"(mask) : );
-    asm("and %0, %2, %1, lsr #5" : "=r"(gs1) : "r"(s1), "r"(mask) : );
-    asm("and %0, %2, %1, lsr #5" : "=r"(gs2) : "r"(s2), "r"(mask) : );
-    asm("and %0, %2, %1, lsr #5" : "=r"(gs3) : "r"(s3), "r"(mask) : );
-    asm("and %0, %2, %1, lsr #5" : "=r"(gs4) : "r"(s4), "r"(mask) : );
-    u32 rs0, rs1, rs2, rs3, rs4;
-    asm("and %0, %2, %1, lsr #10" : "=r"(rs0) : "r"(s0), "r"(mask) : );
-    asm("and %0, %2, %1, lsr #10" : "=r"(rs1) : "r"(s1), "r"(mask) : );
-    asm("and %0, %2, %1, lsr #10" : "=r"(rs2) : "r"(s2), "r"(mask) : );
-    asm("and %0, %2, %1, lsr #10" : "=r"(rs3) : "r"(s3), "r"(mask) : );
-    asm("and %0, %2, %1, lsr #10" : "=r"(rs4) : "r"(s4), "r"(mask) : );
-#endif
-    
-    u32 rd0 = 4*rs0 +   rs1;
-    u32 rd1 = 2*rs1 + rs1 + 2*rs2;
-    u32 rd2 = 2*rs2 + 2*rs3 + rs3;
-    u32 rd3 =   rs3 + 4*rs4;
-    
-    u32 gd0 = 4*gs0 +   gs1;
-    u32 gd1 = 2*gs1 + gs1 + 2*gs2;
-    u32 gd2 = 2*gs2 + 2*gs3 + gs3;
-    u32 gd3 =   gs3 + 4*gs4;
-    
-    u32 bd0 = 4*bs0 +   bs1;
-    u32 bd1 = 2*bs1 + bs1 + 2*bs2;
-    u32 bd2 = 2*bs2 + 2*bs3 + bs3;
-    u32 bd3 =   bs3 + 4*bs4;
-    
-#if 0
-    // Offsetting for correct rounding
-    rd0 = rd0*2+5; rd1 = rd1*2+5; rd2 = rd2*2+5; rd3 = rd3*2+5;
-    gd0 = gd0*2+5; gd1 = gd1*2+5; gd2 = gd2*2+5; gd3 = gd3*2+5;
-    bd0 = bd0*2+5; bd1 = bd1*2+5; bd2 = bd2*2+5; bd3 = bd3*2+5;
-
-	rd0 = (rd0 * 51) >> 9; rd1 = (rd1 * 51) >> 9; rd2 = (rd2 * 51) >> 9; rd3 = (rd3 * 51) >> 9;
-	gd0 = (gd0 * 51) >> 9; gd1 = (gd1 * 51) >> 9; gd2 = (gd2 * 51) >> 9; gd3 = (gd3 * 51) >> 9;
-	bd0 = (bd0 * 51) >> 9; bd1 = (bd1 * 51) >> 9; bd2 = (bd2 * 51) >> 9; bd3 = (bd3 * 51) >> 9;
-#else
-	rd0 = DIV_BY_5[rd0]; rd1 = DIV_BY_5[rd1]; rd2 = DIV_BY_5[rd2]; rd3 = DIV_BY_5[rd3]; 
-	gd0 = DIV_BY_5[gd0]; gd1 = DIV_BY_5[gd1]; gd2 = DIV_BY_5[gd2]; gd3 = DIV_BY_5[gd3]; 
-	bd0 = DIV_BY_5[bd0]; bd1 = DIV_BY_5[bd1]; bd2 = DIV_BY_5[bd2]; bd3 = DIV_BY_5[bd3]; 
-#endif
-    
-    u32 d10 = 0x80008000 | (rd1 << 26) | (gd1 << 21) | (bd1 << 16) | (rd0 << 10) | (gd0 << 5) | bd0;
-    u32 d32 = 0x80008000 | (rd3 << 26) | (gd3 << 21) | (bd3 << 16) | (rd2 << 10) | (gd2 << 5) | bd2;
-    
-    ((u32*)dest)[0] = d10;
-    ((u32*)dest)[1] = d32;
-}
-#else
-static inline void RescaleBlock_5x1555_To_4x1555( u16 s0, u16 s1, u16 s2, u16 s3, u16 s4,
-                                                    u16* dest)
-{
-    u32 ar0bs0 = s0 & 0x7C1F;
-    u32 ar0bs1 = s1 & 0x7C1F;
-    u32 ar0bs2 = s2 & 0x7C1F;
-    u32 ar0bs3 = s3 & 0x7C1F;
-    u32 ar0bs4 = s4 & 0x7C1F;
-
-    u32 gs0 = s0 & 0x03E0;
-    u32 gs1 = s1 & 0x03E0;
-    u32 gs2 = s2 & 0x03E0;
-    u32 gs3 = s3 & 0x03E0;
-    u32 gs4 = s4 & 0x03E0;
-        
-    u32 ar0bd0 = (3*ar0bs0 +   ar0bs1) >> 2;
-    u32 ar0bd1 = (  ar0bs1 +   ar0bs2) >> 1;
-    u32 ar0bd2 = (  ar0bs2 +   ar0bs3) >> 1;
-    u32 ar0bd3 = (  ar0bs3 + 3*ar0bs4) >> 2;
-    
-    u32 gd0 = (3*gs0 +   gs1) >> 2;
-    u32 gd1 = (  gs1 +   gs2) >> 1;
-    u32 gd2 = (  gs2 +   gs3) >> 1;
-    u32 gd3 = (  gs3 + 3*gs4) >> 2;
-
-    u32 d0 = (ar0bd0 & 0xFC1F) | (gd0 & 0x03E0);
-    u32 d1 = (ar0bd1 & 0xFC1F) | (gd1 & 0x03E0);
-    u32 d2 = (ar0bd2 & 0xFC1F) | (gd2 & 0x03E0);
-    u32 d3 = (ar0bd3 & 0xFC1F) | (gd3 & 0x03E0);
-    
-    u32 d10 = 0x80008000 | (d1 << 16) | d0;
-    u32 d32 = 0x80008000 | (d3 << 16) | d2;
-    
-    ((u32*)dest)[0] = d10;
-    ((u32*)dest)[1] = d32;
-}
-#endif
-
-static inline void RescaleBlock_5x8888_To_4x1555( u32 s0, u32 s1, u32 s2, u32 s3, u32 s4,
-                                                    u16* dest)
-{
-    u32 d0 = 4*s0 +   s1;
-    u32 d1 = 2*s1 +   s1 + 2*s2;
-
-    u32 bd0 = (d0 << 24) >> 24;
-    u32 bd1 = (d1 << 24) >> 24;
-    u32 gd0 = (d0 << 16) >> 24;
-    u32 gd1 = (d1 << 16) >> 24;    
-    u32 rd0 = (d0 >> 16);
-    u32 rd1 = (d1 >> 16);
-    
-	rd0 = DIV_BY_5[rd0]; rd1 = DIV_BY_5[rd1];
-	gd0 = DIV_BY_5[gd0]; gd1 = DIV_BY_5[gd1];
-	bd0 = DIV_BY_5[bd0]; bd1 = DIV_BY_5[bd1];    
-    u32 d10 = 0x80008000 | (rd1 << 26) | (gd1 << 21) | (bd1 << 16) | (rd0 << 10) | (gd0 << 5) | bd0;
-    ((u32*)dest)[0] = d10;
-
-    u32 d2 = 2*s2 + 2*s3 +   s3;
-    u32 d3 =   s3 + 4*s4;
-
-    u32 bd2 = (d2 << 24) >> 24;
-    u32 bd3 = (d3 << 24) >> 24;
-    u32 gd2 = (d2 << 16) >> 24;
-    u32 gd3 = (d3 << 16) >> 24;
-    u32 rd2 = (d2 >> 16);
-    u32 rd3 = (d3 >> 16);
-
-    rd2 = DIV_BY_5[rd2]; rd3 = DIV_BY_5[rd3]; 
-    gd2 = DIV_BY_5[gd2]; gd3 = DIV_BY_5[gd3]; 
-    bd2 = DIV_BY_5[bd2]; bd3 = DIV_BY_5[bd3]; 
-    u32 d32 = 0x80008000 | (rd3 << 26) | (gd3 << 21) | (bd3 << 16) | (rd2 << 10) | (gd2 << 5) | bd2;
-    
-    ((u32*)dest)[1] = d32;
-}
-
-// Can't work in place
-#ifdef PERFECT_5_TO_4_RESCALING
-static inline void Rescale_320xPAL8Scanline_To_256x1555Scanline(u16* dest, const u8* src, const u32* palette)
-{
-    ComputeDivBy5TableIFN();
-    
-    for(size_t i=0; i<64; ++i)
-    {
-        u32 s0 = palette[src[5*i+0]];
-        u32 s1 = palette[src[5*i+1]];
-        u32 s2 = palette[src[5*i+2]];
-        u32 s3 = palette[src[5*i+3]];
-        u32 s4 = palette[src[5*i+4]];
-
-        RescaleBlock_5x8888_To_4x1555(s0, s1, s2, s3, s4, dest+4*i);
-    }
-}
-#else
-static inline void Rescale_320xPAL8Scanline_To_256x1555Scanline(u16* dest, const u8* src, const u16* palette)
-{
-    for(size_t i=0; i<64; ++i)
-    {
-        u16 s0 = palette[src[5*i+0]];
-        u16 s1 = palette[src[5*i+1]];
-        u16 s2 = palette[src[5*i+2]];
-        u16 s3 = palette[src[5*i+3]];
-        u16 s4 = palette[src[5*i+4]];
-
-        RescaleBlock_5x1555_To_4x1555(s0, s1, s2, s3, s4, dest+4*i);
-    }
-}
-#endif
-
-
-// Can work in place, because it's a contraction
-static inline void Rescale_320x1555Scanline_To_256x1555Scanline(u16* dest, const u16* src)
-{
-    ComputeDivBy5TableIFN();
-    
-    for(size_t i=0; i<64; ++i)
-    {
-        u16 s0 = src[5*i+0];
-        u16 s1 = src[5*i+1];
-        u16 s2 = src[5*i+2];
-        u16 s3 = src[5*i+3];
-        u16 s4 = src[5*i+4];
-
-        RescaleBlock_5x1555_To_4x1555(s0, s1, s2, s3, s4, dest+4*i);
-    }
-}
-
-#ifdef PERFECT_5_TO_4_RESCALING
-void Rescale_320x256xPAL8_To_256x256x1555(u16* dest, const u8* src, const u16* palette, int destStride, int srcStride)
-{
-	u32 fastRam[768];
-
-    // Palette lookup -> 0_888
-    for(size_t i=0; i<256; ++i)
-    {
-        u32 col = palette[i];
-        u32 result = col & 0x0000001F;
-        result |= (col << 3) & 0x00001F00;
-        result |= (col << 6) & 0x001F0000;
-
-        fastRam[i] = result;
-    }
-
-	for(size_t i=0; i<200; ++i)
-	{
-		Rescale_320xPAL8Scanline_To_256x1555Scanline(dest + i*destStride, src + i *srcStride, fastRam);			
-	}
-}
-#else
-void Rescale_320x256xPAL8_To_256x256x1555(u16* dest, const u8* src, const u16* palette, int destStride, int srcStride)
-{
-	u16 fastRam[256];
-    for(size_t i=0; i<128; ++i)
-        ((u32*)fastRam)[i] = ((const u32*)palette)[i];
-
-	for(size_t i=0; i<200; ++i)
-	{
-		Rescale_320xPAL8Scanline_To_256x1555Scanline(dest + i*destStride, src + i *srcStride, fastRam);			
-	}
-}
-#endif
-
-void Rescale_320x256x1555_To_256x256x1555(u16* dest, const u16* src, int destStride, int srcStride)
-{
-	for(size_t i=0; i<200; ++i)
-	{
-		Rescale_320x1555Scanline_To_256x1555Scanline(dest + i*destStride, src + i *srcStride);
-	}
-}
-
-}
diff --git a/backends/platform/ds/arm9/source/blitters.h b/backends/platform/ds/arm9/source/blitters.h
index 9fb50cdf0d..fe6966fdae 100644
--- a/backends/platform/ds/arm9/source/blitters.h
+++ b/backends/platform/ds/arm9/source/blitters.h
@@ -23,6 +23,10 @@
  #ifndef _BLITTERS_H_
  #define _BLITTERS_H_
 
+#define USING_ARM_BLITTERS
+
+#ifndef USING_ARM_BLITTERS
+
 namespace DS {
 
 void asmDrawStripToScreen(int height, int width, byte const* text, byte const* src, byte* dst, 
@@ -33,4 +37,18 @@ void Rescale_320x256x1555_To_256x256x1555(u16* dest, const u16* src, int destStr
 
 }
 	
+#else
+
+extern "C" {
+
+void asmDrawStripToScreen(int height, int width, byte const* text, byte const* src, byte* dst, 
+	int vsPitch, int vmScreenWidth, int textSurfacePitch);
+void asmCopy8Col(byte* dst, int dstPitch, const byte* src, int height);
+void Rescale_320x256xPAL8_To_256x256x1555(u16* dest, const u8* src, const u16* palette, int destStride, int srcStride);
+void Rescale_320x256x1555_To_256x256x1555(u16* dest, const u16* src, int destStride, int srcStride);
+
+}
+
+#endif
+
 #endif
diff --git a/backends/platform/ds/arm9/source/blitters.s b/backends/platform/ds/arm9/source/blitters.s
new file mode 100644
index 0000000000..2f14c5a140
--- /dev/null
+++ b/backends/platform/ds/arm9/source/blitters.s
@@ -0,0 +1,339 @@
+@ ScummVM Scumm Interpreter
+@ Copyright (C) 2007 The ScummVM project
+@
+@ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+@
+@ $URL:  $
+@ $Id:  $
+@
+@ @author Robin Watts (robin@wss.co.uk)
+
+	.text
+	
+	.global	asmDrawStripToScreen
+	.global	asmCopy8Col
+	.global	Rescale_320x256xPAL8_To_256x256x1555
+	.global	Rescale_320x256x1555_To_256x256x1555
+
+	@ ARM implementation of asmDrawStripToScreen.
+	@
+	@ C prototype would be:
+	@
+	@ extern "C" void asmDrawStripToScreen(int         height,
+	@                                      int         width,
+	@                                      byte const *text,
+	@                                      byte const *src,
+	@                                      byte       *dst,
+	@                                      int         vsPitch,
+	@                                      int         vsScreenWidth,
+	@                                      int         textSurfacePitch);
+	@
+	@ In addition, we assume that text, src and dst are all word (4 byte)
+	@ aligned. This is the same assumption that the old 'inline' version
+	@ made.
+asmDrawStripToScreen:
+	@ r0 = height
+	@ r1 = width
+	@ r2 = text
+	@ r3 = src
+	MOV	r12,r13
+	STMFD	r13!,{r4-r7,r9-r11,R14}
+	LDMIA	r12,{r4,r5,r6,r7}
+	@ r4 = dst
+	@ r5 = vsPitch
+	@ r6 = vmScreenWidth
+	@ r7 = textSurfacePitch
+
+	CMP	r0,#0			@ If height<=0
+	MOVLE	r0,#1			@    height=1
+	CMP	r1,#4			@ If width<4
+	BLT	end			@    return
+
+	@ Width &= ~4 ? What's that about then? Width &= ~3 I could have
+	@ understood...
+	BIC	r1,r1,#4
+
+	SUB	r5,r5,r1		@ vsPitch          -= width
+	SUB	r6,r6,r1		@ vmScreenWidth    -= width
+	SUB	r7,r7,r1		@ textSurfacePitch -= width
+	MOV	r10,#253
+	ORR	r10,r10,r10,LSL #8
+	ORR	r10,r10,r10,LSL #16	@ r10 = mask
+yLoop:
+	MOV	r14,r1			@ r14 = width
+xLoop:
+	LDR	r12,[r2],#4		@ r12 = [text]
+	LDR	r11,[r3],#4		@ r11 = [src]
+	CMP	r12,r10
+	BNE	singleByteCompare
+	SUBS	r14,r14,#4
+	STR	r11,[r4], #4		@ r4 = [dst]
+	BGT	xLoop
+
+	ADD	r2,r2,r7		@ text += textSurfacePitch
+	ADD	r3,r3,r5		@ src  += vsPitch
+	ADD	r4,r4,r6		@ dst  += vmScreenWidth
+	SUBS	r0,r0,#1
+	BGT	yLoop
+	LDMFD	r13!,{r4-r7,r9-r11,PC}
+
+singleByteCompare:
+	MOV	r9,r12,LSR #24		@ r9 = 1st byte of [text]
+	CMP	r9,r10,LSR #24		@ if (r9 == mask)
+	MOVEQ	r9,r11,LSR #24		@     r9 = 1st byte of [src]
+	ORR	r12,r9,r12,LSL #8	@ r12 = combine r9 and r12
+
+	MOV	r9,r12,LSR #24		@ r9 = 1st byte of [text]
+	CMP	r9,r10,LSR #24		@ if (r9 == mask)
+	MOVEQ	r9,r11,LSR #24		@     r9 = 1st byte of [src]
+	ORR	r12,r9,r12,LSL #8	@ r12 = combine r9 and r12
+
+	MOV	r9,r12,LSR #24		@ r9 = 1st byte of [text]
+	CMP	r9,r10,LSR #24		@ if (r9 == mask)
+	MOVEQ	r9,r11,LSR #24		@     r9 = 1st byte of [src]
+	ORR	r12,r9,r12,LSL #8	@ r12 = combine r9 and r12
+
+	MOV	r9,r12,LSR #24		@ r9 = 1st byte of [text]
+	CMP	r9,r10,LSR #24		@ if (r9 == mask)
+	MOVEQ	r9,r11,LSR #24		@     r9 = 1st byte of [src]
+	ORR	r12,r9,r12,LSL #8	@ r12 = combine r9 and r12
+
+	STR	r12,[r4],#4
+	SUBS	r14,r14,#4
+	BGT	xLoop
+
+	ADD	r2,r2,r7		@ text += textSurfacePitch
+	ADD	r3,r3,r5		@ src  += vsPitch
+	ADD	r4,r4,r6		@ dst  += vmScreenWidth
+	SUBS	r0,r0,#1
+	BGT	yLoop
+end:
+	LDMFD	r13!,{r4-r7,r9-r11,PC}
+
+
+	@ ARM implementation of asmCopy8Col
+	@
+	@ C prototype would be:
+	@
+	@ extern "C" void asmCopy8Col(byte       *dst,
+	@                             int         dstPitch,
+	@                             const byte *src,
+	@                             int         height);
+	@
+	@ In addition, we assume that src and dst are both word (4 byte)
+	@ aligned. This is the same assumption that the old 'inline' version
+	@ made.
+asmCopy8Col:
+	@ r0 = dst
+	@ r1 = dstPitch
+	@ r2 = src
+	@ r3 = height
+	STMFD	r13!,{r14}
+	SUB	r1,r1,#4
+	
+	TST	r3,#1
+	ADDNE   r3,r3,#1
+	BNE	roll2
+yLoop2:
+	LDR	r12,[r2],#4
+	LDR	r14,[r2],r1
+	STR	r12,[r0],#4
+	STR	r14,[r0],r1
+roll2:
+	LDR	r12,[r2],#4
+	LDR	r14,[r2],r1
+	SUBS	r3,r3,#2
+	STR	r12,[r0],#4
+	STR	r14,[r0],r1
+	BNE	yLoop2
+
+	LDMFD	r13!,{PC}
+
+
+	@ ARM implementation of Rescale_320x256x1555_To_256x256x1555
+	@
+	@ C prototype would be:
+	@
+	@ extern "C" void Rescale_320x256x1555_To_256x256x1555(
+	@                                      u16        *dst,
+	@                                      const u16  *src,
+	@                                      int         dstStride,
+	@                                      int         srcStride);
+Rescale_320x256x1555_To_256x256x1555:
+	@ r0 = dst
+	@ r1 = src
+	@ r2 = dstStride
+	@ r3 = srcStride
+	STMFD	r13!,{r4-r5,r8-r11,r14}
+	
+	SUB	r2,r2,#64*5		@ srcStride -= line length
+	SUB	r3,r3,#64*4		@ dstStride -= line length
+
+	MOV	r8,    #0x0000001F
+	ORR	r8, r8,#0x00007C00
+	ORR	r8, r8,#0x03E00000	@ r8 = mask
+	MOV	r5, #200		@ r5 = y
+yLoop3:
+	MOV	r4, #64			@ r4 = x
+xLoop3:	
+	LDRH	r9, [r0],#2		@ r9 = src0
+	LDRH	r10,[r0],#2		@ r10= src1
+	LDRH	r11,[r0],#2		@ r11= src2
+	LDRH	r12,[r0],#2		@ r12= src3
+	LDRH	r14,[r0],#2		@ r14= src4
+
+	ORR	r9, r9, r9, LSL #16	@ r9 = src0 | src0
+	ORR	r10,r10,r10,LSL #16	@ r10= src1 | src1
+	ORR	r11,r11,r11,LSL #16	@ r11= src2 | src2
+	ORR	r12,r12,r12,LSL #16	@ r12= src3 | src3
+	ORR	r14,r14,r14,LSL #16	@ r13= src4 | src4
+
+	AND	r9, r9, r8		@ r9 = 0 | G0 | 0 | B0 | 0 | R0
+	AND	r10,r10,r8		@ r10= 0 | G1 | 0 | B1 | 0 | R1
+	AND	r11,r11,r8		@ r11= 0 | G2 | 0 | B2 | 0 | R2
+	AND	r12,r12,r8		@ r12= 0 | G3 | 0 | B3 | 0 | R3
+	AND	r14,r14,r8		@ r14= 0 | G4 | 0 | B4 | 0 | R4
+
+	ADD	r9, r9, r9, LSL #1	@ r9 = 3*src0
+	ADD	r9, r9, r10		@ r9 = dst0<<2
+	ADD	r10,r10,r11		@ r10= dst1
+	ADD	r11,r11,r12		@ r11= dst2
+	ADD	r12,r12,r14		@ r12= src3 + src4
+	ADD	r12,r12,r14,LSL #1	@ r12= src3 + src4*3 = dst3<<2
+	
+	AND	r9, r8, r9, LSR #2	@ r9 = dst0 (split)
+	AND	r10,r8, r10,LSR #1	@ r10= dst1 (split)
+	AND	r11,r8, r11,LSR #1	@ r11= dst2 (split)
+	AND	r12,r8, r12,LSR #2	@ r12= dst3 (split)
+
+	ORR	r9, r9, r9, LSR #16	@ r9 = dst0
+	ORR	r10,r10,r10,LSR #16	@ r10= dst1
+	ORR	r11,r11,r11,LSR #16	@ r11= dst2
+	ORR	r12,r12,r12,LSR #16	@ r12= dst3
+
+	ORR	r9, r9, #0x8000
+	ORR	r10,r10,#0x8000
+	ORR	r11,r11,#0x8000
+	ORR	r12,r12,#0x8000
+	
+	STRH	r9, [r1],#2
+	STRH	r10,[r1],#2
+	STRH	r11,[r1],#2
+	STRH	r12,[r1],#2
+
+	SUBS	r4,r4,#1
+	BGT	xLoop3
+	
+	ADD	r0,r0,r2,LSL #1
+	ADD	r1,r2,r3,LSL #1
+	SUBS	r5,r5,#1
+	BGT	yLoop3
+
+	LDMFD	r13!,{r4-r5,r8-r11,PC}
+
+	@ ARM implementation of Rescale_320x256xPAL8_To_256x256x1555
+	@
+	@ C prototype would be:
+	@
+	@ extern "C" void Rescale_320x256xPAL8_To_256x256x1555(
+	@                                      u16        *dst,
+	@                                      const u8   *src,
+	@                                      int         dstStride,
+	@                                      int         srcStride,
+	@                                      const u16  *pal);
+	@
+	@ This is a slight reordering of the params from the existing C one.
+	@ Sorry, but it makes the code easier.
+Rescale_320x256xPAL8_To_256x256x1555:
+	@ r0 = dst
+	@ r1 = src
+	@ r2 = dstStride
+	@ r3 = srcStride
+	STMFD	r13!,{r4-r5,r8-r11,r14}
+	MOV	r8,    #0x0000001F
+	ORR	r8, r8,#0x00007C00
+	ORR	r8, r8,#0x03E00000	@ r8 = mask
+	LDR	r9, [r13,#7*4]		@ r9 = palette
+	
+	SUB	r13,r13,#256*4		@ r13 = 1K of space on the stack.
+	MOV	r5, r13			@ r5 points to this space
+	MOV	r14,#256
+palLoop:
+	LDRH	r10,[r9],#2		@ r10 = palette entry
+	SUBS	r14,r14,#1
+	ORR	r10,r10,r10,LSL #16
+	AND	r10,r10,r8		@ r10 = separated palette entry
+	STR	r10,[r5], #4
+	BGT	palLoop
+	
+	SUB	r2,r2,#64*5		@ srcStride -= line length
+	SUB	r3,r3,#64*4		@ dstStride -= line length
+
+	MOV	r5,#200			@ r5 = y
+yLoop4:
+	MOV	r4,#64			@ r4 = x
+xLoop4:	
+	LDRB	r9, [r0],#1		@ r9 = src0
+	LDRB	r10,[r0],#1		@ r10= src1
+	LDRB	r11,[r0],#1		@ r11= src2
+	LDRB	r12,[r0],#1		@ r12= src3
+	LDRB	r14,[r0],#1		@ r14= src4
+
+	LDR	r9, [r13,r9, LSL #2]	@ r9 = pal[src0]
+	LDR	r10,[r13,r10,LSL #2]	@ r10= pal[src1]
+	LDR	r11,[r13,r11,LSL #2]	@ r11= pal[src2]
+	LDR	r12,[r13,r12,LSL #2]	@ r12= pal[src3]
+	LDR	r14,[r13,r14,LSL #2]	@ r13= pal[src4]
+
+	ADD	r9, r9, r9, LSL #1	@ r9 = 3*src0
+	ADD	r9, r9, r10		@ r9 = dst0<<2
+	ADD	r10,r10,r11		@ r10= dst1
+	ADD	r11,r11,r12		@ r11= dst2
+	ADD	r12,r12,r14		@ r12= src3 + src4
+	ADD	r12,r12,r14,LSL #1	@ r12= src3 + src4*3 = dst3<<2
+	
+	AND	r9, r8, r9, LSR #2	@ r9 = dst0 (split)
+	AND	r10,r8, r10,LSR #1	@ r10= dst1 (split)
+	AND	r11,r8, r11,LSR #1	@ r11= dst2 (split)
+	AND	r12,r8, r12,LSR #2	@ r12= dst3 (split)
+
+	ORR	r9, r9, r9, LSR #16	@ r9 = dst0
+	ORR	r10,r10,r10,LSR #16	@ r10= dst1
+	ORR	r11,r11,r11,LSR #16	@ r11= dst2
+	ORR	r12,r12,r12,LSR #16	@ r12= dst3
+
+	ORR	r9, r9, #0x8000
+	ORR	r10,r10,#0x8000
+	ORR	r11,r11,#0x8000
+	ORR	r12,r12,#0x8000
+	
+	STRH	r9, [r1],#2
+	STRH	r10,[r1],#2
+	STRH	r11,[r1],#2
+	STRH	r12,[r1],#2
+
+	SUBS	r4,r4,#1
+	BGT	xLoop4
+	
+	ADD	r0,r0,r2
+	ADD	r1,r2,r3,LSL #1
+	SUBS	r5,r5,#1
+	BGT	yLoop4
+
+	ADD	r13,r13,#256*4
+
+	LDMFD	r13!,{r4-r5,r8-r11,PC}
+
+ 	  	 
diff --git a/backends/platform/ds/arm9/source/dsmain.cpp b/backends/platform/ds/arm9/source/dsmain.cpp
index bd7df9b977..48632533ef 100644
--- a/backends/platform/ds/arm9/source/dsmain.cpp
+++ b/backends/platform/ds/arm9/source/dsmain.cpp
@@ -44,9 +44,32 @@
 // - Delete saves?
 // - Software scaler?
 // - 100% scale
+
+// - Arrow keys cause key events when keyboard enabled - Done
+// - Mouse cursor display - Done
+// - Disable scaler on options menu - Done
+// - Fix scale icons on top screen - Done
+// - Fseek optimisation? - No need
+// - Fix agi hack to be cleaner - done
+// - Fix not typing looong words - Done
+// - Show keyboard by default in AGI games
+// - Fix mouse moving when cursor on keyboard screen - Done
+// - Fix 'fit' thingy always appearing - Done
+// - check cine backbuffer code - Done
+// - Add long filename support - Done
+// - New icons
+// - Add key config for gob engine: Start:F1, Shift-numbers: F keys - Done
+// - Fix [ds] appearing in game menu
+
 // - Find out what's going wrong when you turn the console off
+// - enable console when asserting
+
+// - AGI: Adding keyboard hack
+// - CINE: Framebuffer modification should check if it works without, fix for overwrite crash
+// - KYRA: GetFileSize modification
+
 
-#define USE_LIBCARTRESET
+//#define USE_LIBCARTRESET
 //#define USE_BUILT_IN_DRIVER_SELECTION
 
 #include <nds.h>
@@ -78,6 +101,8 @@
 #include "blitters.h"
 #include "cartreset_nolibfat.h"
 #include "keys.h"
+#include "profiler/cyg-profile.h"
+
 
 namespace DS {
 
@@ -151,13 +176,16 @@ bool displayModeIs8Bit = false;
 // Game id
 u8 gameID;
 
-bool consoleEnable = true;
+bool consoleEnable = false;
 bool gameScreenSwap = false;
 bool isCpuScalerEnabled();
 //#define HEAVY_LOGGING
 
 MouseMode mouseMode;
 
+int storedMouseX = 0;
+int storedMouseY = 0;
+
 // Sprites
 SpriteEntry sprites[128];
 SpriteEntry spritesMain[128];
@@ -173,6 +201,9 @@ bool keyboardIcon = false;
 
 // Touch
 int touchScX, touchScY, touchX, touchY;
+int mouseHotspotX, mouseHotspotY;
+bool cursorEnable = false;
+bool mouseCursorVisible = true;
 
 // Dragging
 int dragStartX, dragStartY;
@@ -188,20 +219,12 @@ int gameHeight = 200;
 
 // Scale
 bool twoHundredPercentFixedScale = false;
+#define NUM_SUPPORTED_GAMES 17
 
-enum controlType {
-	CONT_SCUMM_ORIGINAL,
-	CONT_SCUMM_SAMNMAX,
-	CONT_SKY,
-	CONT_SIMON,
-};
-
-struct gameListType {
-	char 			gameId[16];
-	controlType 	control;
-};
+#ifdef USE_PROFILER
+int hBlankCount = 0;
+#endif
 
-#define NUM_SUPPORTED_GAMES 15
 
 gameListType gameList[NUM_SUPPORTED_GAMES] = {
 	// Unknown game - use normal SCUMM controls
@@ -222,8 +245,10 @@ gameListType gameList[NUM_SUPPORTED_GAMES] = {
 	{"sky",			CONT_SKY},
 	{"simon1",		CONT_SIMON},
 	{"simon2",		CONT_SIMON},
-	{"gob1",		CONT_SCUMM_ORIGINAL},
-	{"queen",		CONT_SCUMM_ORIGINAL}
+	{"gob",		CONT_GOBLINS},
+	{"queen",		CONT_SCUMM_ORIGINAL},
+	{"cine",		CONT_FUTURE_WARS},
+	{"agi",			CONT_AGI}
 };
 
 gameListType* currentGame = NULL;
@@ -259,9 +284,11 @@ int getKeysChanged();
 void updateStatus();
 void triggerIcon(int imageNum);
 void setIcon(int num, int x, int y, int imageNum, int flags, bool enable);
+void setIconMain(int num, int x, int y, int imageNum, int flags, bool enable);
 
 TransferSound soundControl;
 
+
 bool isCpuScalerEnabled()
 {
 	return (ConfMan.hasKey("cpu_scaler", "ds") && ConfMan.getBool("cpu_scaler", "ds"));
@@ -332,20 +359,21 @@ void initSprites() {
 
 void saveGameBackBuffer() {
 #ifdef DISABLE_SCUMM
-	if (savedBuffer == NULL) savedBuffer = new u8[gameWidth * gameHeight];
+    if (savedBuffer == NULL) savedBuffer = new u8[gameWidth * gameHeight];
     for (int r = 0; r < gameHeight; r++) {
 		memcpy(savedBuffer + (r * gameWidth), ((u8 *) (get8BitBackBuffer())) + (r * 512), gameWidth);
+    }
 #endif
 }
 
 void restoreGameBackBuffer() {
 #ifdef DISABLE_SCUMM
 	if (savedBuffer) {
-        for (int r = 0; r < gameHeight; r++) {
-            memcpy(((u8 *) (BG_GFX_SUB)) + (r * 512), savedBuffer + (r * gameWidth), gameWidth);
-            memcpy(((u8 *) (get8BitBackBuffer())) + (r * 512), savedBuffer + (r * gameWidth), gameWidth);
-        }
-		
+		for (int r = 0; r < gameHeight; r++) {
+			memcpy(((u8 *) (BG_GFX_SUB)) + (r * 512), savedBuffer + (r * gameWidth), gameWidth);
+			memcpy(((u8 *) (get8BitBackBuffer())) + (r * 512), savedBuffer + (r * gameWidth), gameWidth);
+		}
+			
 		delete savedBuffer;
 		savedBuffer = NULL;
 	}
@@ -413,7 +441,7 @@ void initGame() {
 
 	//strcpy(gameName, ConfMan.getActiveDomain().c_str());
 	strcpy(gameName, ConfMan.get("gameid").c_str());
-//	consolePrintf("\n\n\n\nCurrent game: '%s' %d\n", gameName, gameName[0]);
+	//consolePrintf("\n\n\n\nCurrent game: '%s' %d\n", gameName, gameName[0]);
 
 	currentGame = &gameList[0];		// Default game
 	
@@ -590,7 +618,51 @@ void checkSleepMode() {
 	}
 }
 
-void setCursorIcon(const u8* icon, uint w, uint h, byte keycolor) {
+void setShowCursor(bool enable)
+{
+	if (currentGame->control == CONT_SCUMM_SAMNMAX)
+	{
+		if (cursorEnable) {
+			sprites[1].attribute[0] = ATTR0_BMP | 150;
+		} else {
+			sprites[1].attribute[0] = ATTR0_DISABLED;
+		}
+
+	}
+
+	cursorEnable = enable;
+}
+
+void setMouseCursorVisible(bool enable)
+{
+	mouseCursorVisible = enable;
+}
+
+void setCursorIcon(const u8* icon, uint w, uint h, byte keycolor, int hotspotX, int hotspotY) {
+
+	mouseHotspotX = hotspotX;
+	mouseHotspotY = hotspotY;
+
+	{
+		int off = 128*64;
+	
+	
+		memset(SPRITE_GFX + off, 0, 32 * 32 * 2);
+	
+		for (uint y=0; y<h; y++) {
+			for (uint x=0; x<w; x++) {
+				int color = icon[y*w+x];
+	
+				if (color == keycolor) {
+					SPRITE_GFX[off+(y)*32+x] = 0x0000; // black background
+				} else {
+					SPRITE_GFX[off+(y)*32+x] = BG_PALETTE[color] | 0x8000;
+				}
+			}
+		}
+	
+	}
+
 	if (currentGame->control != CONT_SCUMM_SAMNMAX)
 		return;
 
@@ -619,6 +691,7 @@ void setCursorIcon(const u8* icon, uint w, uint h, byte keycolor) {
 	for (uint y=0; y<h; y++) {
 		for (uint x=0; x<w; x++) {
 			int color = icon[y*w+x];
+
 			if (color == keycolor) {
 				SPRITE_GFX_SUB[off+(y+1+offset)*64+(x+1)] = 0x8000; // black background
 			} else {
@@ -626,10 +699,18 @@ void setCursorIcon(const u8* icon, uint w, uint h, byte keycolor) {
 			}
 		}
 	}
-
-	sprites[1].attribute[0] = ATTR0_BMP | 150;
-	sprites[1].attribute[1] = ATTR1_SIZE_64 | pos;
-	sprites[1].attribute[2] = ATTR2_ALPHA(1) | 48;
+	
+	
+	if ((cursorEnable))
+	{
+		sprites[1].attribute[0] = ATTR0_BMP | 150;
+		sprites[1].attribute[1] = ATTR1_SIZE_64 | pos;
+		sprites[1].attribute[2] = ATTR2_ALPHA(1) | 48;
+	} else {
+		sprites[1].attribute[0] = ATTR0_DISABLED | 150;
+		sprites[1].attribute[1] = ATTR1_SIZE_64 | pos;
+		sprites[1].attribute[2] = ATTR2_ALPHA(1) | 48;
+	}
 }
 
 
@@ -734,7 +815,7 @@ void displayMode16BitFlipBuffer() {
         #endif
 		const u8* back = (const u8*)get8BitBackBuffer();
 		u16* base = BG_GFX + 0x10000;
-		DS::Rescale_320x256xPAL8_To_256x256x1555( base,
+		Rescale_320x256xPAL8_To_256x256x1555( base,
 											      back,
 											      BG_PALETTE,
 											      256,
@@ -867,7 +948,7 @@ void addIndyFightingKeys() {
 	event.type = Common::EVENT_KEYDOWN;
 	event.kbd.flags = 0;
 	
-	consolePrintf("Fight keys\n");
+//	consolePrintf("Fight keys\n");
 
 	if ((getKeysDown() & KEY_L)) {
 		indyFightRight = false;
@@ -877,7 +958,7 @@ void addIndyFightingKeys() {
 		indyFightRight = true;
 	}
 
-	consolePrintf("ifr:%d\n", indyFightRight);
+//	consolePrintf("ifr:%d\n", indyFightRight);
 
 	if ((getKeysChanged() & KEY_UP)) {
 		event.type = getKeyEvent(KEY_UP);
@@ -966,10 +1047,10 @@ void setKeyboardEnable(bool en) {
 	if (keyboardEnable) {
 
 
-		DS::drawKeyboard(1, 12, backupBank);
+		DS::drawKeyboard(1, 14, backupBank);
 		
 		
-		SUB_BG1_CR = BG_TILE_BASE(1) | BG_MAP_BASE(12);
+		SUB_BG1_CR = BG_TILE_BASE(1) | BG_MAP_BASE(14);
 
 		if (displayModeIs8Bit) {
 			SUB_DISPLAY_CR |= DISPLAY_BG1_ACTIVE;	// Turn on keyboard layer
@@ -1025,6 +1106,16 @@ void addEventsToQueue() {
 	Common::Event event;
 
 	
+#ifdef USE_PROFILER
+	if (keysDown() & KEY_R) {
+		cygprofile_begin();
+		cygprofile_enable();
+	}
+	if (keysDown() & KEY_L) {
+		cygprofile_disable();
+		cygprofile_end();
+	}
+#endif
 
 	
 	if (system->isEventQueueEmpty()) {
@@ -1051,7 +1142,7 @@ void addEventsToQueue() {
 
 			if (!indyFightState) {
 
-				if ((!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R))) {	
+				if ((!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R)) && (getKeysChanged() & KEY_B)) {	
 					event.kbd.keycode = 27;		
 					event.kbd.ascii = 27;		
 					event.kbd.flags = 0;
@@ -1073,8 +1164,37 @@ void addEventsToQueue() {
 				}
 			}
 	
+			if (!((getKeysHeld() & KEY_L) || (getKeysHeld() & KEY_R)) && (getKeyboardEnable())) {
+				event.kbd.flags = 0;
+
+				if (getKeysChanged() & KEY_LEFT) {
+					event.kbd.keycode = SDLK_LEFT;
+					event.kbd.ascii = SDLK_LEFT;
+					event.type = getKeyEvent(KEY_LEFT);
+				}
+
+				if (getKeysChanged() & KEY_RIGHT) {
+					event.kbd.keycode = SDLK_RIGHT;
+					event.kbd.ascii = SDLK_RIGHT;
+					event.type = getKeyEvent(KEY_RIGHT);
+				}
+
+				if (getKeysChanged() & KEY_UP) {
+					event.kbd.keycode = SDLK_UP;
+					event.kbd.ascii = SDLK_UP;
+					event.type = getKeyEvent(KEY_UP);
+				}
+
+				if (getKeysChanged() & KEY_DOWN) {
+					event.kbd.keycode = SDLK_DOWN;
+					event.kbd.ascii = SDLK_DOWN;
+					event.type = getKeyEvent(KEY_DOWN);
+				}
+					
+				system->addEvent(event);
+			}
 	
-			if (!((getKeysHeld() & KEY_L) || (getKeysHeld() & KEY_R)) && (!getIndyFightState())) {
+			if (!((getKeysHeld() & KEY_L) || (getKeysHeld() & KEY_R)) && (!getIndyFightState()) && (!getKeyboardEnable())) {
 
 				if ((getKeysDown() & KEY_A) && (!indyFightState)) {
 					gameScreenSwap = !gameScreenSwap;
@@ -1084,16 +1204,25 @@ void addEventsToQueue() {
 					if (getKeysDown() & KEY_LEFT) {
 						mouseMode = MOUSE_LEFT;
 					}
+
 					if (getKeysDown() & KEY_RIGHT) {
-						if (currentGame->control != CONT_SCUMM_SAMNMAX) {
+						if ((currentGame->control != CONT_SCUMM_SAMNMAX) && (currentGame->control != CONT_FUTURE_WARS)) {
 							mouseMode = MOUSE_RIGHT;
 						} else {
 							// If we're playing sam and max, click and release the right mouse
 							// button to change verb
 							Common::Event event;
+
+							if (currentGame->control == CONT_FUTURE_WARS) {
+								event.mouse = Common::Point(320 - 128, 200 - 128);
+								event.type = Common::EVENT_MOUSEMOVE;
+								system->addEvent(event);
+							} else {
+								event.mouse = Common::Point(getPenX(), getPenY());
+							}
+
 		
 							event.type = Common::EVENT_RBUTTONDOWN;
-							event.mouse = Common::Point(getPenX(), getPenY());
 							system->addEvent(event);
 		
 							event.type = Common::EVENT_RBUTTONUP;
@@ -1126,14 +1255,16 @@ void addEventsToQueue() {
 		
 		Common::Event event;
 
-		if ((!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R))) {
-			event.type = Common::EVENT_MOUSEMOVE;
-			event.mouse = Common::Point(getPenX(), getPenY());
-			system->addEvent(event);
-			//consolePrintf("x=%d   y=%d  \n", getPenX(), getPenY());
-		}
 	
 		if (!keyboardEnable) {
+
+			if ((!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R))) {
+				event.type = Common::EVENT_MOUSEMOVE;
+				event.mouse = Common::Point(getPenX(), getPenY());
+				system->addEvent(event);
+				//consolePrintf("x=%d   y=%d  \n", getPenX(), getPenY());
+			}
+
 			if ((mouseMode != MOUSE_HOVER) || (!displayModeIs8Bit)) {
 					if (getPenDown() && (!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R))) {	
 						event.type = ((mouseMode == MOUSE_LEFT) || (!displayModeIs8Bit))? Common::EVENT_LBUTTONDOWN: Common::EVENT_RBUTTONDOWN;
@@ -1253,8 +1384,18 @@ void addEventsToQueue() {
 		
 		if ((getKeysChanged() & KEY_START)) {
 			event.type = getKeyEvent(KEY_START);
-			event.kbd.keycode = Common::KEYCODE_F5;
-			event.kbd.ascii = Common::ASCII_F5;
+			if (currentGame->control == CONT_FUTURE_WARS) {
+				event.kbd.keycode = Common::KEYCODE_F10;
+				event.kbd.ascii = Common::ASCII_F10;
+			} else if (currentGame->control == CONT_GOBLINS) {
+				event.kbd.keycode = Common::KEYCODE_F1;
+				event.kbd.ascii = Common::ASCII_F1;
+//				consolePrintf("!!!!!F1!!!!!");
+			} else {
+				event.kbd.keycode = Common::KEYCODE_F5;
+				event.kbd.ascii = Common::ASCII_F5;
+//				consolePrintf("!!!!!F5!!!!!");
+			}
 			event.kbd.flags = 0;
 			system->addEvent(event);
 		}
@@ -1280,11 +1421,17 @@ void triggerIcon(int imageNum) {
 	
 
 void setIcon(int num, int x, int y, int imageNum, int flags, bool enable) {
-	sprites[num].attribute[0] = ATTR0_BMP | y | (!enable? ATTR0_DISABLED: 0); 
+	sprites[num].attribute[0] = ATTR0_BMP | (enable? y: 192) | (!enable? ATTR0_DISABLED: 0); 
 	sprites[num].attribute[1] = ATTR1_SIZE_32 | x | flags;
 	sprites[num].attribute[2] = ATTR2_ALPHA(1)| (imageNum * 16);
 }
 
+void setIconMain(int num, int x, int y, int imageNum, int flags, bool enable) {
+	spritesMain[num].attribute[0] = ATTR0_BMP | (y & 0x1FF) | (!enable? ATTR0_DISABLED: 0); 
+	spritesMain[num].attribute[1] = ATTR1_SIZE_32 | (x & 0x1FF) | flags;
+	spritesMain[num].attribute[2] = ATTR2_ALPHA(1)| (imageNum * 16);
+}
+
 void updateStatus() {
 	int offs;
 
@@ -1313,7 +1460,7 @@ void updateStatus() {
 	
 		if (indyFightState) {
 			setIcon(1, (190 - 32), 150, 3, (indyFightRight? 0: ATTR1_FLIP_X), true);
-			consolePrintf("%d\n", indyFightRight);
+//			consolePrintf("%d\n", indyFightRight);
 		} else {
 //			setIcon(1, 0, 0, 0, 0, false);
 		}
@@ -1324,7 +1471,7 @@ void updateStatus() {
 		} else {
 			setIcon(4, 0, 0, 0, 0, false);
 		}
-		
+
 	} else {
 		setIcon(0, 0, 0, 0, 0, false);
 		setIcon(1, 0, 0, 0, 0, false);
@@ -1334,14 +1481,16 @@ void updateStatus() {
 	}
 
 	if ((keyboardIcon) && (!keyboardEnable) && (!displayModeIs8Bit)) {
-		spritesMain[0].attribute[0] = ATTR0_BMP | 160;
-		spritesMain[0].attribute[1] = ATTR1_SIZE_32 | 0;
-		spritesMain[0].attribute[2] = ATTR2_ALPHA(1) | 64;
+//		spritesMain[0].attribute[0] = ATTR0_BMP | 160;
+//		spritesMain[0].attribute[1] = ATTR1_SIZE_32 | 0;
+//		spritesMain[0].attribute[2] = ATTR2_ALPHA(1) | 64;
+		setIconMain(0, 0, 160, 4, 0, true);
 	} else {
-		spritesMain[0].attribute[0] = ATTR0_DISABLED;
-		spritesMain[0].attribute[1] = 0;
-		spritesMain[0].attribute[2] = 0;
-		spritesMain[0].attribute[3] = 0;
+//		spritesMain[0].attribute[0] = ATTR0_DISABLED;
+//		spritesMain[0].attribute[1] = 0;
+//		spritesMain[0].attribute[2] = 0;
+//		spritesMain[0].attribute[3] = 0;
+		setIconMain(0, 0, 0, 0, 0, false);
 	}
 
 }
@@ -1428,6 +1577,10 @@ void setZoomedScreenScale(int x, int y) {
 	}
 }
 
+#ifdef USE_PROFILER
+void VBlankHandler(void) __attribute__ ((no_instrument_function));
+#endif
+
 void VBlankHandler(void) {
 //	BG_PALETTE[0] = RGB15(31, 31, 31);
 //	if (*((int *) (0x023FFF00)) != 0xBEEFCAFE) {
@@ -1473,6 +1626,19 @@ void VBlankHandler(void) {
 
 	frameCount++;
 	
+	if ((cursorEnable) && (mouseCursorVisible))
+	{
+		if (!keyboardEnable) {
+			storedMouseX = penX;
+			storedMouseY = penY;
+		}
+
+		setIconMain(3, storedMouseX - mouseHotspotX, storedMouseY - mouseHotspotY, 8, 0, true);
+	}
+	else
+	{
+		setIconMain(3, 0, 0, 0, 0, false);
+	}
 
 
 	if (callback) {
@@ -1563,7 +1729,7 @@ void VBlankHandler(void) {
 			if (zooming) {
 				subScX = subScTargetX;
 				subScY = subScTargetY;
-			 	triggerIcon(0);
+			 	triggerIcon(5);
 			}
 		} else if ( ((subScreenWidth) > 128 - 8) && ((subScreenWidth) < 128 + 8) ) {
 			subScreenWidth = 128;
@@ -1571,7 +1737,7 @@ void VBlankHandler(void) {
 			if (zooming) {
 				subScX = subScTargetX;
 				subScY = subScTargetY;
-				triggerIcon(1);
+				triggerIcon(6);
 			}
 		} else if (subScreenWidth > 256) {
 			subScreenWidth = 320;
@@ -1579,10 +1745,10 @@ void VBlankHandler(void) {
 			if (zooming) {
 				subScX = subScTargetX;
 				subScY = subScTargetY;
-				triggerIcon(2);
+				triggerIcon(7);
 			}
 		} else {
-			triggerIcon(-1);
+			//triggerIcon(-1);
 		}
 	}
 	
@@ -1745,6 +1911,14 @@ void setTopScreenTarget(int x, int y) {
 	subScTargetY <<=8;
 }
 
+#ifdef USE_PROFILER
+void hBlankHanlder() __attribute__ ((no_instrument_function));
+
+void hBlankHandler() {
+	hBlankCount++;
+}
+#endif
+
 void initHardware() {
 	// Guard band
 //((int *) (0x023FFF00)) = 0xBEEFCAFE;
@@ -1757,7 +1931,7 @@ void initHardware() {
 	vramSetBankB(VRAM_B_MAIN_BG); 
 	vramSetBankC(VRAM_C_SUB_BG); */
 	vramSetBankI(VRAM_I_SUB_SPRITE); 
-	vramSetBankG(VRAM_G_MAIN_SPRITE); 
+	vramSetBankE(VRAM_E_MAIN_SPRITE); 
 	
 	currentTimeMillis = 0;
 
@@ -1825,6 +1999,11 @@ void initHardware() {
 	irqEnable(IRQ_VBLANK);
 	irqEnable(IRQ_TIMER0);
 	irqEnable(IRQ_TIMER2);
+
+#ifdef USE_PROFILER
+	irqSet(IRQ_HBLANK, hBlankHandler);
+	irqEnable(IRQ_HBLANK);
+#endif
 	
 	
 	// Set up a millisecond timer
@@ -1847,14 +2026,22 @@ void initHardware() {
 	
 	// Convert texture from 24bit 888 to 16bit 1555, remembering to set top bit!
 	u8* srcTex = (u8 *) icons_raw;
-	for (int r = 32 * 160 ; r >= 0; r--) {
+	for (int r = 32 * 256 ; r >= 0; r--) {
 		SPRITE_GFX_SUB[r] = 0x8000 | (srcTex[r * 3] >> 3) | ((srcTex[r * 3 + 1] >> 3) << 5) | ((srcTex[r * 3 + 2] >> 3) << 10);
 		SPRITE_GFX[r] = 0x8000 | (srcTex[r * 3] >> 3) | ((srcTex[r * 3 + 1] >> 3) << 5) | ((srcTex[r * 3 + 2] >> 3) << 10);
 	}
 
+		
+
+
+
 	WAIT_CR &= ~(0x0080);
 //	REG_WRAM_CNT = 0;
 
+	// This is a bodge to get around the fact that the cursor is turned on before it's image is set
+	// during startup in Sam & Max.  This bodge moves the cursor offscreen so it is not seen.
+	sprites[1].attribute[1] = ATTR1_SIZE_64 | 192;
+
 }
 
 
@@ -2067,23 +2254,28 @@ bool getIndyFightState() {
 	return indyFightState;
 }
 
+gameListType* getCurrentGame() {
+	return currentGame;
+}
+
 ///////////////////
 // Fast Ram
 ///////////////////
 
-#define FAST_RAM_SIZE (30000)
+#define FAST_RAM_SIZE (24000)
 
 u8* fastRamPointer;
 u8 fastRamData[FAST_RAM_SIZE] ITCM_DATA;
 
 void* fastRamAlloc(int size) {
+//	return malloc(size);
 	void* result = (void *) fastRamPointer;
 	fastRamPointer += size;
 	return (void *) (result);
 }
 
 void fastRamReset() {
-	fastRamPointer = fastRamData;
+	fastRamPointer = &fastRamData[0];
 }
 
 
@@ -2308,24 +2500,34 @@ int main(void)
 //	}
 	
 
-	
+	//2372
 	consolePrintf("-------------------------------\n");
 	consolePrintf("ScummVM DS\n");
 	consolePrintf("Ported by Neil Millstone\n");
- FIXME: Change this code to make use of base/internal_version.h
- resp. uses gScummVMVersion from base/version.h
-	consolePrintf("Version 0.10.0SVN ");
+	consolePrintf("Version 0.10.0 beta1 ");
 #if defined(DS_BUILD_A)
 	consolePrintf("build A\n");
-	consolePrintf("Supports: Lucasarts SCUMM\n");
+	consolePrintf("Lucasarts SCUMM games (SCUMM)\n");
 	consolePrintf("-------------------------------\n");
 #elif defined(DS_BUILD_B)
 	consolePrintf("build B\n");
-	consolePrintf("Supports: BASS, QUEEN\n");
+	consolePrintf("BASS, QUEEN\n");
 	consolePrintf("-------------------------------\n");
 #elif defined(DS_BUILD_C)
 	consolePrintf("build C\n");
-	consolePrintf("Supports: SIMON, KYRA, GOB\n");
+	consolePrintf("Simon the Sorcerer 1/2 (SIMON)\n");
+	consolePrintf("-------------------------------\n");
+#elif defined(DS_BUILD_D)
+	consolePrintf("build D\n");
+	consolePrintf("AGI, CINE, GOB\n");
+	consolePrintf("-------------------------------\n");
+#elif defined(DS_BUILD_E)
+	consolePrintf("build E\n");
+	consolePrintf("Inherit the earth (SAGA)\n");
+	consolePrintf("-------------------------------\n");
+#elif defined(DS_BUILD_F)
+	consolePrintf("build F\n");
+	consolePrintf("The Legend of Kyrandia (KYRA)\n");
 	consolePrintf("-------------------------------\n");
 #endif
 	consolePrintf("L/R + D-pad/pen:    Scroll view\n");
@@ -2333,7 +2535,7 @@ int main(void)
 	consolePrintf("D-pad right: Right mouse button\n");
 	consolePrintf("D-pad up:           Hover mouse\n");
 	consolePrintf("B button:        Skip cutscenes\n");
-	consolePrintf("Select:		   DS Options menu\n");
+	consolePrintf("Select:         DS Options menu\n");
 	consolePrintf("Start:   Game menu (some games)\n");
 	consolePrintf("Y (in game):     Toggle console\n");
 	consolePrintf("X:              Toggle keyboard\n");
@@ -2457,10 +2659,13 @@ int main(void)
 #elif defined(DS_BUILD_C)
 	char* argv[2] = {"/scummvmds", "--config=scummvmc.ini"};
 #elif defined(DS_BUILD_D)
-	char* argv[2] = {"/scummvmds", "--config=scummvmd.ini"};
+	char* argv[3] = {"/scummvmds", "--config=scummvmd.ini"};
+#elif defined(DS_BUILD_E)
+	char* argv[3] = {"/scummvmds", "--config=scummvme.ini"};
+#elif defined(DS_BUILD_F)
+	char* argv[3] = {"/scummvmds", "--config=scummvmf.ini"};
 #endif
 
-
 #ifdef DS_NON_SCUMM_BUILD	
 
 	while (1) {
@@ -2482,3 +2687,13 @@ int main(void)
 int main() {
 	DS::main();
 }
+
+
+#ifdef USE_PROFILER
+int cygprofile_getHBlanks() __attribute__ ((no_instrument_function));
+
+
+int cygprofile_getHBlanks() {
+	return DS::hBlankCount;
+}
+#endif
diff --git a/backends/platform/ds/arm9/source/dsmain.h b/backends/platform/ds/arm9/source/dsmain.h
index 58a5be9240..94f02145a2 100644
--- a/backends/platform/ds/arm9/source/dsmain.h
+++ b/backends/platform/ds/arm9/source/dsmain.h
@@ -31,6 +31,22 @@
 
 namespace DS {
 
+
+enum controlType {
+	CONT_SCUMM_ORIGINAL,
+	CONT_SCUMM_SAMNMAX,
+	CONT_SKY,
+	CONT_SIMON,
+	CONT_FUTURE_WARS,
+	CONT_AGI,
+	CONT_GOBLINS
+};
+
+struct gameListType {
+	char 			gameId[16];
+	controlType 	control;
+};
+
 // Pen reading functions
 void 	penInit();
 void 	penUpdate();
@@ -83,7 +99,9 @@ void 	VBlankHandler();
 
 // Sam and Max Stuff
 void 	setGameID(int id);
-void 	setCursorIcon(const u8* icon, uint w, uint h, byte keycolor);
+void 	setCursorIcon(const u8* icon, uint w, uint h, byte keycolor, int hotspotX, int hotspotY);
+void	setShowCursor(bool enable);
+void	setMouseCursorVisible(bool visible);
 
 // Shake
 void 	setShakePos(int shakePos);
@@ -123,7 +141,12 @@ void	fastRamReset();
 void*	fastRamAlloc(int size);
 
 
+gameListType* getCurrentGame();
+
+
 }
 
 
+int cygprofile_getHBlanks();
+
 #endif
diff --git a/backends/platform/ds/arm9/source/dsoptions.cpp b/backends/platform/ds/arm9/source/dsoptions.cpp
index 171d1e044c..b29b1d9fa7 100644
--- a/backends/platform/ds/arm9/source/dsoptions.cpp
+++ b/backends/platform/ds/arm9/source/dsoptions.cpp
@@ -55,7 +55,8 @@ DSOptionsDialog::DSOptionsDialog() : GUI::Dialog(20, 0, 320 - 40, 200 - 20) {
 	_twoHundredPercentCheckbox = new GUI::CheckboxWidget(this, 20, 70, 230, 20, "Zoomed screen at fixed 200% zoom", 0, 'T');
 	_highQualityAudioCheckbox = new GUI::CheckboxWidget(this, 20, 85, 250, 20, "High quality audio (slower) (reboot)", 0, 'T');
 	_disablePowerOff = new GUI::CheckboxWidget(this, 20, 100, 250, 20, "Disable power off on quit", 0, 'T');
-	_cpuScaler = new GUI::CheckboxWidget(this, 20, 115, 250, 20, "CPU scaler", 0, 'T');
+//	_cpuScaler = new GUI::CheckboxWidget(this, 20, 115, 250, 20, "CPU scaler", 0, 'T');
+	_showCursorCheckbox = new GUI::CheckboxWidget(this, 20, 115, 250, 20, "Show mouse cursor", 0, 'T');
 
 	new GUI::StaticTextWidget(this, 20, 130, 110, 15, "Touch X Offset", GUI::kTextAlignLeft);
 	_touchX = new GUI::SliderWidget(this, 130, 130, 130, 12, 1);
@@ -79,6 +80,12 @@ DSOptionsDialog::DSOptionsDialog() : GUI::Dialog(20, 0, 320 - 40, 200 - 20) {
 	_delDialog = new Scumm::SaveLoadChooser("Delete game:", "Delete", false, Scumm::g_scumm);
 #endif
 
+	if (ConfMan.hasKey("showcursor", "ds")) {
+		_showCursorCheckbox->setState(ConfMan.getBool("showcursor", "ds"));
+	} else {
+		_showCursorCheckbox->setState(false);
+	}
+
 	if (ConfMan.hasKey("lefthanded", "ds")) {
 		_leftHandedCheckbox->setState(ConfMan.getBool("lefthanded", "ds"));
 	} else {
@@ -108,13 +115,13 @@ DSOptionsDialog::DSOptionsDialog() : GUI::Dialog(20, 0, 320 - 40, 200 - 20) {
 	} else {
 		_disablePowerOff->setState(false);
 	}
-
+/*
 	if (ConfMan.hasKey("cpu_scaler", "ds")) {
 		_cpuScaler->setState(ConfMan.getBool("cpu_scaler", "ds"));
 	} else {
 		_cpuScaler->setState(false);
 	}
-
+*/
 	_indyFightCheckbox->setState(DS::getIndyFightState());
 
 	if (ConfMan.hasKey("xoffset", "ds")) {
@@ -137,9 +144,10 @@ DSOptionsDialog::~DSOptionsDialog() {
 	ConfMan.setBool("twohundredpercent", _twoHundredPercentCheckbox->getState(), "ds");
 	ConfMan.setBool("22khzaudio", _highQualityAudioCheckbox->getState(), "ds");
 	ConfMan.setBool("disablepoweroff", _disablePowerOff->getState(), "ds");
-	ConfMan.setBool("cpu_scaler", _cpuScaler->getState(), "ds");	
+//	ConfMan.setBool("cpu_scaler", _cpuScaler->getState(), "ds");	
 	ConfMan.setInt("xoffset", _touchX->getValue(), "ds");
 	ConfMan.setInt("yoffset", _touchY->getValue(), "ds");
+	ConfMan.setBool("showcursor", _showCursorCheckbox->getState(), "ds");
 	DS::setOptions();
 	DS::setIndyFightState(_indyFightCheckbox->getState());
 	ConfMan.flushToDisk();
@@ -181,15 +189,27 @@ void DSOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint
 
 }
 
+void togglePause() {
+	// Toggle pause mode by simulating pressing 'p'.  Not a good way of doing things!
+
+	if (getCurrentGame()->control == CONT_SCUMM_ORIGINAL) {
+		Common::Event event;
+		OSystem_DS* system = OSystem_DS::instance();
+
+		event.type = Common::EVENT_KEYDOWN;
+		event.kbd.keycode = 'p';		
+		event.kbd.ascii = 'p';
+		event.kbd.flags = 0;
+		system->addEvent(event);
+	
+		event.type = Common::EVENT_KEYUP;
+		system->addEvent(event);
+	}
+}
+
 void showOptionsDialog() {
-	OSystem_DS* system = OSystem_DS::instance();
 
-	Common::Event event;
-	event.type = Common::EVENT_KEYDOWN;
-	event.kbd.keycode = 'P';		// F5
-	event.kbd.ascii = 'P';
-	event.kbd.flags = 0;
-	system->addEvent(event);
+	togglePause();
 
 	DS::displayMode16Bit();
 	
@@ -201,11 +221,7 @@ void showOptionsDialog() {
 	
 	DS::displayMode8Bit();
 
-	event.type = Common::EVENT_KEYDOWN;
-	event.kbd.keycode = 'P';		// F5
-	event.kbd.ascii = 'P';
-	event.kbd.flags = 0;
-	system->addEvent(event);
+	togglePause();
 }
 
 void setOptions() {
@@ -217,6 +233,12 @@ void setOptions() {
 		DS::setLeftHanded(false);
 	}
 
+	if (ConfMan.hasKey("showcursor", "ds")) {
+		DS::setMouseCursorVisible(ConfMan.getBool("showcursor", "ds"));
+	} else {
+		DS::setMouseCursorVisible(true);
+	}
+
 	if (ConfMan.hasKey("unscaled", "ds")) {
 		DS::setUnscaledMode(ConfMan.getBool("unscaled", "ds"));
 	} else {
diff --git a/backends/platform/ds/arm9/source/dsoptions.h b/backends/platform/ds/arm9/source/dsoptions.h
index 8dde086f57..6976fb1a59 100644
--- a/backends/platform/ds/arm9/source/dsoptions.h
+++ b/backends/platform/ds/arm9/source/dsoptions.h
@@ -43,7 +43,7 @@ public:
 	
 protected:
 	virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
-
+	void togglePause();
 
 	GUI::SliderWidget* _touchX;
 	GUI::SliderWidget* _touchY;
@@ -54,6 +54,7 @@ protected:
 	GUI::CheckboxWidget* _highQualityAudioCheckbox;
 	GUI::CheckboxWidget* _disablePowerOff;
 	GUI::CheckboxWidget* _cpuScaler;
+	GUI::CheckboxWidget* _showCursorCheckbox;
 	
 #ifdef DS_SCUMM_BUILD
 	Scumm::SaveLoadChooser* _delDialog;
diff --git a/backends/platform/ds/arm9/source/fat/disc_io.c b/backends/platform/ds/arm9/source/fat/disc_io.c
index c706cf8b3e..3cb70f510b 100644
--- a/backends/platform/ds/arm9/source/fat/disc_io.c
+++ b/backends/platform/ds/arm9/source/fat/disc_io.c
@@ -358,7 +358,7 @@ void disc_getDldiId(char* id) {
 bool disc_setDsSlotInterface (void)
 {
 #ifdef ARM9
-	REG_EXMEMCNT &= ~(1<<11);
+	REG_EXEMEMCNT &= ~(1<<11);
 #endif
 #ifdef ARM7
 	REG_EXEMEMCNT |= (1<<11);
diff --git a/backends/platform/ds/arm9/source/fat/disc_io.h b/backends/platform/ds/arm9/source/fat/disc_io.h
index 1fbcc78c19..06804afec7 100644
--- a/backends/platform/ds/arm9/source/fat/disc_io.h
+++ b/backends/platform/ds/arm9/source/fat/disc_io.h
@@ -33,7 +33,11 @@
 // Disk caching is disabled on GBA to conserve memory
 
 #define DISC_CACHE				// uncomment this line to enable disc caching
+#ifdef DS_BUILD_F
+#define DISC_CACHE_COUNT	128	// maximum number of sectors to cache (512 bytes per sector)
+#else
 #define DISC_CACHE_COUNT	32	// maximum number of sectors to cache (512 bytes per sector)
+#endif
 //#define DISK_CACHE_DMA		// use DMA for cache copies. If this is enabled, the data buffers must be word aligned
 
 
diff --git a/backends/platform/ds/arm9/source/fat/gba_nds_fat.c b/backends/platform/ds/arm9/source/fat/gba_nds_fat.c
index f343c4b997..b5fdd665df 100644
--- a/backends/platform/ds/arm9/source/fat/gba_nds_fat.c
+++ b/backends/platform/ds/arm9/source/fat/gba_nds_fat.c
@@ -1362,9 +1362,18 @@ DIR_ENT FAT_DirEntFromPath (const char* path)
 	DIR_ENT dirEntry;
 	u32 dirCluster;
 	bool flagLFN, dotSeen;
-	
 	// Start at beginning of path
 	pathPos = 0;
+
+#ifdef DS_BUILD_F
+	// Problems with Kyrandia doing a load of path lookups are reduced by this hack.
+	if (strstr(path, ".voc") || strstr(path, ".voc"))
+	{
+		dirEntry.name[0] = FILE_FREE;
+		dirEntry.attrib = 0x00;
+		return;
+	}
+#endif
 	
 	if (path[pathPos] == '/') 
 	{
@@ -2499,6 +2508,7 @@ int FAT_fseek(FAT_FILE* file, s32 offset, int origin)
 	u32 position;
 	u32 curPos;
 
+
 	if ((file == NULL) || (file->inUse == false))	// invalid file
 	{
 		return -1;
@@ -2613,6 +2623,7 @@ int FAT_fseek(FAT_FILE* file, s32 offset, int origin)
 	}
 
 	return 0;
+
 }
 
 /*-----------------------------------------------------------------
diff --git a/backends/platform/ds/arm9/source/fat/io_dldi.h b/backends/platform/ds/arm9/source/fat/io_dldi.h
index 86c3407374..053de3a94c 100644
--- a/backends/platform/ds/arm9/source/fat/io_dldi.h
+++ b/backends/platform/ds/arm9/source/fat/io_dldi.h
@@ -30,7 +30,7 @@ extern u8 _dldi_driver_name;
 static inline LPIO_INTERFACE DLDI_GetInterface(void) {
 #ifdef NDS
 	// NDM: I'm really not sure about this change ARM9 - ARM7
-	REG_EXMEMCNT &= ~(ARM7_OWNS_ROM | ARM7_OWNS_CARD);
+	REG_EXEMEMCNT &= ~(ARM7_OWNS_ROM | ARM7_OWNS_CARD);
 #endif // defined NDS
 	return &_io_dldi;
 }
diff --git a/backends/platform/ds/arm9/source/gbampsave.cpp b/backends/platform/ds/arm9/source/gbampsave.cpp
index 7f7bf958df..0131040e1d 100644
--- a/backends/platform/ds/arm9/source/gbampsave.cpp
+++ b/backends/platform/ds/arm9/source/gbampsave.cpp
@@ -29,7 +29,7 @@
 
 GBAMPSaveFile::GBAMPSaveFile(char* name, bool saveOrLoad) {
 	handle = DS::std_fopen(name, saveOrLoad? "w": "r");
-//	consolePrintf("%s handle is %d\n", name, handle);
+	consolePrintf("%s handle is %d\n", name, handle);
 //	consolePrintf("Created %s\n", name);
 	bufferPos = 0;
 	saveSize = 0;
@@ -39,6 +39,7 @@ GBAMPSaveFile::GBAMPSaveFile(char* name, bool saveOrLoad) {
 GBAMPSaveFile::~GBAMPSaveFile() {
 	flushSaveBuffer();
 	if (handle) DS::std_fclose(handle);
+	consolePrintf("Closed file\n");
 }
 
 uint32 GBAMPSaveFile::read(void *buf, uint32 size) {
@@ -57,7 +58,7 @@ void GBAMPSaveFile::skip(uint32 bytes) {
 
 void GBAMPSaveFile::flushSaveBuffer() {
 	if (bufferPos != 0) {
-		consolePrintf("Flushing %d bytes from %x\n", bufferPos, buffer);
+//		consolePrintf("Flushing %d bytes from %x\n", bufferPos, buffer);
 		flushed += bufferPos;
 		DS::std_fwrite(buffer, 1, bufferPos, handle);
 		bufferPos = 0;
@@ -174,8 +175,10 @@ void GBAMPSaveFileManager::listSavefiles(char const* prefix, bool* marks, int nu
 	char path[128];
 	
 	DS::std_cwd((char *) getSavePath());
+
+	consolePrintf("Save path: %s\n", getSavePath());
 	
-	int fileType = FAT_FindFirstFile(name);
+	int fileType = FAT_FindFirstFileLFN(name);
 	
 	for (int r = 0; r < num; r++) {
 		marks[r] = false;
@@ -192,17 +195,17 @@ void GBAMPSaveFileManager::listSavefiles(char const* prefix, bool* marks, int nu
 				
 				
 				sprintf(str, "%s%02d", prefix, r);
-//				consolePrintf("%s != %s", str, name);
+				consolePrintf("%s != %s", str, name);
 				if (!stricmp(str, name)) {
 					marks[r] = true;
-//					consolePrintf("Matched %d", r);
+					consolePrintf("Matched %d", r);
 				}
 				
 			}
 			
 		}
 	
-	} while ((fileType = FAT_FindNextFile(name)));
+	} while ((fileType = FAT_FindNextFileLFN(name)));
 	
 	FAT_chdir("/");
 }
diff --git a/backends/platform/ds/arm9/source/gbampsave.h b/backends/platform/ds/arm9/source/gbampsave.h
index 1580533f66..c7d9732d4c 100644
--- a/backends/platform/ds/arm9/source/gbampsave.h
+++ b/backends/platform/ds/arm9/source/gbampsave.h
@@ -37,7 +37,7 @@ class GBAMPSaveFile : public Common::InSaveFile, public Common::OutSaveFile {
 
 public:
 	GBAMPSaveFile(char* name, bool saveOrLoad);
-	~GBAMPSaveFile();
+	virtual ~GBAMPSaveFile();
 		
 	virtual uint32 read(void *buf, uint32 size);
 	virtual uint32 write(const void *buf, uint32 size);
diff --git a/backends/platform/ds/arm9/source/osystem_ds.cpp b/backends/platform/ds/arm9/source/osystem_ds.cpp
index cad6ad6b78..32eafe1af7 100644
--- a/backends/platform/ds/arm9/source/osystem_ds.cpp
+++ b/backends/platform/ds/arm9/source/osystem_ds.cpp
@@ -37,6 +37,7 @@
 #include "common/str.h"
 #include "cdaudio.h"
 #include "graphics/surface.h"
+#include "touchkeyboard.h"
 
 OSystem_DS* OSystem_DS::_instance = NULL;
 
@@ -138,9 +139,12 @@ void OSystem_DS::setPalette(const byte *colors, uint start, uint num) {
 		green >>= 3;
 		blue >>= 3;
 		
-		BG_PALETTE[r] = red | (green << 5) | (blue << 10);
-		if (!DS::getKeyboardEnable()) {
-			BG_PALETTE_SUB[r] = red | (green << 5) | (blue << 10);
+//		if (r != 255)
+		{		
+			BG_PALETTE[r] = red | (green << 5) | (blue << 10);
+			if (!DS::getKeyboardEnable()) {
+				BG_PALETTE_SUB[r] = red | (green << 5) | (blue << 10);
+			}
 		}
 //		if (num == 16) consolePrintf("pal:%d r:%d g:%d b:%d\n", r, red, green, blue);
 		
@@ -173,8 +177,8 @@ void OSystem_DS::copyRectToScreen(const byte *buf, int pitch, int x, int y, int
 	u16* src = (u16 *) buf;
 	
 	if (DS::getKeyboardEnable()) {
-		for (int dy = y; dy < y + h; dy++)
-        {
+	
+		for (int dy = y; dy < y + h; dy++) {
 			u16* dest = bg + (dy << 8) + (x >> 1);
 		
 			DC_FlushRange(src, w << 1);
@@ -185,8 +189,7 @@ void OSystem_DS::copyRectToScreen(const byte *buf, int pitch, int x, int y, int
 		}
 	
 	} else {
-		for (int dy = y; dy < y + h; dy++)
-        {
+		for (int dy = y; dy < y + h; dy++) {
 			u16* dest1 = bg + (dy << 8) + (x >> 1);
 			u16* dest2 = bgSub + (dy << 8) + (x >> 1);
 			
@@ -294,6 +297,7 @@ int16 OSystem_DS::getOverlayWidth()
 	
 bool OSystem_DS::showMouse(bool visible)
 {
+	DS::setShowCursor(visible);
 	return true;
 }
 
@@ -302,7 +306,7 @@ void OSystem_DS::warpMouse(int x, int y)
 }
 
 void OSystem_DS::setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor, int targetCursorScale) {
-	DS::setCursorIcon(buf, w, h, keycolor);
+	DS::setCursorIcon(buf, w, h, keycolor, hotspotX, hotspotY);
 }
 
 void OSystem_DS::addEvent(Common::Event& e) {
@@ -323,11 +327,11 @@ bool OSystem_DS::pollEvent(Common::Event &event)
 			event.kbd.ascii = 0;
 			event.kbd.keycode = 0;
 			event.kbd.flags = 0;
-			consolePrintf("type: %d\n", event.type);
+//			consolePrintf("type: %d\n", event.type);
 			return false;
 		} else {
 			event = eventQueue[eventNum++];
-			consolePrintf("type: %d\n", event.type);
+//			consolePrintf("type: %d\n", event.type);
 			return true;
 		}
 	}
@@ -474,36 +478,25 @@ Common::SaveFileManager* OSystem_DS::getSavefileManager()
 	}
 }
 
-Graphics::Surface *OSystem_DS::lockScreen() {
-	// For now, we create a full temporary screen surface, to which we copy the
-	// the screen content. Later unlockScreen will copy everything back.
-	// Not very nice nor efficient, but at least works, and is not worse
-	// than in the bad old times where we used grabRawScreen + copyRectToScreen.
-	
-	_framebuffer.create(DS::getGameWidth(), DS::getGameHeight(), 1);
+bool OSystem_DS::grabRawScreen(Graphics::Surface* surf) {
+	surf->create(DS::getGameWidth(), DS::getGameHeight(), 1);
 
 	// Ensure we copy using 16 bit quantities due to limitation of VRAM addressing
 	
+    size_t imageStrideInBytes = DS::isCpuScalerEnabled()? DS::getGameWidth() : 512;
+    size_t imageStrideInWords = imageStrideInBytes / 2;
 
 	u16* image = (u16 *) DS::get8BitBackBuffer();
 	for (int y = 0; y <  DS::getGameHeight(); y++)
 	{
-		DC_FlushRange(image + (y << 8), DS::getGameWidth());
+		DC_FlushRange(image + (y * imageStrideInWords), DS::getGameWidth());
 		for (int x = 0; x < DS::getGameWidth() >> 1; x++)
 		{
-			*(((u16 *) (_framebuffer.pixels)) + y * (DS::getGameWidth() >> 1) + x) = image[y << 8 + x];
+			*(((u16 *) (surf->pixels)) + y * (DS::getGameWidth() >> 1) + x) = image[y * imageStrideInWords + x];
 		}
 	}
 
-	return &_framebuffer;
-}
-
-void OSystem_DS::unlockScreen() {
-	// Copy temp framebuffer back to screen
-	copyRectToScreen((byte *)_framebuffer.pixels, _framebuffer.pitch, 0, 0, _framebuffer.w, _framebuffer.h);
-
-	// Free memory
-	_framebuffer.free(); 
+	return true;
 }
 
 void OSystem_DS::setFocusRectangle(const Common::Rect& rect) {
@@ -515,6 +508,18 @@ void OSystem_DS::clearFocusRectangle() {
 }
 
 
+void OSystem_DS::addAutoComplete(const char *word) {
+	DS::addAutoComplete((char *) word);
+}
+
+void OSystem_DS::clearAutoComplete() {
+	DS::clearAutoComplete();
+}
+
+void OSystem_DS::setCharactersEntered(int count) {
+	DS::setCharactersEntered(count);
+}
+
 OSystem *OSystem_DS_create() {
 	return new OSystem_DS();
 }
diff --git a/backends/platform/ds/arm9/source/osystem_ds.h b/backends/platform/ds/arm9/source/osystem_ds.h
index 58b940af2c..d943a362ca 100644
--- a/backends/platform/ds/arm9/source/osystem_ds.h
+++ b/backends/platform/ds/arm9/source/osystem_ds.h
@@ -41,11 +41,12 @@ class DSTimerManager : public DefaultTimerManager {
 
 class OSystem_DS : public OSystem {
 public:
+
 	static OSystem_DS *instance() { return _instance; }
 	int eventNum;
 	int lastPenFrame;
 	
-	Common::Event eventQueue[64];
+	Common::Event eventQueue[96];
 	int queuePos;
 	
 	DSSaveFileManager saveManager;
@@ -53,9 +54,8 @@ public:
 	DSAudioMixer* _mixer;
 	DSTimerManager* _timer;
 
-	Graphics::Surface _framebuffer;
-
 	static OSystem_DS* _instance;
+
 	
 	typedef void (*SoundProc)(void *param, byte *buf, int len);
 	typedef int  (*TimerProc)(int interval);
@@ -129,8 +129,7 @@ public:
 	void addEvent(Common::Event& e);
 	bool isEventQueueEmpty() { return queuePos == 0; }
 	
-	virtual Graphics::Surface *lockScreen();
-	virtual void unlockScreen();
+	virtual bool grabRawScreen(Graphics::Surface* surf);
 	
 	virtual void setFocusRectangle(const Common::Rect& rect);
 	
@@ -141,6 +140,14 @@ public:
 	virtual Audio::Mixer* getMixer() { return _mixer; }
 	virtual Common::TimerManager* getTimerManager() { return _timer; }
 	static int timerHandler(int t);
+
+
+	virtual void addAutoComplete(const char *word);
+	virtual void clearAutoComplete();
+	virtual void setCharactersEntered(int count);
+
+
+
 };
 
 static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
@@ -162,9 +169,4 @@ void OSystem_DS::colorToRGB(OverlayColor color, uint8 &r, uint8 &g, uint8 &b)
 	//consolePrintf("coltorgb\n");
 }
 
-namespace DS
-{
-bool isCpuScalerEnabled();
-}
-
 #endif
diff --git a/backends/platform/ds/arm9/source/touchkeyboard.cpp b/backends/platform/ds/arm9/source/touchkeyboard.cpp
index 8f7af668d8..26f03ca9d1 100644
--- a/backends/platform/ds/arm9/source/touchkeyboard.cpp
+++ b/backends/platform/ds/arm9/source/touchkeyboard.cpp
@@ -23,6 +23,7 @@
 #include "touchkeyboard.h"
 #include "keyboard_raw.h"
 #include "keyboard_pal_raw.h"
+#include "8x8font_tga_raw.h"
 #include "dsmain.h"
 #include "osystem_ds.h"
 
@@ -127,11 +128,22 @@ int keyboardY;
 int mapBase;
 int tileBase;
 
+u16* baseAddress;
+
 bool shiftState;
 bool capsLockState;
 
 bool closed;
 
+char autoCompleteWord[NUM_WORDS][32];
+int autoCompleteCount;
+
+char autoCompleteBuffer[128];
+
+int selectedCompletion = -1;
+int charactersEntered = 0;
+
+
 void restoreVRAM(int tileBase, int mapBase, u16* saveSpace) {
 /*	for (int r = 0; r < 32 * 32; r++) {
 		((u16 *) SCREEN_BASE_BLOCK_SUB(mapBase))[r] = *saveSpace++;
@@ -159,6 +171,26 @@ void drawKeyboard(int tileBase, int mapBase, u16* saveSpace) {
 		BG_PALETTE_SUB[r] = ((u16 *) (keyboard_pal_raw))[r];
 	}
 
+	// this is the font
+	for (int tile = 0; tile < 94; tile++) {
+		
+		u16* tileAddr = (u16 *) (CHAR_BASE_BLOCK_SUB(tileBase) + (8192 + (tile * 32)));
+		u8* src = ((u8 *) (_8x8font_tga_raw)) + 18 + tile * 8;
+
+		for (int y = 0 ; y < 8; y++) {
+			for (int x = 0; x < 2; x++) {
+				 *(tileAddr + (y * 2) + x) =(*(src + (y * 752) + (x * 4) + 0) & 0x0F)
+									 	 | ((*(src + (y * 752) + (x * 4) + 1) & 0x0F) << 4)
+										 | ((*(src + (y * 752) + (x * 4) + 2) & 0x0F) << 8)
+										 | ((*(src + (y * 752) + (x * 4) + 3) & 0x0F) << 12);
+					
+			}
+		}
+	}
+				
+
+
+
 	for (int r = 0; r < 16; r++) {
 		int col = ((u16 *) (keyboard_pal_raw))[r];
 		
@@ -167,17 +199,19 @@ void drawKeyboard(int tileBase, int mapBase, u16* saveSpace) {
 		int blue = (col & 0x7C00) >> 10;
 		
 		red = (red * 8) / 16;
-		green = (green * 8) / 16;
+		green = (green * 24) / 16;
 		blue = (blue * 8) / 16;
+
+		if (green > 31) green = 31;
 				
 		BG_PALETTE_SUB[16 + r] = red | (green << 5) | (blue << 10);
 	}
 	
 	keyboardX = -2;
-	keyboardY = 2;
+	keyboardY = 1;
 	
-	mapBase = mapBase;
-	tileBase = tileBase;
+	DS::mapBase = mapBase;
+	DS::tileBase = tileBase;
 	
 	shiftState = false;
 	capsLockState = false;
@@ -186,6 +220,7 @@ void drawKeyboard(int tileBase, int mapBase, u16* saveSpace) {
 	int y = keyboardY;
 	
 	u16* base = ((u16 *) SCREEN_BASE_BLOCK_SUB(mapBase));
+	baseAddress = base;
 	
 	for (int r = 0; r < DS_NUM_KEYS; r++) {
 		base[(y + keys[r].y) * 32 + x + keys[r].x] = keys[r].keyNum * 2;
@@ -198,6 +233,36 @@ void drawKeyboard(int tileBase, int mapBase, u16* saveSpace) {
 	}
 	
 	closed = false;
+	clearAutoComplete();
+}
+
+void drawAutoComplete() {
+
+	for (int y = 12; y < 24; y++) {
+		for (int x = 0; x < 32; x++) {
+			baseAddress[y * 32 + x] = 127;
+		}
+	}
+			
+
+	for (int r = 0; r < autoCompleteCount; r++) {
+		int y = 12 + (r % 6) * 2;
+		int x = 0 + ((r / 6) * 16);
+
+		for (int p = 0; p < strlen(autoCompleteWord[r]); p++) {
+			char c = autoCompleteWord[r][p];
+			
+			int tile = c - 32 + 255;
+
+			if (selectedCompletion == r) {
+				tile |= 0x1000;
+			}
+
+			baseAddress[y * 32 + x + p] = tile;			
+			
+
+		}
+	}
 }
 
 bool getKeyboardClosed() {
@@ -220,13 +285,106 @@ void setKeyHighlight(int key, bool highlight) {
 	}
 }
 
+void addAutoComplete(char* word) {
+	if (autoCompleteCount == NUM_WORDS) return;
+	strcpy(&autoCompleteWord[autoCompleteCount++][0], word);
+	drawAutoComplete();
+}
+
+void setCharactersEntered(int count) {
+	charactersEntered = count;
+}
+
+void clearAutoComplete() {
+	autoCompleteCount = 0;
+	selectedCompletion = -1;
+	drawAutoComplete();
+}
+
+void typeCompletion(int current) {
+	Common::Event event;
+   	OSystem_DS* system = OSystem_DS::instance();
+
+	strcat(autoCompleteBuffer, &autoCompleteWord[current][charactersEntered]);
+	strcat(autoCompleteBuffer, " ");
+
+/*	consolePrintf("Typing word: %s\n", autoCompleteWord[current]);
+
+	for (int r = charactersEntered; r < strlen(autoCompleteWord[current]); r++) {
+		event.kbd.keycode = autoCompleteWord[current][r];
+		event.kbd.ascii = autoCompleteWord[current][r];
+		event.type = Common::EVENT_KEYDOWN;
+		event.kbd.flags = 0;
+		system->addEvent(event);
+	
+		event.type = Common::EVENT_KEYUP;
+		system->addEvent(event);
+	}
+
+	event.kbd.keycode = ' ';
+	event.kbd.ascii = ' ';
+
+	event.type = Common::EVENT_KEYDOWN;
+	system->addEvent(event);
+
+	event.type = Common::EVENT_KEYUP;
+	system->addEvent(event);*/
+}
+
+void updateTypeEvents()
+{
+	if (autoCompleteBuffer[0] != '\0')
+	{
+		Common::Event event;
+   		OSystem_DS* system = OSystem_DS::instance();
+	
+		event.kbd.keycode = autoCompleteBuffer[0];
+		event.kbd.ascii = autoCompleteBuffer[0];
+		event.type = Common::EVENT_KEYDOWN;
+		event.kbd.flags = 0;
+		system->addEvent(event);
+	
+		event.type = Common::EVENT_KEYUP;
+		system->addEvent(event);
+
+		for (int r = 0; r < strlen(autoCompleteBuffer); r++)
+		{
+			autoCompleteBuffer[r] = autoCompleteBuffer[r + 1];
+		}
+	}
+}
+
+
 void addKeyboardEvents() {
+	updateTypeEvents();
+
 	if (DS::getPenDown()) {
 		int x = IPC->touchXpx;
 		int y = IPC->touchYpx;
 		
-		int tx = (x >> 3) - keyboardX;
-		int ty = (y >> 3) - keyboardY;
+		int tx = (x >> 3);
+		int ty = (y >> 3);
+
+		if (ty >= 12) {
+			int current = -1;
+
+			if (tx < 12) {
+				current = (ty - 12) / 2;
+			} else {
+				current = 6 + (ty - 12) / 2;
+			}
+
+			if (selectedCompletion == current) {
+				typeCompletion(current);
+			} else {
+				selectedCompletion = current;
+			}
+
+			drawAutoComplete();
+		}
+
+		tx -= keyboardX;
+		ty -= keyboardY;
 		
 //		consolePrintf("x=%d y=%d\n", tx, ty);
 		
@@ -241,8 +399,14 @@ void addKeyboardEvents() {
 					// Close button
 					DS::closed = true;
 				} else	if ((keys[r].character >= '0') && (keys[r].character <= '9')) {
-					event.kbd.ascii = keys[r].character;
-					event.kbd.keycode = 0;
+
+					if (!DS::shiftState) {
+						event.kbd.ascii = keys[r].character;
+						event.kbd.keycode = 0;
+					} else {
+						event.kbd.keycode = SDLK_F1 - (keys[r].character - '1');
+						event.kbd.ascii = 0;
+					}					
 				
 				} else if ((keys[r].character >= 'A') && (keys[r].character <= 'Z')) {
 					
diff --git a/backends/platform/ds/arm9/source/touchkeyboard.h b/backends/platform/ds/arm9/source/touchkeyboard.h
index e8f5fda37e..42051a1f11 100644
--- a/backends/platform/ds/arm9/source/touchkeyboard.h
+++ b/backends/platform/ds/arm9/source/touchkeyboard.h
@@ -25,11 +25,18 @@
 
 namespace DS {
 
+static const int NUM_WORDS = 12;
+
+
 void drawKeyboard(int tileBase, int mapBase, u16* saveSpace);
 void restoreVRAM(int tileBase, int mapBase, u16* saveSpace);
 void addKeyboardEvents();
 bool getKeyboardClosed();
 
+void addAutoComplete(char* word);
+void clearAutoComplete();
+void setCharactersEntered(int count);
+
 }
 
 #endif
diff --git a/backends/platform/ds/arm9/source/wordcompletion.cpp b/backends/platform/ds/arm9/source/wordcompletion.cpp
new file mode 100644
index 0000000000..a73656ea61
--- /dev/null
+++ b/backends/platform/ds/arm9/source/wordcompletion.cpp
@@ -0,0 +1,67 @@
+#include "wordcompletion.h"
+#include "engines/agi/agi.h"
+#include "osystem_ds.h"
+
+#ifndef DISABLE_AGI
+
+namespace DS {
+
+void findWordCompletions(char* input) {
+	int start = 0;
+	for (int r = strlen(input) - 1; r>0; r--) {
+		if (input[r] == ' ') {
+			start = r + 1;
+			break;
+		}
+	}
+
+	char word[32];
+	strcpy(word, &input[start]);
+
+	int fchr = word[0] - 'a';
+	int len = strlen(word);
+
+	OSystem_DS* system = (OSystem_DS *) g_system;
+	system->clearAutoComplete();
+	system->setCharactersEntered(strlen(word));
+
+	if (strlen(word) == 0) {
+		return;
+	}		
+
+	uint8 *wordList = Agi::AgiEngine::getWordsData();
+	uint8 *wordListEnd = Agi::AgiEngine::getWordsData() + Agi::AgiEngine::getWordsDataSize();
+
+	/* Get the offset to the first word beginning with the
+	 * right character
+	 */
+	wordList += READ_BE_UINT16(wordList + 2 * fchr);
+
+	char currentWord[32];
+
+	
+	while (wordList < wordListEnd) {
+		int pos = *wordList++;		// Number of chars to keep from previous word
+
+		if (wordList == wordListEnd)
+			break;
+
+		char c;
+		do {
+			c = *wordList++;
+			currentWord[pos++] =  (~c) & 0x7F;
+		} while ((c & 0x80) == 0);		// Top bit indicates end of word
+		currentWord[pos++] = '\0';
+
+		if (!strncmp(currentWord, word, strlen(word))) {
+			system->addAutoComplete(currentWord);
+		}
+
+		wordList += 2;	// Skip the two byte word id.
+
+	}
+
+}
+
+}
+#endif
diff --git a/backends/platform/ds/arm9/source/wordcompletion.h b/backends/platform/ds/arm9/source/wordcompletion.h
new file mode 100644
index 0000000000..b0d43713cc
--- /dev/null
+++ b/backends/platform/ds/arm9/source/wordcompletion.h
@@ -0,0 +1,8 @@
+
+
+
+namespace DS {
+
+extern void findWordCompletions(char* input);
+
+}
\ No newline at end of file
diff --git a/backends/platform/ds/arm9/source/zipreader.cpp b/backends/platform/ds/arm9/source/zipreader.cpp
index 59f695ebce..0c86bd97ae 100644
--- a/backends/platform/ds/arm9/source/zipreader.cpp
+++ b/backends/platform/ds/arm9/source/zipreader.cpp
@@ -31,7 +31,7 @@
 ZipFile::ZipFile() {
 	// Locate a zip file in cartridge memory space
 	
-	consolePrintf("ZIP file check...");
+//	consolePrintf("ZIP file check...");
 	
 	char* p = (char *) ZF_SEARCH_START;
 	bool found = false;
@@ -52,9 +52,9 @@ ZipFile::ZipFile() {
 	}
 
 	if (_zipFile) {
-		consolePrintf("Ok!\n");
+		consolePrintf("ZIP File found Ok!\n");
 	} else {
-		consolePrintf("Not in use!\n");
+//		consolePrintf("Not in use!\n");
 		return;
 	}
 	
-- 
cgit v1.2.3