DZZ Tutorial Sammlung Teil 1
level: Fortgeschrittener
date: 05.12.2006 00:01
author: elektranox

As the sponsor of the gp2x demo competition, I am ineligible to win a prize, but just for fun I will develop my own demo over the next few months anyway. I\'ll document my progress in a series of articles, in case the things I discover will be of use to other developers. Looking at the task, I definitely want to aim for a 64k demo. Preferably, it would be even smaller than that, because striving for tininess is a cool thing to do in a demo. There\'s nothing wrong with using conventional methods to make a bigger demo, of course, and I hope a lot of people give that a try! Just my personal interest. I\'m not elite enough (yet) to contemplate something like a 4k demo on the gp2x, so I\'ll be satisfied with simply keeping it as small as I can. Other goals: Create some cool graphics, have some music, and use the features of the machine as well as possible. So, what\'s available on the machine that might be fun to use? * two 200mhz processors. That\'s a lot of power and it would be a shame to not put it all to good use. * graphical display. By default, 16 bits of color... but 24 bits could conceivably be available. It might be interesting to play around with that a little bit. * hardware blitter. It could be fun to play around with the capabilities of the blitter. * video decoder. Can any good use be made of the video decoding hardware? * audio. This looks fairly routine but it will at least have to be used properly. So, pretty soon some exploration of these capabilities will be in order. First, though, some thoughts about program size. There are two possible ways to go about keeping the size small: 1) dynamically link to features that can be found on the gp2x itself. the advantage of this approach is that I can leverage some big pieces of functionality in this way. A quick look at libs folder on the gp2x shows the basic standard libraries plus compression, ogg decoding, the extensive SDL library with sound and font support, and png file support. That\'s a lot of stuff! 2) do not use any external libraries -- instead, build all functionality into the program. Approach (1) has some huge advantages obviously, but what are the disadvantages? The only one that springs to mind is that I\'d have to use the particular versions of the libraries that exist on the gp2x firmware releases. So I\'d have to research what versions are available in the different firmware builds and live with that. I can\'t see any other downside. But approach (2) is more interesting to me personally, and might have the advantage of being more technically difficult. Also, if I get married to the SDL that comes with the firmware, it could be rather difficult to do things like use the hardware blitter if I want to. Plus, I\'ve never thought about the issues involved with having no reliance on any library before which means there\'s a bunch of fun (?) stuff to learn. So, having cast aside the stifling comfort of libgcc, libc, libm, libsdl, and other trifles, it\'s time to answer this question: How small of a "hello world" program can I make? It should print out "Hello, world!" to the serial port and cleanly exit back to the gp2x menu. First, a blank program that doesn\'t do anything. To avoid fancy linking, I\'ll use "ld" directly and define my own entry point to stop it from whining about \'main\'. So here\'s my entire first program:
void entry() { }
And to compile it:
arm-linux-gcc -Wall -Werror -O2 -c main.c arm-linux-ld -e entry main.o -static -s -o demo.gpe
Sure enough, it produces an actual program, which crashes if I run it. Not to worry about that for now, I need to be friendly and exit in one of the proper ways. Next, to get some output. This will come in handy later for debugging purposes as the demo gets built. To produce output, I\'ll write the string to file descriptor 1 (standard output), which will send it out the serial port where I can see it. So the linux call I want to make is:
write(1, \"Hello, world!\\n\", strlen(\"Hello, world!\\n\"));
After much googling, experimenting, and fits of foul language, I worked out this routine (dzzstrlen() is a trivial string length computation function needed because I don\'t have a library any more that implements strlen()):
void PrintString(char *pszString) { int nLen; nLen = dzzstrlen(pszString); asm volatile ( \"mov r0, #1\\n\" // stdout \"mov r1, %0\\n\" // the string \"mov r2, %1\\n\" // the length \"swi #0x900004\\n\" // write : // no output : \"r\"(pszString), \"r\"(nLen) // %0 and %1 input args : \"r0\", \"r1\", \"r2\" // registers we clobber ); }
This illustrates the general method for making system calls, which turns out to be pretty easy. Similarly, to restart the menu on exit:
void RestartMenu() { char *pszMenuDir = \"/usr/gp2x\"; char *pszMenuCmd = \"/usr/gp2x/gp2xmenu\"; asm volatile ( \"mov r0, %0\\n\" // directory \"swi #0x90000C\\n\" // chdir \"mov r0, %1\\n\" // program to execute \"mov r1, #0\\n\" // arg 2 = NULL \"mov r2, #0\\n\" // arg 3 = NULL \"swi #0x90000B\\n\" // execve : // no output : \"r\"(pszMenuDir), \"r\"(pszMenuCmd) // %0 and %1 inputs : \"r0\", \"r1\", \"r2\" // registers we clobber ); }
This leaves me with just the following "main" (which I call "entry" just for fun):
void entry() { // print our string PrintString(\"Hello, world!\\n\"); // restart the menu RestartMenu(); }
It works! Size so far of demo.gpe: 652 bytes. In the next installment I\'ll look into getting access to the gp2x screen so I can show off my mad grafix skillz.