console-dev.de

Home of VsTortoise, VisualHAM, N3D and HEL Library

Archive for April, 2009

Nintendo DS 4k Intro

Posted by Peter Schraut under NDS, Programming

Over eastern I followed the breakpoint demo party via live stream and was especially attired in the 4k intro competition, that motivated me to try if it is possible to create an application that draws a simple quad in 4096 bytes on the Nintendo DS, using the devkitARM tool-chain.

However, even compiling a .c file containing only the application entry point, without any external libraries, already creates a .nds file that is 54848 bytes:

int main(void)
{
  return 0;
}

After fiddling around for “some” time, I had a .nds file that not only shows a simple quad, I had one that shows hundreds of lit textured cubes that create a tunnel where the camera flies through with a fullscreen distortion effect in less than 4096 bytes.

Once we’ve released it at pouet.net, I figured from the comments I could had shrink the filesize further 480 bytes by just compressing it – I feel so dumb! ;)

Obviously it can not compete with the breakpoint 4k entries, but I felt good that I was able to do it anyway, especially because it seems to be the worlds first 4k intro for the Nintendo DS! Unfortunalety, it features no music.

You can download the binary at: http://pouet.net/prod.php?which=53081

The Giana Sisters are back!

Posted by Peter Schraut under NDS

Quote from giana-sisters.com:

“Giana Sisters”, the cult Jump ‘n’ Run game from the 80s is back at last – now on your Nintendo DS! You will lead Giana on her greatest adventure yet and help her find glittering diamonds in a crazy dream world. You and Giana will meet fantastic creatures and have wonderful adventures as you explore over 80 exciting levels together.

Giana’s dream world awaits you!

The Great Giana Sisters for the Commodore 64 was one of my favorite games back then. Now, after 20 years, I can play a completely overhauled version, how great is that?!

Visit the official website at http://www.giana-sisters.com

Continuing my journey to show what 32bit arm instructions devkitARM generates for particular C++ source code snippets, I thought it’s a good idea to compare classes and structs.

It’s not about C++ classes and C structs, but C++ classes and C++ structs!

I always read in several Nintendo DS homebrew related forums, using classes rather than structs in C++ has a dramatic impact on performance and people recommend not to do this.

Is there really a performance problem? Let’s find it out!

The following C++ code was compiled with devkitARM r25 using optimization level -O1, no runtime type information and no exceptions.

What is the difference between a class and struct in C++?

Actually, the only difference is the default access of members:

  • Default access of members in a class is private.
  • Default access of members in a structure or union is public.
  • Default access of a base class is private for classes and public for structures. Unions cannot have base classes.

When you don’t specify any access specifier (public, protected, private), members of a class have private access by default, while members of a struct have public access.

Both, classes and structs, allow to have member functions, virtual member functions, special member functions (ctor, dtor, …), operators, feature inheritance and so on.

Member variable access of a class vs struct

Let’s take a look what 32bit arm instructions are generated for the following C++ code. Since classes and structs are technically the same, the compiler should output identical code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct MyStruct
{
  int x;
};
 
void SetMyStruct(MyStruct *p)
{
  p->x = 2;
}
 
class MyClass
{
public:
  int x;
};
 
void SetMyClass(MyClass *p)
{
  p->x = 2;
}

Instructions for SetMyStruct:

1
2
3
4
5
; the parameter "p" is stored in r0
_Z11SetMyStructP8MyStruct:
  mov  r3, #2        ; r3 = 2
  str  r3, [r0, #0]  ; *(int*)&((char*)r0)[0] = r3
  bx   lr            ; return

Instructions for SetMyClass:

1
2
3
4
5
; the parameter "p" is stored in r0
__Z10SetMyClassP7MyClass:
  mov  r3, #2        ; r3 = 2
  str  r3, [r0, #0]  ; *(int*)&((char*)r0)[0] = r3
  bx   lr            ; return

The function names went through name mangling, that’s why they look so weird. Name mangling is a technique used to solve various problems caused by the need to resolve unique names for programming entities.

Alright, accessing a member variable of a class or struct produces identical code.

non-virtual member function vs function

Let’s take a look at the generated code for member functions of a class vs passing a struct to a function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
struct MyStruct
{
  int x;
};
 
void InitMyStruct(MyStruct *p)
{
  p->x = 2;
}
 
class MyClass
{
public:
  void Init();
 
  int x;
};
 
void MyClass::Init()
{
  this->x = 2;
}

Instructions for InitMyStruct:

1
2
3
4
5
; the parameter "p" is stored in r0
__Z12InitMyStructP8MyStruct:
  mov  r3, #2        ; r3 = 2
  str  r3, [r0, #0]  ; *(int*)&((char*)r0)[0] = r3
  bx   lr            ; return

Instructions for MyClass::Init:

1
2
3
4
5
; "this" is stored in r0
___ZN7MyClass4InitEv:
  mov  r3, #2        ; r3 = 2
  str  r3, [r0, #0]  ; *(int*)&((char*)r0)[0] = r3
  bx   lr            ; return

The member function code is identical to the code of InitMyStruct! Now you should go like “Why is it identical, why has MyClass::Init also a parameter?”

Because the compiler substitudes a hidden parameter to every member function. The parameter is what you know as this keyword. It is passed as first parameter, thus located in register r0 for the arm instruction set.

The same applies to InitMyStruct, it has one parameter that expects a pointer (to a MyStruct object), so it’s the same.

We also see the member function code is not attached to the object as many people claim! Non-virtual member functions are resolved statically. That is, the member function is selected statically (at compile-time) based on the type of the pointer (or reference) to the object.

How a non-virtual member function gets called

Until now, we only analysed what code is generated for the particular functions, but we don’t know how they get called. Let’s take a look at main, where both functions get called.

1
2
3
4
5
6
7
8
9
10
int main(void)
{
  MyStruct myStruct;
  InitMyStruct(&myStruct);
 
  MyClass myClass;
  myClass.Init();
 
  return 0;
}

Instructions generated for main:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
main:
  ; store link-register to stack
  str  lr, [sp, #-4]!
 
  ; move stack pointer by 12 bytes
  ; 4 bytes for the link-register store above
  ; 4 bytes for storage of MyStruct object
  ; 4 bytes for storage of MyClass object
  sub  sp, sp, #12
 
  ; set r0 to start of MyStruct object
  add  r0, sp, #4
 
  ; call InitMyStruct
  ; "myStruct" pointer is stored r0
  bl   _Z12InitMyStructP8MyStruct
 
  ; set r0 to start of MyClass object
  mov  r0, sp
 
  ; call member function Init of MyClass
  ; "myClass" pointer (which becomes "this") is stored in r0
  bl   _ZN7MyClass4InitEv

The code that calls InitMyStruct and myClass.Init is the same. There is no difference, no difference, no …!

How a virtual member function gets called

I’ll show you what’s going on with virtual member function in an upcoming article, stay tuned for that!

Conclusion

  • C++ classes and C++ structs are technically the same.
  • There is no performance impact when calling a non-virtual member function over a function with one parameter.

Follow up material

I recommend to read the topics about classes and inheritance at C++ FAQ Lite in case you want to know more details about classes.

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