Index: .gitignore ================================================================== --- .gitignore +++ .gitignore @@ -30,12 +30,14 @@ ObjFW.xcodeproj/project.xcworkspace ObjFW.xcodeproj/xcuserdata src/objfw-defs.h src/ObjFW tests/tests +tests/tests.arm9 tests/tests.exe +tests/tests.nds tests/EBOOT.PBP tests/PARAM.SFO tests/objc_sync/objc_sync utils/objfw-config utils/ofzip utils/ofzip.exe Index: PLATFORMS.md ================================================================== --- PLATFORMS.md +++ PLATFORMS.md @@ -82,10 +82,20 @@ * OS Versions: 5.1-6.1 * Architectures: x86, x86_64 * Compilers: Clang 3.0-3.2, GCC 4.1.3 & 4.5.3 * Runtimes: ObjFW + +Nintendo DS +----------- + + * Architectures: ARM (EABI) + * Compilers: GCC 4.8.2 (devkitARM release 42) + * Runtimes: ObjFW + * Limitations: No threads, no sockets + * Note: File support requires an argv-compatible launcher (such as HBMenu) + OpenBSD ------- * OS Versions: 5.2-5.4 Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -55,10 +55,30 @@ enable_threads="no" # TODO AC_SUBST(MAP_LDFLAGS, ['-Wl,-Map,$@.map']) ]) +AC_ARG_WITH(nds, + AS_HELP_STRING([--with-nds], [build for Nintendo DS])) +AS_IF([test x"$with_nds" = x"yes"], [ + AS_IF([test x"$DEVKITPRO" = x""], [ + AC_MSG_ERROR([DEVKITPRO is not set! Please set DEVKITPRO.]) + ]) + + OBJCFLAGS="$OBJCFLAGS -march=armv5te -mtune=arm946e-s" + OBJCFLAGS="$OBJCFLAGS -mthumb -mthumb-interwork" + CPPFLAGS="$CPPFLAGS -DARM9 -I$DEVKITPRO/libnds/include" + LDFLAGS="$LDFLAGS -specs=ds_arm9.specs" + LIBS="$LIBS -L$DEVKITPRO/libnds/lib -lfilesystem -lfat -lnds9" + enable_shared="no" + enable_threads="no" # TODO + enable_sockets="no" # TODO + + AC_DEFINE(OF_NINTENDO_DS, 1, + [Whether we are compiling for the Nintendo DS]) + AC_SUBST(MAP_LDFLAGS, ['-Wl,-Map,$@.map']) +]) CPP="$OBJCPP" CPPFLAGS="$CPPFLAGS $OBJCPPFLAGS" OBJCFLAGS="$OBJCFLAGS -Wall -fexceptions -fobjc-exceptions -funwind-tables" OBJCFLAGS="$OBJCFLAGS -fconstant-string-class=OFConstantString" Index: src/OFApplication.m ================================================================== --- src/OFApplication.m +++ src/OFApplication.m @@ -47,10 +47,16 @@ #ifdef _PSP # include # include #endif + +#ifdef OF_NINTENDO_DS +# define asm __asm__ +# include +# undef asm +#endif @interface OFApplication (OF_PRIVATE_CATEGORY) - (void)OF_setArgumentCount: (int*)argc andArgumentValues: (char**[])argv; #ifdef _WIN32 @@ -333,20 +339,28 @@ _argc = argc; _argv = argv; encoding = [OFString nativeOSEncoding]; - _programName = [[OFString alloc] initWithCString: (*argv)[0] - encoding: encoding]; - arguments = [[OFMutableArray alloc] init]; - - for (i = 1; i < *argc; i++) - [arguments addObject: [OFString stringWithCString: (*argv)[i] - encoding: encoding]]; - - [arguments makeImmutable]; - _arguments = arguments; +# ifdef OF_NINTENDO_DS + if (__system_argv->argvMagic == ARGV_MAGIC && + __system_argv->argc >= 1) { +# endif + _programName = [[OFString alloc] initWithCString: (*argv)[0] + encoding: encoding]; + arguments = [[OFMutableArray alloc] init]; + _arguments = arguments; + + for (i = 1; i < *argc; i++) + [arguments addObject: + [OFString stringWithCString: (*argv)[i] + encoding: encoding]]; + + [arguments makeImmutable]; +# ifdef OF_NINTENDO_DS + } +# endif objc_autoreleasePoolPop(pool); #else _argc = argc; _argv = argv; Index: src/OFFile.m ================================================================== --- src/OFFile.m +++ src/OFFile.m @@ -23,10 +23,11 @@ /* Work around a bug with Clang + glibc */ #ifdef __clang__ # define _HAVE_STRING_ARCH_strcmp #endif +#include #include #include #include #include @@ -45,10 +46,14 @@ #ifdef __wii__ # define BOOL OGC_BOOL # include # undef BOOL #endif + +#ifdef OF_NINTENDO_DS +# include +#endif #import "OFFile.h" #import "OFString.h" #import "OFArray.h" #ifdef OF_HAVE_THREADS @@ -177,10 +182,16 @@ exceptionWithClass: self]; #endif #ifdef __wii__ if (!fatInitDefault()) + @throw [OFInitializationFailedException + exceptionWithClass: self]; +#endif + +#ifdef OF_NINTENDO_DS + if (!nitroFSInit(NULL)) @throw [OFInitializationFailedException exceptionWithClass: self]; #endif } Index: src/OFString.m ================================================================== --- src/OFString.m +++ src/OFString.m @@ -829,10 +829,13 @@ char *tmp; struct stat st; @try { OFFile *file; + + /* Make sure the file system is initialized */ + [OFFile class]; if (stat([path cStringWithEncoding: [OFString nativeOSEncoding]], &st) == -1) @throw [OFOpenFileFailedException exceptionWithPath: path Index: src/OFThread.m ================================================================== --- src/OFThread.m +++ src/OFThread.m @@ -47,10 +47,16 @@ #import "OFAutoreleasePool+Private.h" #ifdef _WIN32 # include #endif + +#ifdef OF_NINTENDO_DS +# define asm __asm__ +# include +# undef asm +#endif #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFNotImplementedException.h" #import "OFOutOfRangeException.h" @@ -193,10 +199,19 @@ if (rqtp.tv_sec != floor(timeInterval)) @throw [OFOutOfRangeException exception]; nanosleep(&rqtp, NULL); +#elif defined(OF_NINTENDO_DS) + uint64_t counter; + + if (timeInterval > UINT64_MAX / 60) + @throw [OFOutOfRangeException exception]; + + counter = timeInterval * 60; + while (counter--) + swiWaitForVBlank(); #else if (timeInterval > UINT_MAX) @throw [OFOutOfRangeException exception]; sleep((unsigned int)timeInterval); Index: src/forwarding/forwarding-arm-elf.S ================================================================== --- src/forwarding/forwarding-arm-elf.S +++ src/forwarding/forwarding-arm-elf.S @@ -142,11 +142,15 @@ sel_forwardingTargetForSelector_$indirect_.L1: .long sel_forwardingTargetForSelector_-(.L1+8) module$indirect_.L2: .long module-(.L2+8) +#ifndef OF_NINTENDO_DS .section .ctors, "aw", %progbits +#else +.section .init_array, "aw", %init_array +#endif .long init .section .rodata str_forwardingTargetForSelector_: .asciz "forwardingTargetForSelector:" Index: src/objfw-defs.h.in ================================================================== --- src/objfw-defs.h.in +++ src/objfw-defs.h.in @@ -23,8 +23,9 @@ #undef OF_HAVE_SCHED_YIELD #undef OF_HAVE_SOCKETS #undef OF_HAVE_SYMLINK #undef OF_HAVE_SYS_SOCKET_H #undef OF_HAVE_THREADS +#undef OF_NINTENDO_DS #undef OF_OBJFW_RUNTIME #undef OF_UNIVERSAL #undef SIZE_MAX Index: src/runtime/exception.m ================================================================== --- src/runtime/exception.m +++ src/runtime/exception.m @@ -466,11 +466,13 @@ tmp = lsda->typestable - (filter * 4); c = *(uintptr_t*)(void*)tmp; if (c != 0) { c += (uintptr_t)tmp; +# if defined(__linux__) || defined(__NetBSD__) c = *(uintptr_t*)c; +# endif } #else uintptr_t i; i = filter * size_for_encoding(lsda->typestable_enc); Index: tests/Makefile ================================================================== --- tests/Makefile +++ tests/Makefile @@ -1,8 +1,13 @@ include ../extra.mk SUBDIRS = ${TESTPLUGIN} + +CLEAN = EBOOT.PBP \ + boot.dol \ + ${PROG_NOINST}.arm9 \ + ${PROG_NOINST}.nds PROG_NOINST = tests${PROG_SUFFIX} SRCS = ForwardingTests.m \ OFArrayTests.m \ ${OFBLOCKTESTS_M} \ @@ -104,14 +109,24 @@ psp-strip ${PROG_NOINST} pack-pbp $@ PARAM.SFO NULL NULL NULL NULL NULL ${PROG_NOINST} NULL boot.dol: ${PROG_NOINST} elf2dol ${PROG_NOINST} $@ + +${PROG_NOINST}.arm9: ${PROG_NOINST} + arm-none-eabi-objcopy -O binary $< $@ + +${PROG_NOINST}.nds: ${PROG_NOINST}.arm9 + rm -fr nds-data + mkdir -p nds-data + cp testfile.bin testfile.txt testfile.ini serialization.xml nds-data + ndstool -c $@ -9 $< -d nds-data + rm -fr nds-data include ../buildsys.mk ${PROG_NOINST}: ${LIBOBJFW_DEP} CPPFLAGS += -I../src -I../src/exceptions -I../src/runtime -I.. -DSTDOUT LIBS := -L../src -lobjfw ${TESTS_LIBS} ${LIBS} LDFLAGS += ${MAP_LDFLAGS} LD = ${OBJC} Index: tests/OFINIFileTests.m ================================================================== --- tests/OFINIFileTests.m +++ tests/OFINIFileTests.m @@ -106,13 +106,18 @@ TEST(@"-[removeValueForKey:]", R([category removeValueForKey: @"quxqux"])) module = @"OFINIFile"; + /* FIXME: Find a way to write files on Nintendo DS */ +#ifndef OF_NINTENDO_DS TEST(@"-[writeToFile:]", R([file writeToFile: @"tmpfile.ini"]) && [[OFString stringWithContentsOfFile: @"tmpfile.ini"] isEqual: output]) [OFFile removeItemAtPath: @"tmpfile.ini"]; +#else + (void)output; +#endif [pool drain]; } @end Index: tests/TestsAppDelegate.m ================================================================== --- tests/TestsAppDelegate.m +++ tests/TestsAppDelegate.m @@ -42,10 +42,16 @@ # include # undef BOOL # undef asm #endif +#ifdef OF_NINTENDO_DS +# define asm __asm__ +# include +# undef asm +#endif + enum { NO_COLOR, RED, GREEN, YELLOW @@ -117,11 +123,15 @@ if ((tid = sceKernelCreateThread("update_thread", callback_thread, 0x11, 0xFA0, 0, 0)) >= 0) sceKernelStartThread(tid, 0, 0); #endif -#if defined(__wii__) || defined(_PSP) +#ifdef OF_NINTENDO_DS + consoleDemoInit(); +#endif + +#if defined(__wii__) || defined(_PSP) || defined(OF_NINTENDO_DS) @try { return of_application_main(&argc, &argv, [TestsAppDelegate class]); } @catch (id e) { TestsAppDelegate *delegate = @@ -137,11 +147,10 @@ [delegate outputString: backtrace inColor: RED]; # if defined(__wii__) [delegate outputString: @"Press home button to exit!\n" inColor: NO_COLOR]; - for (;;) { WPAD_ScanPads(); if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME) [OFApplication terminateWithStatus: 1]; @@ -148,10 +157,19 @@ VIDEO_WaitVSync(); } # elif defined(_PSP) sceKernelSleepThreadCB(); +# elif defined(OF_NINTENDO_DS) + [delegate outputString: @"Press start button to exit!" + inColor: NO_COLOR]; + for (;;) { + swiWaitForVBlank(); + scanKeys(); + if (keysDown() & KEY_START) + [OFApplication terminateWithStatus: 1]; + } # else abort(); # endif } #else @@ -190,11 +208,11 @@ pspDebugScreenPrintData([str UTF8String], [str UTF8StringLength]); #elif defined(STDOUT) switch (color) { case NO_COLOR: [of_stdout writeString: @"\r\033[K"]; -# ifdef __wii__ +# if defined(__wii__) || defined(OF_NINTENDO_DS) [of_stdout writeString: @"\033[37m"]; # endif break; case RED: [of_stdout writeString: @"\r\033[K\033[31;1m"]; @@ -282,10 +300,20 @@ if (!(pad.Buttons & PSP_CTRL_CROSS)) return; } } } +# endif +# ifdef OF_NINTENDO_DS + [self outputString: @"Press A to continue!" + inColor: NO_COLOR]; + for (;;) { + swiWaitForVBlank(); + scanKeys(); + if (keysDown() & KEY_A) + break; + } # endif #else [self outputString: @"failed\n" inColor: RED]; #endif @@ -355,10 +383,19 @@ #elif defined(_PSP) [self outputString: [OFString stringWithFormat: @"%d tests failed!", _fails] inColor: NO_COLOR]; sceKernelSleepThreadCB(); +#elif defined(OF_NINTENDO_DS) + [self outputString: @"Press start button to exit!" + inColor: NO_COLOR]; + for (;;) { + swiWaitForVBlank(); + scanKeys(); + if (keysDown() & KEY_START) + [OFApplication terminateWithStatus: _fails]; + } #else [OFApplication terminateWithStatus: _fails]; #endif } @end