console-dev.de

Home of VsTortoise, VisualHAM, N3D and HEL Library

Archive for September, 2009

The processors built-in the Nintendo DS, an ARM946E-S and ARM7TDMI, support hardware exceptions such as “Data Abort – accessing invalid memory addresses” and “Undefined Instruction”. The Nintendo DS homebrew library libnds includes exception handling and comes with a default handler that displays the exception type, at which address in the instruction sequence the exception occured and a dump of all registers.

In this article I show what you can do with this information and why it is useful during development.

libnds exceptionTest example

If you installed the libnds examples, you should find the exeptionTest example in devkitPro\examples\nds\debugging\exceptionTest.

Copy&Paste from exceptionTest.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <nds.h>
 
/*---------------------------------------------------------------------------------
 
 The default exception handler displays the exception type - data abort or undefined
 instruction you can relate the exception to your code using
 
    arm-eabi-addr2line -e <elf file> <address>
 
 assuming you built with debug info this will display a source file and a line number
 The address of the instruction is shown as pc, beside the address which faulted
 the rest of the screen is a dump of the registers.
 
---------------------------------------------------------------------------------*/
 
//---------------------------------------------------------------------------------
int main(void)
{
  // install the default exception handler
  defaultExceptionHandler();
 
  // generate an exception
  *(unsigned int*)0xFA = 0x64;
 
  // never comes here
  while(1)
    swiWaitForVBlank();
 
  return 0;
}

When you build and run the example project, it displays:

Guru Meditation Error! - Data Abort

This is actually a fake screenshot. I rebuilt the Guru Meditation Error with printf, because the example didn’t behave in any emulator as on actual hardware. I tested no$gba 2.6a, iDeaS 1.0.3.3 beta and DeSmeME 0.9.5, none of them displayed the error report as on the real Nintendo DS hardware.

guru meditation origin

Guru Meditation is the name of the error that occurred on early versions of the Commodore Amiga computer when they crashed. It is analogous to the “Blue Screen Of Death” in Microsoft Windows operating systems.

The Guru Meditation error message was a black screen with the following animation at the top:

Commodore Amiga - Guru Meditation error message

decode nds guru meditation data abort message

One of the Nintendo DS variants of the Guru Meditation error message is the data abort, which includes the following information:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
     Guru Meditation Error!    
          data abort!          
 
  pc: 02000386 addr: 000000FA  
 
  r0: 020005BD   r8 : 00000000 
  r1: 00000000   r9 : 00000000 
  r2: 00000064   r10: 00000000 
  r3: 000000FA   r11: 00000000 
  r4: 0B000000   r12: 02000000 
  r5: 00000000   sp : 0B003CF8 
  r6: 00000000   lr : 020005B5 
  r7: 00000000   pc : 0200038E 
 
  0B003CF8: 0B000000 02000180  
  0B003D00: 00000000 00000000  
  0B003D08: 00000000 00000000  
  0B003D10: 00000000 00000000  
  0B003D18: 00000000 00000000  
  0B003D20: 00000000 00000000  
  0B003D28: 00000000 00000000  
  0B003D30: 00000000 00000000  
  0B003D38: 00000000 00000000  
  0B003D40: 00000000 00000000

The first line is always “Guru Meditation Error!”, followed by the type of the exception:

1
2
     Guru Meditation Error!    
          data abort!

The libnds default exception handler displays “Data Abort” and “Undefined Instructions” exceptions.

Below the exception type is pc and addr displayed, which I guess is not very obvious for many novice programmers:

1
  pc: 02000386 addr: 000000FA

pc is short for Program Counter. The Program Counter register indicates where the processor is in its instruction sequence. In this case, it’s the address of the instruction that caused the exception.

addr represents the exception address. In this case, writing to the memory address 0xFA:

1
2
  // generate an data abort exception
  *(unsigned int*)0xFA = 0x64;

This again is followed by a register dump:

1
2
3
4
5
6
7
8
  r0: 020005BD   r8 : 00000000 
  r1: 00000000   r9 : 00000000 
  r2: 00000064   r10: 00000000 
  r3: 000000FA   r11: 00000000 
  r4: 0B000000   r12: 02000000 
  r5: 00000000   sp : 0B003CF8 
  r6: 00000000   lr : 020005B5 
  r7: 00000000   pc : 0200038E
  • r0r12 are the so called General Purpose Registers.
  • sp (r13) is the Stack Pointer Register, which indicates the current top of stack memory.
  • lr (r14) represents the Link Register, which holds the return address when the current function completes (it’s the address of the caller).
  • pc (r15) is short for Program Counter. The Program Counter register indicates where the processor is in its instruction sequence.

The last information in the error report is a memory dump of the top 80 bytes of stack memory:

1
2
3
4
5
6
7
8
9
10
  0B003CF8: 0B000000 02000180  
  0B003D00: 00000000 00000000  
  0B003D08: 00000000 00000000  
  0B003D10: 00000000 00000000  
  0B003D18: 00000000 00000000  
  0B003D20: 00000000 00000000  
  0B003D28: 00000000 00000000  
  0B003D30: 00000000 00000000  
  0B003D38: 00000000 00000000  
  0B003D40: 00000000 00000000
  • First column specifies the stack address (0B003CF8)
  • Second column shows the 32bit value from the stack address (0B000000)
  • Third column shows the 32bit value from the stack address + 4 bytes (02000180)

how to make use of all this

This information is informative only when the output file was built with debug information. You can include debug information by adding the -g option (produce debugging information) to CFLAGS in the project makefile:

Copy&Paste from exceptionTest makefile:

1
2
3
4
5
CFLAGS	:= -g -Wall -O2\
		-march=armv5te -mtune=arm946e-s \
 		-fomit-frame-pointer\
		-ffast-math \
		$(ARCH)

devkitARM includes an application named “arm-eabi-addr2line.exe”, located in devkitPro\devkitARM\bin, that can be used to convert addresses into line number/file name pairs. It supports the following command line options:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Usage: arm-eabi-addr2line.exe [option(s)] [addr(s)]
 Convert addresses into line number/file name pairs.
 If no addresses are specified on the command line, they will be read from stdin
 
 The options are:
  @<file>                Read options from <file>
  -b --target=<bfdname>  Set the binary file format
  -e --exe=<executable>  Set the input file name (default is a.out)
  -i --inlines           Unwind inlined functions
  -j --section=<name>    Read section-relative offsets instead of addresses
  -s --basenames         Strip directory names
  -f --functions         Show function names
  -C --demangle[=style]  Demangle function names
  -h --help              Display this information
  -v --version           Display the program's version

We are interested in the address where the Data Abort exception occured, named pc here:

1
2
3
4
     Guru Meditation Error!    
          data abort!          
 
  pc: 02000386 addr: 000000FA

I used the following commandline for conversion:

1
arm-eabi-addr2line.exe -f -C -e  -s -i exceptionTest.elf 02000386

The output is:

1
2
main
exceptionTest.c:23

When you scroll at the beginning of this article, where I present the source code of the exceptionTest example, you see line 23 is inside main(), which is stored in exceptionTest.c and contains the code that writes to the address 0xFA.

conclusion

Make sure to install an exception handler in your projects. It’s very helpful to actually see that an error occured rather than a freeze. libnds makes it enormously easy, it’s just one line of code!

introduction

In this article I show how to set up Microsoft Visual Studio 2008 to use the devkitARM compiler to create applications for the Nintendo DS. After you have read this article, you are able to use Visual Studio 2008 to build, rebuild, clean and execute your Nintendo DS application.

Visual Studio 2008 Express can be downloaded for free at microsoft.com, you want to have the C++ edition: Download Visual C++ 2008 Express Edition.

prerequisites

I assume you already have devkitARM and Visual Studio 2008 installed and both function correctly. I further assume you have a project that you want to migrate from e.g. VisualHAM, Programmers Notepad, etc… to Visual Studio, so I use the hello world example from libnds as existing project reference, which is located in devkitPro\examples\nds\hello_world.

create new visual studio project

We need to create an empty makefile project. You can find this in Visual Studio 2008 under Main menu -> New -> Project:

Visual Studio 2008 - Showing the path to create a new project

Select the project template and target location:

Visual Studio 2008 - Create new project dialog

Rather than selecting the hello_world directory, we specify its parent, because Visual Studio creates a sub directory in the specified location with the specified name. This configuration will save the project file directly in the existing hello_world directory.

Click OK to continue.

configure new project

A new dialog pops up, the New Project Wizard:

Visual Studio 2008 - Create new project wizard

Just click Next here to move on to the next page.

The following page looks more like fun! Settings specified in this New Project Wizard can be changed at any time in the Project Settings as well:

Visual Studio 2008 - Create new project wizard

Please note that none of these settings have influence on the build process: Output, Preprocessor definitions, Include search path, Forced include files, CMR assembly search path and Forced using .NET assemblies.

We set Preprocessor definitions so Visual Studio knows which ARM9/ARM7 #if’s to syntax highlight differently. This is not passed to devkitARM.

We set Include search path so Visual Studio knows where to look for the libnds headers to provide code completion and intellisense, it will not add it to the search path used by devkitARM.

Here is an example what code completion and intellisense look like, first code completion:

Visual Studio 2008 - Code completion (with Visual AssistX add-in activated)

Intellisense:
Visual Studio 2008 - Showing intellisense (with Visual AssistX add-in activated)

The remaining commands in the New Project Wizard are what you typically use when working via the command prompt or shell. Now click Finish to complete the Wizard.

The New Project Wizard closes and Visual Studio shows an empty workspace now:

Visual Studio 2008 - Showing an empty project

add files to project

It’s essential to know that Visual Studio will just invoke the commands specified in the New Project Wizard to build the project.

Compiling and linking your Nintendo DS application is entirely handled by devkitARM, NOT Visual Studio!

Visual Studio is only the graphical front-end that triggers these devkitARM build processes and serves as code editor.

The devkitPro makefile system has a feature to add directories that are supposed to contain source code to the so called SOURCES variable. All source files in those directories, added to this variables, are being compiled and considered during the link process.

Copied from devkitPro\examples\nds\hello_world\Makefile:

1
2
3
4
5
6
7
8
9
10
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files
#---------------------------------------------------------------------------------
TARGET		:=	$(shell basename $(CURDIR))
BUILD		:=	build
SOURCES		:=	gfx source data  
INCLUDES	:=	include build

This means that source files don’t get compiled when you add them to the Visual Studio project, but when you store them in the source directory of your file system!

add files to project, really

Now that you know your files don’t get compiled when you only add them to the Visual Studio Project, let’s really add them. You can do this via drag&drop operations from the Windows Explorer or via the Visual Studio Project context menu:

Visual Studio 2008 - Menu path to add an existing item to a project file

A new “File Open” dialog appears, which you have to navigate to your source files, select them and click Add. I recommend you add the makefile too.

Once done, your Visual Studio Project should look similar to this:

Visual Studio 2008 - Editing a .cpp file

compile project

The magic moment has arrived, to compile the project you can use the Build sub-menu from the mainbar or hit CTRL+SHIFT+B:

Visual Studio 2008 - Showing the Build sub-menu in the mainbar

When everything is configured properly, the project should build just fine and the output looks like:

1
2
3
4
5
6
7
8
9
10
11
12
1>------ Build started: Project: hello_world, Configuration: Debug Win32 ------
1>Performing Makefile project actions
1>main.cpp
1>arm-eabi-g++ -MMD -MP -MF /c/devkitPro/examples/nds/hello_world/build/main.d -g -Wall -O2 -march=armv5te -mtune=arm946e-s -fomit-frame-pointer -ffast-math -mthumb -mthumb-interwork -I/c/devkitPro/examples/nds/hello_world/include -I/c/devkitPro/examples/nds/hello_world/build -I/c/devkitPro/libnds/include -I/c/devkitPro/libnds/include -I/c/devkitPro/examples/nds/hello_world/build -DARM9 -fno-rtti -fno-exceptions -c /c/devkitPro/examples/nds/hello_world/source/main.cpp -o main.o
1>linking hello_world.elf
1>built ... hello_world.arm9
1>Nintendo DS rom tool 1.41 - May  1 2009
1>by Rafael Vuijk, Dave Murphy, Alexei Karpenko
1>built ... hello_world.nds
1>Build log was saved at "file://c:\devkitPro\examples\nds\hello_world\Debug\BuildLog.htm"
1>hello_world - 0 error(s), 0 warning(s)
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

compile project, the Vista barrier

I use Microsoft Vista and have to run Visual Studio 2008 as administrator, otherwise it outputs this error:

1
2
3
4
5
6
7
8
9
1>------ Build started: Project: hello_world, Configuration: Debug Win32 ------
1>Performing Makefile project actions
1>      0 [main] us 0 init_cheap: VirtualAlloc pointer is null, Win32 error 487
1>AllocationBase 0x0, BaseAddress 0x71110000, RegionSize 0x2C0000, State 0x10000
1>c:\devkitPro\msys\bin\make.exe: *** Couldn't reserve space for cygwin's heap, Win32 error 0
1>Project : error PRJ0019: A tool returned an error code from "Performing Makefile project actions"
1>Build log was saved at "file://c:\devkitPro\examples\nds\hello_world\Debug\BuildLog.htm"
1>hello_world - 1 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

If you encounter the same problem, see if it fixes the problem when you start Visual Studio 2008 with administrator privileges. You can do this when you right-click the Visual Studio 2008 startmenu entry and select “Run as administrator”.

add a rebuild target

We specified “make rebuild” in the New Project Wizard, but this target does not exist by default, so we have to create it first. Basically it should perform:

1
2
make clean
make

Open the makefile and add this below clean:

1
rebuild: clean $(BUILD)

Visual Studio 2008 - Adding a 'rebuild' target to makefile

Select Build -> Rebuild Solution and see the output if it’s performing correctly.

add run target

So far we were able to compile, clean and rebuild the Nintendo DS project out of Visual Studio, but how to run it? We use a software emulator! I use no$gba to run my Game Boy Advance and Nintendo DS applications, so I want Visual Studio to start no$gba as well!

We do this like we did with rebuild, we add a new target to makefile which is responsible to start and pass the filename to the Nintendo DS emulator, in my case no$gba.

Put this below our earlier added rebuild target:

1
2
run: $(BUILD)
	$(DEVKITPRO)/utilities/nogba/nogba.exe $(TARGET).nds

The tab at the beginning at the 2nd line is important and must not be removed, you also want to modify the path to where the emulator of your choice is located.

Visual Studio 2008 - Adding a target to run the output in an emulator

Now open the Visual Studio Project Properties:

Visual Studio 2008 - Project context menu

Select Debugging in the following dialog and fill out the Command and Command Argument text boxes:

Visual Studio 2008 - Project debugging properties

Confirm the dialog with OK and select Debug -> Start Debugging, the project should build and start in the specified emulator!

Visual Studio compatible build messages

All build messages are redirected to the Visual Studio output “Build” pane. Warnings and errors include the filename and line number, but those are in the GCC format and when you double click them, Visual Studio is smart enough to open this file, but not to go to the line.

1
1>c:/devkitPro/examples/nds/hello_world/source/main.cpp:17: error: expected constructor, destructor, or type conversion before 'void'

Double clicking this line opens main.cpp, but keeps the cursor at line 1.

Fortunalety, Jasper ‘cearn’ Vijn once had a regular expression on his website that transforms GCC messages in to Visual Studio format and I was clever enough to make a backup before the information went offline:

1
's/\(\w\+\):\([0-9]\+\):/\1(\2):/'

We can redirect the build output to sed.exe (stream editor), which uses this regular expresssion to transform and output the text so Visual Studio can handle it.

We do this by extending the commands earlier specified in the New Project Wizard.

Visual Studio 2008 - Project context menu

In the following dialog select NMake and modify the settings as shown below:

Visual Studio 2008 - Makefile Project properties

Build Command line:

1
make 2>&1 | sed -e 's/\(\w\+\):\([0-9]\+\):/\1(\2):/'

Rebuild All Command line:

1
make rebuild 2>&1 | sed -e 's/\(\w\+\):\([0-9]\+\):/\1(\2):/'

If you have never seen this 2>&1 before, it’s called command redirection operator and a feature of Microsoft Windows. >& writes the output from one handle to the input of another handle. Next comes |, the pipe operator. It takes the output of one command and directs it into the input of another command.

Confirm the Project Properties Dialog with OK, add an invalid line of code to one source file and build. The error message should look like this now and is clickable:

1
1>c:/devkitPro/examples/nds/hello_world/source/main.cpp(17): error: expected constructor, destructor, or type conversion before 'void'

we are done

Happy compiling!

This site uses a Hackadelic PlugIn, Hackadelic SEO Table Of Contents 1.6.0.